[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[reactos.git] / dll / win32 / mshtml / script.c
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "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
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
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
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
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
223 static inline ScriptHost *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
224 {
225 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSite_iface);
226 }
227
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
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
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
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
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
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
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
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
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
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
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
395 static inline ScriptHost *impl_from_IActiveScriptSiteInterruptPoll(IActiveScriptSiteInterruptPoll *iface)
396 {
397 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteInterruptPoll_iface);
398 }
399
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
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
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
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
435 static inline ScriptHost *impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow *iface)
436 {
437 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteWindow_iface);
438 }
439
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
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
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
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
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
487 static inline ScriptHost *impl_from_IActiveScriptSiteUIControl(IActiveScriptSiteUIControl *iface)
488 {
489 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteUIControl_iface);
490 }
491
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
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
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
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
528 static inline ScriptHost *impl_from_IActiveScriptSiteDebug(IActiveScriptSiteDebug *iface)
529 {
530 return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteDebug_iface);
531 }
532
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
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
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
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
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
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
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
594 static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface)
595 {
596 return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface);
597 }
598
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
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
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
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
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
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
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
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
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
772 static inline ScriptBSC *impl_from_BSCallback(BSCallback *iface)
773 {
774 return CONTAINING_RECORD(iface, ScriptBSC, bsc);
775 }
776
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
790 static HRESULT ScriptBSC_init_bindinfo(BSCallback *bsc)
791 {
792 return S_OK;
793 }
794
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
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
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
856 static HRESULT ScriptBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
857 {
858 return S_OK;
859 }
860
861 static HRESULT ScriptBSC_on_response(BSCallback *bsc, DWORD response_code,
862 LPCWSTR response_headers)
863 {
864 return S_OK;
865 }
866
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }