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