mshtml: Use inline wrappers and fixed found warnings.
[wine] / dlls / mshtml / nsembed.c
1 /*
2  * Copyright 2005-2007 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 "config.h"
20
21 #include <stdarg.h>
22 #include <assert.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "ole2.h"
31 #include "shlobj.h"
32
33 #include "wine/debug.h"
34
35 #include "mshtml_private.h"
36 #include "htmlevent.h"
37 #include "binding.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40 WINE_DECLARE_DEBUG_CHANNEL(gecko);
41
42 #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1"
43 #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1"
44 #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1"
45 #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1"
46 #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html"
47 #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1"
48 #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1"
49 #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1"
50
51 #define PR_UINT32_MAX 0xffffffff
52
53 #define NS_STRING_CONTAINER_INIT_DEPEND  0x0002
54 #define NS_CSTRING_CONTAINER_INIT_DEPEND 0x0002
55
56 static nsresult (CDECL *NS_InitXPCOM2)(nsIServiceManager**,void*,void*);
57 static nsresult (CDECL *NS_ShutdownXPCOM)(nsIServiceManager*);
58 static nsresult (CDECL *NS_GetComponentRegistrar)(nsIComponentRegistrar**);
59 static nsresult (CDECL *NS_StringContainerInit2)(nsStringContainer*,const PRUnichar*,PRUint32,PRUint32);
60 static nsresult (CDECL *NS_CStringContainerInit2)(nsCStringContainer*,const char*,PRUint32,PRUint32);
61 static nsresult (CDECL *NS_StringContainerFinish)(nsStringContainer*);
62 static nsresult (CDECL *NS_CStringContainerFinish)(nsCStringContainer*);
63 static nsresult (CDECL *NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32);
64 static nsresult (CDECL *NS_CStringSetData)(nsACString*,const char*,PRUint32);
65 static nsresult (CDECL *NS_NewLocalFile)(const nsAString*,cpp_bool,nsIFile**);
66 static PRUint32 (CDECL *NS_StringGetData)(const nsAString*,const PRUnichar **,cpp_bool*);
67 static PRUint32 (CDECL *NS_CStringGetData)(const nsACString*,const char**,cpp_bool*);
68
69 static HINSTANCE xul_handle = NULL;
70
71 static nsIServiceManager *pServMgr = NULL;
72 static nsIComponentManager *pCompMgr = NULL;
73 static nsIMemory *nsmem = NULL;
74 static nsIFile *profile_directory;
75
76 static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0};
77
78 static ATOM nscontainer_class;
79 static WCHAR gecko_path[MAX_PATH];
80 static unsigned gecko_path_len;
81
82 nsresult create_nsfile(const PRUnichar *path, nsIFile **ret)
83 {
84     nsAString str;
85     nsresult nsres;
86
87     nsAString_InitDepend(&str, path);
88     nsres = NS_NewLocalFile(&str, FALSE, ret);
89     nsAString_Finish(&str);
90
91     if(NS_FAILED(nsres))
92         WARN("NS_NewLocalFile failed: %08x\n", nsres);
93     return nsres;
94 }
95
96 static nsresult NSAPI nsDirectoryServiceProvider_QueryInterface(nsIDirectoryServiceProvider *iface,
97         nsIIDRef riid, void **result)
98 {
99     if(IsEqualGUID(&IID_nsISupports, riid)) {
100         TRACE("(IID_nsISupports %p)\n", result);
101         *result = iface;
102     }else if(IsEqualGUID(&IID_nsIDirectoryServiceProvider, riid)) {
103         TRACE("(IID_nsIDirectoryServiceProvider %p)\n", result);
104         *result = iface;
105     }else {
106         WARN("(%s %p)\n", debugstr_guid(riid), result);
107         *result = NULL;
108         return NS_NOINTERFACE;
109     }
110
111     nsISupports_AddRef((nsISupports*)*result);
112     return NS_OK;
113 }
114
115 static nsrefcnt NSAPI nsDirectoryServiceProvider_AddRef(nsIDirectoryServiceProvider *iface)
116 {
117     return 2;
118 }
119
120 static nsrefcnt NSAPI nsDirectoryServiceProvider_Release(nsIDirectoryServiceProvider *iface)
121 {
122     return 1;
123 }
124
125 static nsresult create_profile_directory(void)
126 {
127     static const WCHAR wine_geckoW[] = {'\\','w','i','n','e','_','g','e','c','k','o',0};
128
129     WCHAR path[MAX_PATH + sizeof(wine_geckoW)/sizeof(WCHAR)];
130     cpp_bool exists;
131     nsresult nsres;
132     HRESULT hres;
133
134     hres = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path);
135     if(FAILED(hres)) {
136         ERR("SHGetFolderPath failed: %08x\n", hres);
137         return NS_ERROR_FAILURE;
138     }
139
140     strcatW(path, wine_geckoW);
141     nsres = create_nsfile(path, &profile_directory);
142     if(NS_FAILED(nsres))
143         return nsres;
144
145     nsres = nsIFile_Exists(profile_directory, &exists);
146     if(NS_FAILED(nsres)) {
147         ERR("Exists failed: %08x\n", nsres);
148         return nsres;
149     }
150
151     if(!exists) {
152         nsres = nsIFile_Create(profile_directory, 1, 0700);
153         if(NS_FAILED(nsres))
154             ERR("Create failed: %08x\n", nsres);
155     }
156
157     return nsres;
158 }
159
160 static nsresult NSAPI nsDirectoryServiceProvider_GetFile(nsIDirectoryServiceProvider *iface,
161         const char *prop, cpp_bool *persistent, nsIFile **_retval)
162 {
163     TRACE("(%s %p %p)\n", debugstr_a(prop), persistent, _retval);
164
165     if(!strcmp(prop, "ProfD")) {
166         if(!profile_directory) {
167             nsresult nsres;
168
169             nsres = create_profile_directory();
170             if(NS_FAILED(nsres))
171                 return nsres;
172         }
173
174         return nsIFile_Clone(profile_directory, _retval);
175     }
176
177     return NS_ERROR_FAILURE;
178 }
179
180 static const nsIDirectoryServiceProviderVtbl nsDirectoryServiceProviderVtbl = {
181     nsDirectoryServiceProvider_QueryInterface,
182     nsDirectoryServiceProvider_AddRef,
183     nsDirectoryServiceProvider_Release,
184     nsDirectoryServiceProvider_GetFile
185 };
186
187 static nsIDirectoryServiceProvider nsDirectoryServiceProvider =
188     { &nsDirectoryServiceProviderVtbl };
189
190 static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
191 {
192     NSContainer *This;
193     nsresult nsres;
194
195     static const WCHAR wszTHIS[] = {'T','H','I','S',0};
196
197     if(msg == WM_CREATE) {
198         This = *(NSContainer**)lParam;
199         SetPropW(hwnd, wszTHIS, This);
200     }else {
201         This = GetPropW(hwnd, wszTHIS);
202     }
203
204     switch(msg) {
205     case WM_SIZE:
206         TRACE("(%p)->(WM_SIZE)\n", This);
207
208         nsres = nsIBaseWindow_SetSize(This->window,
209                 LOWORD(lParam), HIWORD(lParam), TRUE);
210         if(NS_FAILED(nsres))
211             WARN("SetSize failed: %08x\n", nsres);
212         break;
213
214     case WM_PARENTNOTIFY:
215         TRACE("WM_PARENTNOTIFY %x\n", (unsigned)wParam);
216
217         switch(wParam) {
218         case WM_LBUTTONDOWN:
219         case WM_RBUTTONDOWN:
220             nsIWebBrowserFocus_Activate(This->focus);
221         }
222     }
223
224     return DefWindowProcW(hwnd, msg, wParam, lParam);
225 }
226
227
228 static void register_nscontainer_class(void)
229 {
230     static WNDCLASSEXW wndclass = {
231         sizeof(WNDCLASSEXW),
232         CS_DBLCLKS,
233         nsembed_proc,
234         0, 0, NULL, NULL, NULL, NULL, NULL,
235         wszNsContainer,
236         NULL,
237     };
238     wndclass.hInstance = hInst;
239     nscontainer_class = RegisterClassExW(&wndclass);
240 }
241
242 static BOOL install_wine_gecko(void)
243 {
244     PROCESS_INFORMATION pi;
245     STARTUPINFOW si;
246     WCHAR app[MAX_PATH];
247     WCHAR *args;
248     LONG len;
249     BOOL ret;
250
251     static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0};
252     static const WCHAR argsW[] =
253         {' ','a','p','p','w','i','z','.','c','p','l',' ','i','n','s','t','a','l','l','_','g','e','c','k','o',0};
254
255     len = GetSystemDirectoryW(app, MAX_PATH-sizeof(controlW)/sizeof(WCHAR));
256     memcpy(app+len, controlW, sizeof(controlW));
257
258     args = heap_alloc(len*sizeof(WCHAR) + sizeof(controlW) + sizeof(argsW));
259     if(!args)
260         return FALSE;
261
262     memcpy(args, app, len*sizeof(WCHAR) + sizeof(controlW));
263     memcpy(args + len + sizeof(controlW)/sizeof(WCHAR)-1, argsW, sizeof(argsW));
264
265     TRACE("starting %s\n", debugstr_w(args));
266
267     memset(&si, 0, sizeof(si));
268     si.cb = sizeof(si);
269     ret = CreateProcessW(app, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
270     heap_free(args);
271     if (ret) {
272         CloseHandle(pi.hThread);
273         WaitForSingleObject(pi.hProcess, INFINITE);
274         CloseHandle(pi.hProcess);
275     }
276
277     return ret;
278 }
279
280 static void set_environment(LPCWSTR gre_path)
281 {
282     WCHAR path_env[MAX_PATH], buf[20];
283     int len, debug_level = 0;
284
285     static const WCHAR pathW[] = {'P','A','T','H',0};
286     static const WCHAR warnW[] = {'w','a','r','n',0};
287     static const WCHAR xpcom_debug_breakW[] =
288         {'X','P','C','O','M','_','D','E','B','U','G','_','B','R','E','A','K',0};
289     static const WCHAR nspr_log_modulesW[] =
290         {'N','S','P','R','_','L','O','G','_','M','O','D','U','L','E','S',0};
291     static const WCHAR debug_formatW[] = {'a','l','l',':','%','d',0};
292     static const WCHAR moz_plugin_pathW[] = {'M','O','Z','_','P','L','U','G','I','N','_','P','A','T','H',0};
293     static const WCHAR gecko_pluginW[] = {'\\','g','e','c','k','o','\\','p','l','u','g','i','n',0};
294
295     /* We have to modify PATH as XPCOM loads other DLLs from this directory. */
296     GetEnvironmentVariableW(pathW, path_env, sizeof(path_env)/sizeof(WCHAR));
297     len = strlenW(path_env);
298     path_env[len++] = ';';
299     strcpyW(path_env+len, gre_path);
300     SetEnvironmentVariableW(pathW, path_env);
301
302     SetEnvironmentVariableW(xpcom_debug_breakW, warnW);
303
304     if(TRACE_ON(gecko))
305         debug_level = 5;
306     else if(WARN_ON(gecko))
307         debug_level = 3;
308     else if(ERR_ON(gecko))
309         debug_level = 2;
310
311     sprintfW(buf, debug_formatW, debug_level);
312     SetEnvironmentVariableW(nspr_log_modulesW, buf);
313
314     len = GetSystemDirectoryW(path_env, (sizeof(path_env)-sizeof(gecko_pluginW))/sizeof(WCHAR)+1);
315     if(len) {
316         strcpyW(path_env+len, gecko_pluginW);
317         SetEnvironmentVariableW(moz_plugin_pathW, path_env);
318     }
319 }
320
321 static BOOL load_xul(const PRUnichar *gre_path)
322 {
323     static const WCHAR xul_dllW[] = {'\\','x','u','l','.','d','l','l',0};
324     WCHAR file_name[MAX_PATH];
325
326     strcpyW(file_name, gre_path);
327     strcatW(file_name, xul_dllW);
328
329     TRACE("(%s)\n", debugstr_w(file_name));
330
331     set_environment(gre_path);
332
333     xul_handle = LoadLibraryExW(file_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
334     if(!xul_handle) {
335         WARN("Could not load XUL: %d\n", GetLastError());
336         return FALSE;
337     }
338
339 #define NS_DLSYM(func) \
340     func = (void *)GetProcAddress(xul_handle, #func "_P"); \
341     if(!func) \
342         ERR("Could not GetProcAddress(" #func ") failed\n")
343
344     NS_DLSYM(NS_InitXPCOM2);
345     NS_DLSYM(NS_ShutdownXPCOM);
346     NS_DLSYM(NS_GetComponentRegistrar);
347     NS_DLSYM(NS_StringContainerInit2);
348     NS_DLSYM(NS_CStringContainerInit2);
349     NS_DLSYM(NS_StringContainerFinish);
350     NS_DLSYM(NS_CStringContainerFinish);
351     NS_DLSYM(NS_StringSetData);
352     NS_DLSYM(NS_CStringSetData);
353     NS_DLSYM(NS_NewLocalFile);
354     NS_DLSYM(NS_StringGetData);
355     NS_DLSYM(NS_CStringGetData);
356
357 #undef NS_DLSYM
358
359 #define NS_DLSYM(func) \
360     func = (void *)GetProcAddress(xul_handle, #func); \
361     if(!func) \
362         ERR("Could not GetProcAddress(" #func ") failed\n")
363
364     NS_DLSYM(ccref_incr);
365     NS_DLSYM(ccref_decr);
366     NS_DLSYM(ccref_init);
367     NS_DLSYM(ccref_unmark_if_purple);
368     NS_DLSYM(ccp_init);
369     NS_DLSYM(describe_cc_node);
370     NS_DLSYM(note_cc_edge);
371
372 #undef NS_DLSYM
373
374     return TRUE;
375 }
376
377 static BOOL check_version(LPCWSTR gre_path, const char *version_string)
378 {
379     WCHAR file_name[MAX_PATH];
380     char version[128];
381     DWORD read=0;
382     HANDLE hfile;
383
384     static const WCHAR wszVersion[] = {'\\','V','E','R','S','I','O','N',0};
385
386     strcpyW(file_name, gre_path);
387     strcatW(file_name, wszVersion);
388
389     hfile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
390                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
391     if(hfile == INVALID_HANDLE_VALUE) {
392         ERR("Could not open VERSION file\n");
393         return FALSE;
394     }
395
396     ReadFile(hfile, version, sizeof(version), &read, NULL);
397     version[read] = 0;
398     CloseHandle(hfile);
399
400     TRACE("%s\n", debugstr_a(version));
401
402     if(strcmp(version, version_string)) {
403         ERR("Unexpected version %s, expected %s\n", debugstr_a(version),
404             debugstr_a(version_string));
405         return FALSE;
406     }
407
408     return TRUE;
409 }
410
411 static BOOL load_wine_gecko_v(PRUnichar *gre_path, HKEY mshtml_key,
412         const char *version, const char *version_string)
413 {
414     DWORD res, type, size = MAX_PATH;
415     HKEY hkey = mshtml_key;
416
417     static const WCHAR wszGeckoPath[] =
418         {'G','e','c','k','o','P','a','t','h',0};
419
420     if(version) {
421         /* @@ Wine registry key: HKLM\Software\Wine\MSHTML\<version> */
422         res = RegOpenKeyA(mshtml_key, version, &hkey);
423         if(res != ERROR_SUCCESS)
424             return FALSE;
425     }
426
427     res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size);
428     if(hkey != mshtml_key)
429         RegCloseKey(hkey);
430     if(res != ERROR_SUCCESS || type != REG_SZ)
431         return FALSE;
432
433     if(!check_version(gre_path, version_string))
434         return FALSE;
435
436     return load_xul(gre_path);
437 }
438
439 static BOOL load_wine_gecko(PRUnichar *gre_path)
440 {
441     HKEY hkey;
442     DWORD res;
443     BOOL ret;
444
445     static const WCHAR wszMshtmlKey[] = {
446         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
447         '\\','M','S','H','T','M','L',0};
448
449     /* @@ Wine registry key: HKLM\Software\Wine\MSHTML */
450     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszMshtmlKey, &hkey);
451     if(res != ERROR_SUCCESS)
452         return FALSE;
453
454     ret = load_wine_gecko_v(gre_path, hkey, GECKO_VERSION, GECKO_VERSION_STRING);
455
456     RegCloseKey(hkey);
457     return ret;
458 }
459
460 static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val)
461 {
462     nsresult nsres;
463
464     nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val);
465     if(NS_FAILED(nsres))
466         ERR("Could not set pref %s\n", debugstr_a(pref_name));
467 }
468
469 static void set_int_pref(nsIPrefBranch *pref, const char *pref_name, int val)
470 {
471     nsresult nsres;
472
473     nsres = nsIPrefBranch_SetIntPref(pref, pref_name, val);
474     if(NS_FAILED(nsres))
475         ERR("Could not set pref %s\n", debugstr_a(pref_name));
476 }
477
478 static void set_string_pref(nsIPrefBranch *pref, const char *pref_name, const char *val)
479 {
480     nsresult nsres;
481
482     nsres = nsIPrefBranch_SetCharPref(pref, pref_name, val);
483     if(NS_FAILED(nsres))
484         ERR("Could not set pref %s\n", debugstr_a(pref_name));
485 }
486
487 static void set_lang(nsIPrefBranch *pref)
488 {
489     char langs[100];
490     DWORD res, size, type;
491     HKEY hkey;
492
493     static const WCHAR international_keyW[] =
494         {'S','o','f','t','w','a','r','e',
495          '\\','M','i','c','r','o','s','o','f','t',
496          '\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',
497          '\\','I','n','t','e','r','n','a','t','i','o','n','a','l',0};
498
499     res = RegOpenKeyW(HKEY_CURRENT_USER, international_keyW, &hkey);
500     if(res != ERROR_SUCCESS)
501         return;
502
503     size = sizeof(langs);
504     res = RegQueryValueExA(hkey, "AcceptLanguage", 0, &type, (LPBYTE)langs, &size);
505     RegCloseKey(hkey);
506     if(res != ERROR_SUCCESS || type != REG_SZ)
507         return;
508
509     TRACE("Setting lang %s\n", debugstr_a(langs));
510
511     set_string_pref(pref, "intl.accept_languages", langs);
512 }
513
514 static void set_preferences(void)
515 {
516     nsIPrefBranch *pref;
517     nsresult nsres;
518
519     nsres = nsIServiceManager_GetServiceByContractID(pServMgr, NS_PREFERENCES_CONTRACTID,
520             &IID_nsIPrefBranch, (void**)&pref);
521     if(NS_FAILED(nsres)) {
522         ERR("Could not get preference service: %08x\n", nsres);
523         return;
524     }
525
526     set_lang(pref);
527     set_bool_pref(pref, "security.warn_entering_secure", FALSE);
528     set_bool_pref(pref, "security.warn_submit_insecure", FALSE);
529     set_int_pref(pref, "layout.spellcheckDefault", 0);
530
531     nsIPrefBranch_Release(pref);
532 }
533
534 static BOOL init_xpcom(const PRUnichar *gre_path)
535 {
536     nsIComponentRegistrar *registrar = NULL;
537     nsIFile *gre_dir;
538     WCHAR *ptr;
539     nsresult nsres;
540
541     nsres = create_nsfile(gre_path, &gre_dir);
542     if(NS_FAILED(nsres)) {
543         FreeLibrary(xul_handle);
544         return FALSE;
545     }
546
547     nsres = NS_InitXPCOM2(&pServMgr, gre_dir, &nsDirectoryServiceProvider);
548     if(NS_FAILED(nsres)) {
549         ERR("NS_InitXPCOM2 failed: %08x\n", nsres);
550         FreeLibrary(xul_handle);
551         return FALSE;
552     }
553
554     strcpyW(gecko_path, gre_path);
555     for(ptr = gecko_path; *ptr; ptr++) {
556         if(*ptr == '\\')
557             *ptr = '/';
558     }
559     gecko_path_len = ptr-gecko_path;
560
561     nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr);
562     if(NS_FAILED(nsres))
563         ERR("Could not get nsIComponentManager: %08x\n", nsres);
564
565     nsres = NS_GetComponentRegistrar(&registrar);
566     if(NS_SUCCEEDED(nsres))
567         init_nsio(pCompMgr, registrar);
568     else
569         ERR("NS_GetComponentRegistrar failed: %08x\n", nsres);
570
571     init_mutation(pCompMgr);
572     set_preferences();
573
574     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_MEMORY_CONTRACTID,
575             NULL, &IID_nsIMemory, (void**)&nsmem);
576     if(NS_FAILED(nsres))
577         ERR("Could not get nsIMemory: %08x\n", nsres);
578
579     if(registrar) {
580         register_nsservice(registrar, pServMgr);
581         nsIComponentRegistrar_Release(registrar);
582     }
583
584     init_node_cc();
585
586     return TRUE;
587 }
588
589 static CRITICAL_SECTION cs_load_gecko;
590 static CRITICAL_SECTION_DEBUG cs_load_gecko_dbg =
591 {
592     0, 0, &cs_load_gecko,
593     { &cs_load_gecko_dbg.ProcessLocksList, &cs_load_gecko_dbg.ProcessLocksList },
594       0, 0, { (DWORD_PTR)(__FILE__ ": load_gecko") }
595 };
596 static CRITICAL_SECTION cs_load_gecko = { &cs_load_gecko_dbg, -1, 0, 0, 0, 0 };
597
598 BOOL load_gecko(void)
599 {
600     PRUnichar gre_path[MAX_PATH];
601     BOOL ret = FALSE;
602
603     static DWORD loading_thread;
604
605     TRACE("()\n");
606
607     /* load_gecko may be called recursively */
608     if(loading_thread == GetCurrentThreadId())
609         return pCompMgr != NULL;
610
611     EnterCriticalSection(&cs_load_gecko);
612
613     if(!loading_thread) {
614         loading_thread = GetCurrentThreadId();
615
616         if(load_wine_gecko(gre_path)
617            || (install_wine_gecko() && load_wine_gecko(gre_path)))
618             ret = init_xpcom(gre_path);
619         else
620            MESSAGE("Could not load wine-gecko. HTML rendering will be disabled.\n");
621     }else {
622         ret = pCompMgr != NULL;
623     }
624
625     LeaveCriticalSection(&cs_load_gecko);
626
627     return ret;
628 }
629
630 void *nsalloc(size_t size)
631 {
632     return nsIMemory_Alloc(nsmem, size);
633 }
634
635 void nsfree(void *mem)
636 {
637     nsIMemory_Free(nsmem, mem);
638 }
639
640 static BOOL nsACString_Init(nsACString *str, const char *data)
641 {
642     return NS_SUCCEEDED(NS_CStringContainerInit2(str, data, PR_UINT32_MAX, 0));
643 }
644
645 /*
646  * Initializes nsACString with data owned by caller.
647  * Caller must ensure that data is valid during lifetime of string object.
648  */
649 void nsACString_InitDepend(nsACString *str, const char *data)
650 {
651     NS_CStringContainerInit2(str, data, PR_UINT32_MAX, NS_CSTRING_CONTAINER_INIT_DEPEND);
652 }
653
654 void nsACString_SetData(nsACString *str, const char *data)
655 {
656     NS_CStringSetData(str, data, PR_UINT32_MAX);
657 }
658
659 PRUint32 nsACString_GetData(const nsACString *str, const char **data)
660 {
661     return NS_CStringGetData(str, data, NULL);
662 }
663
664 void nsACString_Finish(nsACString *str)
665 {
666     NS_CStringContainerFinish(str);
667 }
668
669 BOOL nsAString_Init(nsAString *str, const PRUnichar *data)
670 {
671     return NS_SUCCEEDED(NS_StringContainerInit2(str, data, PR_UINT32_MAX, 0));
672 }
673
674 /*
675  * Initializes nsAString with data owned by caller.
676  * Caller must ensure that data is valid during lifetime of string object.
677  */
678 void nsAString_InitDepend(nsAString *str, const PRUnichar *data)
679 {
680     NS_StringContainerInit2(str, data, PR_UINT32_MAX, NS_STRING_CONTAINER_INIT_DEPEND);
681 }
682
683 void nsAString_SetData(nsAString *str, const PRUnichar *data)
684 {
685     NS_StringSetData(str, data, PR_UINT32_MAX);
686 }
687
688 PRUint32 nsAString_GetData(const nsAString *str, const PRUnichar **data)
689 {
690     return NS_StringGetData(str, data, NULL);
691 }
692
693 void nsAString_Finish(nsAString *str)
694 {
695     NS_StringContainerFinish(str);
696 }
697
698 HRESULT return_nsstr(nsresult nsres, nsAString *nsstr, BSTR *p)
699 {
700     const PRUnichar *str;
701
702     if(NS_FAILED(nsres)) {
703         ERR("failed: %08x\n", nsres);
704         nsAString_Finish(nsstr);
705         return E_FAIL;
706     }
707
708     nsAString_GetData(nsstr, &str);
709     TRACE("ret %s\n", debugstr_w(str));
710     if(*str) {
711         *p = SysAllocString(str);
712         if(!*p)
713             return E_OUTOFMEMORY;
714     }else {
715         *p = NULL;
716     }
717
718     nsAString_Finish(nsstr);
719     return S_OK;
720 }
721
722 nsICommandParams *create_nscommand_params(void)
723 {
724     nsICommandParams *ret = NULL;
725     nsresult nsres;
726
727     if(!pCompMgr)
728         return NULL;
729
730     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
731             NS_COMMANDPARAMS_CONTRACTID, NULL, &IID_nsICommandParams,
732             (void**)&ret);
733     if(NS_FAILED(nsres))
734         ERR("Could not get nsICommandParams\n");
735
736     return ret;
737 }
738
739 nsIWritableVariant *create_nsvariant(void)
740 {
741     nsIWritableVariant *ret = NULL;
742     nsresult nsres;
743
744     if(!pCompMgr)
745         return NULL;
746
747     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
748             NS_VARIANT_CONTRACTID, NULL, &IID_nsIWritableVariant, (void**)&ret);
749     if(NS_FAILED(nsres))
750         ERR("Could not get nsIVariant\n");
751
752     return ret;
753 }
754
755 nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv)
756 {
757     nsIInterfaceRequestor *iface_req;
758     nsresult nsres;
759
760     nsres = nsISupports_QueryInterface(iface, &IID_nsIInterfaceRequestor, (void**)&iface_req);
761     if(NS_FAILED(nsres))
762         return nsres;
763
764     nsres = nsIInterfaceRequestor_GetInterface(iface_req, riid, ppv);
765     nsIInterfaceRequestor_Release(iface_req);
766
767     return nsres;
768 }
769
770 static HRESULT nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str)
771 {
772     nsIDOMNodeList *node_list = NULL;
773     cpp_bool has_children = FALSE;
774     nsIContent *nscontent;
775     PRUint16 type;
776     nsresult nsres;
777
778     nsIDOMNode_HasChildNodes(nsnode, &has_children);
779
780     nsres = nsIDOMNode_GetNodeType(nsnode, &type);
781     if(NS_FAILED(nsres)) {
782         ERR("GetType failed: %08x\n", nsres);
783         return E_FAIL;
784     }
785
786     if(type != DOCUMENT_NODE) {
787         nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIContent, (void**)&nscontent);
788         if(NS_FAILED(nsres)) {
789             ERR("Could not get nsIContent interface: %08x\n", nsres);
790             return E_FAIL;
791         }
792     }
793
794     switch(type) {
795     case ELEMENT_NODE:
796         nsIContentSerializer_AppendElementStart(serializer, nscontent, nscontent, str);
797         break;
798     case TEXT_NODE:
799         nsIContentSerializer_AppendText(serializer, nscontent, 0, -1, str);
800         break;
801     case COMMENT_NODE:
802         nsres = nsIContentSerializer_AppendComment(serializer, nscontent, 0, -1, str);
803         break;
804     case DOCUMENT_NODE: {
805         nsIDocument *nsdoc;
806         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDocument, (void**)&nsdoc);
807         nsIContentSerializer_AppendDocumentStart(serializer, nsdoc, str);
808         nsIDocument_Release(nsdoc);
809         break;
810     }
811     case DOCUMENT_TYPE_NODE:
812         WARN("Ignoring DOCUMENT_TYPE_NODE\n");
813         break;
814     case DOCUMENT_FRAGMENT_NODE:
815         break;
816     default:
817         FIXME("Unhandled type %u\n", type);
818     }
819
820     if(has_children) {
821         PRUint32 child_cnt, i;
822         nsIDOMNode *child_node;
823
824         nsIDOMNode_GetChildNodes(nsnode, &node_list);
825         nsIDOMNodeList_GetLength(node_list, &child_cnt);
826
827         for(i=0; i<child_cnt; i++) {
828             nsres = nsIDOMNodeList_Item(node_list, i, &child_node);
829             if(NS_SUCCEEDED(nsres)) {
830                 nsnode_to_nsstring_rec(serializer, child_node, str);
831                 nsIDOMNode_Release(child_node);
832             }else {
833                 ERR("Item failed: %08x\n", nsres);
834             }
835         }
836
837         nsIDOMNodeList_Release(node_list);
838     }
839
840     if(type == ELEMENT_NODE)
841         nsIContentSerializer_AppendElementEnd(serializer, nscontent, str);
842
843     if(type != DOCUMENT_NODE)
844         nsIContent_Release(nscontent);
845     return S_OK;
846 }
847
848 HRESULT nsnode_to_nsstring(nsIDOMNode *nsnode, nsAString *str)
849 {
850     nsIContentSerializer *serializer;
851     nsresult nsres;
852     HRESULT hres;
853
854     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
855             NS_HTMLSERIALIZER_CONTRACTID, NULL, &IID_nsIContentSerializer,
856             (void**)&serializer);
857     if(NS_FAILED(nsres)) {
858         ERR("Could not get nsIContentSerializer: %08x\n", nsres);
859         return E_FAIL;
860     }
861
862     nsres = nsIContentSerializer_Init(serializer, 0, 100, NULL, FALSE, FALSE /* FIXME */);
863     if(NS_FAILED(nsres))
864         ERR("Init failed: %08x\n", nsres);
865
866     hres = nsnode_to_nsstring_rec(serializer, nsnode, str);
867     if(SUCCEEDED(hres)) {
868         nsres = nsIContentSerializer_Flush(serializer, str);
869         if(NS_FAILED(nsres))
870             ERR("Flush failed: %08x\n", nsres);
871     }
872
873     nsIContentSerializer_Release(serializer);
874     return hres;
875 }
876
877 void get_editor_controller(NSContainer *This)
878 {
879     nsIEditingSession *editing_session = NULL;
880     nsIControllerContext *ctrlctx;
881     nsresult nsres;
882
883     if(This->editor) {
884         nsIEditor_Release(This->editor);
885         This->editor = NULL;
886     }
887
888     if(This->editor_controller) {
889         nsIController_Release(This->editor_controller);
890         This->editor_controller = NULL;
891     }
892
893     nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession,
894             (void**)&editing_session);
895     if(NS_FAILED(nsres)) {
896         ERR("Could not get nsIEditingSession: %08x\n", nsres);
897         return;
898     }
899
900     nsres = nsIEditingSession_GetEditorForWindow(editing_session,
901             This->doc->basedoc.window->nswindow, &This->editor);
902     nsIEditingSession_Release(editing_session);
903     if(NS_FAILED(nsres)) {
904         ERR("Could not get editor: %08x\n", nsres);
905         return;
906     }
907
908     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
909             NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx);
910     if(NS_SUCCEEDED(nsres)) {
911         nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor);
912         if(NS_FAILED(nsres))
913             ERR("SetCommandContext failed: %08x\n", nsres);
914         nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController,
915                 (void**)&This->editor_controller);
916         nsIControllerContext_Release(ctrlctx);
917         if(NS_FAILED(nsres))
918             ERR("Could not get nsIController interface: %08x\n", nsres);
919     }else {
920         ERR("Could not create edit controller: %08x\n", nsres);
921     }
922 }
923
924 void close_gecko(void)
925 {
926     TRACE("()\n");
927
928     release_nsio();
929     init_mutation(NULL);
930
931     if(profile_directory) {
932         nsIFile_Release(profile_directory);
933         profile_directory = NULL;
934     }
935
936     if(pCompMgr)
937         nsIComponentManager_Release(pCompMgr);
938
939     if(pServMgr)
940         nsIServiceManager_Release(pServMgr);
941
942     if(nsmem)
943         nsIMemory_Release(nsmem);
944
945     /* Gecko doesn't really support being unloaded */
946     /* if (hXPCOM) FreeLibrary(hXPCOM); */
947
948     DeleteCriticalSection(&cs_load_gecko);
949 }
950
951 BOOL is_gecko_path(const char *path)
952 {
953     WCHAR *buf, *ptr;
954     BOOL ret;
955
956     buf = heap_strdupAtoW(path);
957     if(strlenW(buf) < gecko_path_len)
958         return FALSE;
959
960     buf[gecko_path_len] = 0;
961     for(ptr = buf; *ptr; ptr++) {
962         if(*ptr == '\\')
963             *ptr = '/';
964     }
965
966     ret = !strcmpiW(buf, gecko_path);
967     heap_free(buf);
968     return ret;
969 }
970
971 struct nsWeakReference {
972     nsIWeakReference nsIWeakReference_iface;
973
974     LONG ref;
975
976     NSContainer *nscontainer;
977 };
978
979 static inline nsWeakReference *impl_from_nsIWeakReference(nsIWeakReference *iface)
980 {
981     return CONTAINING_RECORD(iface, nsWeakReference, nsIWeakReference_iface);
982 }
983
984 static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface,
985         nsIIDRef riid, void **result)
986 {
987     nsWeakReference *This = impl_from_nsIWeakReference(iface);
988
989     if(IsEqualGUID(&IID_nsISupports, riid)) {
990         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
991         *result = &This->nsIWeakReference_iface;
992     }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) {
993         TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result);
994         *result = &This->nsIWeakReference_iface;
995     }else {
996         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
997         *result = NULL;
998         return NS_NOINTERFACE;
999     }
1000
1001     nsISupports_AddRef((nsISupports*)*result);
1002     return NS_OK;
1003 }
1004
1005 static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface)
1006 {
1007     nsWeakReference *This = impl_from_nsIWeakReference(iface);
1008     LONG ref = InterlockedIncrement(&This->ref);
1009
1010     TRACE("(%p) ref=%d\n", This, ref);
1011
1012     return ref;
1013 }
1014
1015 static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface)
1016 {
1017     nsWeakReference *This = impl_from_nsIWeakReference(iface);
1018     LONG ref = InterlockedIncrement(&This->ref);
1019
1020     TRACE("(%p) ref=%d\n", This, ref);
1021
1022     if(!ref) {
1023         assert(!This->nscontainer);
1024         heap_free(This);
1025     }
1026
1027     return ref;
1028 }
1029
1030 static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface,
1031         const nsIID *riid, void **result)
1032 {
1033     nsWeakReference *This = impl_from_nsIWeakReference(iface);
1034
1035     if(!This->nscontainer)
1036         return NS_ERROR_NULL_POINTER;
1037
1038     return nsIWebBrowserChrome_QueryInterface(&This->nscontainer->nsIWebBrowserChrome_iface, riid, result);
1039 }
1040
1041 static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = {
1042     nsWeakReference_QueryInterface,
1043     nsWeakReference_AddRef,
1044     nsWeakReference_Release,
1045     nsWeakReference_QueryReferent
1046 };
1047
1048 /**********************************************************
1049  *      nsIWebBrowserChrome interface
1050  */
1051
1052 static inline NSContainer *impl_from_nsIWebBrowserChrome(nsIWebBrowserChrome *iface)
1053 {
1054     return CONTAINING_RECORD(iface, NSContainer, nsIWebBrowserChrome_iface);
1055 }
1056
1057 static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface,
1058         nsIIDRef riid, void **result)
1059 {
1060     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1061
1062     *result = NULL;
1063     if(IsEqualGUID(&IID_nsISupports, riid)) {
1064         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
1065         *result = &This->nsIWebBrowserChrome_iface;
1066     }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) {
1067         TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result);
1068         *result = &This->nsIWebBrowserChrome_iface;
1069     }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) {
1070         TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result);
1071         *result = &This->nsIContextMenuListener_iface;
1072     }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) {
1073         TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result);
1074         *result = &This->nsIURIContentListener_iface;
1075     }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) {
1076         TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result);
1077         *result = &This->nsIEmbeddingSiteWindow_iface;
1078     }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) {
1079         TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result);
1080         *result = &This->nsITooltipListener_iface;
1081     }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) {
1082         TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result);
1083         *result = &This->nsIInterfaceRequestor_iface;
1084     }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) {
1085         TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result);
1086         *result = &This->nsISupportsWeakReference_iface;
1087     }
1088
1089     if(*result) {
1090         nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1091         return NS_OK;
1092     }
1093
1094     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
1095     return NS_NOINTERFACE;
1096 }
1097
1098 static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface)
1099 {
1100     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1101     LONG ref = InterlockedIncrement(&This->ref);
1102
1103     TRACE("(%p) ref=%d\n", This, ref);
1104
1105     return ref;
1106 }
1107
1108 static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface)
1109 {
1110     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1111     LONG ref = InterlockedDecrement(&This->ref);
1112
1113     TRACE("(%p) ref=%d\n", This, ref);
1114
1115     if(!ref) {
1116         if(This->parent)
1117             nsIWebBrowserChrome_Release(&This->parent->nsIWebBrowserChrome_iface);
1118         if(This->weak_reference) {
1119             This->weak_reference->nscontainer = NULL;
1120             nsIWeakReference_Release(&This->weak_reference->nsIWeakReference_iface);
1121         }
1122         heap_free(This);
1123     }
1124
1125     return ref;
1126 }
1127
1128 static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface,
1129         PRUint32 statusType, const PRUnichar *status)
1130 {
1131     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1132     TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status));
1133     return NS_OK;
1134 }
1135
1136 static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface,
1137         nsIWebBrowser **aWebBrowser)
1138 {
1139     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1140
1141     TRACE("(%p)->(%p)\n", This, aWebBrowser);
1142
1143     if(!aWebBrowser)
1144         return NS_ERROR_INVALID_ARG;
1145
1146     if(This->webbrowser)
1147         nsIWebBrowser_AddRef(This->webbrowser);
1148     *aWebBrowser = This->webbrowser;
1149     return S_OK;
1150 }
1151
1152 static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface,
1153         nsIWebBrowser *aWebBrowser)
1154 {
1155     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1156
1157     TRACE("(%p)->(%p)\n", This, aWebBrowser);
1158
1159     if(aWebBrowser != This->webbrowser)
1160         ERR("Wrong nsWebBrowser!\n");
1161
1162     return NS_OK;
1163 }
1164
1165 static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface,
1166         PRUint32 *aChromeFlags)
1167 {
1168     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1169     WARN("(%p)->(%p)\n", This, aChromeFlags);
1170     return NS_ERROR_NOT_IMPLEMENTED;
1171 }
1172
1173 static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface,
1174         PRUint32 aChromeFlags)
1175 {
1176     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1177     WARN("(%p)->(%08x)\n", This, aChromeFlags);
1178     return NS_ERROR_NOT_IMPLEMENTED;
1179 }
1180
1181 static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface)
1182 {
1183     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1184     TRACE("(%p)\n", This);
1185     return NS_ERROR_NOT_IMPLEMENTED;
1186 }
1187
1188 static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface,
1189         PRInt32 aCX, PRInt32 aCY)
1190 {
1191     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1192     WARN("(%p)->(%d %d)\n", This, aCX, aCY);
1193     return NS_ERROR_NOT_IMPLEMENTED;
1194 }
1195
1196 static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface)
1197 {
1198     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1199     WARN("(%p)\n", This);
1200     return NS_ERROR_NOT_IMPLEMENTED;
1201 }
1202
1203 static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, cpp_bool *_retval)
1204 {
1205     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1206     WARN("(%p)->(%p)\n", This, _retval);
1207     return NS_ERROR_NOT_IMPLEMENTED;
1208 }
1209
1210 static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface,
1211         nsresult aStatus)
1212 {
1213     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1214     WARN("(%p)->(%08x)\n", This, aStatus);
1215     return NS_ERROR_NOT_IMPLEMENTED;
1216 }
1217
1218 static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = {
1219     nsWebBrowserChrome_QueryInterface,
1220     nsWebBrowserChrome_AddRef,
1221     nsWebBrowserChrome_Release,
1222     nsWebBrowserChrome_SetStatus,
1223     nsWebBrowserChrome_GetWebBrowser,
1224     nsWebBrowserChrome_SetWebBrowser,
1225     nsWebBrowserChrome_GetChromeFlags,
1226     nsWebBrowserChrome_SetChromeFlags,
1227     nsWebBrowserChrome_DestroyBrowserWindow,
1228     nsWebBrowserChrome_SizeBrowserTo,
1229     nsWebBrowserChrome_ShowAsModal,
1230     nsWebBrowserChrome_IsWindowModal,
1231     nsWebBrowserChrome_ExitModalEventLoop
1232 };
1233
1234 /**********************************************************
1235  *      nsIContextMenuListener interface
1236  */
1237
1238 static inline NSContainer *impl_from_nsIContextMenuListener(nsIContextMenuListener *iface)
1239 {
1240     return CONTAINING_RECORD(iface, NSContainer, nsIContextMenuListener_iface);
1241 }
1242
1243 static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface,
1244         nsIIDRef riid, void **result)
1245 {
1246     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1247     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1248 }
1249
1250 static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface)
1251 {
1252     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1253     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1254 }
1255
1256 static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface)
1257 {
1258     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1259     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1260 }
1261
1262 static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface,
1263         PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
1264 {
1265     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1266     nsIDOMMouseEvent *event;
1267     HTMLDOMNode *node;
1268     POINT pt;
1269     DWORD dwID = CONTEXT_MENU_DEFAULT;
1270     nsresult nsres;
1271     HRESULT hres;
1272
1273     TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode);
1274
1275     fire_event(This->doc->basedoc.doc_node /* FIXME */, EVENTID_CONTEXTMENU, TRUE, aNode, aEvent);
1276
1277     nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
1278     if(NS_FAILED(nsres)) {
1279         ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres);
1280         return nsres;
1281     }
1282
1283     nsIDOMMouseEvent_GetScreenX(event, &pt.x);
1284     nsIDOMMouseEvent_GetScreenY(event, &pt.y);
1285     nsIDOMMouseEvent_Release(event);
1286
1287     switch(aContextFlags) {
1288     case CONTEXT_NONE:
1289     case CONTEXT_DOCUMENT:
1290     case CONTEXT_TEXT:
1291         dwID = CONTEXT_MENU_DEFAULT;
1292         break;
1293     case CONTEXT_IMAGE:
1294     case CONTEXT_IMAGE|CONTEXT_LINK:
1295         dwID = CONTEXT_MENU_IMAGE;
1296         break;
1297     case CONTEXT_LINK:
1298         dwID = CONTEXT_MENU_ANCHOR;
1299         break;
1300     case CONTEXT_INPUT:
1301         dwID = CONTEXT_MENU_CONTROL;
1302         break;
1303     default:
1304         FIXME("aContextFlags=%08x\n", aContextFlags);
1305     };
1306
1307     hres = get_node(This->doc->basedoc.doc_node, aNode, TRUE, &node);
1308     if(FAILED(hres))
1309         return NS_ERROR_FAILURE;
1310
1311     show_context_menu(This->doc, dwID, &pt, (IDispatch*)&node->IHTMLDOMNode_iface);
1312     node_release(node);
1313     return NS_OK;
1314 }
1315
1316 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
1317     nsContextMenuListener_QueryInterface,
1318     nsContextMenuListener_AddRef,
1319     nsContextMenuListener_Release,
1320     nsContextMenuListener_OnShowContextMenu
1321 };
1322
1323 /**********************************************************
1324  *      nsIURIContentListener interface
1325  */
1326
1327 static inline NSContainer *impl_from_nsIURIContentListener(nsIURIContentListener *iface)
1328 {
1329     return CONTAINING_RECORD(iface, NSContainer, nsIURIContentListener_iface);
1330 }
1331
1332 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
1333         nsIIDRef riid, void **result)
1334 {
1335     NSContainer *This = impl_from_nsIURIContentListener(iface);
1336     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1337 }
1338
1339 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
1340 {
1341     NSContainer *This = impl_from_nsIURIContentListener(iface);
1342     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1343 }
1344
1345 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
1346 {
1347     NSContainer *This = impl_from_nsIURIContentListener(iface);
1348     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1349 }
1350
1351 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1352                                                           nsIURI *aURI, cpp_bool *_retval)
1353 {
1354     NSContainer *This = impl_from_nsIURIContentListener(iface);
1355     nsACString spec_str;
1356     const char *spec;
1357     nsresult nsres;
1358
1359     nsACString_Init(&spec_str, NULL);
1360     nsIURI_GetSpec(aURI, &spec_str);
1361     nsACString_GetData(&spec_str, &spec);
1362
1363     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1364
1365     nsACString_Finish(&spec_str);
1366
1367     nsres = on_start_uri_open(This, aURI, _retval);
1368     if(NS_FAILED(nsres))
1369         return nsres;
1370
1371     return !*_retval && This->content_listener
1372         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1373         : NS_OK;
1374 }
1375
1376 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1377         const char *aContentType, cpp_bool aIsContentPreferred, nsIRequest *aRequest,
1378         nsIStreamListener **aContentHandler, cpp_bool *_retval)
1379 {
1380     NSContainer *This = impl_from_nsIURIContentListener(iface);
1381
1382     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1383             aRequest, aContentHandler, _retval);
1384
1385     return This->content_listener
1386         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1387                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1388         : NS_ERROR_NOT_IMPLEMENTED;
1389 }
1390
1391 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1392         const char *aContentType, char **aDesiredContentType, cpp_bool *_retval)
1393 {
1394     NSContainer *This = impl_from_nsIURIContentListener(iface);
1395
1396     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1397
1398     /* FIXME: Should we do something here? */
1399     *_retval = TRUE; 
1400
1401     return This->content_listener
1402         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1403                   aDesiredContentType, _retval)
1404         : NS_OK;
1405 }
1406
1407 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1408         const char *aContentType, cpp_bool aIsContentPreferred, char **aDesiredContentType,
1409         cpp_bool *_retval)
1410 {
1411     NSContainer *This = impl_from_nsIURIContentListener(iface);
1412
1413     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1414             aDesiredContentType, _retval);
1415
1416     return This->content_listener
1417         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1418                 aIsContentPreferred, aDesiredContentType, _retval)
1419         : NS_ERROR_NOT_IMPLEMENTED;
1420 }
1421
1422 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1423         nsISupports **aLoadCookie)
1424 {
1425     NSContainer *This = impl_from_nsIURIContentListener(iface);
1426
1427     WARN("(%p)->(%p)\n", This, aLoadCookie);
1428
1429     return This->content_listener
1430         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1431         : NS_ERROR_NOT_IMPLEMENTED;
1432 }
1433
1434 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1435         nsISupports *aLoadCookie)
1436 {
1437     NSContainer *This = impl_from_nsIURIContentListener(iface);
1438
1439     WARN("(%p)->(%p)\n", This, aLoadCookie);
1440
1441     return This->content_listener
1442         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1443         : NS_ERROR_NOT_IMPLEMENTED;
1444 }
1445
1446 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1447         nsIURIContentListener **aParentContentListener)
1448 {
1449     NSContainer *This = impl_from_nsIURIContentListener(iface);
1450
1451     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1452
1453     if(This->content_listener)
1454         nsIURIContentListener_AddRef(This->content_listener);
1455
1456     *aParentContentListener = This->content_listener;
1457     return NS_OK;
1458 }
1459
1460 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1461         nsIURIContentListener *aParentContentListener)
1462 {
1463     NSContainer *This = impl_from_nsIURIContentListener(iface);
1464
1465     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1466
1467     if(aParentContentListener == &This->nsIURIContentListener_iface)
1468         return NS_OK;
1469
1470     if(This->content_listener)
1471         nsIURIContentListener_Release(This->content_listener);
1472
1473     This->content_listener = aParentContentListener;
1474     if(This->content_listener)
1475         nsIURIContentListener_AddRef(This->content_listener);
1476
1477     return NS_OK;
1478 }
1479
1480 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1481     nsURIContentListener_QueryInterface,
1482     nsURIContentListener_AddRef,
1483     nsURIContentListener_Release,
1484     nsURIContentListener_OnStartURIOpen,
1485     nsURIContentListener_DoContent,
1486     nsURIContentListener_IsPreferred,
1487     nsURIContentListener_CanHandleContent,
1488     nsURIContentListener_GetLoadCookie,
1489     nsURIContentListener_SetLoadCookie,
1490     nsURIContentListener_GetParentContentListener,
1491     nsURIContentListener_SetParentContentListener
1492 };
1493
1494 /**********************************************************
1495  *      nsIEmbeddinSiteWindow interface
1496  */
1497
1498 static inline NSContainer *impl_from_nsIEmbeddingSiteWindow(nsIEmbeddingSiteWindow *iface)
1499 {
1500     return CONTAINING_RECORD(iface, NSContainer, nsIEmbeddingSiteWindow_iface);
1501 }
1502
1503 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1504         nsIIDRef riid, void **result)
1505 {
1506     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1507     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1508 }
1509
1510 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1511 {
1512     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1513     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1514 }
1515
1516 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1517 {
1518     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1519     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1520 }
1521
1522 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1523         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1524 {
1525     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1526     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1527     return NS_ERROR_NOT_IMPLEMENTED;
1528 }
1529
1530 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1531         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1532 {
1533     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1534     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1535     return NS_ERROR_NOT_IMPLEMENTED;
1536 }
1537
1538 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1539 {
1540     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1541
1542     TRACE("(%p)\n", This);
1543
1544     return nsIBaseWindow_SetFocus(This->window);
1545 }
1546
1547 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1548         cpp_bool *aVisibility)
1549 {
1550     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1551
1552     TRACE("(%p)->(%p)\n", This, aVisibility);
1553
1554     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1555     return NS_OK;
1556 }
1557
1558 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1559         cpp_bool aVisibility)
1560 {
1561     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1562
1563     TRACE("(%p)->(%x)\n", This, aVisibility);
1564
1565     return NS_OK;
1566 }
1567
1568 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1569         PRUnichar **aTitle)
1570 {
1571     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1572     WARN("(%p)->(%p)\n", This, aTitle);
1573     return NS_ERROR_NOT_IMPLEMENTED;
1574 }
1575
1576 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1577         const PRUnichar *aTitle)
1578 {
1579     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1580     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1581     return NS_ERROR_NOT_IMPLEMENTED;
1582 }
1583
1584 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1585         void **aSiteWindow)
1586 {
1587     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1588
1589     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1590
1591     *aSiteWindow = This->hwnd;
1592     return NS_OK;
1593 }
1594
1595 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1596     nsEmbeddingSiteWindow_QueryInterface,
1597     nsEmbeddingSiteWindow_AddRef,
1598     nsEmbeddingSiteWindow_Release,
1599     nsEmbeddingSiteWindow_SetDimensions,
1600     nsEmbeddingSiteWindow_GetDimensions,
1601     nsEmbeddingSiteWindow_SetFocus,
1602     nsEmbeddingSiteWindow_GetVisibility,
1603     nsEmbeddingSiteWindow_SetVisibility,
1604     nsEmbeddingSiteWindow_GetTitle,
1605     nsEmbeddingSiteWindow_SetTitle,
1606     nsEmbeddingSiteWindow_GetSiteWindow
1607 };
1608
1609 static inline NSContainer *impl_from_nsITooltipListener(nsITooltipListener *iface)
1610 {
1611     return CONTAINING_RECORD(iface, NSContainer, nsITooltipListener_iface);
1612 }
1613
1614 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1615         void **result)
1616 {
1617     NSContainer *This = impl_from_nsITooltipListener(iface);
1618     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1619 }
1620
1621 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1622 {
1623     NSContainer *This = impl_from_nsITooltipListener(iface);
1624     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1625 }
1626
1627 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1628 {
1629     NSContainer *This = impl_from_nsITooltipListener(iface);
1630     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1631 }
1632
1633 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1634         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1635 {
1636     NSContainer *This = impl_from_nsITooltipListener(iface);
1637
1638     if (This->doc)
1639         show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1640
1641     return NS_OK;
1642 }
1643
1644 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1645 {
1646     NSContainer *This = impl_from_nsITooltipListener(iface);
1647
1648     if (This->doc)
1649         hide_tooltip(This->doc);
1650
1651     return NS_OK;
1652 }
1653
1654 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1655     nsTooltipListener_QueryInterface,
1656     nsTooltipListener_AddRef,
1657     nsTooltipListener_Release,
1658     nsTooltipListener_OnShowTooltip,
1659     nsTooltipListener_OnHideTooltip
1660 };
1661
1662 static inline NSContainer *impl_from_nsIInterfaceRequestor(nsIInterfaceRequestor *iface)
1663 {
1664     return CONTAINING_RECORD(iface, NSContainer, nsIInterfaceRequestor_iface);
1665 }
1666
1667 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1668         nsIIDRef riid, void **result)
1669 {
1670     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1671     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1672 }
1673
1674 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1675 {
1676     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1677     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1678 }
1679
1680 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1681 {
1682     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1683     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1684 }
1685
1686 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1687         nsIIDRef riid, void **result)
1688 {
1689     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1690
1691     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1692         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1693         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1694     }
1695
1696     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1697 }
1698
1699 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1700     nsInterfaceRequestor_QueryInterface,
1701     nsInterfaceRequestor_AddRef,
1702     nsInterfaceRequestor_Release,
1703     nsInterfaceRequestor_GetInterface
1704 };
1705
1706 static inline NSContainer *impl_from_nsISupportsWeakReference(nsISupportsWeakReference *iface)
1707 {
1708     return CONTAINING_RECORD(iface, NSContainer, nsISupportsWeakReference_iface);
1709 }
1710
1711 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1712         nsIIDRef riid, void **result)
1713 {
1714     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1715     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1716 }
1717
1718 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1719 {
1720     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1721     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1722 }
1723
1724 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1725 {
1726     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1727     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1728 }
1729
1730 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1731         nsIWeakReference **_retval)
1732 {
1733     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1734
1735     TRACE("(%p)->(%p)\n", This, _retval);
1736
1737     if(!This->weak_reference) {
1738         This->weak_reference = heap_alloc(sizeof(nsWeakReference));
1739         if(!This->weak_reference)
1740             return NS_ERROR_OUT_OF_MEMORY;
1741
1742         This->weak_reference->nsIWeakReference_iface.lpVtbl = &nsWeakReferenceVtbl;
1743         This->weak_reference->ref = 1;
1744         This->weak_reference->nscontainer = This;
1745     }
1746
1747     *_retval = &This->weak_reference->nsIWeakReference_iface;
1748     nsIWeakReference_AddRef(*_retval);
1749     return NS_OK;
1750 }
1751
1752 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1753     nsSupportsWeakReference_QueryInterface,
1754     nsSupportsWeakReference_AddRef,
1755     nsSupportsWeakReference_Release,
1756     nsSupportsWeakReference_GetWeakReference
1757 };
1758
1759 static HRESULT init_nscontainer(NSContainer *nscontainer)
1760 {
1761     nsIWebBrowserSetup *wbsetup;
1762     nsIScrollable *scrollable;
1763     nsresult nsres;
1764
1765     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1766             NULL, &IID_nsIWebBrowser, (void**)&nscontainer->webbrowser);
1767     if(NS_FAILED(nsres)) {
1768         ERR("Creating WebBrowser failed: %08x\n", nsres);
1769         return E_FAIL;
1770     }
1771
1772     nsres = nsIWebBrowser_SetContainerWindow(nscontainer->webbrowser, &nscontainer->nsIWebBrowserChrome_iface);
1773     if(NS_FAILED(nsres)) {
1774         ERR("SetContainerWindow failed: %08x\n", nsres);
1775         return E_FAIL;
1776     }
1777
1778     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIBaseWindow,
1779             (void**)&nscontainer->window);
1780     if(NS_FAILED(nsres)) {
1781         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1782         return E_FAIL;
1783     }
1784
1785     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserSetup,
1786                                          (void**)&wbsetup);
1787     if(NS_SUCCEEDED(nsres)) {
1788         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE);
1789         nsIWebBrowserSetup_Release(wbsetup);
1790         if(NS_FAILED(nsres)) {
1791             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1792             return E_FAIL;
1793         }
1794     }else {
1795         ERR("Could not get nsIWebBrowserSetup interface\n");
1796         return E_FAIL;
1797     }
1798
1799     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebNavigation,
1800             (void**)&nscontainer->navigation);
1801     if(NS_FAILED(nsres)) {
1802         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1803         return E_FAIL;
1804     }
1805
1806     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserFocus,
1807             (void**)&nscontainer->focus);
1808     if(NS_FAILED(nsres)) {
1809         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1810         return E_FAIL;
1811     }
1812
1813     if(!nscontainer_class) {
1814         register_nscontainer_class();
1815         if(!nscontainer_class)
1816             return E_FAIL;
1817     }
1818
1819     nscontainer->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1820             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1821             GetDesktopWindow(), NULL, hInst, nscontainer);
1822     if(!nscontainer->hwnd) {
1823         WARN("Could not create window\n");
1824         return E_FAIL;
1825     }
1826
1827     nsres = nsIBaseWindow_InitWindow(nscontainer->window, nscontainer->hwnd, NULL, 0, 0, 100, 100);
1828     if(NS_SUCCEEDED(nsres)) {
1829         nsres = nsIBaseWindow_Create(nscontainer->window);
1830         if(NS_FAILED(nsres)) {
1831             WARN("Creating window failed: %08x\n", nsres);
1832             return E_FAIL;
1833         }
1834
1835         nsIBaseWindow_SetVisibility(nscontainer->window, FALSE);
1836         nsIBaseWindow_SetEnabled(nscontainer->window, FALSE);
1837     }else {
1838         ERR("InitWindow failed: %08x\n", nsres);
1839         return E_FAIL;
1840     }
1841
1842     nsres = nsIWebBrowser_SetParentURIContentListener(nscontainer->webbrowser,
1843             &nscontainer->nsIURIContentListener_iface);
1844     if(NS_FAILED(nsres))
1845         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1846
1847     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1848     if(NS_SUCCEEDED(nsres)) {
1849         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1850                 ScrollOrientation_Y, Scrollbar_Always);
1851         if(NS_FAILED(nsres))
1852             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1853
1854         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1855                 ScrollOrientation_X, Scrollbar_Auto);
1856         if(NS_FAILED(nsres))
1857             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1858
1859         nsIScrollable_Release(scrollable);
1860     }else {
1861         ERR("Could not get nsIScrollable: %08x\n", nsres);
1862     }
1863
1864     return S_OK;
1865 }
1866
1867 HRESULT create_nscontainer(HTMLDocumentObj *doc, NSContainer **_ret)
1868 {
1869     NSContainer *ret;
1870     HRESULT hres;
1871
1872     if(!load_gecko())
1873         return CLASS_E_CLASSNOTAVAILABLE;
1874
1875     ret = heap_alloc_zero(sizeof(NSContainer));
1876     if(!ret)
1877         return E_OUTOFMEMORY;
1878
1879     ret->nsIWebBrowserChrome_iface.lpVtbl = &nsWebBrowserChromeVtbl;
1880     ret->nsIContextMenuListener_iface.lpVtbl = &nsContextMenuListenerVtbl;
1881     ret->nsIURIContentListener_iface.lpVtbl = &nsURIContentListenerVtbl;
1882     ret->nsIEmbeddingSiteWindow_iface.lpVtbl = &nsEmbeddingSiteWindowVtbl;
1883     ret->nsITooltipListener_iface.lpVtbl = &nsTooltipListenerVtbl;
1884     ret->nsIInterfaceRequestor_iface.lpVtbl = &nsInterfaceRequestorVtbl;
1885     ret->nsISupportsWeakReference_iface.lpVtbl = &nsSupportsWeakReferenceVtbl;
1886
1887     ret->doc = doc;
1888     ret->ref = 1;
1889
1890     hres = init_nscontainer(ret);
1891     if(SUCCEEDED(hres))
1892         *_ret = ret;
1893     else
1894         nsIWebBrowserChrome_Release(&ret->nsIWebBrowserChrome_iface);
1895     return hres;
1896 }
1897
1898 void NSContainer_Release(NSContainer *This)
1899 {
1900     TRACE("(%p)\n", This);
1901
1902     This->doc = NULL;
1903
1904     ShowWindow(This->hwnd, SW_HIDE);
1905     SetParent(This->hwnd, NULL);
1906
1907     nsIBaseWindow_SetVisibility(This->window, FALSE);
1908     nsIBaseWindow_Destroy(This->window);
1909
1910     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1911
1912     nsIWebBrowser_Release(This->webbrowser);
1913     This->webbrowser = NULL;
1914
1915     nsIWebNavigation_Release(This->navigation);
1916     This->navigation = NULL;
1917
1918     nsIBaseWindow_Release(This->window);
1919     This->window = NULL;
1920
1921     nsIWebBrowserFocus_Release(This->focus);
1922     This->focus = NULL;
1923
1924     if(This->editor_controller) {
1925         nsIController_Release(This->editor_controller);
1926         This->editor_controller = NULL;
1927     }
1928
1929     if(This->editor) {
1930         nsIEditor_Release(This->editor);
1931         This->editor = NULL;
1932     }
1933
1934     if(This->content_listener) {
1935         nsIURIContentListener_Release(This->content_listener);
1936         This->content_listener = NULL;
1937     }
1938
1939     if(This->hwnd) {
1940         DestroyWindow(This->hwnd);
1941         This->hwnd = NULL;
1942     }
1943
1944     nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1945 }