hlink/tests: Add a trailing '\n' to an ok() call.
[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 nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1128                                                           nsIURI *aURI, PRBool *_retval)
1129 {
1130     NSContainer *This = NSURICL_THIS(iface);
1131     nsACString spec_str;
1132     const char *spec;
1133     nsresult nsres;
1134
1135     nsACString_Init(&spec_str, NULL);
1136     nsIURI_GetSpec(aURI, &spec_str);
1137     nsACString_GetData(&spec_str, &spec);
1138
1139     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1140
1141     nsACString_Finish(&spec_str);
1142
1143     nsres = on_start_uri_open(This, aURI, _retval);
1144     if(NS_FAILED(nsres))
1145         return nsres;
1146
1147     return !*_retval && This->content_listener
1148         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1149         : NS_OK;
1150 }
1151
1152 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1153         const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest,
1154         nsIStreamListener **aContentHandler, PRBool *_retval)
1155 {
1156     NSContainer *This = NSURICL_THIS(iface);
1157
1158     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1159             aRequest, aContentHandler, _retval);
1160
1161     return This->content_listener
1162         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1163                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1164         : NS_ERROR_NOT_IMPLEMENTED;
1165 }
1166
1167 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1168         const char *aContentType, char **aDesiredContentType, PRBool *_retval)
1169 {
1170     NSContainer *This = NSURICL_THIS(iface);
1171
1172     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1173
1174     /* FIXME: Should we do something here? */
1175     *_retval = TRUE; 
1176
1177     return This->content_listener
1178         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1179                   aDesiredContentType, _retval)
1180         : NS_OK;
1181 }
1182
1183 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1184         const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType,
1185         PRBool *_retval)
1186 {
1187     NSContainer *This = NSURICL_THIS(iface);
1188
1189     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1190             aDesiredContentType, _retval);
1191
1192     return This->content_listener
1193         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1194                 aIsContentPreferred, aDesiredContentType, _retval)
1195         : NS_ERROR_NOT_IMPLEMENTED;
1196 }
1197
1198 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1199         nsISupports **aLoadCookie)
1200 {
1201     NSContainer *This = NSURICL_THIS(iface);
1202
1203     WARN("(%p)->(%p)\n", This, aLoadCookie);
1204
1205     return This->content_listener
1206         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1207         : NS_ERROR_NOT_IMPLEMENTED;
1208 }
1209
1210 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1211         nsISupports *aLoadCookie)
1212 {
1213     NSContainer *This = NSURICL_THIS(iface);
1214
1215     WARN("(%p)->(%p)\n", This, aLoadCookie);
1216
1217     return This->content_listener
1218         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1219         : NS_ERROR_NOT_IMPLEMENTED;
1220 }
1221
1222 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1223         nsIURIContentListener **aParentContentListener)
1224 {
1225     NSContainer *This = NSURICL_THIS(iface);
1226
1227     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1228
1229     if(This->content_listener)
1230         nsIURIContentListener_AddRef(This->content_listener);
1231
1232     *aParentContentListener = This->content_listener;
1233     return NS_OK;
1234 }
1235
1236 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1237         nsIURIContentListener *aParentContentListener)
1238 {
1239     NSContainer *This = NSURICL_THIS(iface);
1240
1241     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1242
1243     if(aParentContentListener == NSURICL(This))
1244         return NS_OK;
1245
1246     if(This->content_listener)
1247         nsIURIContentListener_Release(This->content_listener);
1248
1249     This->content_listener = aParentContentListener;
1250     if(This->content_listener)
1251         nsIURIContentListener_AddRef(This->content_listener);
1252
1253     return NS_OK;
1254 }
1255
1256 #undef NSURICL_THIS
1257
1258 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1259     nsURIContentListener_QueryInterface,
1260     nsURIContentListener_AddRef,
1261     nsURIContentListener_Release,
1262     nsURIContentListener_OnStartURIOpen,
1263     nsURIContentListener_DoContent,
1264     nsURIContentListener_IsPreferred,
1265     nsURIContentListener_CanHandleContent,
1266     nsURIContentListener_GetLoadCookie,
1267     nsURIContentListener_SetLoadCookie,
1268     nsURIContentListener_GetParentContentListener,
1269     nsURIContentListener_SetParentContentListener
1270 };
1271
1272 /**********************************************************
1273  *      nsIEmbeddinSiteWindow interface
1274  */
1275
1276 #define NSEMBWNDS_THIS(iface) DEFINE_THIS(NSContainer, EmbeddingSiteWindow, iface)
1277
1278 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1279         nsIIDRef riid, nsQIResult result)
1280 {
1281     NSContainer *This = NSEMBWNDS_THIS(iface);
1282     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1283 }
1284
1285 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1286 {
1287     NSContainer *This = NSEMBWNDS_THIS(iface);
1288     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1289 }
1290
1291 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1292 {
1293     NSContainer *This = NSEMBWNDS_THIS(iface);
1294     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1295 }
1296
1297 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1298         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1299 {
1300     NSContainer *This = NSEMBWNDS_THIS(iface);
1301     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1302     return NS_ERROR_NOT_IMPLEMENTED;
1303 }
1304
1305 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1306         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1307 {
1308     NSContainer *This = NSEMBWNDS_THIS(iface);
1309     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1310     return NS_ERROR_NOT_IMPLEMENTED;
1311 }
1312
1313 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1314 {
1315     NSContainer *This = NSEMBWNDS_THIS(iface);
1316
1317     TRACE("(%p)\n", This);
1318
1319     if(This->reset_focus)
1320         PostMessageW(This->hwnd, WM_RESETFOCUS_HACK, 0, 0);
1321
1322     return nsIBaseWindow_SetFocus(This->window);
1323 }
1324
1325 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1326         PRBool *aVisibility)
1327 {
1328     NSContainer *This = NSEMBWNDS_THIS(iface);
1329
1330     TRACE("(%p)->(%p)\n", This, aVisibility);
1331
1332     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1333     return NS_OK;
1334 }
1335
1336 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1337         PRBool aVisibility)
1338 {
1339     NSContainer *This = NSEMBWNDS_THIS(iface);
1340
1341     TRACE("(%p)->(%x)\n", This, aVisibility);
1342
1343     return NS_OK;
1344 }
1345
1346 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1347         PRUnichar **aTitle)
1348 {
1349     NSContainer *This = NSEMBWNDS_THIS(iface);
1350     WARN("(%p)->(%p)\n", This, aTitle);
1351     return NS_ERROR_NOT_IMPLEMENTED;
1352 }
1353
1354 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1355         const PRUnichar *aTitle)
1356 {
1357     NSContainer *This = NSEMBWNDS_THIS(iface);
1358     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1359     return NS_ERROR_NOT_IMPLEMENTED;
1360 }
1361
1362 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1363         void **aSiteWindow)
1364 {
1365     NSContainer *This = NSEMBWNDS_THIS(iface);
1366
1367     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1368
1369     *aSiteWindow = This->hwnd;
1370     return NS_OK;
1371 }
1372
1373 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1374     nsEmbeddingSiteWindow_QueryInterface,
1375     nsEmbeddingSiteWindow_AddRef,
1376     nsEmbeddingSiteWindow_Release,
1377     nsEmbeddingSiteWindow_SetDimensions,
1378     nsEmbeddingSiteWindow_GetDimensions,
1379     nsEmbeddingSiteWindow_SetFocus,
1380     nsEmbeddingSiteWindow_GetVisibility,
1381     nsEmbeddingSiteWindow_SetVisibility,
1382     nsEmbeddingSiteWindow_GetTitle,
1383     nsEmbeddingSiteWindow_SetTitle,
1384     nsEmbeddingSiteWindow_GetSiteWindow
1385 };
1386
1387 #define NSTOOLTIP_THIS(iface) DEFINE_THIS(NSContainer, TooltipListener, iface)
1388
1389 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1390                                                        nsQIResult result)
1391 {
1392     NSContainer *This = NSTOOLTIP_THIS(iface);
1393     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1394 }
1395
1396 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1397 {
1398     NSContainer *This = NSTOOLTIP_THIS(iface);
1399     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1400 }
1401
1402 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1403 {
1404     NSContainer *This = NSTOOLTIP_THIS(iface);
1405     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1406 }
1407
1408 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1409         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1410 {
1411     NSContainer *This = NSTOOLTIP_THIS(iface);
1412
1413     if (This->doc)
1414         show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1415
1416     return NS_OK;
1417 }
1418
1419 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1420 {
1421     NSContainer *This = NSTOOLTIP_THIS(iface);
1422
1423     if (This->doc)
1424         hide_tooltip(This->doc);
1425
1426     return NS_OK;
1427 }
1428
1429 #undef NSTOOLTIM_THIS
1430
1431 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1432     nsTooltipListener_QueryInterface,
1433     nsTooltipListener_AddRef,
1434     nsTooltipListener_Release,
1435     nsTooltipListener_OnShowTooltip,
1436     nsTooltipListener_OnHideTooltip
1437 };
1438
1439 #define NSIFACEREQ_THIS(iface) DEFINE_THIS(NSContainer, InterfaceRequestor, iface)
1440
1441 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1442                                                           nsIIDRef riid, nsQIResult result)
1443 {
1444     NSContainer *This = NSIFACEREQ_THIS(iface);
1445     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1446 }
1447
1448 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1449 {
1450     NSContainer *This = NSIFACEREQ_THIS(iface);
1451     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1452 }
1453
1454 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1455 {
1456     NSContainer *This = NSIFACEREQ_THIS(iface);
1457     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1458 }
1459
1460 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1461                                                         nsIIDRef riid, nsQIResult result)
1462 {
1463     NSContainer *This = NSIFACEREQ_THIS(iface);
1464
1465     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1466         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1467         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1468     }
1469
1470     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1471 }
1472
1473 #undef NSIFACEREQ_THIS
1474
1475 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1476     nsInterfaceRequestor_QueryInterface,
1477     nsInterfaceRequestor_AddRef,
1478     nsInterfaceRequestor_Release,
1479     nsInterfaceRequestor_GetInterface
1480 };
1481
1482 #define NSWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, WeakReference, iface)
1483
1484 static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface,
1485         nsIIDRef riid, nsQIResult result)
1486 {
1487     NSContainer *This = NSWEAKREF_THIS(iface);
1488     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1489 }
1490
1491 static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface)
1492 {
1493     NSContainer *This = NSWEAKREF_THIS(iface);
1494     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1495 }
1496
1497 static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface)
1498 {
1499     NSContainer *This = NSWEAKREF_THIS(iface);
1500     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1501 }
1502
1503 static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface,
1504         const nsIID *riid, void **result)
1505 {
1506     NSContainer *This = NSWEAKREF_THIS(iface);
1507     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1508 }
1509
1510 #undef NSWEAKREF_THIS
1511
1512 static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = {
1513     nsWeakReference_QueryInterface,
1514     nsWeakReference_AddRef,
1515     nsWeakReference_Release,
1516     nsWeakReference_QueryReferent
1517 };
1518
1519 #define NSSUPWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, SupportsWeakReference, iface)
1520
1521 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1522         nsIIDRef riid, nsQIResult result)
1523 {
1524     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1525     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1526 }
1527
1528 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1529 {
1530     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1531     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1532 }
1533
1534 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1535 {
1536     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1537     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1538 }
1539
1540 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1541         nsIWeakReference **_retval)
1542 {
1543     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1544
1545     TRACE("(%p)->(%p)\n", This, _retval);
1546
1547     nsIWeakReference_AddRef(NSWEAKREF(This));
1548     *_retval = NSWEAKREF(This);
1549     return NS_OK;
1550 }
1551
1552 #undef NSWEAKREF_THIS
1553
1554 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1555     nsSupportsWeakReference_QueryInterface,
1556     nsSupportsWeakReference_AddRef,
1557     nsSupportsWeakReference_Release,
1558     nsSupportsWeakReference_GetWeakReference
1559 };
1560
1561
1562 NSContainer *NSContainer_Create(HTMLDocumentObj *doc, NSContainer *parent)
1563 {
1564     nsIWebBrowserSetup *wbsetup;
1565     nsIScrollable *scrollable;
1566     NSContainer *ret;
1567     nsresult nsres;
1568
1569     if(!load_gecko(TRUE))
1570         return NULL;
1571
1572     ret = heap_alloc_zero(sizeof(NSContainer));
1573
1574     ret->lpWebBrowserChromeVtbl      = &nsWebBrowserChromeVtbl;
1575     ret->lpContextMenuListenerVtbl   = &nsContextMenuListenerVtbl;
1576     ret->lpURIContentListenerVtbl    = &nsURIContentListenerVtbl;
1577     ret->lpEmbeddingSiteWindowVtbl   = &nsEmbeddingSiteWindowVtbl;
1578     ret->lpTooltipListenerVtbl       = &nsTooltipListenerVtbl;
1579     ret->lpInterfaceRequestorVtbl    = &nsInterfaceRequestorVtbl;
1580     ret->lpWeakReferenceVtbl         = &nsWeakReferenceVtbl;
1581     ret->lpSupportsWeakReferenceVtbl = &nsSupportsWeakReferenceVtbl;
1582
1583     ret->doc = doc;
1584     ret->ref = 1;
1585
1586     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1587             NULL, &IID_nsIWebBrowser, (void**)&ret->webbrowser);
1588     if(NS_FAILED(nsres)) {
1589         ERR("Creating WebBrowser failed: %08x\n", nsres);
1590         heap_free(ret);
1591         return NULL;
1592     }
1593
1594     if(parent)
1595         nsIWebBrowserChrome_AddRef(NSWBCHROME(parent));
1596     ret->parent = parent;
1597
1598     nsres = nsIWebBrowser_SetContainerWindow(ret->webbrowser, NSWBCHROME(ret));
1599     if(NS_FAILED(nsres))
1600         ERR("SetContainerWindow failed: %08x\n", nsres);
1601
1602     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIBaseWindow,
1603             (void**)&ret->window);
1604     if(NS_FAILED(nsres))
1605         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1606
1607     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserSetup,
1608                                          (void**)&wbsetup);
1609     if(NS_SUCCEEDED(nsres)) {
1610         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE);
1611         nsIWebBrowserSetup_Release(wbsetup);
1612         if(NS_FAILED(nsres))
1613             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1614     }else {
1615         ERR("Could not get nsIWebBrowserSetup interface\n");
1616     }
1617
1618     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebNavigation,
1619             (void**)&ret->navigation);
1620     if(NS_FAILED(nsres))
1621         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1622
1623     nsres = nsIWebBrowserFocus_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserFocus,
1624             (void**)&ret->focus);
1625     if(NS_FAILED(nsres))
1626         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1627
1628     if(!nscontainer_class)
1629         register_nscontainer_class();
1630
1631     ret->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1632             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1633             GetDesktopWindow(), NULL, hInst, ret);
1634
1635     nsres = nsIBaseWindow_InitWindow(ret->window, ret->hwnd, NULL, 0, 0, 100, 100);
1636     if(NS_SUCCEEDED(nsres)) {
1637         nsres = nsIBaseWindow_Create(ret->window);
1638         if(NS_FAILED(nsres))
1639             WARN("Creating window failed: %08x\n", nsres);
1640
1641         nsIBaseWindow_SetVisibility(ret->window, FALSE);
1642         nsIBaseWindow_SetEnabled(ret->window, FALSE);
1643     }else {
1644         ERR("InitWindow failed: %08x\n", nsres);
1645     }
1646
1647     nsres = nsIWebBrowser_SetParentURIContentListener(ret->webbrowser, NSURICL(ret));
1648     if(NS_FAILED(nsres))
1649         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1650
1651     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1652     if(NS_SUCCEEDED(nsres)) {
1653         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1654                 ScrollOrientation_Y, Scrollbar_Always);
1655         if(NS_FAILED(nsres))
1656             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1657
1658         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1659                 ScrollOrientation_X, Scrollbar_Auto);
1660         if(NS_FAILED(nsres))
1661             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1662
1663         nsIScrollable_Release(scrollable);
1664     }else {
1665         ERR("Could not get nsIScrollable: %08x\n", nsres);
1666     }
1667
1668     return ret;
1669 }
1670
1671 void NSContainer_Release(NSContainer *This)
1672 {
1673     TRACE("(%p)\n", This);
1674
1675     This->doc = NULL;
1676
1677     ShowWindow(This->hwnd, SW_HIDE);
1678     SetParent(This->hwnd, NULL);
1679
1680     nsIBaseWindow_SetVisibility(This->window, FALSE);
1681     nsIBaseWindow_Destroy(This->window);
1682
1683     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1684
1685     nsIWebBrowser_Release(This->webbrowser);
1686     This->webbrowser = NULL;
1687
1688     nsIWebNavigation_Release(This->navigation);
1689     This->navigation = NULL;
1690
1691     nsIBaseWindow_Release(This->window);
1692     This->window = NULL;
1693
1694     nsIWebBrowserFocus_Release(This->focus);
1695     This->focus = NULL;
1696
1697     if(This->editor_controller) {
1698         nsIController_Release(This->editor_controller);
1699         This->editor_controller = NULL;
1700     }
1701
1702     if(This->editor) {
1703         nsIEditor_Release(This->editor);
1704         This->editor = NULL;
1705     }
1706
1707     if(This->content_listener) {
1708         nsIURIContentListener_Release(This->content_listener);
1709         This->content_listener = NULL;
1710     }
1711
1712     if(This->hwnd) {
1713         DestroyWindow(This->hwnd);
1714         This->hwnd = NULL;
1715     }
1716
1717     nsIWebBrowserChrome_Release(NSWBCHROME(This));
1718 }