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