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