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 } 1605