/* * Copyright 2005-2007 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 #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winreg.h" #include "ole2.h" #include "shlobj.h" #include "wine/debug.h" #include "mshtml_private.h" #include "htmlevent.h" #include "binding.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); WINE_DECLARE_DEBUG_CHANNEL(gecko); #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1" #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1" #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html" #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1" #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1" #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" #define PR_UINT32_MAX 0xffffffff #define NS_STRING_CONTAINER_INIT_DEPEND 0x0002 #define NS_CSTRING_CONTAINER_INIT_DEPEND 0x0002 static nsresult (CDECL *NS_InitXPCOM2)(nsIServiceManager**,void*,void*); static nsresult (CDECL *NS_ShutdownXPCOM)(nsIServiceManager*); static nsresult (CDECL *NS_GetComponentRegistrar)(nsIComponentRegistrar**); static nsresult (CDECL *NS_StringContainerInit2)(nsStringContainer*,const PRUnichar*,PRUint32,PRUint32); static nsresult (CDECL *NS_CStringContainerInit2)(nsCStringContainer*,const char*,PRUint32,PRUint32); static nsresult (CDECL *NS_StringContainerFinish)(nsStringContainer*); static nsresult (CDECL *NS_CStringContainerFinish)(nsCStringContainer*); static nsresult (CDECL *NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32); static nsresult (CDECL *NS_CStringSetData)(nsACString*,const char*,PRUint32); static nsresult (CDECL *NS_NewLocalFile)(const nsAString*,cpp_bool,nsIFile**); static PRUint32 (CDECL *NS_StringGetData)(const nsAString*,const PRUnichar **,cpp_bool*); static PRUint32 (CDECL *NS_CStringGetData)(const nsACString*,const char**,cpp_bool*); static HINSTANCE xul_handle = NULL; static nsIServiceManager *pServMgr = NULL; static nsIComponentManager *pCompMgr = NULL; static nsIMemory *nsmem = NULL; static nsIFile *profile_directory; static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0}; static ATOM nscontainer_class; static WCHAR gecko_path[MAX_PATH]; static unsigned gecko_path_len; nsresult create_nsfile(const PRUnichar *path, nsIFile **ret) { nsAString str; nsresult nsres; nsAString_InitDepend(&str, path); nsres = NS_NewLocalFile(&str, FALSE, ret); nsAString_Finish(&str); if(NS_FAILED(nsres)) WARN("NS_NewLocalFile failed: %08x\n", nsres); return nsres; } static nsresult NSAPI nsDirectoryServiceProvider_QueryInterface(nsIDirectoryServiceProvider *iface, nsIIDRef riid, void **result) { if(IsEqualGUID(&IID_nsISupports, riid)) { TRACE("(IID_nsISupports %p)\n", result); *result = iface; }else if(IsEqualGUID(&IID_nsIDirectoryServiceProvider, riid)) { TRACE("(IID_nsIDirectoryServiceProvider %p)\n", result); *result = iface; }else { WARN("(%s %p)\n", debugstr_guid(riid), result); *result = NULL; return NS_NOINTERFACE; } nsISupports_AddRef((nsISupports*)*result); return NS_OK; } static nsrefcnt NSAPI nsDirectoryServiceProvider_AddRef(nsIDirectoryServiceProvider *iface) { return 2; } static nsrefcnt NSAPI nsDirectoryServiceProvider_Release(nsIDirectoryServiceProvider *iface) { return 1; } static nsresult create_profile_directory(void) { static const WCHAR wine_geckoW[] = {'\\','w','i','n','e','_','g','e','c','k','o',0}; WCHAR path[MAX_PATH + sizeof(wine_geckoW)/sizeof(WCHAR)]; cpp_bool exists; nsresult nsres; HRESULT hres; hres = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path); if(FAILED(hres)) { ERR("SHGetFolderPath failed: %08x\n", hres); return NS_ERROR_FAILURE; } strcatW(path, wine_geckoW); nsres = create_nsfile(path, &profile_directory); if(NS_FAILED(nsres)) return nsres; nsres = nsIFile_Exists(profile_directory, &exists); if(NS_FAILED(nsres)) { ERR("Exists failed: %08x\n", nsres); return nsres; } if(!exists) { nsres = nsIFile_Create(profile_directory, 1, 0700); if(NS_FAILED(nsres)) ERR("Create failed: %08x\n", nsres); } return nsres; } static nsresult NSAPI nsDirectoryServiceProvider_GetFile(nsIDirectoryServiceProvider *iface, const char *prop, cpp_bool *persistent, nsIFile **_retval) { TRACE("(%s %p %p)\n", debugstr_a(prop), persistent, _retval); if(!strcmp(prop, "ProfD")) { if(!profile_directory) { nsresult nsres; nsres = create_profile_directory(); if(NS_FAILED(nsres)) return nsres; } return nsIFile_Clone(profile_directory, _retval); } return NS_ERROR_FAILURE; } static const nsIDirectoryServiceProviderVtbl nsDirectoryServiceProviderVtbl = { nsDirectoryServiceProvider_QueryInterface, nsDirectoryServiceProvider_AddRef, nsDirectoryServiceProvider_Release, nsDirectoryServiceProvider_GetFile }; static nsIDirectoryServiceProvider nsDirectoryServiceProvider = { &nsDirectoryServiceProviderVtbl }; static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { NSContainer *This; nsresult nsres; static const WCHAR wszTHIS[] = {'T','H','I','S',0}; if(msg == WM_CREATE) { This = *(NSContainer**)lParam; SetPropW(hwnd, wszTHIS, This); }else { This = GetPropW(hwnd, wszTHIS); } switch(msg) { case WM_SIZE: TRACE("(%p)->(WM_SIZE)\n", This); nsres = nsIBaseWindow_SetSize(This->window, LOWORD(lParam), HIWORD(lParam), TRUE); if(NS_FAILED(nsres)) WARN("SetSize failed: %08x\n", nsres); break; case WM_PARENTNOTIFY: TRACE("WM_PARENTNOTIFY %x\n", (unsigned)wParam); switch(wParam) { case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: nsIWebBrowserFocus_Activate(This->focus); } } return DefWindowProcW(hwnd, msg, wParam, lParam); } static void register_nscontainer_class(void) { static WNDCLASSEXW wndclass = { sizeof(WNDCLASSEXW), CS_DBLCLKS, nsembed_proc, 0, 0, NULL, NULL, NULL, NULL, NULL, wszNsContainer, NULL, }; wndclass.hInstance = hInst; nscontainer_class = RegisterClassExW(&wndclass); } static BOOL install_wine_gecko(void) { PROCESS_INFORMATION pi; STARTUPINFOW si; WCHAR app[MAX_PATH]; WCHAR *args; LONG len; BOOL ret; static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0}; static const WCHAR argsW[] = {' ','a','p','p','w','i','z','.','c','p','l',' ','i','n','s','t','a','l','l','_','g','e','c','k','o',0}; len = GetSystemDirectoryW(app, MAX_PATH-sizeof(controlW)/sizeof(WCHAR)); memcpy(app+len, controlW, sizeof(controlW)); args = heap_alloc(len*sizeof(WCHAR) + sizeof(controlW) + sizeof(argsW)); if(!args) return FALSE; memcpy(args, app, len*sizeof(WCHAR) + sizeof(controlW)); memcpy(args + len + sizeof(controlW)/sizeof(WCHAR)-1, argsW, sizeof(argsW)); TRACE("starting %s\n", debugstr_w(args)); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ret = CreateProcessW(app, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); heap_free(args); if (ret) { CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } return ret; } static void set_environment(LPCWSTR gre_path) { WCHAR path_env[MAX_PATH], buf[20]; int len, debug_level = 0; static const WCHAR pathW[] = {'P','A','T','H',0}; static const WCHAR warnW[] = {'w','a','r','n',0}; static const WCHAR xpcom_debug_breakW[] = {'X','P','C','O','M','_','D','E','B','U','G','_','B','R','E','A','K',0}; static const WCHAR nspr_log_modulesW[] = {'N','S','P','R','_','L','O','G','_','M','O','D','U','L','E','S',0}; static const WCHAR debug_formatW[] = {'a','l','l',':','%','d',0}; static const WCHAR moz_plugin_pathW[] = {'M','O','Z','_','P','L','U','G','I','N','_','P','A','T','H',0}; static const WCHAR gecko_pluginW[] = {'\\','g','e','c','k','o','\\','p','l','u','g','i','n',0}; /* We have to modify PATH as XPCOM loads other DLLs from this directory. */ GetEnvironmentVariableW(pathW, path_env, sizeof(path_env)/sizeof(WCHAR)); len = strlenW(path_env); path_env[len++] = ';'; strcpyW(path_env+len, gre_path); SetEnvironmentVariableW(pathW, path_env); SetEnvironmentVariableW(xpcom_debug_breakW, warnW); if(TRACE_ON(gecko)) debug_level = 5; else if(WARN_ON(gecko)) debug_level = 3; else if(ERR_ON(gecko)) debug_level = 2; sprintfW(buf, debug_formatW, debug_level); SetEnvironmentVariableW(nspr_log_modulesW, buf); len = GetSystemDirectoryW(path_env, (sizeof(path_env)-sizeof(gecko_pluginW))/sizeof(WCHAR)+1); if(len) { strcpyW(path_env+len, gecko_pluginW); SetEnvironmentVariableW(moz_plugin_pathW, path_env); } } static BOOL load_xul(const PRUnichar *gre_path) { static const WCHAR xul_dllW[] = {'\\','x','u','l','.','d','l','l',0}; WCHAR file_name[MAX_PATH]; strcpyW(file_name, gre_path); strcatW(file_name, xul_dllW); TRACE("(%s)\n", debugstr_w(file_name)); set_environment(gre_path); xul_handle = LoadLibraryExW(file_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if(!xul_handle) { WARN("Could not load XUL: %d\n", GetLastError()); return FALSE; } #define NS_DLSYM(func) \ func = (void *)GetProcAddress(xul_handle, #func "_P"); \ if(!func) \ ERR("Could not GetProcAddress(" #func ") failed\n") NS_DLSYM(NS_InitXPCOM2); NS_DLSYM(NS_ShutdownXPCOM); NS_DLSYM(NS_GetComponentRegistrar); NS_DLSYM(NS_StringContainerInit2); NS_DLSYM(NS_CStringContainerInit2); NS_DLSYM(NS_StringContainerFinish); NS_DLSYM(NS_CStringContainerFinish); NS_DLSYM(NS_StringSetData); NS_DLSYM(NS_CStringSetData); NS_DLSYM(NS_NewLocalFile); NS_DLSYM(NS_StringGetData); NS_DLSYM(NS_CStringGetData); #undef NS_DLSYM #define NS_DLSYM(func) \ func = (void *)GetProcAddress(xul_handle, #func); \ if(!func) \ ERR("Could not GetProcAddress(" #func ") failed\n") NS_DLSYM(ccref_incr); NS_DLSYM(ccref_decr); NS_DLSYM(ccref_init); NS_DLSYM(ccref_unmark_if_purple); NS_DLSYM(ccp_init); NS_DLSYM(describe_cc_node); NS_DLSYM(note_cc_edge); #undef NS_DLSYM return TRUE; } static BOOL check_version(LPCWSTR gre_path, const char *version_string) { WCHAR file_name[MAX_PATH]; char version[128]; DWORD read=0; HANDLE hfile; static const WCHAR wszVersion[] = {'\\','V','E','R','S','I','O','N',0}; strcpyW(file_name, gre_path); strcatW(file_name, wszVersion); hfile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hfile == INVALID_HANDLE_VALUE) { ERR("Could not open VERSION file\n"); return FALSE; } ReadFile(hfile, version, sizeof(version), &read, NULL); version[read] = 0; CloseHandle(hfile); TRACE("%s\n", debugstr_a(version)); if(strcmp(version, version_string)) { ERR("Unexpected version %s, expected %s\n", debugstr_a(version), debugstr_a(version_string)); return FALSE; } return TRUE; } static BOOL load_wine_gecko_v(PRUnichar *gre_path, HKEY mshtml_key, const char *version, const char *version_string) { DWORD res, type, size = MAX_PATH; HKEY hkey = mshtml_key; static const WCHAR wszGeckoPath[] = {'G','e','c','k','o','P','a','t','h',0}; if(version) { /* @@ Wine registry key: HKLM\Software\Wine\MSHTML\ */ res = RegOpenKeyA(mshtml_key, version, &hkey); if(res != ERROR_SUCCESS) return FALSE; } res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size); if(hkey != mshtml_key) RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) return FALSE; if(!check_version(gre_path, version_string)) return FALSE; return load_xul(gre_path); } static BOOL load_wine_gecko(PRUnichar *gre_path) { HKEY hkey; DWORD res; BOOL ret; static const WCHAR wszMshtmlKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e', '\\','M','S','H','T','M','L',0}; /* @@ Wine registry key: HKLM\Software\Wine\MSHTML */ res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszMshtmlKey, &hkey); if(res != ERROR_SUCCESS) return FALSE; ret = load_wine_gecko_v(gre_path, hkey, GECKO_VERSION, GECKO_VERSION_STRING); RegCloseKey(hkey); return ret; } static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val) { nsresult nsres; nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val); if(NS_FAILED(nsres)) ERR("Could not set pref %s\n", debugstr_a(pref_name)); } static void set_int_pref(nsIPrefBranch *pref, const char *pref_name, int val) { nsresult nsres; nsres = nsIPrefBranch_SetIntPref(pref, pref_name, val); if(NS_FAILED(nsres)) ERR("Could not set pref %s\n", debugstr_a(pref_name)); } static void set_string_pref(nsIPrefBranch *pref, const char *pref_name, const char *val) { nsresult nsres; nsres = nsIPrefBranch_SetCharPref(pref, pref_name, val); if(NS_FAILED(nsres)) ERR("Could not set pref %s\n", debugstr_a(pref_name)); } static void set_lang(nsIPrefBranch *pref) { char langs[100]; DWORD res, size, type; HKEY hkey; static const WCHAR international_keyW[] = {'S','o','f','t','w','a','r','e', '\\','M','i','c','r','o','s','o','f','t', '\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r', '\\','I','n','t','e','r','n','a','t','i','o','n','a','l',0}; res = RegOpenKeyW(HKEY_CURRENT_USER, international_keyW, &hkey); if(res != ERROR_SUCCESS) return; size = sizeof(langs); res = RegQueryValueExA(hkey, "AcceptLanguage", 0, &type, (LPBYTE)langs, &size); RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) return; TRACE("Setting lang %s\n", debugstr_a(langs)); set_string_pref(pref, "intl.accept_languages", langs); } static void set_preferences(void) { nsIPrefBranch *pref; nsresult nsres; nsres = nsIServiceManager_GetServiceByContractID(pServMgr, NS_PREFERENCES_CONTRACTID, &IID_nsIPrefBranch, (void**)&pref); if(NS_FAILED(nsres)) { ERR("Could not get preference service: %08x\n", nsres); return; } set_lang(pref); set_bool_pref(pref, "security.warn_entering_secure", FALSE); set_bool_pref(pref, "security.warn_submit_insecure", FALSE); set_int_pref(pref, "layout.spellcheckDefault", 0); nsIPrefBranch_Release(pref); } static BOOL init_xpcom(const PRUnichar *gre_path) { nsIComponentRegistrar *registrar = NULL; nsIFile *gre_dir; WCHAR *ptr; nsresult nsres; nsres = create_nsfile(gre_path, &gre_dir); if(NS_FAILED(nsres)) { FreeLibrary(xul_handle); return FALSE; } nsres = NS_InitXPCOM2(&pServMgr, gre_dir, &nsDirectoryServiceProvider); if(NS_FAILED(nsres)) { ERR("NS_InitXPCOM2 failed: %08x\n", nsres); FreeLibrary(xul_handle); return FALSE; } strcpyW(gecko_path, gre_path); for(ptr = gecko_path; *ptr; ptr++) { if(*ptr == '\\') *ptr = '/'; } gecko_path_len = ptr-gecko_path; nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr); if(NS_FAILED(nsres)) ERR("Could not get nsIComponentManager: %08x\n", nsres); nsres = NS_GetComponentRegistrar(®istrar); if(NS_SUCCEEDED(nsres)) init_nsio(pCompMgr, registrar); else ERR("NS_GetComponentRegistrar failed: %08x\n", nsres); init_mutation(pCompMgr); set_preferences(); nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_MEMORY_CONTRACTID, NULL, &IID_nsIMemory, (void**)&nsmem); if(NS_FAILED(nsres)) ERR("Could not get nsIMemory: %08x\n", nsres); if(registrar) { register_nsservice(registrar, pServMgr); nsIComponentRegistrar_Release(registrar); } init_node_cc(); return TRUE; } static CRITICAL_SECTION cs_load_gecko; static CRITICAL_SECTION_DEBUG cs_load_gecko_dbg = { 0, 0, &cs_load_gecko, { &cs_load_gecko_dbg.ProcessLocksList, &cs_load_gecko_dbg.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": load_gecko") } }; static CRITICAL_SECTION cs_load_gecko = { &cs_load_gecko_dbg, -1, 0, 0, 0, 0 }; BOOL load_gecko(void) { PRUnichar gre_path[MAX_PATH]; BOOL ret = FALSE; static DWORD loading_thread; TRACE("()\n"); /* load_gecko may be called recursively */ if(loading_thread == GetCurrentThreadId()) return pCompMgr != NULL; EnterCriticalSection(&cs_load_gecko); if(!loading_thread) { loading_thread = GetCurrentThreadId(); if(load_wine_gecko(gre_path) || (install_wine_gecko() && load_wine_gecko(gre_path))) ret = init_xpcom(gre_path); else MESSAGE("Could not load wine-gecko. HTML rendering will be disabled.\n"); }else { ret = pCompMgr != NULL; } LeaveCriticalSection(&cs_load_gecko); return ret; } void *nsalloc(size_t size) { return nsIMemory_Alloc(nsmem, size); } void nsfree(void *mem) { nsIMemory_Free(nsmem, mem); } static BOOL nsACString_Init(nsACString *str, const char *data) { return NS_SUCCEEDED(NS_CStringContainerInit2(str, data, PR_UINT32_MAX, 0)); } /* * Initializes nsACString with data owned by caller. * Caller must ensure that data is valid during lifetime of string object. */ void nsACString_InitDepend(nsACString *str, const char *data) { NS_CStringContainerInit2(str, data, PR_UINT32_MAX, NS_CSTRING_CONTAINER_INIT_DEPEND); } void nsACString_SetData(nsACString *str, const char *data) { NS_CStringSetData(str, data, PR_UINT32_MAX); } PRUint32 nsACString_GetData(const nsACString *str, const char **data) { return NS_CStringGetData(str, data, NULL); } void nsACString_Finish(nsACString *str) { NS_CStringContainerFinish(str); } BOOL nsAString_Init(nsAString *str, const PRUnichar *data) { return NS_SUCCEEDED(NS_StringContainerInit2(str, data, PR_UINT32_MAX, 0)); } /* * Initializes nsAString with data owned by caller. * Caller must ensure that data is valid during lifetime of string object. */ void nsAString_InitDepend(nsAString *str, const PRUnichar *data) { NS_StringContainerInit2(str, data, PR_UINT32_MAX, NS_STRING_CONTAINER_INIT_DEPEND); } void nsAString_SetData(nsAString *str, const PRUnichar *data) { NS_StringSetData(str, data, PR_UINT32_MAX); } PRUint32 nsAString_GetData(const nsAString *str, const PRUnichar **data) { return NS_StringGetData(str, data, NULL); } void nsAString_Finish(nsAString *str) { NS_StringContainerFinish(str); } HRESULT return_nsstr(nsresult nsres, nsAString *nsstr, BSTR *p) { const PRUnichar *str; if(NS_FAILED(nsres)) { ERR("failed: %08x\n", nsres); nsAString_Finish(nsstr); return E_FAIL; } nsAString_GetData(nsstr, &str); TRACE("ret %s\n", debugstr_w(str)); if(*str) { *p = SysAllocString(str); if(!*p) return E_OUTOFMEMORY; }else { *p = NULL; } nsAString_Finish(nsstr); return S_OK; } nsICommandParams *create_nscommand_params(void) { nsICommandParams *ret = NULL; nsresult nsres; if(!pCompMgr) return NULL; nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_COMMANDPARAMS_CONTRACTID, NULL, &IID_nsICommandParams, (void**)&ret); if(NS_FAILED(nsres)) ERR("Could not get nsICommandParams\n"); return ret; } nsIWritableVariant *create_nsvariant(void) { nsIWritableVariant *ret = NULL; nsresult nsres; if(!pCompMgr) return NULL; nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_VARIANT_CONTRACTID, NULL, &IID_nsIWritableVariant, (void**)&ret); if(NS_FAILED(nsres)) ERR("Could not get nsIVariant\n"); return ret; } nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv) { nsIInterfaceRequestor *iface_req; nsresult nsres; nsres = nsISupports_QueryInterface(iface, &IID_nsIInterfaceRequestor, (void**)&iface_req); if(NS_FAILED(nsres)) return nsres; nsres = nsIInterfaceRequestor_GetInterface(iface_req, riid, ppv); nsIInterfaceRequestor_Release(iface_req); return nsres; } static HRESULT nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str) { nsIDOMNodeList *node_list = NULL; cpp_bool has_children = FALSE; nsIContent *nscontent; PRUint16 type; nsresult nsres; nsIDOMNode_HasChildNodes(nsnode, &has_children); nsres = nsIDOMNode_GetNodeType(nsnode, &type); if(NS_FAILED(nsres)) { ERR("GetType failed: %08x\n", nsres); return E_FAIL; } if(type != DOCUMENT_NODE) { nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIContent, (void**)&nscontent); if(NS_FAILED(nsres)) { ERR("Could not get nsIContent interface: %08x\n", nsres); return E_FAIL; } } switch(type) { case ELEMENT_NODE: nsIContentSerializer_AppendElementStart(serializer, nscontent, nscontent, str); break; case TEXT_NODE: nsIContentSerializer_AppendText(serializer, nscontent, 0, -1, str); break; case COMMENT_NODE: nsres = nsIContentSerializer_AppendComment(serializer, nscontent, 0, -1, str); break; case DOCUMENT_NODE: { nsIDocument *nsdoc; nsIDOMNode_QueryInterface(nsnode, &IID_nsIDocument, (void**)&nsdoc); nsIContentSerializer_AppendDocumentStart(serializer, nsdoc, str); nsIDocument_Release(nsdoc); break; } case DOCUMENT_TYPE_NODE: WARN("Ignoring DOCUMENT_TYPE_NODE\n"); break; case DOCUMENT_FRAGMENT_NODE: break; default: FIXME("Unhandled type %u\n", type); } if(has_children) { PRUint32 child_cnt, i; nsIDOMNode *child_node; nsIDOMNode_GetChildNodes(nsnode, &node_list); nsIDOMNodeList_GetLength(node_list, &child_cnt); for(i=0; ieditor) { nsIEditor_Release(This->editor); This->editor = NULL; } if(This->editor_controller) { nsIController_Release(This->editor_controller); This->editor_controller = NULL; } nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession, (void**)&editing_session); if(NS_FAILED(nsres)) { ERR("Could not get nsIEditingSession: %08x\n", nsres); return; } nsres = nsIEditingSession_GetEditorForWindow(editing_session, This->doc->basedoc.window->nswindow, &This->editor); nsIEditingSession_Release(editing_session); if(NS_FAILED(nsres)) { ERR("Could not get editor: %08x\n", nsres); return; } nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx); if(NS_SUCCEEDED(nsres)) { nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor); if(NS_FAILED(nsres)) ERR("SetCommandContext failed: %08x\n", nsres); nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController, (void**)&This->editor_controller); nsIControllerContext_Release(ctrlctx); if(NS_FAILED(nsres)) ERR("Could not get nsIController interface: %08x\n", nsres); }else { ERR("Could not create edit controller: %08x\n", nsres); } } void close_gecko(void) { TRACE("()\n"); release_nsio(); init_mutation(NULL); if(profile_directory) { nsIFile_Release(profile_directory); profile_directory = NULL; } if(pCompMgr) nsIComponentManager_Release(pCompMgr); if(pServMgr) nsIServiceManager_Release(pServMgr); if(nsmem) nsIMemory_Release(nsmem); /* Gecko doesn't really support being unloaded */ /* if (hXPCOM) FreeLibrary(hXPCOM); */ DeleteCriticalSection(&cs_load_gecko); } BOOL is_gecko_path(const char *path) { WCHAR *buf, *ptr; BOOL ret; buf = heap_strdupAtoW(path); if(strlenW(buf) < gecko_path_len) return FALSE; buf[gecko_path_len] = 0; for(ptr = buf; *ptr; ptr++) { if(*ptr == '\\') *ptr = '/'; } ret = !strcmpiW(buf, gecko_path); heap_free(buf); return ret; } struct nsWeakReference { nsIWeakReference nsIWeakReference_iface; LONG ref; NSContainer *nscontainer; }; static inline nsWeakReference *impl_from_nsIWeakReference(nsIWeakReference *iface) { return CONTAINING_RECORD(iface, nsWeakReference, nsIWeakReference_iface); } static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface, nsIIDRef riid, void **result) { nsWeakReference *This = impl_from_nsIWeakReference(iface); if(IsEqualGUID(&IID_nsISupports, riid)) { TRACE("(%p)->(IID_nsISupports %p)\n", This, result); *result = &This->nsIWeakReference_iface; }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) { TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result); *result = &This->nsIWeakReference_iface; }else { WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result); *result = NULL; return NS_NOINTERFACE; } nsISupports_AddRef((nsISupports*)*result); return NS_OK; } static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface) { nsWeakReference *This = impl_from_nsIWeakReference(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface) { nsWeakReference *This = impl_from_nsIWeakReference(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { assert(!This->nscontainer); heap_free(This); } return ref; } static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface, const nsIID *riid, void **result) { nsWeakReference *This = impl_from_nsIWeakReference(iface); if(!This->nscontainer) return NS_ERROR_NULL_POINTER; return nsIWebBrowserChrome_QueryInterface(&This->nscontainer->nsIWebBrowserChrome_iface, riid, result); } static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = { nsWeakReference_QueryInterface, nsWeakReference_AddRef, nsWeakReference_Release, nsWeakReference_QueryReferent }; /********************************************************** * nsIWebBrowserChrome interface */ static inline NSContainer *impl_from_nsIWebBrowserChrome(nsIWebBrowserChrome *iface) { return CONTAINING_RECORD(iface, NSContainer, nsIWebBrowserChrome_iface); } static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); *result = NULL; if(IsEqualGUID(&IID_nsISupports, riid)) { TRACE("(%p)->(IID_nsISupports, %p)\n", This, result); *result = &This->nsIWebBrowserChrome_iface; }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) { TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result); *result = &This->nsIWebBrowserChrome_iface; }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) { TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result); *result = &This->nsIContextMenuListener_iface; }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) { TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result); *result = &This->nsIURIContentListener_iface; }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) { TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result); *result = &This->nsIEmbeddingSiteWindow_iface; }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) { TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result); *result = &This->nsITooltipListener_iface; }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) { TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result); *result = &This->nsIInterfaceRequestor_iface; }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) { TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result); *result = &This->nsISupportsWeakReference_iface; } if(*result) { nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); return NS_OK; } TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result); return NS_NOINTERFACE; } static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { if(This->parent) nsIWebBrowserChrome_Release(&This->parent->nsIWebBrowserChrome_iface); if(This->weak_reference) { This->weak_reference->nscontainer = NULL; nsIWeakReference_Release(&This->weak_reference->nsIWeakReference_iface); } heap_free(This); } return ref; } static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface, PRUint32 statusType, const PRUnichar *status) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status)); return NS_OK; } static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface, nsIWebBrowser **aWebBrowser) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); TRACE("(%p)->(%p)\n", This, aWebBrowser); if(!aWebBrowser) return NS_ERROR_INVALID_ARG; if(This->webbrowser) nsIWebBrowser_AddRef(This->webbrowser); *aWebBrowser = This->webbrowser; return S_OK; } static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface, nsIWebBrowser *aWebBrowser) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); TRACE("(%p)->(%p)\n", This, aWebBrowser); if(aWebBrowser != This->webbrowser) ERR("Wrong nsWebBrowser!\n"); return NS_OK; } static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface, PRUint32 *aChromeFlags) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)->(%p)\n", This, aChromeFlags); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface, PRUint32 aChromeFlags) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)->(%08x)\n", This, aChromeFlags); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); TRACE("(%p)\n", This); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface, PRInt32 aCX, PRInt32 aCY) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)->(%d %d)\n", This, aCX, aCY); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)\n", This); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, cpp_bool *_retval) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)->(%p)\n", This, _retval); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface, nsresult aStatus) { NSContainer *This = impl_from_nsIWebBrowserChrome(iface); WARN("(%p)->(%08x)\n", This, aStatus); return NS_ERROR_NOT_IMPLEMENTED; } static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = { nsWebBrowserChrome_QueryInterface, nsWebBrowserChrome_AddRef, nsWebBrowserChrome_Release, nsWebBrowserChrome_SetStatus, nsWebBrowserChrome_GetWebBrowser, nsWebBrowserChrome_SetWebBrowser, nsWebBrowserChrome_GetChromeFlags, nsWebBrowserChrome_SetChromeFlags, nsWebBrowserChrome_DestroyBrowserWindow, nsWebBrowserChrome_SizeBrowserTo, nsWebBrowserChrome_ShowAsModal, nsWebBrowserChrome_IsWindowModal, nsWebBrowserChrome_ExitModalEventLoop }; /********************************************************** * nsIContextMenuListener interface */ static inline NSContainer *impl_from_nsIContextMenuListener(nsIContextMenuListener *iface) { return CONTAINING_RECORD(iface, NSContainer, nsIContextMenuListener_iface); } static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIContextMenuListener(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface) { NSContainer *This = impl_from_nsIContextMenuListener(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface) { NSContainer *This = impl_from_nsIContextMenuListener(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface, PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode) { NSContainer *This = impl_from_nsIContextMenuListener(iface); nsIDOMMouseEvent *event; HTMLDOMNode *node; POINT pt; DWORD dwID = CONTEXT_MENU_DEFAULT; nsresult nsres; HRESULT hres; TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode); fire_event(This->doc->basedoc.doc_node /* FIXME */, EVENTID_CONTEXTMENU, TRUE, aNode, aEvent); nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event); if(NS_FAILED(nsres)) { ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres); return nsres; } nsIDOMMouseEvent_GetScreenX(event, &pt.x); nsIDOMMouseEvent_GetScreenY(event, &pt.y); nsIDOMMouseEvent_Release(event); switch(aContextFlags) { case CONTEXT_NONE: case CONTEXT_DOCUMENT: case CONTEXT_TEXT: dwID = CONTEXT_MENU_DEFAULT; break; case CONTEXT_IMAGE: case CONTEXT_IMAGE|CONTEXT_LINK: dwID = CONTEXT_MENU_IMAGE; break; case CONTEXT_LINK: dwID = CONTEXT_MENU_ANCHOR; break; case CONTEXT_INPUT: dwID = CONTEXT_MENU_CONTROL; break; default: FIXME("aContextFlags=%08x\n", aContextFlags); }; hres = get_node(This->doc->basedoc.doc_node, aNode, TRUE, &node); if(FAILED(hres)) return NS_ERROR_FAILURE; show_context_menu(This->doc, dwID, &pt, (IDispatch*)&node->IHTMLDOMNode_iface); node_release(node); return NS_OK; } static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = { nsContextMenuListener_QueryInterface, nsContextMenuListener_AddRef, nsContextMenuListener_Release, nsContextMenuListener_OnShowContextMenu }; /********************************************************** * nsIURIContentListener interface */ static inline NSContainer *impl_from_nsIURIContentListener(nsIURIContentListener *iface) { return CONTAINING_RECORD(iface, NSContainer, nsIURIContentListener_iface); } static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIURIContentListener(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface) { NSContainer *This = impl_from_nsIURIContentListener(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface) { NSContainer *This = impl_from_nsIURIContentListener(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface, nsIURI *aURI, cpp_bool *_retval) { NSContainer *This = impl_from_nsIURIContentListener(iface); nsACString spec_str; const char *spec; nsresult nsres; nsACString_Init(&spec_str, NULL); nsIURI_GetSpec(aURI, &spec_str); nsACString_GetData(&spec_str, &spec); TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval); nsACString_Finish(&spec_str); nsres = on_start_uri_open(This, aURI, _retval); if(NS_FAILED(nsres)) return nsres; return !*_retval && This->content_listener ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval) : NS_OK; } static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface, const char *aContentType, cpp_bool aIsContentPreferred, nsIRequest *aRequest, nsIStreamListener **aContentHandler, cpp_bool *_retval) { NSContainer *This = impl_from_nsIURIContentListener(iface); TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred, aRequest, aContentHandler, _retval); return This->content_listener ? nsIURIContentListener_DoContent(This->content_listener, aContentType, aIsContentPreferred, aRequest, aContentHandler, _retval) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface, const char *aContentType, char **aDesiredContentType, cpp_bool *_retval) { NSContainer *This = impl_from_nsIURIContentListener(iface); TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval); /* FIXME: Should we do something here? */ *_retval = TRUE; return This->content_listener ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType, aDesiredContentType, _retval) : NS_OK; } static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface, const char *aContentType, cpp_bool aIsContentPreferred, char **aDesiredContentType, cpp_bool *_retval) { NSContainer *This = impl_from_nsIURIContentListener(iface); TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred, aDesiredContentType, _retval); return This->content_listener ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType, aIsContentPreferred, aDesiredContentType, _retval) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface, nsISupports **aLoadCookie) { NSContainer *This = impl_from_nsIURIContentListener(iface); WARN("(%p)->(%p)\n", This, aLoadCookie); return This->content_listener ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface, nsISupports *aLoadCookie) { NSContainer *This = impl_from_nsIURIContentListener(iface); WARN("(%p)->(%p)\n", This, aLoadCookie); return This->content_listener ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface, nsIURIContentListener **aParentContentListener) { NSContainer *This = impl_from_nsIURIContentListener(iface); TRACE("(%p)->(%p)\n", This, aParentContentListener); if(This->content_listener) nsIURIContentListener_AddRef(This->content_listener); *aParentContentListener = This->content_listener; return NS_OK; } static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface, nsIURIContentListener *aParentContentListener) { NSContainer *This = impl_from_nsIURIContentListener(iface); TRACE("(%p)->(%p)\n", This, aParentContentListener); if(aParentContentListener == &This->nsIURIContentListener_iface) return NS_OK; if(This->content_listener) nsIURIContentListener_Release(This->content_listener); This->content_listener = aParentContentListener; if(This->content_listener) nsIURIContentListener_AddRef(This->content_listener); return NS_OK; } static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = { nsURIContentListener_QueryInterface, nsURIContentListener_AddRef, nsURIContentListener_Release, nsURIContentListener_OnStartURIOpen, nsURIContentListener_DoContent, nsURIContentListener_IsPreferred, nsURIContentListener_CanHandleContent, nsURIContentListener_GetLoadCookie, nsURIContentListener_SetLoadCookie, nsURIContentListener_GetParentContentListener, nsURIContentListener_SetParentContentListener }; /********************************************************** * nsIEmbeddinSiteWindow interface */ static inline NSContainer *impl_from_nsIEmbeddingSiteWindow(nsIEmbeddingSiteWindow *iface) { return CONTAINING_RECORD(iface, NSContainer, nsIEmbeddingSiteWindow_iface); } static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface, PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface, PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); TRACE("(%p)\n", This); return nsIBaseWindow_SetFocus(This->window); } static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface, cpp_bool *aVisibility) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); TRACE("(%p)->(%p)\n", This, aVisibility); *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd); return NS_OK; } static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface, cpp_bool aVisibility) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); TRACE("(%p)->(%x)\n", This, aVisibility); return NS_OK; } static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface, PRUnichar **aTitle) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); WARN("(%p)->(%p)\n", This, aTitle); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface, const PRUnichar *aTitle) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); WARN("(%p)->(%s)\n", This, debugstr_w(aTitle)); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface, void **aSiteWindow) { NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface); TRACE("(%p)->(%p)\n", This, aSiteWindow); *aSiteWindow = This->hwnd; return NS_OK; } static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = { nsEmbeddingSiteWindow_QueryInterface, nsEmbeddingSiteWindow_AddRef, nsEmbeddingSiteWindow_Release, nsEmbeddingSiteWindow_SetDimensions, nsEmbeddingSiteWindow_GetDimensions, nsEmbeddingSiteWindow_SetFocus, nsEmbeddingSiteWindow_GetVisibility, nsEmbeddingSiteWindow_SetVisibility, nsEmbeddingSiteWindow_GetTitle, nsEmbeddingSiteWindow_SetTitle, nsEmbeddingSiteWindow_GetSiteWindow }; static inline NSContainer *impl_from_nsITooltipListener(nsITooltipListener *iface) { return CONTAINING_RECORD(iface, NSContainer, nsITooltipListener_iface); } static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsITooltipListener(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface) { NSContainer *This = impl_from_nsITooltipListener(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface) { NSContainer *This = impl_from_nsITooltipListener(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface, PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText) { NSContainer *This = impl_from_nsITooltipListener(iface); if (This->doc) show_tooltip(This->doc, aXCoord, aYCoord, aTipText); return NS_OK; } static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface) { NSContainer *This = impl_from_nsITooltipListener(iface); if (This->doc) hide_tooltip(This->doc); return NS_OK; } static const nsITooltipListenerVtbl nsTooltipListenerVtbl = { nsTooltipListener_QueryInterface, nsTooltipListener_AddRef, nsTooltipListener_Release, nsTooltipListener_OnShowTooltip, nsTooltipListener_OnHideTooltip }; static inline NSContainer *impl_from_nsIInterfaceRequestor(nsIInterfaceRequestor *iface) { return CONTAINING_RECORD(iface, NSContainer, nsIInterfaceRequestor_iface); } static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIInterfaceRequestor(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface) { NSContainer *This = impl_from_nsIInterfaceRequestor(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface) { NSContainer *This = impl_from_nsIInterfaceRequestor(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsIInterfaceRequestor(iface); if(IsEqualGUID(&IID_nsIDOMWindow, riid)) { TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result); return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result); } return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = { nsInterfaceRequestor_QueryInterface, nsInterfaceRequestor_AddRef, nsInterfaceRequestor_Release, nsInterfaceRequestor_GetInterface }; static inline NSContainer *impl_from_nsISupportsWeakReference(nsISupportsWeakReference *iface) { return CONTAINING_RECORD(iface, NSContainer, nsISupportsWeakReference_iface); } static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface, nsIIDRef riid, void **result) { NSContainer *This = impl_from_nsISupportsWeakReference(iface); return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result); } static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface) { NSContainer *This = impl_from_nsISupportsWeakReference(iface); return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface); } static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface) { NSContainer *This = impl_from_nsISupportsWeakReference(iface); return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); } static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface, nsIWeakReference **_retval) { NSContainer *This = impl_from_nsISupportsWeakReference(iface); TRACE("(%p)->(%p)\n", This, _retval); if(!This->weak_reference) { This->weak_reference = heap_alloc(sizeof(nsWeakReference)); if(!This->weak_reference) return NS_ERROR_OUT_OF_MEMORY; This->weak_reference->nsIWeakReference_iface.lpVtbl = &nsWeakReferenceVtbl; This->weak_reference->ref = 1; This->weak_reference->nscontainer = This; } *_retval = &This->weak_reference->nsIWeakReference_iface; nsIWeakReference_AddRef(*_retval); return NS_OK; } static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = { nsSupportsWeakReference_QueryInterface, nsSupportsWeakReference_AddRef, nsSupportsWeakReference_Release, nsSupportsWeakReference_GetWeakReference }; static HRESULT init_nscontainer(NSContainer *nscontainer) { nsIWebBrowserSetup *wbsetup; nsIScrollable *scrollable; nsresult nsres; nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID, NULL, &IID_nsIWebBrowser, (void**)&nscontainer->webbrowser); if(NS_FAILED(nsres)) { ERR("Creating WebBrowser failed: %08x\n", nsres); return E_FAIL; } nsres = nsIWebBrowser_SetContainerWindow(nscontainer->webbrowser, &nscontainer->nsIWebBrowserChrome_iface); if(NS_FAILED(nsres)) { ERR("SetContainerWindow failed: %08x\n", nsres); return E_FAIL; } nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIBaseWindow, (void**)&nscontainer->window); if(NS_FAILED(nsres)) { ERR("Could not get nsIBaseWindow interface: %08x\n", nsres); return E_FAIL; } nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserSetup, (void**)&wbsetup); if(NS_SUCCEEDED(nsres)) { nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE); nsIWebBrowserSetup_Release(wbsetup); if(NS_FAILED(nsres)) { ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres); return E_FAIL; } }else { ERR("Could not get nsIWebBrowserSetup interface\n"); return E_FAIL; } nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebNavigation, (void**)&nscontainer->navigation); if(NS_FAILED(nsres)) { ERR("Could not get nsIWebNavigation interface: %08x\n", nsres); return E_FAIL; } nsres = nsIWebBrowserFocus_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserFocus, (void**)&nscontainer->focus); if(NS_FAILED(nsres)) { ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres); return E_FAIL; } if(!nscontainer_class) { register_nscontainer_class(); if(!nscontainer_class) return E_FAIL; } nscontainer->hwnd = CreateWindowExW(0, wszNsContainer, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100, GetDesktopWindow(), NULL, hInst, nscontainer); if(!nscontainer->hwnd) { WARN("Could not create window\n"); return E_FAIL; } nsres = nsIBaseWindow_InitWindow(nscontainer->window, nscontainer->hwnd, NULL, 0, 0, 100, 100); if(NS_SUCCEEDED(nsres)) { nsres = nsIBaseWindow_Create(nscontainer->window); if(NS_FAILED(nsres)) { WARN("Creating window failed: %08x\n", nsres); return E_FAIL; } nsIBaseWindow_SetVisibility(nscontainer->window, FALSE); nsIBaseWindow_SetEnabled(nscontainer->window, FALSE); }else { ERR("InitWindow failed: %08x\n", nsres); return E_FAIL; } nsres = nsIWebBrowser_SetParentURIContentListener(nscontainer->webbrowser, &nscontainer->nsIURIContentListener_iface); if(NS_FAILED(nsres)) ERR("SetParentURIContentListener failed: %08x\n", nsres); nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIScrollable, (void**)&scrollable); if(NS_SUCCEEDED(nsres)) { nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_Y, Scrollbar_Always); if(NS_FAILED(nsres)) ERR("Could not set default Y scrollbar prefs: %08x\n", nsres); nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_X, Scrollbar_Auto); if(NS_FAILED(nsres)) ERR("Could not set default X scrollbar prefs: %08x\n", nsres); nsIScrollable_Release(scrollable); }else { ERR("Could not get nsIScrollable: %08x\n", nsres); } return S_OK; } HRESULT create_nscontainer(HTMLDocumentObj *doc, NSContainer **_ret) { NSContainer *ret; HRESULT hres; if(!load_gecko()) return CLASS_E_CLASSNOTAVAILABLE; ret = heap_alloc_zero(sizeof(NSContainer)); if(!ret) return E_OUTOFMEMORY; ret->nsIWebBrowserChrome_iface.lpVtbl = &nsWebBrowserChromeVtbl; ret->nsIContextMenuListener_iface.lpVtbl = &nsContextMenuListenerVtbl; ret->nsIURIContentListener_iface.lpVtbl = &nsURIContentListenerVtbl; ret->nsIEmbeddingSiteWindow_iface.lpVtbl = &nsEmbeddingSiteWindowVtbl; ret->nsITooltipListener_iface.lpVtbl = &nsTooltipListenerVtbl; ret->nsIInterfaceRequestor_iface.lpVtbl = &nsInterfaceRequestorVtbl; ret->nsISupportsWeakReference_iface.lpVtbl = &nsSupportsWeakReferenceVtbl; ret->doc = doc; ret->ref = 1; hres = init_nscontainer(ret); if(SUCCEEDED(hres)) *_ret = ret; else nsIWebBrowserChrome_Release(&ret->nsIWebBrowserChrome_iface); return hres; } void NSContainer_Release(NSContainer *This) { TRACE("(%p)\n", This); This->doc = NULL; ShowWindow(This->hwnd, SW_HIDE); SetParent(This->hwnd, NULL); nsIBaseWindow_SetVisibility(This->window, FALSE); nsIBaseWindow_Destroy(This->window); nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL); nsIWebBrowser_Release(This->webbrowser); This->webbrowser = NULL; nsIWebNavigation_Release(This->navigation); This->navigation = NULL; nsIBaseWindow_Release(This->window); This->window = NULL; nsIWebBrowserFocus_Release(This->focus); This->focus = NULL; if(This->editor_controller) { nsIController_Release(This->editor_controller); This->editor_controller = NULL; } if(This->editor) { nsIEditor_Release(This->editor); This->editor = NULL; } if(This->content_listener) { nsIURIContentListener_Release(This->content_listener); This->content_listener = NULL; } if(This->hwnd) { DestroyWindow(This->hwnd); This->hwnd = NULL; } nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface); }