mshtml: Added script engine loading implementation.
authorJacek Caban <jacek@codeweavers.com>
Tue, 25 Mar 2008 01:10:47 +0000 (02:10 +0100)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 25 Mar 2008 10:44:26 +0000 (11:44 +0100)
dlls/mshtml/Makefile.in
dlls/mshtml/htmldoc.c
dlls/mshtml/mshtml_private.h
dlls/mshtml/nsevents.c
dlls/mshtml/script.c [new file with mode: 0644]

index 8cf0b8723bd88717b8911374953073d8b2acb39c..1ca2d1d4dba53a5cc17331323f45d2ad92c3854f 100644 (file)
@@ -43,6 +43,7 @@ C_SRCS = \
        olewnd.c \
        persist.c \
        protocol.c \
+       script.c \
        selection.c \
        service.c \
        task.c \
index b93fe95b63dd523f7c4aa1f280fef93d72698c61..966dcf06e8931c5f44b91a277607373f2679f11c 100644 (file)
@@ -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);
 
index fa6798a0c2be06b504cc6130669a09879f57767a..569ab6c903b29730c4ce36c041db048331cb1d4c 100644 (file)
@@ -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 */
index ccec4242aa1d1f1ae4c71844ed17e6a1196b26a9..2fb5ab0bd08439db3d7b72506ea78c2d38528316 100644 (file)
@@ -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 (file)
index 0000000..6433ac0
--- /dev/null
@@ -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 <stdarg.h>
+
+#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));
+    }
+}