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