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