mshtml: Set default fontname to 'Times New Roman'.
[wine] / dlls / mshtml / editor.c
1 /*
2  * Copyright 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 "mshtmcid.h"
32
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 #include "mshtml_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39
40 #define NSCMD_ALIGN        "cmd_align"
41 #define NSCMD_BOLD         "cmd_bold"
42 #define NSCMD_FONTCOLOR    "cmd_fontColor"
43 #define NSCMD_FONTFACE     "cmd_fontFace"
44 #define NSCMD_INDENT       "cmd_indent"
45 #define NSCMD_INSERTHR     "cmd_insertHR"
46 #define NSCMD_ITALIC       "cmd_italic"
47 #define NSCMD_OL           "cmd_ol"
48 #define NSCMD_OUTDENT      "cmd_outdent"
49 #define NSCMD_UL           "cmd_ul"
50 #define NSCMD_UNDERLINE    "cmd_underline"
51
52 #define NSSTATE_ATTRIBUTE "state_attribute"
53 #define NSSTATE_ALL       "state_all"
54
55 #define NSALIGN_CENTER "center"
56 #define NSALIGN_LEFT   "left"
57 #define NSALIGN_RIGHT  "right"
58
59 #define DOM_VK_LEFT  VK_LEFT
60 #define DOM_VK_UP    VK_UP
61 #define DOM_VK_RIGHT VK_RIGHT
62 #define DOM_VK_DOWN  VK_DOWN
63
64 static const WCHAR wszFont[] = {'f','o','n','t',0};
65 static const WCHAR wszSize[] = {'s','i','z','e',0};
66
67 static void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
68 {
69     nsICommandManager *cmdmgr;
70     nsIInterfaceRequestor *iface_req;
71     nsresult nsres;
72
73     TRACE("(%p)\n", This);
74
75     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
76             &IID_nsIInterfaceRequestor, (void**)&iface_req);
77     if(NS_FAILED(nsres)) {
78         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
79         return;
80     }
81
82     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
83                                                (void**)&cmdmgr);
84     nsIInterfaceRequestor_Release(iface_req);
85     if(NS_FAILED(nsres)) {
86         ERR("Could not get nsICommandManager: %08x\n", nsres);
87         return;
88     }
89
90     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, NULL);
91     if(NS_FAILED(nsres))
92         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
93
94     nsICommandManager_Release(cmdmgr);
95 }
96
97 static nsresult get_ns_command_state(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
98 {
99     nsICommandManager *cmdmgr;
100     nsIInterfaceRequestor *iface_req;
101     nsresult nsres;
102
103     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
104             &IID_nsIInterfaceRequestor, (void**)&iface_req);
105     if(NS_FAILED(nsres)) {
106         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
107         return nsres;
108     }
109
110     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
111                                                (void**)&cmdmgr);
112     nsIInterfaceRequestor_Release(iface_req);
113     if(NS_FAILED(nsres)) {
114         ERR("Could not get nsICommandManager: %08x\n", nsres);
115         return nsres;
116     }
117
118     nsres = nsICommandManager_GetCommandState(cmdmgr, cmd, NULL, nsparam);
119     if(NS_FAILED(nsres))
120         ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd), nsres);
121
122     nsICommandManager_Release(cmdmgr);
123     return nsres;
124 }
125
126 static DWORD query_ns_edit_status(HTMLDocument *This, const char *nscmd)
127 {
128     nsICommandParams *nsparam;
129     PRBool b = FALSE;
130
131     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
132         return OLECMDF_SUPPORTED;
133
134     if(This->nscontainer && nscmd) {
135         nsparam = create_nscommand_params();
136         get_ns_command_state(This->nscontainer, nscmd, nsparam);
137
138         nsICommandParams_GetBooleanValue(nsparam, NSSTATE_ALL, &b);
139
140         nsICommandParams_Release(nsparam);
141     }
142
143     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (b ? OLECMDF_LATCHED : 0);
144 }
145
146 static void set_ns_align(HTMLDocument *This, const char *align_str)
147 {
148     nsICommandParams *nsparam;
149
150     if(!This->nscontainer)
151         return;
152
153     nsparam = create_nscommand_params();
154     nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, align_str);
155
156     do_ns_command(This->nscontainer, NSCMD_ALIGN, nsparam);
157
158     nsICommandParams_Release(nsparam);
159 }
160
161 static DWORD query_align_status(HTMLDocument *This, const char *align_str)
162 {
163     nsICommandParams *nsparam;
164     char *align = NULL;
165
166     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
167         return OLECMDF_SUPPORTED;
168
169     if(This->nscontainer) {
170         nsparam = create_nscommand_params();
171         get_ns_command_state(This->nscontainer, NSCMD_ALIGN, nsparam);
172
173         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &align);
174
175         nsICommandParams_Release(nsparam);
176     }
177
178     return OLECMDF_SUPPORTED | OLECMDF_ENABLED
179         | (align && !strcmp(align_str, align) ? OLECMDF_LATCHED : 0);
180 }
181
182
183 static nsISelection *get_ns_selection(HTMLDocument *This)
184 {
185     nsIDOMWindow *dom_window;
186     nsISelection *nsselection = NULL;
187     nsresult nsres;
188
189     if(!This->nscontainer)
190         return NULL;
191
192     nsres = nsIWebBrowser_GetContentDOMWindow(This->nscontainer->webbrowser, &dom_window);
193     if(NS_FAILED(nsres))
194         return NULL;
195
196     nsIDOMWindow_GetSelection(dom_window, &nsselection);
197     nsIDOMWindow_Release(dom_window);
198
199     return nsselection;
200
201 }
202
203 static void remove_child_attr(nsIDOMElement *elem, LPCWSTR tag, nsAString *attr_str)
204 {
205     PRBool has_children;
206     PRUint32 child_cnt, i;
207     nsIDOMNode *child_node;
208     nsIDOMNodeList *node_list;
209     PRUint16 node_type;
210
211     nsIDOMElement_HasChildNodes(elem, &has_children);
212     if(!has_children)
213         return;
214
215     nsIDOMElement_GetChildNodes(elem, &node_list);
216     nsIDOMNodeList_GetLength(node_list, &child_cnt);
217
218     for(i=0; i<child_cnt; i++) {
219         nsIDOMNodeList_Item(node_list, i, &child_node);
220
221         nsIDOMNode_GetNodeType(child_node, &node_type);
222         if(node_type == ELEMENT_NODE) {
223             nsIDOMElement *child_elem;
224             nsAString tag_str;
225             const PRUnichar *ctag;
226
227             nsIDOMNode_QueryInterface(child_node, &IID_nsIDOMElement, (void**)&child_elem);
228
229             nsAString_Init(&tag_str, NULL);
230             nsIDOMElement_GetTagName(child_elem, &tag_str);
231             nsAString_GetData(&tag_str, &ctag, NULL);
232
233             if(!strcmpiW(ctag, tag))
234                 /* FIXME: remove node if there are no more attributes */
235                 nsIDOMElement_RemoveAttribute(child_elem, attr_str);
236
237             nsAString_Finish(&tag_str);
238
239             remove_child_attr(child_elem, tag, attr_str);
240
241             nsIDOMNode_Release(child_elem);
242         }
243
244         nsIDOMNode_Release(child_node);
245     }
246
247     nsIDOMNodeList_Release(node_list);
248 }
249
250 static void get_font_size(HTMLDocument *This, WCHAR *ret)
251 {
252     nsISelection *nsselection = get_ns_selection(This);
253     nsIDOMElement *elem = NULL;
254     nsIDOMNode *node = NULL, *tmp_node;
255     nsAString tag_str;
256     LPCWSTR tag;
257     PRUint16 node_type;
258     nsresult nsres;
259
260     *ret = 0;
261
262     if(!nsselection)
263         return;
264
265     nsISelection_GetFocusNode(nsselection, &node);
266     nsISelection_Release(nsselection);
267
268     while(node) {
269         nsres = nsIDOMNode_GetNodeType(node, &node_type);
270         if(NS_FAILED(nsres) || node_type == DOCUMENT_NODE)
271             break;
272
273         if(node_type == ELEMENT_NODE) {
274             nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
275
276             nsAString_Init(&tag_str, NULL);
277             nsIDOMElement_GetTagName(elem, &tag_str);
278             nsAString_GetData(&tag_str, &tag, NULL);
279
280             if(!strcmpiW(tag, wszFont)) {
281                 nsAString size_str, val_str;
282                 LPCWSTR val;
283
284                 TRACE("found font tag %p\n", elem);
285
286                 nsAString_Init(&size_str, wszSize);
287                 nsAString_Init(&val_str, NULL);
288
289                 nsIDOMElement_GetAttribute(elem, &size_str, &val_str);
290                 nsAString_GetData(&val_str, &val, NULL);
291
292                 if(*val) {
293                     TRACE("found size %s\n", debugstr_w(val));
294                     strcpyW(ret, val);
295                 }
296
297                 nsAString_Finish(&size_str);
298                 nsAString_Finish(&val_str);
299             }
300
301             nsAString_Finish(&tag_str);
302
303             nsIDOMElement_Release(elem);
304         }
305
306         if(*ret)
307             break;
308
309         tmp_node = node;
310         nsIDOMNode_GetParentNode(node, &node);
311         nsIDOMNode_Release(tmp_node);
312     }
313
314     if(node)
315         nsIDOMNode_Release(node);
316 }
317
318 static void set_font_size(HTMLDocument *This, LPCWSTR size)
319 {
320     nsISelection *nsselection;
321     PRBool collapsed;
322     nsIDOMDocument *nsdoc;
323     nsIDOMElement *elem;
324     nsIDOMRange *range;
325     PRInt32 range_cnt = 0;
326     nsAString font_str;
327     nsAString size_str;
328     nsAString val_str;
329     nsresult nsres;
330
331     nsselection = get_ns_selection(This);
332
333     if(!nsselection)
334         return;
335
336     nsres = nsIWebNavigation_GetDocument(This->nscontainer->navigation, &nsdoc);
337     if(NS_FAILED(nsres))
338         return;
339
340     nsAString_Init(&font_str, wszFont);
341     nsAString_Init(&size_str, wszSize);
342     nsAString_Init(&val_str, size);
343
344     nsISelection_GetRangeCount(nsselection, &range_cnt);
345     if(range_cnt != 1)
346         FIXME("range_cnt %d not supprted\n", range_cnt);
347
348     nsIDOMDocument_CreateElement(nsdoc, &font_str, &elem);
349     nsIDOMElement_SetAttribute(elem, &size_str, &val_str);
350
351     nsISelection_GetRangeAt(nsselection, 0, &range);
352     nsISelection_GetIsCollapsed(nsselection, &collapsed);
353     nsISelection_RemoveAllRanges(nsselection);
354
355     nsIDOMRange_SurroundContents(range, (nsIDOMNode*)elem);
356
357     if(collapsed) {
358         nsISelection_Collapse(nsselection, (nsIDOMNode*)elem, 0);
359     }else {
360         /* Remove all size attrbutes from the range */
361         remove_child_attr(elem, wszFont, &size_str);
362         nsISelection_SelectAllChildren(nsselection, (nsIDOMNode*)elem);
363     }
364
365     nsIDOMRange_Release(range);
366     nsIDOMElement_Release(elem);
367
368     nsAString_Finish(&font_str);
369     nsAString_Finish(&size_str);
370     nsAString_Finish(&val_str);
371
372     nsISelection_Release(nsselection);
373     nsIDOMDocument_Release(nsdoc);
374 }
375
376 static BOOL is_visible_text_node(nsIDOMNode *node)
377 {
378     nsIDOMCharacterData *char_data;
379     nsAString data_str;
380     LPCWSTR data, ptr;
381     PRUint32 len;
382
383     nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
384
385     nsIDOMCharacterData_GetLength(char_data, &len);
386
387     nsAString_Init(&data_str, NULL);
388     nsIDOMCharacterData_GetData(char_data, &data_str);
389     nsAString_GetData(&data_str, &data, NULL);
390
391     if(*data == '\n') {
392         len--;
393         for(ptr=data+1; ptr && isspaceW(*ptr); ptr++)
394             len--;
395     }
396
397     nsAString_Finish(&data_str);
398
399     nsIDOMCharacterData_Release(char_data);
400
401     return len != 0;
402 }
403
404 static nsIDOMNode *get_child_text_node(nsIDOMNode *node, BOOL first)
405 {
406     nsIDOMNode *iter, *iter2;
407
408     if(first)
409         nsIDOMNode_GetFirstChild(node, &iter);
410     else
411         nsIDOMNode_GetLastChild(node, &iter);
412
413     while(iter) {
414         PRUint16 node_type;
415
416         nsIDOMNode_GetNodeType(iter, &node_type);
417         switch(node_type) {
418         case TEXT_NODE:
419             if(is_visible_text_node(iter))
420                 return iter;
421         case ELEMENT_NODE:
422             iter2 = get_child_text_node(iter, first);
423             if(iter2) {
424                 nsIDOMNode_Release(iter);
425                 return iter2;
426             }
427         }
428
429         if(first)
430             nsIDOMNode_GetNextSibling(iter, &iter2);
431         else
432             nsIDOMNode_GetPreviousSibling(iter, &iter2);
433
434         nsIDOMNode_Release(iter);
435         iter = iter2;
436     }
437
438     return NULL;
439 }
440
441 static nsIDOMNode *get_next_text_node(nsIDOMNode *node, BOOL next)
442 {
443     nsIDOMNode *iter, *iter2 = NULL, *parent = NULL;
444     PRUint16 node_type;
445
446     iter = node;
447     nsIDOMNode_AddRef(iter);
448
449     while(1) {
450         if(next)
451             nsIDOMNode_GetNextSibling(iter, &iter2);
452         else
453             nsIDOMNode_GetPreviousSibling(iter, &iter2);
454
455         while(!iter2) {
456             nsIDOMNode_GetParentNode(iter, &parent);
457             nsIDOMNode_Release(iter);
458             if(!parent)
459                 return NULL;
460
461             iter = parent;
462
463             if(next)
464                 nsIDOMNode_GetNextSibling(iter, &iter2);
465             else
466                 nsIDOMNode_GetPreviousSibling(iter, &iter2);
467         }
468
469         nsIDOMNode_Release(iter);
470         iter = iter2;
471
472         nsIDOMNode_GetNodeType(iter, &node_type);
473
474         switch(node_type) {
475         case TEXT_NODE:
476             if(is_visible_text_node(iter))
477                 return iter;
478         case ELEMENT_NODE:
479             iter2 = get_child_text_node(iter, next);
480             if(iter2) {
481                 nsIDOMNode_Release(iter);
482                 return iter2;
483             }
484         }
485     }
486
487     return NULL;
488 }
489
490 static void collapse_end_node(nsISelection *selection, nsIDOMNode *node)
491 {
492     nsIDOMCharacterData *char_data;
493     PRUint32 len;
494
495     nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
496     nsIDOMCharacterData_GetLength(char_data, &len);
497     nsIDOMCharacterData_Release(char_data);
498
499     nsISelection_Collapse(selection, node, len);
500 }
501
502 static void collapse_next_char(HTMLDocument *doc, nsIDOMKeyEvent *event, BOOL next)
503 {
504     nsISelection *selection = get_ns_selection(doc);
505     nsIDOMNode *node;
506     PRBool collapsed, b;
507     PRUint16 node_type;
508     nsIDOMNode *text_node;
509
510     nsIDOMKeyEvent_GetCtrlKey(event, &b);
511     if(b) return;
512
513     nsIDOMKeyEvent_GetShiftKey(event, &b);
514     if(b) return;
515
516     nsISelection_GetIsCollapsed(selection, &collapsed);
517     if(!collapsed)
518         nsISelection_CollapseToEnd(selection);
519
520     nsISelection_GetFocusNode(selection, &node);
521     nsIDOMNode_GetNodeType(node, &node_type);
522
523     if(node_type == TEXT_NODE) {
524         nsIDOMCharacterData *char_data;
525         PRInt32 offset;
526         PRUint32 len;
527
528         nsISelection_GetFocusOffset(selection, &offset);
529
530         nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
531         nsIDOMCharacterData_GetLength(char_data, &len);
532         nsIDOMCharacterData_Release(char_data);
533
534         if(next ? offset != len : offset) {
535             nsISelection_Collapse(selection, node, offset + (next?1:-1));
536             return;
537         }
538     }
539
540     text_node = get_next_text_node(node, next);
541     if(text_node) {
542         if(next)
543             nsISelection_Collapse(selection, text_node, 1);
544         else
545             collapse_end_node(selection, text_node);
546         nsIDOMNode_Release(text_node);
547     }
548
549     nsIDOMNode_Release(node);
550     nsISelection_Release(selection);
551 }
552
553 void handle_edit_event(HTMLDocument *This, nsIDOMEvent *event)
554 {
555     nsIDOMKeyEvent *key_event;
556     PRUint32 code;
557
558     nsIDOMEvent_QueryInterface(event, &IID_nsIDOMKeyEvent, (void**)&key_event);
559
560     nsIDOMKeyEvent_GetKeyCode(key_event, &code);
561
562     switch(code) {
563     case DOM_VK_LEFT:
564         TRACE("left\n");
565         collapse_next_char(This, key_event, FALSE);
566         break;
567     case DOM_VK_RIGHT:
568         TRACE("right\n");
569         collapse_next_char(This, key_event, TRUE);
570     };
571
572     nsIDOMKeyEvent_Release(key_event);
573 }
574
575 static void set_ns_fontname(NSContainer *This, const char *fontname)
576 {
577     nsICommandParams *nsparam = create_nscommand_params();
578
579     nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, fontname);
580     do_ns_command(This, NSCMD_FONTFACE, nsparam);
581     nsICommandParams_Release(nsparam);
582 }
583
584 static HRESULT exec_fontname(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
585 {
586     TRACE("(%p)->(%p %p)\n", This, in, out);
587
588     if(!This->nscontainer)
589         return E_FAIL;
590
591     if(in) {
592         char *stra;
593         DWORD len;
594
595         if(V_VT(in) != VT_BSTR) {
596             FIXME("Unsupported vt=%d\n", V_VT(out));
597             return E_INVALIDARG;
598         }
599
600         TRACE("%s\n", debugstr_w(V_BSTR(in)));
601
602         len = WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, NULL, 0, NULL, NULL);
603         stra = mshtml_alloc(len);
604         WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, stra, -1, NULL, NULL);
605
606         set_ns_fontname(This->nscontainer, stra);
607
608         mshtml_free(stra);
609
610         update_doc(This, UPDATE_UI);
611     }
612
613     if(out) {
614         nsICommandParams *nsparam;
615         LPWSTR strw;
616         char *stra;
617         DWORD len;
618         nsresult nsres;
619
620         nsparam = create_nscommand_params();
621
622         nsres = get_ns_command_state(This->nscontainer, NSCMD_FONTFACE, nsparam);
623         if(NS_FAILED(nsres))
624             return S_OK;
625
626         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &stra);
627         nsICommandParams_Release(nsparam);
628
629         len = MultiByteToWideChar(CP_ACP, 0, stra, -1, NULL, 0);
630         strw = mshtml_alloc(len*sizeof(WCHAR));
631         MultiByteToWideChar(CP_ACP, 0, stra, -1, strw, -1);
632         nsfree(stra);
633
634         V_VT(out) = VT_BSTR;
635         V_BSTR(out) = SysAllocString(strw);
636         mshtml_free(strw);
637     }
638
639     return S_OK;
640 }
641
642 static HRESULT exec_forecolor(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
643 {
644     TRACE("(%p)->(%p %p)\n", This, in, out);
645
646     if(in) {
647         if(V_VT(in) == VT_I4) {
648             nsICommandParams *nsparam = create_nscommand_params();
649             char color_str[10];
650
651             sprintf(color_str, "#%02x%02x%02x",
652                     V_I4(in)&0xff, (V_I4(in)>>8)&0xff, (V_I4(in)>>16)&0xff);
653
654             nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, color_str);
655             do_ns_command(This->nscontainer, NSCMD_FONTCOLOR, nsparam);
656
657             nsICommandParams_Release(nsparam);
658         }else {
659             FIXME("unsupported in vt=%d\n", V_VT(in));
660         }
661     }
662
663     if(out) {
664         FIXME("unsupported out\n");
665         return E_NOTIMPL;
666     }
667
668     return S_OK;
669 }
670
671 static HRESULT exec_fontsize(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
672 {
673     TRACE("(%p)->(%p %p)\n", This, in, out);
674
675     if(out) {
676         WCHAR val[10] = {0};
677
678         switch(V_VT(out)) {
679         case VT_I4:
680             get_font_size(This, val);
681             V_I4(out) = strtolW(val, NULL, 10);
682             break;
683         case VT_BSTR:
684             get_font_size(This, val);
685             V_BSTR(out) = SysAllocString(val);
686             break;
687         default:
688             FIXME("unsupported vt %d\n", V_VT(out));
689         }
690     }
691
692     if(in) {
693         switch(V_VT(in)) {
694         case VT_I4: {
695             WCHAR size[10];
696             static const WCHAR format[] = {'%','d',0};
697             wsprintfW(size, format, V_I4(in));
698             set_font_size(This, size);
699             break;
700         }
701         case VT_BSTR:
702             set_font_size(This, V_BSTR(in));
703             break;
704         default:
705             FIXME("unsupported vt %d\n", V_VT(in));
706         }
707     }
708
709     return S_OK;
710 }
711
712 static HRESULT exec_bold(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
713 {
714     TRACE("(%p)\n", This);
715
716     if(in || out)
717         FIXME("unsupported args\n");
718
719     if(This->nscontainer)
720         do_ns_command(This->nscontainer, NSCMD_BOLD, NULL);
721
722     return S_OK;
723 }
724
725 static HRESULT exec_italic(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
726 {
727     TRACE("(%p)\n", This);
728
729     if(in || out)
730         FIXME("unsupported args\n");
731
732     if(This->nscontainer)
733         do_ns_command(This->nscontainer, NSCMD_ITALIC, NULL);
734
735     return S_OK;
736 }
737
738 static HRESULT query_justify(HTMLDocument *This, OLECMD *cmd)
739 {
740     switch(cmd->cmdID) {
741     case IDM_JUSTIFYCENTER:
742         TRACE("(%p) IDM_JUSTIFYCENTER\n", This);
743         cmd->cmdf = query_align_status(This, NSALIGN_CENTER);
744         break;
745     case IDM_JUSTIFYLEFT:
746         TRACE("(%p) IDM_JUSTIFYLEFT\n", This);
747         /* FIXME: We should set OLECMDF_LATCHED only if it's set explicitly. */
748         if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
749             cmd->cmdf = OLECMDF_SUPPORTED;
750         else
751             cmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
752         break;
753     case IDM_JUSTIFYRIGHT:
754         TRACE("(%p) IDM_JUSTIFYRIGHT\n", This);
755         cmd->cmdf = query_align_status(This, NSALIGN_RIGHT);
756         break;
757     }
758
759     return S_OK;
760 }
761
762 static HRESULT exec_justifycenter(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
763 {
764     TRACE("(%p)\n", This);
765
766     if(in || out)
767         FIXME("unsupported args\n");
768
769     set_ns_align(This, NSALIGN_CENTER);
770     return S_OK;
771 }
772
773 static HRESULT exec_justifyleft(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
774 {
775     TRACE("(%p)\n", This);
776
777     if(in || out)
778         FIXME("unsupported args\n");
779
780     set_ns_align(This, NSALIGN_LEFT);
781     return S_OK;
782 }
783
784 static HRESULT exec_justifyright(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
785 {
786     TRACE("(%p)\n", This);
787     set_ns_align(This, NSALIGN_RIGHT);
788     return S_OK;
789 }
790
791 static HRESULT exec_underline(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
792 {
793     TRACE("(%p)\n", This);
794
795     if(in || out)
796         FIXME("unsupported args\n");
797
798     if(This->nscontainer)
799         do_ns_command(This->nscontainer, NSCMD_UNDERLINE, NULL);
800
801     return S_OK;
802 }
803
804 static HRESULT exec_horizontalline(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
805 {
806     TRACE("(%p)\n", This);
807
808     if(in || out)
809         FIXME("unsupported args\n");
810
811     if(This->nscontainer)
812         do_ns_command(This->nscontainer, NSCMD_INSERTHR, NULL);
813
814     return S_OK;
815 }
816
817 static HRESULT exec_orderlist(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
818 {
819     TRACE("(%p)\n", This);
820
821     if(in || out)
822         FIXME("unsupported args\n");
823
824     if(This->nscontainer)
825         do_ns_command(This->nscontainer, NSCMD_OL, NULL);
826
827     return S_OK;
828 }
829
830 static HRESULT exec_unorderlist(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
831 {
832     TRACE("(%p)\n", This);
833
834     if(in || out)
835         FIXME("unsupported args\n");
836
837     if(This->nscontainer)
838         do_ns_command(This->nscontainer, NSCMD_UL, NULL);
839
840     return S_OK;
841 }
842
843 static HRESULT exec_indent(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
844 {
845     TRACE("(%p)\n", This);
846
847     if(in || out)
848         FIXME("unsupported args\n");
849
850     if(This->nscontainer)
851         do_ns_command(This->nscontainer, NSCMD_INDENT, NULL);
852
853     return S_OK;
854 }
855
856 static HRESULT exec_outdent(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
857 {
858     TRACE("(%p)\n", This);
859
860     if(in || out)
861         FIXME("unsupported args\n");
862
863     if(This->nscontainer)
864         do_ns_command(This->nscontainer, NSCMD_OUTDENT, NULL);
865
866     return S_OK;
867 }
868
869 static HRESULT exec_composesettings(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
870 {
871     if(out || !in || V_VT(in) != VT_BSTR) {
872         WARN("invalid arg\n");
873         return E_INVALIDARG;
874     }
875
876     FIXME("%s\n", debugstr_w(V_BSTR(in)));
877
878     return S_OK;
879 }
880
881 static HRESULT query_edit_status(HTMLDocument *This, OLECMD *cmd)
882 {
883     switch(cmd->cmdID) {
884     case IDM_FONTNAME:
885         TRACE("CGID_MSHTML: IDM_FONTNAME\n");
886         cmd->cmdf = query_ns_edit_status(This, NULL);
887         break;
888     case IDM_FONTSIZE:
889         TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
890         cmd->cmdf = query_ns_edit_status(This, NULL);
891         break;
892     case IDM_BOLD:
893         TRACE("CGID_MSHTML: IDM_BOLD\n");
894         cmd->cmdf = query_ns_edit_status(This, NSCMD_BOLD);
895         break;
896     case IDM_FORECOLOR:
897         TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
898         cmd->cmdf = query_ns_edit_status(This, NULL);
899         break;
900     case IDM_ITALIC:
901         TRACE("CGID_MSHTML: IDM_ITALIC\n");
902         cmd->cmdf = query_ns_edit_status(This, NSCMD_ITALIC);
903         break;
904     case IDM_UNDERLINE:
905         TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
906         cmd->cmdf = query_ns_edit_status(This, NSCMD_UNDERLINE);
907         break;
908     case IDM_HORIZONTALLINE:
909         TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
910         cmd->cmdf = query_ns_edit_status(This, NULL);
911         break;
912     case IDM_ORDERLIST:
913         TRACE("CGID_MSHTML: IDM_ORDERLIST\n");
914         cmd->cmdf = query_ns_edit_status(This, NSCMD_OL);
915         break;
916     case IDM_UNORDERLIST:
917         TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
918         cmd->cmdf = query_ns_edit_status(This, NSCMD_UL);
919         break;
920     case IDM_INDENT:
921         TRACE("CGID_MSHTML: IDM_INDENT\n");
922         cmd->cmdf = query_ns_edit_status(This, NULL);
923         break;
924     case IDM_OUTDENT:
925         TRACE("CGID_MSHTML: IDM_OUTDENT\n");
926         cmd->cmdf = query_ns_edit_status(This, NULL);
927         break;
928     }
929
930     return S_OK;
931 }
932
933 const cmdtable_t editmode_cmds[] = {
934     {IDM_FONTNAME,        query_edit_status,    exec_fontname},
935     {IDM_FONTSIZE,        query_edit_status,    exec_fontsize},
936     {IDM_FORECOLOR,       query_edit_status,    exec_forecolor},
937     {IDM_BOLD,            query_edit_status,    exec_bold},
938     {IDM_ITALIC,          query_edit_status,    exec_italic},
939     {IDM_JUSTIFYCENTER,   query_justify,        exec_justifycenter},
940     {IDM_JUSTIFYRIGHT,    query_justify,        exec_justifyright},
941     {IDM_JUSTIFYLEFT,     query_justify,        exec_justifyleft},
942     {IDM_UNDERLINE,       query_edit_status,    exec_underline},
943     {IDM_HORIZONTALLINE,  query_edit_status,    exec_horizontalline},
944     {IDM_ORDERLIST,       query_edit_status,    exec_orderlist},
945     {IDM_UNORDERLIST,     query_edit_status,    exec_unorderlist},
946     {IDM_INDENT,          query_edit_status,    exec_indent},
947     {IDM_OUTDENT,         query_edit_status,    exec_outdent},
948     {IDM_COMPOSESETTINGS, NULL,                 exec_composesettings},
949     {0,NULL,NULL}
950 };
951
952 void init_editor(HTMLDocument *This)
953 {
954     if(!This->nscontainer)
955         return;
956
957     set_ns_fontname(This->nscontainer, "Times New Roman");
958 }