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