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