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