gdi32: Disable the freetype mmap sharing on Mac OS.
[wine] / dlls / mshtml / olecmd.c
1 /*
2  * Copyright 2005-2006 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 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "shlguid.h"
32 #include "mshtmdid.h"
33 #include "idispids.h"
34 #include "mshtmcid.h"
35
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 #include "mshtml_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
42
43 #define NSCMD_BOLD "cmd_bold"
44 #define NSCMD_ITALIC "cmd_italic"
45 #define NSCMD_UNDERLINE "cmd_underline"
46 #define NSCMD_FONTCOLOR "cmd_fontColor"
47 #define NSCMD_ALIGN "cmd_align"
48 #define NSCMD_FONTFACE "cmd_fontFace"
49 #define NSCMD_INDENT "cmd_indent"
50 #define NSCMD_OUTDENT "cmd_outdent"
51 #define NSCMD_INSERTHR "cmd_insertHR"
52 #define NSCMD_UL "cmd_ul"
53 #define NSCMD_OL "cmd_ol"
54
55 #define NSSTATE_ATTRIBUTE "state_attribute"
56 #define NSSTATE_ALL "state_all"
57
58 #define NSALIGN_CENTER "center"
59 #define NSALIGN_LEFT   "left"
60 #define NSALIGN_RIGHT  "right"
61
62 /**********************************************************
63  * IOleCommandTarget implementation
64  */
65
66 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
67
68 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
69 {
70     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
71     return E_NOTIMPL;
72 }
73
74 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
75 {
76     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
77     return E_NOTIMPL;
78 }
79
80 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
81 {
82     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
83     return E_NOTIMPL;
84 }
85
86 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
87 {
88     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
89     return E_NOTIMPL;
90 }
91
92 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
93 {
94     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
95     return E_NOTIMPL;
96 }
97
98 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
99 {
100     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
101     return E_NOTIMPL;
102 }
103
104 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
105 {
106     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
107     return E_NOTIMPL;
108 }
109
110 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
111 {
112     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
113     return E_NOTIMPL;
114 }
115
116 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
117 {
118     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
119     return E_NOTIMPL;
120 }
121
122 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
123 {
124     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
125     return E_NOTIMPL;
126 }
127
128 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
129 {
130     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
131     return E_NOTIMPL;
132 }
133
134 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
135 {
136     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
137     return E_NOTIMPL;
138 }
139
140 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
141 {
142     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
143     return E_NOTIMPL;
144 }
145
146 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
147 {
148     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
149     return E_NOTIMPL;
150 }
151
152 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
153 {
154     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
155     return E_NOTIMPL;
156 }
157
158 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
159 {
160     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
161     return E_NOTIMPL;
162 }
163
164 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
165 {
166     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
167     return E_NOTIMPL;
168 }
169
170 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
171 {
172     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
173     return E_NOTIMPL;
174 }
175
176 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
177 {
178     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
179     return E_NOTIMPL;
180 }
181
182 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
183 {
184     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
185     return E_NOTIMPL;
186 }
187
188 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
189 {
190     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
191     return E_NOTIMPL;
192 }
193
194 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
195 {
196     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
197     return E_NOTIMPL;
198 }
199
200 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
201 {
202     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
203     return E_NOTIMPL;
204 }
205
206 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
207 {
208     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
209     return E_NOTIMPL;
210 }
211
212 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
213 {
214     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
215     return E_NOTIMPL;
216 }
217
218 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
219 {
220     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
221
222     /* Tests show that we have nothing more to do here */
223
224     if(pvaOut) {
225         V_VT(pvaOut) = VT_BOOL;
226         V_BOOL(pvaOut) = VARIANT_TRUE;
227     }
228
229     return S_OK;
230 }
231
232 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
233 {
234     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
235     return E_NOTIMPL;
236 }
237
238 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
239 {
240     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
241     return E_NOTIMPL;
242 }
243
244 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
245 {
246     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
247     return E_NOTIMPL;
248 }
249
250 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
251 {
252     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
253     return E_NOTIMPL;
254 }
255
256 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
257 {
258     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
259     return E_NOTIMPL;
260 }
261
262 static void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
263 {
264     nsICommandManager *cmdmgr;
265     nsIInterfaceRequestor *iface_req;
266     nsresult nsres;
267
268     TRACE("(%p)\n", This);
269
270     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
271             &IID_nsIInterfaceRequestor, (void**)&iface_req);
272     if(NS_FAILED(nsres)) {
273         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
274         return;
275     }
276
277     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
278                                                (void**)&cmdmgr);
279     nsIInterfaceRequestor_Release(iface_req);
280     if(NS_FAILED(nsres)) {
281         ERR("Could not get nsICommandManager: %08x\n", nsres);
282         return;
283     }
284
285     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, NULL);
286     if(NS_FAILED(nsres))
287         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
288
289     nsICommandManager_Release(cmdmgr);
290 }
291
292 static nsresult get_ns_command_state(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
293 {
294     nsICommandManager *cmdmgr;
295     nsIInterfaceRequestor *iface_req;
296     nsresult nsres;
297
298     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
299             &IID_nsIInterfaceRequestor, (void**)&iface_req);
300     if(NS_FAILED(nsres)) {
301         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
302         return nsres;
303     }
304
305     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
306                                                (void**)&cmdmgr);
307     nsIInterfaceRequestor_Release(iface_req);
308     if(NS_FAILED(nsres)) {
309         ERR("Could not get nsICommandManager: %08x\n", nsres);
310         return nsres;
311     }
312
313     nsres = nsICommandManager_GetCommandState(cmdmgr, cmd, NULL, nsparam);
314     if(NS_FAILED(nsres))
315         ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd), nsres);
316
317     nsICommandManager_Release(cmdmgr);
318     return nsres;
319 }
320
321 static DWORD query_edit_status(HTMLDocument *This, const char *nscmd)
322 {
323     nsICommandParams *nsparam;
324     PRBool b = FALSE;
325
326     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
327         return OLECMDF_SUPPORTED;
328
329     if(This->nscontainer && nscmd) {
330         nsparam = create_nscommand_params();
331         get_ns_command_state(This->nscontainer, nscmd, nsparam);
332
333         nsICommandParams_GetBooleanValue(nsparam, NSSTATE_ALL, &b);
334
335         nsICommandParams_Release(nsparam);
336     }
337
338     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (b ? OLECMDF_LATCHED : 0);
339 }
340
341 static DWORD query_align_status(HTMLDocument *This, const char *align_str)
342 {
343     nsICommandParams *nsparam;
344     char *align = NULL;
345
346     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
347         return OLECMDF_SUPPORTED;
348
349     if(This->nscontainer) {
350         nsparam = create_nscommand_params();
351         get_ns_command_state(This->nscontainer, NSCMD_ALIGN, nsparam);
352
353         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &align);
354
355         nsICommandParams_Release(nsparam);
356     }
357
358     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (align && !strcmp(align_str, align) ? OLECMDF_LATCHED : 0);
359 }
360
361 static void set_ns_align(HTMLDocument *This, const char *align_str)
362 {
363     nsICommandParams *nsparam;
364
365     if(!This->nscontainer)
366         return;
367
368     nsparam = create_nscommand_params();
369     nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, align_str);
370
371     do_ns_command(This->nscontainer, NSCMD_ALIGN, nsparam);
372
373     nsICommandParams_Release(nsparam);
374 }
375
376 static HRESULT exec_fontname(HTMLDocument *This, VARIANT *in, VARIANT *out)
377 {
378     TRACE("(%p)->(%p %p)\n", This, in, out);
379
380     if(!This->nscontainer)
381         return E_FAIL;
382
383     if(in) {
384         nsICommandParams *nsparam = create_nscommand_params();
385         char *stra;
386         DWORD len;
387
388         if(V_VT(in) != VT_BSTR) {
389             FIXME("Unsupported vt=%d\n", V_VT(out));
390             return E_INVALIDARG;
391         }
392
393         len = WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, NULL, 0, NULL, NULL);
394         stra = mshtml_alloc(len);
395         WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, stra, -1, NULL, NULL);
396         nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, stra);
397         mshtml_free(stra);
398
399         do_ns_command(This->nscontainer, NSCMD_FONTFACE, nsparam);
400
401         nsICommandParams_Release(nsparam);
402     }
403
404     if(out) {
405         nsICommandParams *nsparam;
406         LPWSTR strw;
407         char *stra;
408         DWORD len;
409         nsresult nsres;
410
411         if(V_VT(out) != VT_BSTR) {
412             FIXME("Unsupported vt=%d\n", V_VT(out));
413             return E_INVALIDARG;
414         }
415
416         nsparam = create_nscommand_params();
417
418         nsres = get_ns_command_state(This->nscontainer, NSCMD_FONTFACE, nsparam);
419         if(NS_FAILED(nsres))
420             return S_OK;
421
422         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &stra);
423         nsICommandParams_Release(nsparam);
424
425         len = MultiByteToWideChar(CP_ACP, 0, stra, -1, NULL, 0);
426         strw = mshtml_alloc(len*sizeof(WCHAR));
427         MultiByteToWideChar(CP_ACP, 0, stra, -1, strw, -1);
428         nsfree(stra);
429
430         V_BSTR(out) = SysAllocString(strw);
431         mshtml_free(strw);
432     }
433
434     return S_OK;
435 }
436
437 static HRESULT exec_forecolor(HTMLDocument *This, VARIANT *in, VARIANT *out)
438 {
439     TRACE("(%p)->(%p %p)\n", This, in, out);
440
441     if(in) {
442         if(V_VT(in) == VT_I4) {
443             nsICommandParams *nsparam = create_nscommand_params();
444             char color_str[10];
445
446             sprintf(color_str, "#%02x%02x%02x",
447                     V_I4(in)&0xff, (V_I4(in)>>8)&0xff, (V_I4(in)>>16)&0xff);
448
449             nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, color_str);
450             do_ns_command(This->nscontainer, NSCMD_FONTCOLOR, nsparam);
451
452             nsICommandParams_Release(nsparam);
453         }else {
454             FIXME("unsupported in vt=%d\n", V_VT(in));
455         }
456     }
457
458     if(out) {
459         FIXME("unsupported out\n");
460         return E_NOTIMPL;
461     }
462
463     return S_OK;
464 }
465
466 static HRESULT exec_fontsize(HTMLDocument *This, VARIANT *in, VARIANT *out)
467 {
468     TRACE("(%p)->(%p %p)\n", This, in, out);
469
470     if(out) {
471         WCHAR val[10] = {0};
472
473         switch(V_VT(out)) {
474         case VT_I4:
475             get_font_size(This, val);
476             V_I4(out) = strtolW(val, NULL, 10);
477             break;
478         case VT_BSTR:
479             get_font_size(This, val);
480             V_BSTR(out) = SysAllocString(val);
481             break;
482         default:
483             FIXME("unsupported vt %d\n", V_VT(out));
484         }
485     }
486
487     if(in) {
488         switch(V_VT(in)) {
489         case VT_I4: {
490             WCHAR size[10];
491             static const WCHAR format[] = {'%','d',0};
492             wsprintfW(size, format, V_I4(in));
493             set_font_size(This, size);
494             break;
495         }
496         case VT_BSTR:
497             set_font_size(This, V_BSTR(in));
498             break;
499         default:
500             FIXME("unsupported vt %d\n", V_VT(out));
501         }
502     }
503
504     return S_OK;
505 }
506
507 static HRESULT exec_bold(HTMLDocument *This)
508 {
509     TRACE("(%p)\n", This);
510
511     if(This->nscontainer)
512         do_ns_command(This->nscontainer, NSCMD_BOLD, NULL);
513
514     return S_OK;
515 }
516
517 static HRESULT exec_italic(HTMLDocument *This)
518 {
519     TRACE("(%p)\n", This);
520
521     if(This->nscontainer)
522         do_ns_command(This->nscontainer, NSCMD_ITALIC, NULL);
523
524     return S_OK;
525 }
526
527 static HRESULT exec_justifycenter(HTMLDocument *This)
528 {
529     TRACE("(%p)\n", This);
530     set_ns_align(This, NSALIGN_CENTER);
531     return S_OK;
532 }
533
534 static HRESULT exec_justifyleft(HTMLDocument *This)
535 {
536     TRACE("(%p)\n", This);
537     set_ns_align(This, NSALIGN_LEFT);
538     return S_OK;
539 }
540
541 static HRESULT exec_justifyright(HTMLDocument *This)
542 {
543     TRACE("(%p)\n", This);
544     set_ns_align(This, NSALIGN_RIGHT);
545     return S_OK;
546 }
547
548 static HRESULT exec_underline(HTMLDocument *This)
549 {
550     TRACE("(%p)\n", This);
551
552     if(This->nscontainer)
553         do_ns_command(This->nscontainer, NSCMD_UNDERLINE, NULL);
554
555     return S_OK;
556 }
557
558 static HRESULT exec_browsemode(HTMLDocument *This)
559 {
560     WARN("(%p)\n", This);
561
562     This->usermode = BROWSEMODE;
563
564     return S_OK;
565 }
566
567 static void setup_ns_editing(NSContainer *This)
568 {
569     nsIInterfaceRequestor *iface_req;
570     nsIEditingSession *editing_session = NULL;
571     nsIURIContentListener *listener = NULL;
572     nsIDOMWindow *dom_window = NULL;
573     nsresult nsres;
574
575     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
576             &IID_nsIInterfaceRequestor, (void**)&iface_req);
577     if(NS_FAILED(nsres)) {
578         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
579         return;
580     }
581
582     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
583                                                (void**)&editing_session);
584     nsIInterfaceRequestor_Release(iface_req);
585     if(NS_FAILED(nsres)) {
586         ERR("Could not get nsIEditingSession: %08x\n", nsres);
587         return;
588     }
589
590     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
591     if(NS_FAILED(nsres)) {
592         ERR("Could not get content DOM window: %08x\n", nsres);
593         nsIEditingSession_Release(editing_session);
594         return;
595     }
596
597     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
598     nsIEditingSession_Release(editing_session);
599     nsIDOMWindow_Release(dom_window);
600     if(NS_FAILED(nsres)) {
601         ERR("MakeWindowEditable failed: %08x\n", nsres);
602         return;
603     }
604
605     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
606      * It seams to be a bug in Gecko. To workaround it we set our content
607      * listener again and Gecko's one as its parent.
608      */
609     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
610     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
611     nsIURIContentListener_Release(listener);
612     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
613 }
614
615 static HRESULT exec_editmode(HTMLDocument *This)
616 {
617     IMoniker *mon;
618     HRESULT hres;
619
620     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
621
622     TRACE("(%p)\n", This);
623
624     This->usermode = EDITMODE;
625
626     if(This->frame)
627         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
628
629     if(This->hostui) {
630         DOCHOSTUIINFO hostinfo;
631
632         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
633         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
634         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
635         if(SUCCEEDED(hres))
636             /* FIXME: use hostinfo */
637             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
638                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
639                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
640     }
641
642     if(This->nscontainer)
643         setup_ns_editing(This->nscontainer);
644
645     hres = CreateURLMoniker(NULL, wszAboutBlank, &mon);
646     if(FAILED(hres)) {
647         FIXME("CreateURLMoniker failed: %08x\n", hres);
648         return hres;
649     }
650
651     return IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
652 }
653
654 static HRESULT exec_baselinefont3(HTMLDocument *This)
655 {
656     FIXME("(%p)\n", This);
657     return S_OK;
658 }
659
660 static HRESULT exec_horizontalline(HTMLDocument *This)
661 {
662     TRACE("(%p)\n", This);
663
664     if(This->nscontainer)
665         do_ns_command(This->nscontainer, NSCMD_INSERTHR, NULL);
666
667     return S_OK;
668 }
669
670 static HRESULT exec_orderlist(HTMLDocument *This)
671 {
672     TRACE("(%p)\n", This);
673
674     if(This->nscontainer)
675         do_ns_command(This->nscontainer, NSCMD_OL, NULL);
676
677     return S_OK;
678 }
679
680 static HRESULT exec_unorderlist(HTMLDocument *This)
681 {
682     TRACE("(%p)\n", This);
683
684     if(This->nscontainer)
685         do_ns_command(This->nscontainer, NSCMD_UL, NULL);
686
687     return S_OK;
688 }
689
690 static HRESULT exec_indent(HTMLDocument *This)
691 {
692     TRACE("(%p)\n", This);
693
694     if(This->nscontainer)
695         do_ns_command(This->nscontainer, NSCMD_INDENT, NULL);
696
697     return S_OK;
698 }
699
700 static HRESULT exec_outdent(HTMLDocument *This)
701 {
702     TRACE("(%p)\n", This);
703
704     if(This->nscontainer)
705         do_ns_command(This->nscontainer, NSCMD_OUTDENT, NULL);
706
707     return S_OK;
708 }
709
710 static const struct {
711     OLECMDF cmdf;
712     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
713 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
714     {0},
715     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
716     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
717     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
718     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
719     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
720     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
721     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
722     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
723     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
724     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
725     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
726     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
727     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
728     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
729     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
730     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
731     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
732     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
733     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
734     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
735     {0},
736     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
737     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
738     {0},{0},{0},{0},{0},{0},
739     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
740     {0},{0},
741     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
742     {0},{0},
743     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
744     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
745     {0},{0},{0},{0},{0},
746     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
747     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
748     {0},{0},
749     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
750     {0},{0},{0},
751     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
752     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
753 };
754
755 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
756 {
757     HTMLDocument *This = CMDTARGET_THIS(iface);
758     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
759 }
760
761 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
762 {
763     HTMLDocument *This = CMDTARGET_THIS(iface);
764     return IHTMLDocument2_AddRef(HTMLDOC(This));
765 }
766
767 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
768 {
769     HTMLDocument *This = CMDTARGET_THIS(iface);
770     return IHTMLDocument_Release(HTMLDOC(This));
771 }
772
773 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
774         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
775 {
776     HTMLDocument *This = CMDTARGET_THIS(iface);
777     HRESULT hres = S_OK, hr;
778
779     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
780
781     if(!pguidCmdGroup) {
782         ULONG i;
783
784         for(i=0; i<cCmds; i++) {
785             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
786                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
787                 prgCmds[i].cmdf = 0;
788                 hres = OLECMDERR_E_NOTSUPPORTED;
789             }else {
790                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
791                     IOleCommandTarget *cmdtrg = NULL;
792                     OLECMD olecmd;
793
794                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
795                     if(This->client) {
796                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
797                                 (void**)&cmdtrg);
798                         if(SUCCEEDED(hr)) {
799                             olecmd.cmdID = prgCmds[i].cmdID;
800                             olecmd.cmdf = 0;
801
802                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
803                             if(SUCCEEDED(hr) && olecmd.cmdf)
804                                 prgCmds[i].cmdf = olecmd.cmdf;
805                         }
806                     }else {
807                         ERR("This->client == NULL, native would crash\n");
808                     }
809                 }else {
810                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
811                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
812                 }
813                 hres = S_OK;
814             }
815         }
816
817         if(pCmdText)
818             FIXME("Set pCmdText\n");
819     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
820         ULONG i;
821
822         for(i=0; i<cCmds; i++) {
823             switch(prgCmds[i].cmdID) {
824             case IDM_COPY:
825                 FIXME("CGID_MSHTML: IDM_COPY\n");
826                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
827                 break;
828             case IDM_CUT:
829                 FIXME("CGID_MSHTML: IDM_CUT\n");
830                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
831                 break;
832             case IDM_FONTNAME:
833                 TRACE("CGID_MSHTML: IDM_FONTNAME\n");
834                 prgCmds[i].cmdf = query_edit_status(This, NULL);
835                 break;
836             case IDM_FONTSIZE:
837                 TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
838                 prgCmds[i].cmdf = query_edit_status(This, NULL);
839                 break;
840             case IDM_PASTE:
841                 FIXME("CGID_MSHTML: IDM_PASTE\n");
842                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
843                 break;
844             case IDM_BOLD:
845                 TRACE("CGID_MSHTML: IDM_BOLD\n");
846                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_BOLD);
847                 break;
848             case IDM_FORECOLOR:
849                 TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
850                 prgCmds[i].cmdf = query_edit_status(This, NULL);
851                 break;
852             case IDM_ITALIC:
853                 TRACE("CGID_MSHTML: IDM_ITALIC\n");
854                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_ITALIC);
855                 break;
856             case IDM_JUSTIFYCENTER:
857                 TRACE("CGID_MSHTML: IDM_JUSTIFYCENTER\n");
858                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_CENTER);
859                 break;
860             case IDM_JUSTIFYLEFT:
861                 TRACE("CGID_MSHTML: IDM_JUSTIFYLEFT\n");
862                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_LEFT);
863                 break;
864             case IDM_JUSTIFYRIGHT:
865                 TRACE("CGID_MSHTML: IDM_JUSTIFYRIGHT\n");
866                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_RIGHT);
867                 break;
868             case IDM_UNDERLINE:
869                 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
870                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UNDERLINE);
871                 break;
872             case IDM_HORIZONTALLINE:
873                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
874                 prgCmds[i].cmdf = query_edit_status(This, NULL);
875                 break;
876             case IDM_ORDERLIST:
877                 TRACE("CGID_MSHTML: IDM_ORDERLIST\n");
878                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_OL);
879                 break;
880             case IDM_UNORDERLIST:
881                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
882                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UL);
883                 break;
884             case IDM_INDENT:
885                 TRACE("CGID_MSHTML: IDM_INDENT\n");
886                 prgCmds[i].cmdf = query_edit_status(This, NULL);
887                 break;
888             case IDM_OUTDENT:
889                 TRACE("CGID_MSHTML: IDM_OUTDENT\n");
890                 prgCmds[i].cmdf = query_edit_status(This, NULL);
891                 break;
892             case IDM_BLOCKDIRLTR:
893                 FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
894                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
895                 break;
896             case IDM_BLOCKDIRRTL:
897                 FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
898                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
899                 break;
900             default:
901                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
902                 prgCmds[i].cmdf = 0;
903             }
904         }
905
906         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
907
908         if(pCmdText)
909             FIXME("Set pCmdText\n");
910     }else {
911         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
912         hres = OLECMDERR_E_UNKNOWNGROUP;
913     }
914
915     return hres;
916 }
917
918 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
919         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
920 {
921     HTMLDocument *This = CMDTARGET_THIS(iface);
922
923     if(!pguidCmdGroup) {
924         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
925             WARN("Unsupported cmdID = %d\n", nCmdID);
926             return OLECMDERR_E_NOTSUPPORTED;
927         }
928
929         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
930     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
931         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
932         TRACE("%p %p\n", pvaIn, pvaOut);
933         return OLECMDERR_E_NOTSUPPORTED;
934     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
935         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
936         return OLECMDERR_E_NOTSUPPORTED;
937     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
938         switch(nCmdID) {
939         case IDM_FONTNAME:
940             return exec_fontname(This, pvaIn, pvaOut);
941         case IDM_FONTSIZE:
942             return exec_fontsize(This, pvaIn, pvaOut);
943         case IDM_BOLD:
944             if(pvaIn || pvaOut)
945                 FIXME("unsupported arguments\n");
946             return exec_bold(This);
947         case IDM_FORECOLOR:
948             return exec_forecolor(This, pvaIn, pvaOut);
949         case IDM_ITALIC:
950             if(pvaIn || pvaOut)
951                 FIXME("unsupported arguments\n");
952             return exec_italic(This);
953         case IDM_JUSTIFYCENTER:
954             if(pvaIn || pvaOut)
955                 FIXME("unsupported arguments\n");
956             return exec_justifycenter(This);
957         case IDM_JUSTIFYLEFT:
958             if(pvaIn || pvaOut)
959                 FIXME("unsupported arguments\n");
960             return exec_justifyleft(This);
961         case IDM_JUSTIFYRIGHT:
962             if(pvaIn || pvaOut)
963                 FIXME("unsupported arguments\n");
964             return exec_justifyright(This);
965         case IDM_UNDERLINE:
966             if(pvaIn || pvaOut)
967                 FIXME("unsupported arguments\n");
968             return exec_underline(This);
969         case IDM_BROWSEMODE:
970             if(pvaIn || pvaOut)
971                 FIXME("unsupported arguments\n");
972             return exec_browsemode(This);
973         case IDM_EDITMODE:
974             if(pvaIn || pvaOut)
975                 FIXME("unsupported arguments\n");
976             return exec_editmode(This);
977         case IDM_BASELINEFONT3:
978             return exec_baselinefont3(This);
979         case IDM_HORIZONTALLINE:
980             if(pvaIn || pvaOut)
981                 FIXME("unsupported arguments\n");
982             return exec_horizontalline(This);
983         case IDM_ORDERLIST:
984             if(pvaIn || pvaOut)
985                 FIXME("unsupported arguments\n");
986             return exec_orderlist(This);
987         case IDM_UNORDERLIST:
988             if(pvaIn || pvaOut)
989                 FIXME("unsupported arguments\n");
990             return exec_unorderlist(This);
991         case IDM_INDENT:
992             if(pvaIn || pvaOut)
993                 FIXME("unsupported arguments\n");
994             return exec_indent(This);
995         case IDM_OUTDENT:
996             if(pvaIn || pvaOut)
997                 FIXME("unsupported arguments\n");
998             return exec_outdent(This);
999         default:
1000             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
1001             return OLECMDERR_E_NOTSUPPORTED;
1002         }
1003     }
1004
1005     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
1006     return OLECMDERR_E_UNKNOWNGROUP;
1007 }
1008
1009 #undef CMDTARGET_THIS
1010
1011 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
1012     OleCommandTarget_QueryInterface,
1013     OleCommandTarget_AddRef,
1014     OleCommandTarget_Release,
1015     OleCommandTarget_QueryStatus,
1016     OleCommandTarget_Exec
1017 };
1018
1019 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
1020 {
1021     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
1022 }