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