mshtml: Added support for IDispatch-only ActiveX objects.
[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     return NS_OK;
1291 }
1292
1293 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
1294     nsContextMenuListener_QueryInterface,
1295     nsContextMenuListener_AddRef,
1296     nsContextMenuListener_Release,
1297     nsContextMenuListener_OnShowContextMenu
1298 };
1299
1300 /**********************************************************
1301  *      nsIURIContentListener interface
1302  */
1303
1304 static inline NSContainer *impl_from_nsIURIContentListener(nsIURIContentListener *iface)
1305 {
1306     return CONTAINING_RECORD(iface, NSContainer, nsIURIContentListener_iface);
1307 }
1308
1309 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
1310         nsIIDRef riid, void **result)
1311 {
1312     NSContainer *This = impl_from_nsIURIContentListener(iface);
1313     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1314 }
1315
1316 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
1317 {
1318     NSContainer *This = impl_from_nsIURIContentListener(iface);
1319     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1320 }
1321
1322 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
1323 {
1324     NSContainer *This = impl_from_nsIURIContentListener(iface);
1325     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1326 }
1327
1328 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1329                                                           nsIURI *aURI, cpp_bool *_retval)
1330 {
1331     NSContainer *This = impl_from_nsIURIContentListener(iface);
1332     nsACString spec_str;
1333     const char *spec;
1334     nsresult nsres;
1335
1336     nsACString_Init(&spec_str, NULL);
1337     nsIURI_GetSpec(aURI, &spec_str);
1338     nsACString_GetData(&spec_str, &spec);
1339
1340     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1341
1342     nsACString_Finish(&spec_str);
1343
1344     nsres = on_start_uri_open(This, aURI, _retval);
1345     if(NS_FAILED(nsres))
1346         return nsres;
1347
1348     return !*_retval && This->content_listener
1349         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1350         : NS_OK;
1351 }
1352
1353 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1354         const char *aContentType, cpp_bool aIsContentPreferred, nsIRequest *aRequest,
1355         nsIStreamListener **aContentHandler, cpp_bool *_retval)
1356 {
1357     NSContainer *This = impl_from_nsIURIContentListener(iface);
1358
1359     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1360             aRequest, aContentHandler, _retval);
1361
1362     return This->content_listener
1363         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1364                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1365         : NS_ERROR_NOT_IMPLEMENTED;
1366 }
1367
1368 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1369         const char *aContentType, char **aDesiredContentType, cpp_bool *_retval)
1370 {
1371     NSContainer *This = impl_from_nsIURIContentListener(iface);
1372
1373     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1374
1375     /* FIXME: Should we do something here? */
1376     *_retval = TRUE; 
1377
1378     return This->content_listener
1379         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1380                   aDesiredContentType, _retval)
1381         : NS_OK;
1382 }
1383
1384 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1385         const char *aContentType, cpp_bool aIsContentPreferred, char **aDesiredContentType,
1386         cpp_bool *_retval)
1387 {
1388     NSContainer *This = impl_from_nsIURIContentListener(iface);
1389
1390     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1391             aDesiredContentType, _retval);
1392
1393     return This->content_listener
1394         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1395                 aIsContentPreferred, aDesiredContentType, _retval)
1396         : NS_ERROR_NOT_IMPLEMENTED;
1397 }
1398
1399 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1400         nsISupports **aLoadCookie)
1401 {
1402     NSContainer *This = impl_from_nsIURIContentListener(iface);
1403
1404     WARN("(%p)->(%p)\n", This, aLoadCookie);
1405
1406     return This->content_listener
1407         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1408         : NS_ERROR_NOT_IMPLEMENTED;
1409 }
1410
1411 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1412         nsISupports *aLoadCookie)
1413 {
1414     NSContainer *This = impl_from_nsIURIContentListener(iface);
1415
1416     WARN("(%p)->(%p)\n", This, aLoadCookie);
1417
1418     return This->content_listener
1419         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1420         : NS_ERROR_NOT_IMPLEMENTED;
1421 }
1422
1423 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1424         nsIURIContentListener **aParentContentListener)
1425 {
1426     NSContainer *This = impl_from_nsIURIContentListener(iface);
1427
1428     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1429
1430     if(This->content_listener)
1431         nsIURIContentListener_AddRef(This->content_listener);
1432
1433     *aParentContentListener = This->content_listener;
1434     return NS_OK;
1435 }
1436
1437 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1438         nsIURIContentListener *aParentContentListener)
1439 {
1440     NSContainer *This = impl_from_nsIURIContentListener(iface);
1441
1442     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1443
1444     if(aParentContentListener == &This->nsIURIContentListener_iface)
1445         return NS_OK;
1446
1447     if(This->content_listener)
1448         nsIURIContentListener_Release(This->content_listener);
1449
1450     This->content_listener = aParentContentListener;
1451     if(This->content_listener)
1452         nsIURIContentListener_AddRef(This->content_listener);
1453
1454     return NS_OK;
1455 }
1456
1457 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1458     nsURIContentListener_QueryInterface,
1459     nsURIContentListener_AddRef,
1460     nsURIContentListener_Release,
1461     nsURIContentListener_OnStartURIOpen,
1462     nsURIContentListener_DoContent,
1463     nsURIContentListener_IsPreferred,
1464     nsURIContentListener_CanHandleContent,
1465     nsURIContentListener_GetLoadCookie,
1466     nsURIContentListener_SetLoadCookie,
1467     nsURIContentListener_GetParentContentListener,
1468     nsURIContentListener_SetParentContentListener
1469 };
1470
1471 /**********************************************************
1472  *      nsIEmbeddinSiteWindow interface
1473  */
1474
1475 static inline NSContainer *impl_from_nsIEmbeddingSiteWindow(nsIEmbeddingSiteWindow *iface)
1476 {
1477     return CONTAINING_RECORD(iface, NSContainer, nsIEmbeddingSiteWindow_iface);
1478 }
1479
1480 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1481         nsIIDRef riid, void **result)
1482 {
1483     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1484     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1485 }
1486
1487 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1488 {
1489     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1490     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1491 }
1492
1493 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1494 {
1495     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1496     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1497 }
1498
1499 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1500         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1501 {
1502     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1503     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1504     return NS_ERROR_NOT_IMPLEMENTED;
1505 }
1506
1507 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1508         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1509 {
1510     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1511     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1512     return NS_ERROR_NOT_IMPLEMENTED;
1513 }
1514
1515 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1516 {
1517     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1518
1519     TRACE("(%p)\n", This);
1520
1521     return nsIBaseWindow_SetFocus(This->window);
1522 }
1523
1524 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1525         cpp_bool *aVisibility)
1526 {
1527     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1528
1529     TRACE("(%p)->(%p)\n", This, aVisibility);
1530
1531     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1532     return NS_OK;
1533 }
1534
1535 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1536         cpp_bool aVisibility)
1537 {
1538     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1539
1540     TRACE("(%p)->(%x)\n", This, aVisibility);
1541
1542     return NS_OK;
1543 }
1544
1545 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1546         PRUnichar **aTitle)
1547 {
1548     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1549     WARN("(%p)->(%p)\n", This, aTitle);
1550     return NS_ERROR_NOT_IMPLEMENTED;
1551 }
1552
1553 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1554         const PRUnichar *aTitle)
1555 {
1556     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1557     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1558     return NS_ERROR_NOT_IMPLEMENTED;
1559 }
1560
1561 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1562         void **aSiteWindow)
1563 {
1564     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1565
1566     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1567
1568     *aSiteWindow = This->hwnd;
1569     return NS_OK;
1570 }
1571
1572 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1573     nsEmbeddingSiteWindow_QueryInterface,
1574     nsEmbeddingSiteWindow_AddRef,
1575     nsEmbeddingSiteWindow_Release,
1576     nsEmbeddingSiteWindow_SetDimensions,
1577     nsEmbeddingSiteWindow_GetDimensions,
1578     nsEmbeddingSiteWindow_SetFocus,
1579     nsEmbeddingSiteWindow_GetVisibility,
1580     nsEmbeddingSiteWindow_SetVisibility,
1581     nsEmbeddingSiteWindow_GetTitle,
1582     nsEmbeddingSiteWindow_SetTitle,
1583     nsEmbeddingSiteWindow_GetSiteWindow
1584 };
1585
1586 static inline NSContainer *impl_from_nsITooltipListener(nsITooltipListener *iface)
1587 {
1588     return CONTAINING_RECORD(iface, NSContainer, nsITooltipListener_iface);
1589 }
1590
1591 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1592         void **result)
1593 {
1594     NSContainer *This = impl_from_nsITooltipListener(iface);
1595     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1596 }
1597
1598 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1599 {
1600     NSContainer *This = impl_from_nsITooltipListener(iface);
1601     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1602 }
1603
1604 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1605 {
1606     NSContainer *This = impl_from_nsITooltipListener(iface);
1607     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1608 }
1609
1610 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1611         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1612 {
1613     NSContainer *This = impl_from_nsITooltipListener(iface);
1614
1615     if (This->doc)
1616         show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1617
1618     return NS_OK;
1619 }
1620
1621 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1622 {
1623     NSContainer *This = impl_from_nsITooltipListener(iface);
1624
1625     if (This->doc)
1626         hide_tooltip(This->doc);
1627
1628     return NS_OK;
1629 }
1630
1631 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1632     nsTooltipListener_QueryInterface,
1633     nsTooltipListener_AddRef,
1634     nsTooltipListener_Release,
1635     nsTooltipListener_OnShowTooltip,
1636     nsTooltipListener_OnHideTooltip
1637 };
1638
1639 static inline NSContainer *impl_from_nsIInterfaceRequestor(nsIInterfaceRequestor *iface)
1640 {
1641     return CONTAINING_RECORD(iface, NSContainer, nsIInterfaceRequestor_iface);
1642 }
1643
1644 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1645         nsIIDRef riid, void **result)
1646 {
1647     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1648     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1649 }
1650
1651 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1652 {
1653     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1654     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1655 }
1656
1657 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1658 {
1659     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1660     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1661 }
1662
1663 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1664         nsIIDRef riid, void **result)
1665 {
1666     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1667
1668     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1669         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1670         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1671     }
1672
1673     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1674 }
1675
1676 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1677     nsInterfaceRequestor_QueryInterface,
1678     nsInterfaceRequestor_AddRef,
1679     nsInterfaceRequestor_Release,
1680     nsInterfaceRequestor_GetInterface
1681 };
1682
1683 static inline NSContainer *impl_from_nsISupportsWeakReference(nsISupportsWeakReference *iface)
1684 {
1685     return CONTAINING_RECORD(iface, NSContainer, nsISupportsWeakReference_iface);
1686 }
1687
1688 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1689         nsIIDRef riid, void **result)
1690 {
1691     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1692     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1693 }
1694
1695 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1696 {
1697     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1698     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1699 }
1700
1701 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1702 {
1703     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1704     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1705 }
1706
1707 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1708         nsIWeakReference **_retval)
1709 {
1710     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1711
1712     TRACE("(%p)->(%p)\n", This, _retval);
1713
1714     if(!This->weak_reference) {
1715         This->weak_reference = heap_alloc(sizeof(nsWeakReference));
1716         if(!This->weak_reference)
1717             return NS_ERROR_OUT_OF_MEMORY;
1718
1719         This->weak_reference->nsIWeakReference_iface.lpVtbl = &nsWeakReferenceVtbl;
1720         This->weak_reference->ref = 1;
1721         This->weak_reference->nscontainer = This;
1722     }
1723
1724     *_retval = &This->weak_reference->nsIWeakReference_iface;
1725     nsIWeakReference_AddRef(*_retval);
1726     return NS_OK;
1727 }
1728
1729 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1730     nsSupportsWeakReference_QueryInterface,
1731     nsSupportsWeakReference_AddRef,
1732     nsSupportsWeakReference_Release,
1733     nsSupportsWeakReference_GetWeakReference
1734 };
1735
1736 nsresult create_chrome_window(nsIWebBrowserChrome *parent, nsIWebBrowserChrome **ret)
1737 {
1738     NSContainer *new_container;
1739     HRESULT hres;
1740
1741     if(parent->lpVtbl != &nsWebBrowserChromeVtbl)
1742         return NS_ERROR_UNEXPECTED;
1743
1744     hres = create_nscontainer(NULL, impl_from_nsIWebBrowserChrome(parent), &new_container);
1745     if(FAILED(hres))
1746         return NS_ERROR_FAILURE;
1747
1748     *ret = &new_container->nsIWebBrowserChrome_iface;
1749     return NS_OK;
1750 }
1751
1752 static HRESULT init_nscontainer(NSContainer *nscontainer)
1753 {
1754     nsIWebBrowserSetup *wbsetup;
1755     nsIScrollable *scrollable;
1756     nsresult nsres;
1757
1758     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1759             NULL, &IID_nsIWebBrowser, (void**)&nscontainer->webbrowser);
1760     if(NS_FAILED(nsres)) {
1761         ERR("Creating WebBrowser failed: %08x\n", nsres);
1762         return E_FAIL;
1763     }
1764
1765     nsres = nsIWebBrowser_SetContainerWindow(nscontainer->webbrowser, &nscontainer->nsIWebBrowserChrome_iface);
1766     if(NS_FAILED(nsres)) {
1767         ERR("SetContainerWindow failed: %08x\n", nsres);
1768         return E_FAIL;
1769     }
1770
1771     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIBaseWindow,
1772             (void**)&nscontainer->window);
1773     if(NS_FAILED(nsres)) {
1774         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1775         return E_FAIL;
1776     }
1777
1778     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserSetup,
1779                                          (void**)&wbsetup);
1780     if(NS_SUCCEEDED(nsres)) {
1781         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE);
1782         nsIWebBrowserSetup_Release(wbsetup);
1783         if(NS_FAILED(nsres)) {
1784             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1785             return E_FAIL;
1786         }
1787     }else {
1788         ERR("Could not get nsIWebBrowserSetup interface\n");
1789         return E_FAIL;
1790     }
1791
1792     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIWebNavigation,
1793             (void**)&nscontainer->navigation);
1794     if(NS_FAILED(nsres)) {
1795         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1796         return E_FAIL;
1797     }
1798
1799     nsres = nsIWebBrowserFocus_QueryInterface(nscontainer->webbrowser, &IID_nsIWebBrowserFocus,
1800             (void**)&nscontainer->focus);
1801     if(NS_FAILED(nsres)) {
1802         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1803         return E_FAIL;
1804     }
1805
1806     if(!nscontainer_class) {
1807         register_nscontainer_class();
1808         if(!nscontainer_class)
1809             return E_FAIL;
1810     }
1811
1812     nscontainer->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1813             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1814             GetDesktopWindow(), NULL, hInst, nscontainer);
1815     if(!nscontainer->hwnd) {
1816         WARN("Could not create window\n");
1817         return E_FAIL;
1818     }
1819
1820     nsres = nsIBaseWindow_InitWindow(nscontainer->window, nscontainer->hwnd, NULL, 0, 0, 100, 100);
1821     if(NS_SUCCEEDED(nsres)) {
1822         nsres = nsIBaseWindow_Create(nscontainer->window);
1823         if(NS_FAILED(nsres)) {
1824             WARN("Creating window failed: %08x\n", nsres);
1825             return E_FAIL;
1826         }
1827
1828         nsIBaseWindow_SetVisibility(nscontainer->window, FALSE);
1829         nsIBaseWindow_SetEnabled(nscontainer->window, FALSE);
1830     }else {
1831         ERR("InitWindow failed: %08x\n", nsres);
1832         return E_FAIL;
1833     }
1834
1835     nsres = nsIWebBrowser_SetParentURIContentListener(nscontainer->webbrowser,
1836             &nscontainer->nsIURIContentListener_iface);
1837     if(NS_FAILED(nsres))
1838         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1839
1840     nsres = nsIWebBrowser_QueryInterface(nscontainer->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1841     if(NS_SUCCEEDED(nsres)) {
1842         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1843                 ScrollOrientation_Y, Scrollbar_Always);
1844         if(NS_FAILED(nsres))
1845             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1846
1847         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1848                 ScrollOrientation_X, Scrollbar_Auto);
1849         if(NS_FAILED(nsres))
1850             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1851
1852         nsIScrollable_Release(scrollable);
1853     }else {
1854         ERR("Could not get nsIScrollable: %08x\n", nsres);
1855     }
1856
1857     return S_OK;
1858 }
1859
1860 HRESULT create_nscontainer(HTMLDocumentObj *doc, NSContainer *parent, NSContainer **_ret)
1861 {
1862     NSContainer *ret;
1863     HRESULT hres;
1864
1865     if(!load_gecko())
1866         return CLASS_E_CLASSNOTAVAILABLE;
1867
1868     ret = heap_alloc_zero(sizeof(NSContainer));
1869     if(!ret)
1870         return E_OUTOFMEMORY;
1871
1872     ret->nsIWebBrowserChrome_iface.lpVtbl = &nsWebBrowserChromeVtbl;
1873     ret->nsIContextMenuListener_iface.lpVtbl = &nsContextMenuListenerVtbl;
1874     ret->nsIURIContentListener_iface.lpVtbl = &nsURIContentListenerVtbl;
1875     ret->nsIEmbeddingSiteWindow_iface.lpVtbl = &nsEmbeddingSiteWindowVtbl;
1876     ret->nsITooltipListener_iface.lpVtbl = &nsTooltipListenerVtbl;
1877     ret->nsIInterfaceRequestor_iface.lpVtbl = &nsInterfaceRequestorVtbl;
1878     ret->nsISupportsWeakReference_iface.lpVtbl = &nsSupportsWeakReferenceVtbl;
1879
1880     ret->doc = doc;
1881     ret->ref = 1;
1882
1883     if(parent)
1884         nsIWebBrowserChrome_AddRef(&parent->nsIWebBrowserChrome_iface);
1885     ret->parent = parent;
1886
1887     hres = init_nscontainer(ret);
1888     if(SUCCEEDED(hres))
1889         *_ret = ret;
1890     else
1891         nsIWebBrowserChrome_Release(&ret->nsIWebBrowserChrome_iface);
1892     return hres;
1893 }
1894
1895 void NSContainer_Release(NSContainer *This)
1896 {
1897     TRACE("(%p)\n", This);
1898
1899     This->doc = NULL;
1900
1901     ShowWindow(This->hwnd, SW_HIDE);
1902     SetParent(This->hwnd, NULL);
1903
1904     nsIBaseWindow_SetVisibility(This->window, FALSE);
1905     nsIBaseWindow_Destroy(This->window);
1906
1907     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1908
1909     nsIWebBrowser_Release(This->webbrowser);
1910     This->webbrowser = NULL;
1911
1912     nsIWebNavigation_Release(This->navigation);
1913     This->navigation = NULL;
1914
1915     nsIBaseWindow_Release(This->window);
1916     This->window = NULL;
1917
1918     nsIWebBrowserFocus_Release(This->focus);
1919     This->focus = NULL;
1920
1921     if(This->editor_controller) {
1922         nsIController_Release(This->editor_controller);
1923         This->editor_controller = NULL;
1924     }
1925
1926     if(This->editor) {
1927         nsIEditor_Release(This->editor);
1928         This->editor = NULL;
1929     }
1930
1931     if(This->content_listener) {
1932         nsIURIContentListener_Release(This->content_listener);
1933         This->content_listener = NULL;
1934     }
1935
1936     if(This->hwnd) {
1937         DestroyWindow(This->hwnd);
1938         This->hwnd = NULL;
1939     }
1940
1941     nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1942 }