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