From 1b5bce0d4c7e53ef0a151d2d916f99063c135d73 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 25 Mar 2008 02:10:47 +0100 Subject: [PATCH] mshtml: Added script engine loading implementation. --- dlls/mshtml/Makefile.in | 1 + dlls/mshtml/htmldoc.c | 2 + dlls/mshtml/mshtml_private.h | 5 + dlls/mshtml/nsevents.c | 30 ++++ dlls/mshtml/script.c | 311 +++++++++++++++++++++++++++++++++++ 5 files changed, 349 insertions(+) create mode 100644 dlls/mshtml/script.c diff --git a/dlls/mshtml/Makefile.in b/dlls/mshtml/Makefile.in index 8cf0b8723bd..1ca2d1d4dba 100644 --- a/dlls/mshtml/Makefile.in +++ b/dlls/mshtml/Makefile.in @@ -43,6 +43,7 @@ C_SRCS = \ olewnd.c \ persist.c \ protocol.c \ + script.c \ selection.c \ service.c \ task.c \ diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index b93fe95b63d..966dcf06e89 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -159,6 +159,7 @@ static ULONG WINAPI HTMLDocument_Release(IHTMLDocument2 *iface) if(!ref) { remove_doc_tasks(This); + release_script_hosts(This); if(This->client) IOleObject_SetClientSite(OLEOBJ(This), NULL); @@ -1256,6 +1257,7 @@ HRESULT HTMLDocument_Create(IUnknown *pUnkOuter, REFIID riid, void** ppvObject) ret->option_factory = NULL; list_init(&ret->bindings); + list_init(&ret->script_hosts); list_init(&ret->selection_list); list_init(&ret->range_list); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index fa6798a0c2b..569ab6c903b 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -144,6 +144,8 @@ struct HTMLDocument { LPOLESTR url; struct list bindings; + struct list script_hosts; + HWND hwnd; HWND tooltips_hwnd; @@ -436,6 +438,9 @@ void HTMLElement_destructor(HTMLDOMNode*); HTMLDOMNode *get_node(HTMLDocument*,nsIDOMNode*); void release_nodes(HTMLDocument*); +void release_script_hosts(HTMLDocument*); +void doc_insert_script(HTMLDocument*,nsIDOMHTMLScriptElement*); + IHTMLElementCollection *create_all_collection(HTMLDOMNode*); /* commands */ diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index ccec4242aa1..2fb5ab0bd08 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -161,6 +161,31 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event return NS_OK; } +static nsresult NSAPI handle_node_insert(nsIDOMEventListener *iface, nsIDOMEvent *event) +{ + NSContainer *This = NSEVENTLIST_THIS(iface)->This; + nsIDOMHTMLScriptElement *script; + nsIDOMEventTarget *target; + nsresult nsres; + + TRACE("(%p %p)\n", This, event); + + nsres = nsIDOMEvent_GetTarget(event, &target); + if(NS_FAILED(nsres)) { + ERR("GetTarget failed: %08x\n", nsres); + return nsres; + } + + nsres = nsISupports_QueryInterface(target, &IID_nsIDOMHTMLScriptElement, (void**)&script); + if(SUCCEEDED(nsres)) { + doc_insert_script(This->doc, script); + nsIDOMHTMLScriptElement_Release(script); + } + + nsIDOMEventTarget_Release(target); + return NS_OK; +} + #undef NSEVENTLIST_THIS #define EVENTLISTENER_VTBL(handler) \ @@ -175,6 +200,7 @@ static const nsIDOMEventListenerVtbl blur_vtbl = EVENTLISTENER_VTBL(handle_ static const nsIDOMEventListenerVtbl focus_vtbl = EVENTLISTENER_VTBL(handle_focus); static const nsIDOMEventListenerVtbl keypress_vtbl = EVENTLISTENER_VTBL(handle_keypress); static const nsIDOMEventListenerVtbl load_vtbl = EVENTLISTENER_VTBL(handle_load); +static const nsIDOMEventListenerVtbl node_insert_vtbl = EVENTLISTENER_VTBL(handle_node_insert); static void init_event(nsIDOMEventTarget *target, const PRUnichar *type, nsIDOMEventListener *listener, BOOL capture) @@ -207,11 +233,14 @@ void init_nsevents(NSContainer *This) static const PRUnichar wsz_focus[] = {'f','o','c','u','s',0}; static const PRUnichar wsz_keypress[] = {'k','e','y','p','r','e','s','s',0}; static const PRUnichar wsz_load[] = {'l','o','a','d',0}; + static const PRUnichar DOMNodeInsertedW[] = + {'D','O','M','N','o','d','e','I','n','s','e','r','t','e','d',0}; init_listener(&This->blur_listener, This, &blur_vtbl); init_listener(&This->focus_listener, This, &focus_vtbl); init_listener(&This->keypress_listener, This, &keypress_vtbl); init_listener(&This->load_listener, This, &load_vtbl); + init_listener(&This->node_insert_listener, This, &node_insert_vtbl); nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window); if(NS_FAILED(nsres)) { @@ -230,6 +259,7 @@ void init_nsevents(NSContainer *This) init_event(target, wsz_focus, NSEVENTLIST(&This->focus_listener), TRUE); init_event(target, wsz_keypress, NSEVENTLIST(&This->keypress_listener), FALSE); init_event(target, wsz_load, NSEVENTLIST(&This->load_listener), TRUE); + init_event(target, DOMNodeInsertedW,NSEVENTLIST(&This->node_insert_listener),TRUE); nsIDOMEventTarget_Release(target); } diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c new file mode 100644 index 00000000000..6433ac00428 --- /dev/null +++ b/dlls/mshtml/script.c @@ -0,0 +1,311 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "activscp.h" + +#include "wine/debug.h" + +#include "mshtml_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mshtml); + +static const CLSID CLSID_JScript = + {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}}; + +typedef struct { + const IActiveScriptSiteVtbl *lpActiveScriptSiteVtbl; + + LONG ref; + + IActiveScript *script; + HTMLDocument *doc; + + GUID guid; + struct list entry; +} ScriptHost; + +#define ACTSCPSITE(x) ((IActiveScriptSite*) &(x)->lpActiveScriptSiteVtbl) + +#define ACTSCPSITE_THIS(iface) DEFINE_THIS(ScriptHost, ActiveScriptSite, iface) + +static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = ACTSCPSITE(This); + }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) { + TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv); + *ppv = ACTSCPSITE(This); + }else { + FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + if(This->doc) + list_remove(&This->entry); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%p)\n", This, plcid); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName, + DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%p)\n", This, pbstrVersion); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, + const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%x)\n", This, ssScriptState); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->(%p)\n", This, pscripterror); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->()\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) +{ + ScriptHost *This = ACTSCPSITE_THIS(iface); + FIXME("(%p)->()\n", This); + return E_NOTIMPL; +} + +#undef ACTSCPSITE_THIS + +static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { + ActiveScriptSite_QueryInterface, + ActiveScriptSite_AddRef, + ActiveScriptSite_Release, + ActiveScriptSite_GetLCID, + ActiveScriptSite_GetItemInfo, + ActiveScriptSite_GetDocVersionString, + ActiveScriptSite_OnScriptTerminate, + ActiveScriptSite_OnStateChange, + ActiveScriptSite_OnScriptError, + ActiveScriptSite_OnEnterScript, + ActiveScriptSite_OnLeaveScript +}; + +static ScriptHost *create_script_host(HTMLDocument *doc, GUID *guid) +{ + ScriptHost *ret; + HRESULT hres; + + ret = heap_alloc_zero(sizeof(*ret)); + ret->lpActiveScriptSiteVtbl = &ActiveScriptSiteVtbl; + ret->ref = 1; + ret->doc = doc; + + ret->guid = *guid; + list_add_tail(&doc->script_hosts, &ret->entry); + + hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IActiveScript, (void**)&ret->script); + if(FAILED(hres)) + WARN("Could not load script engine: %08x\n", hres); + + return ret; +} + +static BOOL get_guid_from_type(LPCWSTR type, GUID *guid) +{ + const WCHAR text_javascriptW[] = + {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0}; + + /* FIXME: Handle more types */ + if(!strcmpW(type, text_javascriptW)) { + *guid = CLSID_JScript; + }else { + FIXME("Unknown type %s\n", debugstr_w(type)); + return FALSE; + } + + return TRUE; +} + +static BOOL get_guid_from_language(LPCWSTR type, GUID *guid) +{ + HRESULT hres; + + hres = CLSIDFromProgID(type, guid); + if(FAILED(hres)) + return FALSE; + + /* FIXME: Check CATID_ActiveScriptParse */ + + return TRUE; +} + +static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid) +{ + nsAString attr_str, val_str; + BOOL ret = FALSE; + nsresult nsres; + + static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0}; + + nsAString_Init(&val_str, NULL); + + nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *type; + + nsAString_GetData(&val_str, &type); + if(*type) { + ret = get_guid_from_type(type, guid); + nsAString_Finish(&val_str); + return ret; + } + }else { + ERR("GetType failed: %08x\n", nsres); + } + + nsAString_Init(&attr_str, languageW); + + nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *language; + + nsAString_GetData(&val_str, &language); + + if(*language) { + ret = get_guid_from_language(language, guid); + }else { + *guid = CLSID_JScript; + ret = TRUE; + } + }else { + ERR("GetAttribute(language) failed: %08x\n", nsres); + } + + nsAString_Finish(&attr_str); + nsAString_Finish(&val_str); + + return ret; +} + +static ScriptHost *get_script_host(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript) +{ + ScriptHost *iter; + GUID guid; + + if(!get_script_guid(nsscript, &guid)) { + WARN("Could not find script GUID\n"); + return NULL; + } + + if(IsEqualGUID(&CLSID_JScript, &guid)) { + FIXME("Ignoring JScript\n"); + return NULL; + } + + LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) { + if(IsEqualGUID(&guid, &iter->guid)) + return iter; + } + + return create_script_host(doc, &guid); +} + +void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript) +{ + get_script_host(doc, nsscript); +} + +void release_script_hosts(HTMLDocument *doc) +{ + ScriptHost *iter; + + LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) { + iter->doc = NULL; + IActiveScriptSite_Release(ACTSCPSITE(iter)); + } +}