xref: /reactos/dll/win32/mshtml/script.c (revision 207a0f52)
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 "mshtml_private.h"
20 
21 #include <activdbg.h>
22 
23 #ifdef _WIN64
24 
25 #define CTXARG_T DWORDLONG
26 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug64Vtbl
27 
28 #define IActiveScriptParse_Release IActiveScriptParse64_Release
29 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
30 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
31 #define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release
32 #define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_64_ParseProcedureText
33 
34 #else
35 
36 #define CTXARG_T DWORD
37 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug32Vtbl
38 
39 #define IActiveScriptParse_Release IActiveScriptParse32_Release
40 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
41 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
42 #define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release
43 #define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_32_ParseProcedureText
44 
45 #endif
46 
47 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
48 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
49 static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
50 static const WCHAR emptyW[] = {0};
51 
52 struct ScriptHost {
53     IActiveScriptSite              IActiveScriptSite_iface;
54     IActiveScriptSiteInterruptPoll IActiveScriptSiteInterruptPoll_iface;
55     IActiveScriptSiteWindow        IActiveScriptSiteWindow_iface;
56     IActiveScriptSiteUIControl     IActiveScriptSiteUIControl_iface;
57     IActiveScriptSiteDebug         IActiveScriptSiteDebug_iface;
58     IServiceProvider               IServiceProvider_iface;
59 
60     LONG ref;
61 
62     IActiveScript *script;
63     IActiveScriptParse *parse;
64     IActiveScriptParseProcedure2 *parse_proc;
65 
66     SCRIPTSTATE script_state;
67 
68     HTMLInnerWindow *window;
69 
70     GUID guid;
71     struct list entry;
72 };
73 
set_script_prop(ScriptHost * script_host,DWORD property,VARIANT * val)74 static void set_script_prop(ScriptHost *script_host, DWORD property, VARIANT *val)
75 {
76     IActiveScriptProperty *script_prop;
77     HRESULT hres;
78 
79     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty,
80             (void**)&script_prop);
81     if(FAILED(hres)) {
82         WARN("Could not get IActiveScriptProperty iface: %08x\n", hres);
83         return;
84     }
85 
86     hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
87     IActiveScriptProperty_Release(script_prop);
88     if(FAILED(hres))
89         WARN("SetProperty(%x) failed: %08x\n", property, hres);
90 }
91 
init_script_engine(ScriptHost * script_host)92 static BOOL init_script_engine(ScriptHost *script_host)
93 {
94     IObjectSafety *safety;
95     SCRIPTSTATE state;
96     DWORD supported_opts=0, enabled_opts=0;
97     VARIANT var;
98     HRESULT hres;
99 
100     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
101     if(FAILED(hres)) {
102         WARN("Could not get IActiveScriptHost: %08x\n", hres);
103         return FALSE;
104     }
105 
106     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
107     if(FAILED(hres)) {
108         FIXME("Could not get IObjectSafety: %08x\n", hres);
109         return FALSE;
110     }
111 
112     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
113     if(FAILED(hres)) {
114         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
115     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
116         FIXME("INTERFACE_USES_DISPEX is not supported\n");
117     }else {
118         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
119                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
120                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
121         if(FAILED(hres))
122             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
123     }
124 
125     IObjectSafety_Release(safety);
126     if(FAILED(hres))
127         return FALSE;
128 
129     V_VT(&var) = VT_I4;
130     V_I4(&var) = 1;
131     set_script_prop(script_host, SCRIPTPROP_INVOKEVERSIONING, &var);
132 
133     V_VT(&var) = VT_BOOL;
134     V_BOOL(&var) = VARIANT_TRUE;
135     set_script_prop(script_host, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
136 
137     hres = IActiveScriptParse_InitNew(script_host->parse);
138     if(FAILED(hres)) {
139         WARN("InitNew failed: %08x\n", hres);
140         return FALSE;
141     }
142 
143     hres = IActiveScript_SetScriptSite(script_host->script, &script_host->IActiveScriptSite_iface);
144     if(FAILED(hres)) {
145         WARN("SetScriptSite failed: %08x\n", hres);
146         IActiveScript_Close(script_host->script);
147         return FALSE;
148     }
149 
150     hres = IActiveScript_GetScriptState(script_host->script, &state);
151     if(FAILED(hres))
152         WARN("GetScriptState failed: %08x\n", hres);
153     else if(state != SCRIPTSTATE_INITIALIZED)
154         FIXME("state = %x\n", state);
155 
156     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
157     if(FAILED(hres)) {
158         WARN("Starting script failed: %08x\n", hres);
159         return FALSE;
160     }
161 
162     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
163             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
164     if(SUCCEEDED(hres)) {
165         V_VT(&var) = VT_BOOL;
166         V_BOOL(&var) = VARIANT_TRUE;
167         set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
168     }else {
169        WARN("AddNamedItem failed: %08x\n", hres);
170     }
171 
172     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
173                                         (void**)&script_host->parse_proc);
174     if(FAILED(hres)) {
175         /* FIXME: QI for IActiveScriptParseProcedure */
176         WARN("Could not get IActiveScriptParseProcedure iface: %08x\n", hres);
177     }
178 
179     return TRUE;
180 }
181 
release_script_engine(ScriptHost * This)182 static void release_script_engine(ScriptHost *This)
183 {
184     if(!This->script)
185         return;
186 
187     switch(This->script_state) {
188     case SCRIPTSTATE_CONNECTED:
189         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
190 
191     case SCRIPTSTATE_STARTED:
192     case SCRIPTSTATE_DISCONNECTED:
193     case SCRIPTSTATE_INITIALIZED:
194         IActiveScript_Close(This->script);
195 
196     default:
197         if(This->parse_proc) {
198             IActiveScriptParseProcedure2_Release(This->parse_proc);
199             This->parse_proc = NULL;
200         }
201 
202         if(This->parse) {
203             IActiveScriptParse_Release(This->parse);
204             This->parse = NULL;
205         }
206     }
207 
208     IActiveScript_Release(This->script);
209     This->script = NULL;
210     This->script_state = SCRIPTSTATE_UNINITIALIZED;
211 }
212 
connect_scripts(HTMLInnerWindow * window)213 void connect_scripts(HTMLInnerWindow *window)
214 {
215     ScriptHost *iter;
216 
217     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
218         if(iter->script_state == SCRIPTSTATE_STARTED)
219             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
220     }
221 }
222 
impl_from_IActiveScriptSite(IActiveScriptSite * iface)223 static inline ScriptHost *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
224 {
225     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSite_iface);
226 }
227 
ActiveScriptSite_QueryInterface(IActiveScriptSite * iface,REFIID riid,void ** ppv)228 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
229 {
230     ScriptHost *This = impl_from_IActiveScriptSite(iface);
231 
232     *ppv = NULL;
233 
234     if(IsEqualGUID(&IID_IUnknown, riid)) {
235         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
236         *ppv = &This->IActiveScriptSite_iface;
237     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
238         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
239         *ppv = &This->IActiveScriptSite_iface;
240     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
241         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
242         *ppv = &This->IActiveScriptSiteInterruptPoll_iface;
243     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
244         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
245         *ppv = &This->IActiveScriptSiteWindow_iface;
246     }else if(IsEqualGUID(&IID_IActiveScriptSiteUIControl, riid)) {
247         TRACE("(%p)->(IID_IActiveScriptSiteUIControl %p)\n", This, ppv);
248         *ppv = &This->IActiveScriptSiteUIControl_iface;
249     }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug, riid)) {
250         TRACE("(%p)->(IID_IActiveScriptSiteDebug %p)\n", This, ppv);
251         *ppv = &This->IActiveScriptSiteDebug_iface;
252     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
253         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
254         *ppv = &This->IServiceProvider_iface;
255     }else if(IsEqualGUID(&IID_ICanHandleException, riid)) {
256         TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
257         return E_NOINTERFACE;
258     }else {
259         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
260         return E_NOINTERFACE;
261     }
262 
263     IUnknown_AddRef((IUnknown*)*ppv);
264     return S_OK;
265 }
266 
ActiveScriptSite_AddRef(IActiveScriptSite * iface)267 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
268 {
269     ScriptHost *This = impl_from_IActiveScriptSite(iface);
270     LONG ref = InterlockedIncrement(&This->ref);
271 
272     TRACE("(%p) ref=%d\n", This, ref);
273 
274     return ref;
275 }
276 
ActiveScriptSite_Release(IActiveScriptSite * iface)277 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
278 {
279     ScriptHost *This = impl_from_IActiveScriptSite(iface);
280     LONG ref = InterlockedDecrement(&This->ref);
281 
282     TRACE("(%p) ref=%d\n", This, ref);
283 
284     if(!ref) {
285         release_script_engine(This);
286         if(This->window)
287             list_remove(&This->entry);
288         heap_free(This);
289     }
290 
291     return ref;
292 }
293 
ActiveScriptSite_GetLCID(IActiveScriptSite * iface,LCID * plcid)294 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
295 {
296     ScriptHost *This = impl_from_IActiveScriptSite(iface);
297 
298     TRACE("(%p)->(%p)\n", This, plcid);
299 
300     *plcid = GetUserDefaultLCID();
301     return S_OK;
302 }
303 
ActiveScriptSite_GetItemInfo(IActiveScriptSite * iface,LPCOLESTR pstrName,DWORD dwReturnMask,IUnknown ** ppiunkItem,ITypeInfo ** ppti)304 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
305         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
306 {
307     ScriptHost *This = impl_from_IActiveScriptSite(iface);
308 
309     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
310 
311     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
312         FIXME("Unsupported mask %x\n", dwReturnMask);
313         return E_NOTIMPL;
314     }
315 
316     *ppiunkItem = NULL;
317 
318     if(strcmpW(pstrName, windowW))
319         return DISP_E_MEMBERNOTFOUND;
320 
321     if(!This->window)
322         return E_FAIL;
323 
324     /* FIXME: Return proxy object */
325     *ppiunkItem = (IUnknown*)&This->window->base.IHTMLWindow2_iface;
326     IUnknown_AddRef(*ppiunkItem);
327 
328     return S_OK;
329 }
330 
ActiveScriptSite_GetDocVersionString(IActiveScriptSite * iface,BSTR * pbstrVersion)331 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
332 {
333     ScriptHost *This = impl_from_IActiveScriptSite(iface);
334     FIXME("(%p)->(%p)\n", This, pbstrVersion);
335     return E_NOTIMPL;
336 }
337 
ActiveScriptSite_OnScriptTerminate(IActiveScriptSite * iface,const VARIANT * pvarResult,const EXCEPINFO * pexcepinfo)338 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
339         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
340 {
341     ScriptHost *This = impl_from_IActiveScriptSite(iface);
342     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
343     return E_NOTIMPL;
344 }
345 
ActiveScriptSite_OnStateChange(IActiveScriptSite * iface,SCRIPTSTATE ssScriptState)346 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
347 {
348     ScriptHost *This = impl_from_IActiveScriptSite(iface);
349 
350     TRACE("(%p)->(%x)\n", This, ssScriptState);
351 
352     This->script_state = ssScriptState;
353     return S_OK;
354 }
355 
ActiveScriptSite_OnScriptError(IActiveScriptSite * iface,IActiveScriptError * pscripterror)356 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
357 {
358     ScriptHost *This = impl_from_IActiveScriptSite(iface);
359     FIXME("(%p)->(%p)\n", This, pscripterror);
360     return E_NOTIMPL;
361 }
362 
ActiveScriptSite_OnEnterScript(IActiveScriptSite * iface)363 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
364 {
365     ScriptHost *This = impl_from_IActiveScriptSite(iface);
366 
367     TRACE("(%p)->()\n", This);
368 
369     return S_OK;
370 }
371 
ActiveScriptSite_OnLeaveScript(IActiveScriptSite * iface)372 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
373 {
374     ScriptHost *This = impl_from_IActiveScriptSite(iface);
375 
376     TRACE("(%p)->()\n", This);
377 
378     return S_OK;
379 }
380 
381 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
382     ActiveScriptSite_QueryInterface,
383     ActiveScriptSite_AddRef,
384     ActiveScriptSite_Release,
385     ActiveScriptSite_GetLCID,
386     ActiveScriptSite_GetItemInfo,
387     ActiveScriptSite_GetDocVersionString,
388     ActiveScriptSite_OnScriptTerminate,
389     ActiveScriptSite_OnStateChange,
390     ActiveScriptSite_OnScriptError,
391     ActiveScriptSite_OnEnterScript,
392     ActiveScriptSite_OnLeaveScript
393 };
394 
impl_from_IActiveScriptSiteInterruptPoll(IActiveScriptSiteInterruptPoll * iface)395 static inline ScriptHost *impl_from_IActiveScriptSiteInterruptPoll(IActiveScriptSiteInterruptPoll *iface)
396 {
397     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteInterruptPoll_iface);
398 }
399 
ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll * iface,REFIID riid,void ** ppv)400 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
401         REFIID riid, void **ppv)
402 {
403     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
404     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
405 }
406 
ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll * iface)407 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
408 {
409     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
410     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
411 }
412 
ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll * iface)413 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
414 {
415     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
416     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
417 }
418 
ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll * iface)419 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
420 {
421     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
422 
423     TRACE("(%p)\n", This);
424 
425     return S_OK;
426 }
427 
428 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
429     ActiveScriptSiteInterruptPoll_QueryInterface,
430     ActiveScriptSiteInterruptPoll_AddRef,
431     ActiveScriptSiteInterruptPoll_Release,
432     ActiveScriptSiteInterruptPoll_QueryContinue
433 };
434 
impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow * iface)435 static inline ScriptHost *impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow *iface)
436 {
437     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteWindow_iface);
438 }
439 
ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow * iface,REFIID riid,void ** ppv)440 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
441         REFIID riid, void **ppv)
442 {
443     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
444     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
445 }
446 
ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow * iface)447 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
448 {
449     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
450     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
451 }
452 
ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow * iface)453 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
454 {
455     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
456     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
457 }
458 
ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow * iface,HWND * phwnd)459 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
460 {
461     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
462 
463     TRACE("(%p)->(%p)\n", This, phwnd);
464 
465     if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->doc_obj)
466         return E_UNEXPECTED;
467 
468     *phwnd = This->window->base.outer_window->doc_obj->hwnd;
469     return S_OK;
470 }
471 
ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow * iface,BOOL fEnable)472 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
473 {
474     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
475     FIXME("(%p)->(%x)\n", This, fEnable);
476     return S_OK;
477 }
478 
479 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
480     ActiveScriptSiteWindow_QueryInterface,
481     ActiveScriptSiteWindow_AddRef,
482     ActiveScriptSiteWindow_Release,
483     ActiveScriptSiteWindow_GetWindow,
484     ActiveScriptSiteWindow_EnableModeless
485 };
486 
impl_from_IActiveScriptSiteUIControl(IActiveScriptSiteUIControl * iface)487 static inline ScriptHost *impl_from_IActiveScriptSiteUIControl(IActiveScriptSiteUIControl *iface)
488 {
489     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteUIControl_iface);
490 }
491 
ActiveScriptSiteUIControl_QueryInterface(IActiveScriptSiteUIControl * iface,REFIID riid,void ** ppv)492 static HRESULT WINAPI ActiveScriptSiteUIControl_QueryInterface(IActiveScriptSiteUIControl *iface, REFIID riid, void **ppv)
493 {
494     ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
495     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
496 }
497 
ActiveScriptSiteUIControl_AddRef(IActiveScriptSiteUIControl * iface)498 static ULONG WINAPI ActiveScriptSiteUIControl_AddRef(IActiveScriptSiteUIControl *iface)
499 {
500     ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
501     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
502 }
503 
ActiveScriptSiteUIControl_Release(IActiveScriptSiteUIControl * iface)504 static ULONG WINAPI ActiveScriptSiteUIControl_Release(IActiveScriptSiteUIControl *iface)
505 {
506     ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
507     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
508 }
509 
ActiveScriptSiteUIControl_GetUIBehavior(IActiveScriptSiteUIControl * iface,SCRIPTUICITEM UicItem,SCRIPTUICHANDLING * pUicHandling)510 static HRESULT WINAPI ActiveScriptSiteUIControl_GetUIBehavior(IActiveScriptSiteUIControl *iface, SCRIPTUICITEM UicItem,
511         SCRIPTUICHANDLING *pUicHandling)
512 {
513     ScriptHost *This = impl_from_IActiveScriptSiteUIControl(iface);
514 
515     WARN("(%p)->(%d %p) semi-stub\n", This, UicItem, pUicHandling);
516 
517     *pUicHandling = SCRIPTUICHANDLING_ALLOW;
518     return S_OK;
519 }
520 
521 static const IActiveScriptSiteUIControlVtbl ActiveScriptSiteUIControlVtbl = {
522     ActiveScriptSiteUIControl_QueryInterface,
523     ActiveScriptSiteUIControl_AddRef,
524     ActiveScriptSiteUIControl_Release,
525     ActiveScriptSiteUIControl_GetUIBehavior
526 };
527 
impl_from_IActiveScriptSiteDebug(IActiveScriptSiteDebug * iface)528 static inline ScriptHost *impl_from_IActiveScriptSiteDebug(IActiveScriptSiteDebug *iface)
529 {
530     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteDebug_iface);
531 }
532 
ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug * iface,REFIID riid,void ** ppv)533 static HRESULT WINAPI ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug *iface,
534         REFIID riid, void **ppv)
535 {
536     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
537     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
538 }
539 
ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug * iface)540 static ULONG WINAPI ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug *iface)
541 {
542     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
543     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
544 }
545 
ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug * iface)546 static ULONG WINAPI ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug *iface)
547 {
548     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
549     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
550 }
551 
ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug * iface,CTXARG_T dwSourceContext,ULONG uCharacterOffset,ULONG uNumChars,IDebugDocumentContext ** ppsc)552 static HRESULT WINAPI ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug *iface,
553             CTXARG_T dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
554 {
555     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
556     FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(dwSourceContext), uCharacterOffset,
557           uNumChars, ppsc);
558     return E_NOTIMPL;
559 }
560 
ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug * iface,IDebugApplication ** ppda)561 static HRESULT WINAPI ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug *iface, IDebugApplication **ppda)
562 {
563     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
564     FIXME("(%p)->(%p)\n", This, ppda);
565     return E_NOTIMPL;
566 }
567 
ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug * iface,IDebugApplicationNode ** ppdanRoot)568 static HRESULT WINAPI ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug *iface,
569             IDebugApplicationNode **ppdanRoot)
570 {
571     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
572     FIXME("(%p)->(%p)\n", This, ppdanRoot);
573     return E_NOTIMPL;
574 }
575 
ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug * iface,IActiveScriptErrorDebug * pErrorDebug,BOOL * pfEnterDebugger,BOOL * pfCallOnScriptErrorWhenContinuing)576 static HRESULT WINAPI ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug *iface,
577             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
578 {
579     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
580     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
581     return E_NOTIMPL;
582 }
583 
584 static const IActiveScriptSiteDebugVtbl ActiveScriptSiteDebugVtbl = {
585     ActiveScriptSiteDebug_QueryInterface,
586     ActiveScriptSiteDebug_AddRef,
587     ActiveScriptSiteDebug_Release,
588     ActiveScriptSiteDebug_GetDocumentContextFromPosition,
589     ActiveScriptSiteDebug_GetApplication,
590     ActiveScriptSiteDebug_GetRootApplicationNode,
591     ActiveScriptSiteDebug_OnScriptErrorDebug
592 };
593 
impl_from_IServiceProvider(IServiceProvider * iface)594 static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface)
595 {
596     return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface);
597 }
598 
ASServiceProvider_QueryInterface(IServiceProvider * iface,REFIID riid,void ** ppv)599 static HRESULT WINAPI ASServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
600 {
601     ScriptHost *This = impl_from_IServiceProvider(iface);
602     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
603 }
604 
ASServiceProvider_AddRef(IServiceProvider * iface)605 static ULONG WINAPI ASServiceProvider_AddRef(IServiceProvider *iface)
606 {
607     ScriptHost *This = impl_from_IServiceProvider(iface);
608     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
609 }
610 
ASServiceProvider_Release(IServiceProvider * iface)611 static ULONG WINAPI ASServiceProvider_Release(IServiceProvider *iface)
612 {
613     ScriptHost *This = impl_from_IServiceProvider(iface);
614     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
615 }
616 
ASServiceProvider_QueryService(IServiceProvider * iface,REFGUID guidService,REFIID riid,void ** ppv)617 static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
618         REFIID riid, void **ppv)
619 {
620     ScriptHost *This = impl_from_IServiceProvider(iface);
621 
622     if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) {
623         TRACE("(%p)->(SID_SInternetHostSecurityManager)\n", This);
624 
625         if(!This->window || !This->window->doc)
626             return E_NOINTERFACE;
627 
628         return IInternetHostSecurityManager_QueryInterface(&This->window->doc->IInternetHostSecurityManager_iface,
629                 riid, ppv);
630     }
631 
632     if(IsEqualGUID(&SID_SContainerDispatch, guidService)) {
633         TRACE("(%p)->(SID_SContainerDispatch)\n", This);
634 
635         if(!This->window || !This->window->doc)
636             return E_NOINTERFACE;
637 
638         return IHTMLDocument2_QueryInterface(&This->window->doc->basedoc.IHTMLDocument2_iface, riid, ppv);
639     }
640 
641     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
642     return E_NOINTERFACE;
643 }
644 
645 static const IServiceProviderVtbl ASServiceProviderVtbl = {
646     ASServiceProvider_QueryInterface,
647     ASServiceProvider_AddRef,
648     ASServiceProvider_Release,
649     ASServiceProvider_QueryService
650 };
651 
create_script_host(HTMLInnerWindow * window,const GUID * guid)652 static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid)
653 {
654     ScriptHost *ret;
655     HRESULT hres;
656 
657     ret = heap_alloc_zero(sizeof(*ret));
658     if(!ret)
659         return NULL;
660 
661     ret->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl;
662     ret->IActiveScriptSiteInterruptPoll_iface.lpVtbl = &ActiveScriptSiteInterruptPollVtbl;
663     ret->IActiveScriptSiteWindow_iface.lpVtbl = &ActiveScriptSiteWindowVtbl;
664     ret->IActiveScriptSiteUIControl_iface.lpVtbl = &ActiveScriptSiteUIControlVtbl;
665     ret->IActiveScriptSiteDebug_iface.lpVtbl = &ActiveScriptSiteDebugVtbl;
666     ret->IServiceProvider_iface.lpVtbl = &ASServiceProviderVtbl;
667     ret->ref = 1;
668     ret->window = window;
669     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
670 
671     ret->guid = *guid;
672     list_add_tail(&window->script_hosts, &ret->entry);
673 
674     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
675             &IID_IActiveScript, (void**)&ret->script);
676     if(FAILED(hres))
677         WARN("Could not load script engine: %08x\n", hres);
678     else if(!init_script_engine(ret))
679         release_script_engine(ret);
680 
681     return ret;
682 }
683 
684 typedef struct {
685     task_t header;
686     HTMLScriptElement *elem;
687 } fire_readystatechange_task_t;
688 
fire_readystatechange_proc(task_t * _task)689 static void fire_readystatechange_proc(task_t *_task)
690 {
691     fire_readystatechange_task_t *task = (fire_readystatechange_task_t*)_task;
692 
693     if(!task->elem->pending_readystatechange_event)
694         return;
695 
696     task->elem->pending_readystatechange_event = FALSE;
697     fire_event(task->elem->element.node.doc, EVENTID_READYSTATECHANGE, FALSE, task->elem->element.node.nsnode, NULL, NULL);
698 }
699 
fire_readystatechange_task_destr(task_t * _task)700 static void fire_readystatechange_task_destr(task_t *_task)
701 {
702     fire_readystatechange_task_t *task = (fire_readystatechange_task_t*)_task;
703 
704     IHTMLScriptElement_Release(&task->elem->IHTMLScriptElement_iface);
705 }
706 
set_script_elem_readystate(HTMLScriptElement * script_elem,READYSTATE readystate)707 static void set_script_elem_readystate(HTMLScriptElement *script_elem, READYSTATE readystate)
708 {
709     script_elem->readystate = readystate;
710 
711     if(readystate != READYSTATE_INTERACTIVE) {
712         if(!script_elem->element.node.doc->window->parser_callback_cnt) {
713             fire_readystatechange_task_t *task;
714             HRESULT hres;
715 
716             if(script_elem->pending_readystatechange_event)
717                 return;
718 
719             task = heap_alloc(sizeof(*task));
720             if(!task)
721                 return;
722 
723             IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
724             task->elem = script_elem;
725 
726             hres = push_task(&task->header, fire_readystatechange_proc, fire_readystatechange_task_destr,
727                     script_elem->element.node.doc->window->task_magic);
728             if(SUCCEEDED(hres))
729                 script_elem->pending_readystatechange_event = TRUE;
730         }else {
731             script_elem->pending_readystatechange_event = FALSE;
732             fire_event(script_elem->element.node.doc, EVENTID_READYSTATECHANGE, FALSE,
733                     script_elem->element.node.nsnode, NULL, NULL);
734         }
735     }
736 }
737 
parse_elem_text(ScriptHost * script_host,HTMLScriptElement * script_elem,LPCWSTR text)738 static void parse_elem_text(ScriptHost *script_host, HTMLScriptElement *script_elem, LPCWSTR text)
739 {
740     EXCEPINFO excepinfo;
741     VARIANT var;
742     HRESULT hres;
743 
744     TRACE("%s\n", debugstr_w(text));
745 
746     set_script_elem_readystate(script_elem, READYSTATE_INTERACTIVE);
747 
748     VariantInit(&var);
749     memset(&excepinfo, 0, sizeof(excepinfo));
750     TRACE(">>>\n");
751     hres = IActiveScriptParse_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
752                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
753                                               &var, &excepinfo);
754     if(SUCCEEDED(hres))
755         TRACE("<<<\n");
756     else
757         WARN("<<< %08x\n", hres);
758 
759 }
760 
761 typedef struct {
762     BSCallback bsc;
763 
764     HTMLScriptElement *script_elem;
765     DWORD scheme;
766 
767     DWORD size;
768     char *buf;
769     HRESULT hres;
770 } ScriptBSC;
771 
impl_from_BSCallback(BSCallback * iface)772 static inline ScriptBSC *impl_from_BSCallback(BSCallback *iface)
773 {
774     return CONTAINING_RECORD(iface, ScriptBSC, bsc);
775 }
776 
ScriptBSC_destroy(BSCallback * bsc)777 static void ScriptBSC_destroy(BSCallback *bsc)
778 {
779     ScriptBSC *This = impl_from_BSCallback(bsc);
780 
781     if(This->script_elem) {
782         IHTMLScriptElement_Release(&This->script_elem->IHTMLScriptElement_iface);
783         This->script_elem = NULL;
784     }
785 
786     heap_free(This->buf);
787     heap_free(This);
788 }
789 
ScriptBSC_init_bindinfo(BSCallback * bsc)790 static HRESULT ScriptBSC_init_bindinfo(BSCallback *bsc)
791 {
792     return S_OK;
793 }
794 
ScriptBSC_start_binding(BSCallback * bsc)795 static HRESULT ScriptBSC_start_binding(BSCallback *bsc)
796 {
797     ScriptBSC *This = impl_from_BSCallback(bsc);
798 
799     /* FIXME: We should find a better to decide if 'loading' state is supposed to be used by the protocol. */
800     if(This->scheme == URL_SCHEME_HTTPS || This->scheme == URL_SCHEME_HTTP)
801         set_script_elem_readystate(This->script_elem, READYSTATE_LOADING);
802 
803     return S_OK;
804 }
805 
ScriptBSC_stop_binding(BSCallback * bsc,HRESULT result)806 static HRESULT ScriptBSC_stop_binding(BSCallback *bsc, HRESULT result)
807 {
808     ScriptBSC *This = impl_from_BSCallback(bsc);
809 
810     This->hres = result;
811 
812     if(SUCCEEDED(result)) {
813         if(This->script_elem->readystate == READYSTATE_LOADING)
814             set_script_elem_readystate(This->script_elem, READYSTATE_LOADED);
815     }else {
816         FIXME("binding failed %08x\n", result);
817         heap_free(This->buf);
818         This->buf = NULL;
819         This->size = 0;
820     }
821 
822     IHTMLScriptElement_Release(&This->script_elem->IHTMLScriptElement_iface);
823     This->script_elem = NULL;
824     return S_OK;
825 }
826 
ScriptBSC_read_data(BSCallback * bsc,IStream * stream)827 static HRESULT ScriptBSC_read_data(BSCallback *bsc, IStream *stream)
828 {
829     ScriptBSC *This = impl_from_BSCallback(bsc);
830     DWORD readed;
831     HRESULT hres;
832 
833     if(!This->buf) {
834         This->buf = heap_alloc(128);
835         if(!This->buf)
836             return E_OUTOFMEMORY;
837         This->size = 128;
838     }
839 
840     do {
841         if(This->bsc.readed >= This->size) {
842             void *new_buf;
843             new_buf = heap_realloc(This->buf, This->size << 1);
844             if(!new_buf)
845                 return E_OUTOFMEMORY;
846             This->size <<= 1;
847             This->buf = new_buf;
848         }
849 
850         hres = read_stream(&This->bsc, stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
851     }while(hres == S_OK);
852 
853     return S_OK;
854 }
855 
ScriptBSC_on_progress(BSCallback * bsc,ULONG status_code,LPCWSTR status_text)856 static HRESULT ScriptBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
857 {
858     return S_OK;
859 }
860 
ScriptBSC_on_response(BSCallback * bsc,DWORD response_code,LPCWSTR response_headers)861 static HRESULT ScriptBSC_on_response(BSCallback *bsc, DWORD response_code,
862         LPCWSTR response_headers)
863 {
864     return S_OK;
865 }
866 
ScriptBSC_beginning_transaction(BSCallback * bsc,WCHAR ** additional_headers)867 static HRESULT ScriptBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
868 {
869     return S_FALSE;
870 }
871 
872 static const BSCallbackVtbl ScriptBSCVtbl = {
873     ScriptBSC_destroy,
874     ScriptBSC_init_bindinfo,
875     ScriptBSC_start_binding,
876     ScriptBSC_stop_binding,
877     ScriptBSC_read_data,
878     ScriptBSC_on_progress,
879     ScriptBSC_on_response,
880     ScriptBSC_beginning_transaction
881 };
882 
883 
bind_script_to_text(HTMLInnerWindow * window,IUri * uri,HTMLScriptElement * script_elem,WCHAR ** ret)884 static HRESULT bind_script_to_text(HTMLInnerWindow *window, IUri *uri, HTMLScriptElement *script_elem, WCHAR **ret)
885 {
886     UINT cp = CP_UTF8;
887     ScriptBSC *bsc;
888     IMoniker *mon;
889     WCHAR *text;
890     HRESULT hres;
891 
892     hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
893     if(FAILED(hres))
894         return hres;
895 
896     bsc = heap_alloc_zero(sizeof(*bsc));
897     if(!bsc) {
898         IMoniker_Release(mon);
899         return E_OUTOFMEMORY;
900     }
901 
902     init_bscallback(&bsc->bsc, &ScriptBSCVtbl, mon, 0);
903     IMoniker_Release(mon);
904     bsc->hres = E_FAIL;
905 
906     hres = IUri_GetScheme(uri, &bsc->scheme);
907     if(FAILED(hres))
908         bsc->scheme = URL_SCHEME_UNKNOWN;
909 
910     IHTMLScriptElement_AddRef(&script_elem->IHTMLScriptElement_iface);
911     bsc->script_elem = script_elem;
912 
913     hres = start_binding(window, &bsc->bsc, NULL);
914     if(SUCCEEDED(hres))
915         hres = bsc->hres;
916     if(FAILED(hres)) {
917         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
918         return hres;
919     }
920 
921     if(!bsc->bsc.readed) {
922         *ret = NULL;
923         return S_OK;
924     }
925 
926     switch(bsc->bsc.bom) {
927     case BOM_UTF16:
928         if(bsc->bsc.readed % sizeof(WCHAR)) {
929             FIXME("The buffer is not a valid utf16 string\n");
930             hres = E_FAIL;
931             break;
932         }
933 
934         text = heap_alloc(bsc->bsc.readed+sizeof(WCHAR));
935         if(!text) {
936             hres = E_OUTOFMEMORY;
937             break;
938         }
939 
940         memcpy(text, bsc->buf, bsc->bsc.readed);
941         text[bsc->bsc.readed/sizeof(WCHAR)] = 0;
942         break;
943 
944     default:
945         /* FIXME: Try to use charset from HTTP headers first */
946         cp = get_document_charset(window->doc);
947         /* fall through */
948     case BOM_UTF8: {
949         DWORD len;
950 
951         len = MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.readed, NULL, 0);
952         text = heap_alloc((len+1)*sizeof(WCHAR));
953         if(!text) {
954             hres = E_OUTOFMEMORY;
955             break;
956         }
957 
958         MultiByteToWideChar(cp, 0, bsc->buf, bsc->bsc.readed, text, len);
959         text[len] = 0;
960     }
961     }
962 
963     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
964     if(FAILED(hres))
965         return hres;
966 
967     *ret = text;
968     return S_OK;
969 }
970 
parse_extern_script(ScriptHost * script_host,HTMLScriptElement * script_elem,LPCWSTR src)971 static void parse_extern_script(ScriptHost *script_host, HTMLScriptElement *script_elem, LPCWSTR src)
972 {
973     WCHAR *text;
974     IUri *uri;
975     HRESULT hres;
976 
977     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
978 
979     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
980         src += sizeof(wine_schemaW)/sizeof(WCHAR);
981 
982     hres = create_uri(src, 0, &uri);
983     if(FAILED(hres))
984         return;
985 
986     hres = bind_script_to_text(script_host->window, uri, script_elem, &text);
987     IUri_Release(uri);
988     if(FAILED(hres) || !text)
989         return;
990 
991     parse_elem_text(script_host, script_elem, text);
992 
993     heap_free(text);
994 }
995 
parse_inline_script(ScriptHost * script_host,HTMLScriptElement * script_elem)996 static void parse_inline_script(ScriptHost *script_host, HTMLScriptElement *script_elem)
997 {
998     const PRUnichar *text;
999     nsAString text_str;
1000     nsresult nsres;
1001 
1002     nsAString_Init(&text_str, NULL);
1003     nsres = nsIDOMHTMLScriptElement_GetText(script_elem->nsscript, &text_str);
1004     nsAString_GetData(&text_str, &text);
1005 
1006     if(NS_FAILED(nsres)) {
1007         ERR("GetText failed: %08x\n", nsres);
1008     }else if(*text) {
1009         parse_elem_text(script_host, script_elem, text);
1010     }
1011 
1012     nsAString_Finish(&text_str);
1013 }
1014 
parse_script_elem(ScriptHost * script_host,HTMLScriptElement * script_elem)1015 static void parse_script_elem(ScriptHost *script_host, HTMLScriptElement *script_elem)
1016 {
1017     nsAString src_str, event_str;
1018     const PRUnichar *src;
1019     nsresult nsres;
1020 
1021     nsAString_Init(&event_str, NULL);
1022     nsres = nsIDOMHTMLScriptElement_GetEvent(script_elem->nsscript, &event_str);
1023     if(NS_SUCCEEDED(nsres)) {
1024         const PRUnichar *event;
1025 
1026         nsAString_GetData(&event_str, &event);
1027         if(*event) {
1028             TRACE("deferring event %s script evaluation\n", debugstr_w(event));
1029             nsAString_Finish(&event_str);
1030             return;
1031         }
1032     }else {
1033         ERR("GetEvent failed: %08x\n", nsres);
1034     }
1035     nsAString_Finish(&event_str);
1036 
1037     nsAString_Init(&src_str, NULL);
1038     nsres = nsIDOMHTMLScriptElement_GetSrc(script_elem->nsscript, &src_str);
1039     nsAString_GetData(&src_str, &src);
1040 
1041     if(NS_FAILED(nsres)) {
1042         ERR("GetSrc failed: %08x\n", nsres);
1043     }else if(*src) {
1044         script_elem->parsed = TRUE;
1045         parse_extern_script(script_host, script_elem, src);
1046     }else {
1047         parse_inline_script(script_host, script_elem);
1048     }
1049 
1050     nsAString_Finish(&src_str);
1051 
1052     set_script_elem_readystate(script_elem, READYSTATE_COMPLETE);
1053 }
1054 
get_default_script_guid(HTMLInnerWindow * window)1055 static GUID get_default_script_guid(HTMLInnerWindow *window)
1056 {
1057     /* If not specified, we should use very first script host that was created for the page (or JScript if none) */
1058     return list_empty(&window->script_hosts)
1059         ? CLSID_JScript
1060         : LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry)->guid;
1061 }
1062 
get_guid_from_type(LPCWSTR type,GUID * guid)1063 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
1064 {
1065     const WCHAR text_javascriptW[] =
1066         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
1067     const WCHAR text_jscriptW[] =
1068         {'t','e','x','t','/','j','s','c','r','i','p','t',0};
1069     const WCHAR text_vbscriptW[] =
1070         {'t','e','x','t','/','v','b','s','c','r','i','p','t',0};
1071 
1072     /* FIXME: Handle more types */
1073     if(!strcmpiW(type, text_javascriptW) || !strcmpiW(type, text_jscriptW)) {
1074         *guid = CLSID_JScript;
1075     }else if(!strcmpiW(type, text_vbscriptW)) {
1076         *guid = CLSID_VBScript;
1077     }else {
1078         FIXME("Unknown type %s\n", debugstr_w(type));
1079         return FALSE;
1080     }
1081 
1082     return TRUE;
1083 }
1084 
get_guid_from_language(LPCWSTR type,GUID * guid)1085 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
1086 {
1087     HRESULT hres;
1088 
1089     hres = CLSIDFromProgID(type, guid);
1090     if(FAILED(hres))
1091         return FALSE;
1092 
1093     /* FIXME: Check CATID_ActiveScriptParse */
1094 
1095     return TRUE;
1096 }
1097 
get_script_guid(HTMLInnerWindow * window,nsIDOMHTMLScriptElement * nsscript,GUID * guid)1098 static BOOL get_script_guid(HTMLInnerWindow *window, nsIDOMHTMLScriptElement *nsscript, GUID *guid)
1099 {
1100     nsIDOMHTMLElement *nselem;
1101     const PRUnichar *language;
1102     nsAString val_str;
1103     BOOL ret = FALSE;
1104     nsresult nsres;
1105 
1106     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
1107 
1108     nsAString_Init(&val_str, NULL);
1109 
1110     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
1111     if(NS_SUCCEEDED(nsres)) {
1112         const PRUnichar *type;
1113 
1114         nsAString_GetData(&val_str, &type);
1115         if(*type) {
1116             ret = get_guid_from_type(type, guid);
1117             nsAString_Finish(&val_str);
1118             return ret;
1119         }
1120     }else {
1121         ERR("GetType failed: %08x\n", nsres);
1122     }
1123 
1124     nsres = nsIDOMHTMLScriptElement_QueryInterface(nsscript, &IID_nsIDOMHTMLElement, (void**)&nselem);
1125     assert(nsres == NS_OK);
1126 
1127     nsres = get_elem_attr_value(nselem, languageW, &val_str, &language);
1128     nsIDOMHTMLElement_Release(nselem);
1129     if(NS_SUCCEEDED(nsres)) {
1130         if(*language) {
1131             ret = get_guid_from_language(language, guid);
1132         }else {
1133             *guid = get_default_script_guid(window);
1134             ret = TRUE;
1135         }
1136         nsAString_Finish(&val_str);
1137     }
1138 
1139     return ret;
1140 }
1141 
get_script_host(HTMLInnerWindow * window,const GUID * guid)1142 static ScriptHost *get_script_host(HTMLInnerWindow *window, const GUID *guid)
1143 {
1144     ScriptHost *iter;
1145 
1146     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
1147         if(IsEqualGUID(guid, &iter->guid))
1148             return iter;
1149     }
1150 
1151     return create_script_host(window, guid);
1152 }
1153 
get_elem_script_host(HTMLInnerWindow * window,HTMLScriptElement * script_elem)1154 static ScriptHost *get_elem_script_host(HTMLInnerWindow *window, HTMLScriptElement *script_elem)
1155 {
1156     GUID guid;
1157 
1158     if(!get_script_guid(window, script_elem->nsscript, &guid)) {
1159         WARN("Could not find script GUID\n");
1160         return NULL;
1161     }
1162 
1163     if(IsEqualGUID(&CLSID_JScript, &guid)
1164        && (!window->base.outer_window || window->base.outer_window->scriptmode != SCRIPTMODE_ACTIVESCRIPT)) {
1165         TRACE("Ignoring JScript\n");
1166         return NULL;
1167     }
1168 
1169     return get_script_host(window, &guid);
1170 }
1171 
doc_insert_script(HTMLInnerWindow * window,HTMLScriptElement * script_elem)1172 void doc_insert_script(HTMLInnerWindow *window, HTMLScriptElement *script_elem)
1173 {
1174     ScriptHost *script_host;
1175 
1176     script_host = get_elem_script_host(window, script_elem);
1177     if(!script_host)
1178         return;
1179 
1180     if(script_host->parse)
1181         parse_script_elem(script_host, script_elem);
1182 }
1183 
script_parse_event(HTMLInnerWindow * window,LPCWSTR text)1184 IDispatch *script_parse_event(HTMLInnerWindow *window, LPCWSTR text)
1185 {
1186     ScriptHost *script_host;
1187     GUID guid;
1188     const WCHAR *ptr;
1189     IDispatch *disp;
1190     HRESULT hres;
1191 
1192     static const WCHAR delimiterW[] = {'\"',0};
1193 
1194     TRACE("%s\n", debugstr_w(text));
1195 
1196     for(ptr = text; isalnumW(*ptr); ptr++);
1197     if(*ptr == ':') {
1198         LPWSTR language;
1199         BOOL b;
1200 
1201         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
1202         if(!language)
1203             return NULL;
1204 
1205         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
1206         language[ptr-text] = 0;
1207 
1208         b = get_guid_from_language(language, &guid);
1209 
1210         heap_free(language);
1211 
1212         if(!b) {
1213             WARN("Could not find language\n");
1214             return NULL;
1215         }
1216 
1217         ptr++;
1218     }else {
1219         ptr = text;
1220         guid = get_default_script_guid(window);
1221     }
1222 
1223     if(IsEqualGUID(&CLSID_JScript, &guid)
1224        && (!window->base.outer_window || window->base.outer_window->scriptmode != SCRIPTMODE_ACTIVESCRIPT)) {
1225         TRACE("Ignoring JScript\n");
1226         return NULL;
1227     }
1228 
1229     script_host = get_script_host(window, &guid);
1230     if(!script_host || !script_host->parse_proc)
1231         return NULL;
1232 
1233     hres = IActiveScriptParseProcedure2_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
1234             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
1235             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
1236     if(FAILED(hres)) {
1237         WARN("ParseProcedureText failed: %08x\n", hres);
1238         return NULL;
1239     }
1240 
1241     TRACE("ret %p\n", disp);
1242     return disp;
1243 }
1244 
exec_script(HTMLInnerWindow * window,const WCHAR * code,const WCHAR * lang,VARIANT * ret)1245 HRESULT exec_script(HTMLInnerWindow *window, const WCHAR *code, const WCHAR *lang, VARIANT *ret)
1246 {
1247     ScriptHost *script_host;
1248     EXCEPINFO ei;
1249     GUID guid;
1250     HRESULT hres;
1251 
1252     static const WCHAR delimW[] = {'"',0};
1253 
1254     if(!get_guid_from_language(lang, &guid)) {
1255         WARN("Could not find script GUID\n");
1256         return CO_E_CLASSSTRING;
1257     }
1258 
1259     script_host = get_script_host(window, &guid);
1260     if(!script_host) {
1261         FIXME("No script host\n");
1262         return E_FAIL;
1263     }
1264 
1265     if(!script_host->parse) {
1266         FIXME("script_host->parse == NULL\n");
1267         return E_FAIL;
1268     }
1269 
1270     memset(&ei, 0, sizeof(ei));
1271     TRACE(">>>\n");
1272     hres = IActiveScriptParse_ParseScriptText(script_host->parse, code, NULL, NULL, delimW, 0, 0, SCRIPTTEXT_ISVISIBLE, ret, &ei);
1273     if(SUCCEEDED(hres))
1274         TRACE("<<<\n");
1275     else
1276         WARN("<<< %08x\n", hres);
1277 
1278     return hres;
1279 }
1280 
get_script_disp(ScriptHost * script_host)1281 IDispatch *get_script_disp(ScriptHost *script_host)
1282 {
1283     IDispatch *disp;
1284     HRESULT hres;
1285 
1286     if(!script_host->script)
1287         return NULL;
1288 
1289     hres = IActiveScript_GetScriptDispatch(script_host->script, windowW, &disp);
1290     if(FAILED(hres))
1291         return NULL;
1292 
1293     return disp;
1294 }
1295 
find_event_target(HTMLDocumentNode * doc,HTMLScriptElement * script_elem)1296 static EventTarget *find_event_target(HTMLDocumentNode *doc, HTMLScriptElement *script_elem)
1297 {
1298     EventTarget *event_target = NULL;
1299     const PRUnichar *target_id;
1300     nsAString target_id_str;
1301     nsresult nsres;
1302     HRESULT hres;
1303 
1304     nsAString_Init(&target_id_str, NULL);
1305     nsres = nsIDOMHTMLScriptElement_GetHtmlFor(script_elem->nsscript, &target_id_str);
1306     if(NS_FAILED(nsres)) {
1307         ERR("GetScriptFor failed: %08x\n", nsres);
1308         nsAString_Finish(&target_id_str);
1309         return NULL;
1310     }
1311 
1312     nsAString_GetData(&target_id_str, &target_id);
1313     if(!*target_id) {
1314         FIXME("Empty for attribute\n");
1315     }else if(!strcmpW(target_id, documentW)) {
1316         event_target = &doc->node.event_target;
1317         htmldoc_addref(&doc->basedoc);
1318     }else if(!strcmpW(target_id, windowW)) {
1319         if(doc->window) {
1320             event_target = &doc->window->event_target;
1321             IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
1322         }
1323     }else {
1324         HTMLElement *target_elem;
1325 
1326         hres = get_doc_elem_by_id(doc, target_id, &target_elem);
1327         if(SUCCEEDED(hres) && target_elem) {
1328             event_target = &target_elem->node.event_target;
1329         }
1330     }
1331 
1332     nsAString_Finish(&target_id_str);
1333     return event_target;
1334 }
1335 
parse_event_str(WCHAR * event,const WCHAR ** args)1336 static BOOL parse_event_str(WCHAR *event, const WCHAR **args)
1337 {
1338     WCHAR *ptr;
1339 
1340     TRACE("%s\n", debugstr_w(event));
1341 
1342     for(ptr = event; isalnumW(*ptr); ptr++);
1343     if(!*ptr) {
1344         *args = NULL;
1345         return TRUE;
1346     }
1347 
1348     if(*ptr != '(')
1349         return FALSE;
1350 
1351     *ptr++ = 0;
1352     *args = ptr;
1353     while(isalnumW(*ptr) || isspaceW(*ptr) || *ptr == ',')
1354         ptr++;
1355 
1356     if(*ptr != ')')
1357         return FALSE;
1358 
1359     *ptr++ = 0;
1360     return !*ptr;
1361 }
1362 
parse_event_elem(HTMLDocumentNode * doc,HTMLScriptElement * script_elem,WCHAR ** ret_event)1363 static IDispatch *parse_event_elem(HTMLDocumentNode *doc, HTMLScriptElement *script_elem, WCHAR **ret_event)
1364 {
1365     ScriptHost *script_host;
1366     WCHAR *event = NULL;
1367     const WCHAR *args;
1368     nsAString nsstr;
1369     IDispatch *disp;
1370     nsresult nsres;
1371     HRESULT hres;
1372 
1373     if(script_elem->parsed)
1374         return NULL;
1375 
1376     script_host = get_elem_script_host(doc->window, script_elem);
1377     if(!script_host || !script_host->parse_proc)
1378         return NULL;
1379 
1380     nsAString_Init(&nsstr, NULL);
1381     nsres = nsIDOMHTMLScriptElement_GetEvent(script_elem->nsscript, &nsstr);
1382     if(NS_SUCCEEDED(nsres)) {
1383         const PRUnichar *event_val;
1384 
1385         nsAString_GetData(&nsstr, &event_val);
1386         event = heap_strdupW(event_val);
1387     }
1388     nsAString_Finish(&nsstr);
1389     if(!event)
1390         return NULL;
1391 
1392     if(!parse_event_str(event, &args)) {
1393         WARN("parsing %s failed\n", debugstr_w(event));
1394         heap_free(event);
1395         return NULL;
1396     }
1397 
1398     nsAString_Init(&nsstr, NULL);
1399     nsres = nsIDOMHTMLScriptElement_GetText(script_elem->nsscript, &nsstr);
1400     if(NS_SUCCEEDED(nsres)) {
1401         const PRUnichar *text;
1402 
1403         nsAString_GetData(&nsstr, &text);
1404         hres = IActiveScriptParseProcedure2_ParseProcedureText(script_host->parse_proc, text, args,
1405                 emptyW, NULL, NULL, script_endW, 0, 0,
1406                 SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
1407         if(FAILED(hres))
1408             disp = NULL;
1409     }else {
1410         ERR("GetText failed: %08x\n", nsres);
1411         disp = NULL;
1412     }
1413     nsAString_Finish(&nsstr);
1414     if(!disp) {
1415         heap_free(event);
1416         return NULL;
1417     }
1418 
1419     *ret_event = event;
1420     return disp;
1421 }
1422 
bind_event_scripts(HTMLDocumentNode * doc)1423 void bind_event_scripts(HTMLDocumentNode *doc)
1424 {
1425     HTMLPluginContainer *plugin_container;
1426     nsIDOMHTMLScriptElement *nsscript;
1427     HTMLScriptElement *script_elem;
1428     EventTarget *event_target;
1429     nsIDOMNodeList *node_list;
1430     nsIDOMNode *script_node;
1431     nsAString selector_str;
1432     IDispatch *event_disp;
1433     UINT32 length, i;
1434     WCHAR *event;
1435     nsresult nsres;
1436     HRESULT hres;
1437 
1438     static const PRUnichar selectorW[] = {'s','c','r','i','p','t','[','e','v','e','n','t',']',0};
1439 
1440     TRACE("%p\n", doc);
1441 
1442     if(!doc->nsdoc)
1443         return;
1444 
1445     nsAString_InitDepend(&selector_str, selectorW);
1446     nsres = nsIDOMHTMLDocument_QuerySelectorAll(doc->nsdoc, &selector_str, &node_list);
1447     nsAString_Finish(&selector_str);
1448     if(NS_FAILED(nsres)) {
1449         ERR("QuerySelectorAll failed: %08x\n", nsres);
1450         return;
1451     }
1452 
1453     if(!node_list)
1454         return;
1455 
1456     nsres = nsIDOMNodeList_GetLength(node_list, &length);
1457     assert(nsres == NS_OK);
1458 
1459     for(i=0; i < length; i++) {
1460         nsres = nsIDOMNodeList_Item(node_list, i, &script_node);
1461         if(NS_FAILED(nsres) || !script_node) {
1462             ERR("Item(%d) failed: %08x\n", i, nsres);
1463             continue;
1464         }
1465 
1466         nsres = nsIDOMNode_QueryInterface(script_node, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
1467         assert(nsres == NS_OK);
1468         nsIDOMNode_Release(script_node);
1469 
1470         hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
1471         if(FAILED(hres))
1472             continue;
1473 
1474         event_disp = parse_event_elem(doc, script_elem, &event);
1475         if(event_disp) {
1476             event_target = find_event_target(doc, script_elem);
1477             if(event_target) {
1478                 hres = IDispatchEx_QueryInterface(&event_target->dispex.IDispatchEx_iface, &IID_HTMLPluginContainer,
1479                         (void**)&plugin_container);
1480                 if(SUCCEEDED(hres))
1481                     bind_activex_event(doc, plugin_container, event, event_disp);
1482                 else
1483                     bind_target_event(doc, event_target, event, event_disp);
1484 
1485                 IDispatchEx_Release(&event_target->dispex.IDispatchEx_iface);
1486                 if(plugin_container)
1487                     node_release(&plugin_container->element.node);
1488             }
1489 
1490             heap_free(event);
1491             IDispatch_Release(event_disp);
1492         }
1493 
1494         IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
1495     }
1496 
1497     nsIDOMNodeList_Release(node_list);
1498 }
1499 
find_global_prop(HTMLInnerWindow * window,BSTR name,DWORD flags,ScriptHost ** ret_host,DISPID * ret_id)1500 BOOL find_global_prop(HTMLInnerWindow *window, BSTR name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id)
1501 {
1502     IDispatchEx *dispex;
1503     IDispatch *disp;
1504     ScriptHost *iter;
1505     HRESULT hres;
1506 
1507     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
1508         disp = get_script_disp(iter);
1509         if(!disp)
1510             continue;
1511 
1512         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1513         if(SUCCEEDED(hres)) {
1514             hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id);
1515             IDispatchEx_Release(dispex);
1516         }else {
1517             FIXME("No IDispatchEx\n");
1518             hres = E_NOTIMPL;
1519         }
1520 
1521         IDispatch_Release(disp);
1522         if(SUCCEEDED(hres)) {
1523             *ret_host = iter;
1524             return TRUE;
1525         }
1526     }
1527 
1528     return FALSE;
1529 }
1530 
is_jscript_available(void)1531 static BOOL is_jscript_available(void)
1532 {
1533     static BOOL available, checked;
1534 
1535     if(!checked) {
1536         IUnknown *unk;
1537         HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
1538 
1539         if(SUCCEEDED(hres)) {
1540             available = TRUE;
1541             IUnknown_Release(unk);
1542         }else {
1543             available = FALSE;
1544         }
1545         checked = TRUE;
1546     }
1547 
1548     return available;
1549 }
1550 
set_script_mode(HTMLOuterWindow * window,SCRIPTMODE mode)1551 void set_script_mode(HTMLOuterWindow *window, SCRIPTMODE mode)
1552 {
1553     nsIWebBrowserSetup *setup;
1554     nsresult nsres;
1555 
1556     if(mode == SCRIPTMODE_ACTIVESCRIPT && !is_jscript_available()) {
1557         TRACE("jscript.dll not available\n");
1558         window->scriptmode = SCRIPTMODE_GECKO;
1559         return;
1560     }
1561 
1562     window->scriptmode = mode;
1563 
1564     if(!window->doc_obj->nscontainer || !window->doc_obj->nscontainer->webbrowser)
1565         return;
1566 
1567     nsres = nsIWebBrowser_QueryInterface(window->doc_obj->nscontainer->webbrowser,
1568             &IID_nsIWebBrowserSetup, (void**)&setup);
1569     if(NS_SUCCEEDED(nsres)) {
1570         nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
1571                 window->scriptmode == SCRIPTMODE_GECKO);
1572 
1573         if(NS_SUCCEEDED(nsres))
1574             nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_DISABLE_NOSCRIPT, TRUE);
1575 
1576         nsIWebBrowserSetup_Release(setup);
1577     }
1578 
1579     if(NS_FAILED(nsres))
1580         ERR("JavaScript setup failed: %08x\n", nsres);
1581 }
1582 
release_script_hosts(HTMLInnerWindow * window)1583 void release_script_hosts(HTMLInnerWindow *window)
1584 {
1585     script_queue_entry_t *queue_iter;
1586     ScriptHost *iter;
1587 
1588     while(!list_empty(&window->script_queue)) {
1589         queue_iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
1590 
1591         list_remove(&queue_iter->entry);
1592         IHTMLScriptElement_Release(&queue_iter->script->IHTMLScriptElement_iface);
1593         heap_free(queue_iter);
1594     }
1595 
1596     while(!list_empty(&window->script_hosts)) {
1597         iter = LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry);
1598 
1599         release_script_engine(iter);
1600         list_remove(&iter->entry);
1601         iter->window = NULL;
1602         IActiveScriptSite_Release(&iter->IActiveScriptSite_iface);
1603     }
1604 }
1605