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