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