LayoutTests:
[WebKit-https.git] / WebCore / editing / JSEditor.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSEditor.h"
28
29 #include "CSSPropertyNames.h"
30 #include "CreateLinkCommand.h"
31 #include "Document.h"
32 #include "DocumentFragment.h"
33 #include "Editor.h"
34 #include "FormatBlockCommand.h"
35 #include "Frame.h"
36 #include "HTMLNames.h"
37 #include "HTMLImageElement.h"
38 #include "IndentOutdentCommand.h"
39 #include "InsertListCommand.h"
40 #include "ReplaceSelectionCommand.h"
41 #include "SelectionController.h"
42 #include "TypingCommand.h"
43 #include "UnlinkCommand.h"
44 #include "htmlediting.h"
45 #include "markup.h"
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50
51 class Document;
52
53 namespace {
54
55 bool supportsPasteCommand = false;
56
57 struct CommandImp {
58     bool (*execFn)(Frame*, bool userInterface, const String& value);
59     bool (*enabledFn)(Frame*);
60     Frame::TriState (*stateFn)(Frame*);
61     String (*valueFn)(Frame*);
62 };
63
64 typedef HashMap<StringImpl*, const CommandImp*, CaseInsensitiveHash<StringImpl*> > CommandMap;
65
66 CommandMap* createCommandDictionary();
67
68 const CommandImp* commandImp(const String& command)
69 {
70     static CommandMap* commandDictionary = createCommandDictionary();
71     return commandDictionary->get(command.impl());
72 }
73
74 } // anonymous namespace
75
76 bool JSEditor::execCommand(const String& command, bool userInterface, const String& value)
77 {
78     const CommandImp* cmd = commandImp(command);
79     if (!cmd)
80         return false;
81     Frame* frame = m_document->frame();
82     if (!frame)
83         return false;
84     m_document->updateLayoutIgnorePendingStylesheets();
85     return cmd->enabledFn(frame) && cmd->execFn(frame, userInterface, value);
86 }
87
88 bool JSEditor::queryCommandEnabled(const String& command)
89 {
90     const CommandImp* cmd = commandImp(command);
91     if (!cmd)
92         return false;
93     Frame* frame = m_document->frame();
94     if (!frame)
95         return false;
96     m_document->updateLayoutIgnorePendingStylesheets();
97     return cmd->enabledFn(frame);
98 }
99
100 bool JSEditor::queryCommandIndeterm(const String& command)
101 {
102     const CommandImp* cmd = commandImp(command);
103     if (!cmd)
104         return false;
105     Frame* frame = m_document->frame();
106     if (!frame)
107         return false;
108     m_document->updateLayoutIgnorePendingStylesheets();
109     return cmd->stateFn(frame) == Frame::mixedTriState;
110 }
111
112 bool JSEditor::queryCommandState(const String& command)
113 {
114     const CommandImp* cmd = commandImp(command);
115     if (!cmd)
116         return false;
117     Frame* frame = m_document->frame();
118     if (!frame)
119         return false;
120     m_document->updateLayoutIgnorePendingStylesheets();
121     return cmd->stateFn(frame) != Frame::falseTriState;
122 }
123
124 bool JSEditor::queryCommandSupported(const String& command)
125 {
126     if (!supportsPasteCommand && command.lower() == "paste")
127         return false;
128     return commandImp(command) != 0;
129 }
130
131 String JSEditor::queryCommandValue(const String& command)
132 {
133     const CommandImp* cmd = commandImp(command);
134     if (!cmd)
135         return String();
136     Frame* frame = m_document->frame();
137     if (!frame)
138         return String();
139     m_document->updateLayoutIgnorePendingStylesheets();
140     return cmd->valueFn(frame);
141 }
142
143 void JSEditor::setSupportsPasteCommand(bool flag)
144 {
145     supportsPasteCommand = flag;
146 }
147
148 // =============================================================================================
149
150 // Private stuff, all inside an anonymous namespace.
151
152 namespace {
153
154 bool execStyleChange(Frame* frame, int propertyID, const String& propertyValue)
155 {
156     RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
157     style->setProperty(propertyID, propertyValue);
158     frame->applyStyle(style.get());
159     return true;
160 }
161
162 bool execStyleChange(Frame* frame, int propertyID, const char* propertyValue)
163 {
164     return execStyleChange(frame, propertyID, String(propertyValue));
165 }
166
167 Frame::TriState stateStyle(Frame* frame, int propertyID, const char* desiredValue)
168 {
169     RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
170     style->setProperty(propertyID, desiredValue);
171     return frame->selectionHasStyle(style.get());
172 }
173
174 bool selectionStartHasStyle(Frame* frame, int propertyID, const char* desiredValue)
175 {
176     RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
177     style->setProperty(propertyID, desiredValue);
178     return frame->selectionStartHasStyle(style.get());
179 }
180
181 String valueStyle(Frame* frame, int propertyID)
182 {
183     return frame->selectionStartStylePropertyValue(propertyID);
184 }
185
186 // =============================================================================================
187 //
188 // execCommand implementations
189 //
190
191 bool execBackColor(Frame* frame, bool, const String& value)
192 {
193     return execStyleChange(frame, CSS_PROP_BACKGROUND_COLOR, value);
194 }
195
196 bool execBold(Frame* frame, bool, const String&)
197 {
198     bool isBold = selectionStartHasStyle(frame, CSS_PROP_FONT_WEIGHT, "bold");
199     return execStyleChange(frame, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
200 }
201
202 bool execCopy(Frame* frame, bool, const String&)
203 {
204     frame->copyToPasteboard();
205     return true;
206 }
207
208 bool execCreateLink(Frame* frame, bool userInterface, const String& value)
209 {
210     // FIXME: If userInterface is true, we should display a dialog box to let the user enter a url.
211     if (userInterface)
212         LOG_ERROR("A dialog box for link creation is not yet implemented.\n");
213     
214     if (value.isEmpty())
215         return false;
216     
217     applyCommand(new CreateLinkCommand(frame->document(), value));
218     return true;
219 }
220
221 bool execCut(Frame* frame, bool, const String&)
222 {
223     frame->cutToPasteboard();
224     return true;
225 }
226
227 bool execDelete(Frame* frame, bool, const String&)
228 {
229     TypingCommand::deleteKeyPressed(frame->document(), frame->selectionGranularity() == WordGranularity);
230     return true;
231 }
232
233 // FIXME: Come up with a way to send more parameters to execCommand so that we can support all of the features of Frame::findString.
234 bool execFindString(Frame* frame, bool, const String& value)
235 {
236     return frame->findString(value, true, false, true);
237 }
238
239 bool execForwardDelete(Frame* frame, bool, const String&)
240 {
241     TypingCommand::forwardDeleteKeyPressed(frame->document());
242     return true;
243 }
244
245 bool execFontName(Frame* frame, bool, const String& value)
246 {
247     return execStyleChange(frame, CSS_PROP_FONT_FAMILY, value);
248 }
249
250 bool execFontSize(Frame* frame, bool, const String& value)
251 {
252     return execStyleChange(frame, CSS_PROP_FONT_SIZE, value);
253 }
254
255 bool execFontSizeDelta(Frame* frame, bool, const String& value)
256 {
257     return execStyleChange(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA, value);
258 }
259
260 bool execForeColor(Frame* frame, bool, const String& value)
261 {
262     return execStyleChange(frame, CSS_PROP_COLOR, value);
263 }
264
265 bool execFormatBlock(Frame* frame, bool, const String& value)
266 {
267     String tagName = value.lower();
268     if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>')
269         tagName = tagName.substring(1, tagName.length() - 2);
270     if (!validBlockTag(tagName))
271         return false;
272     applyCommand(new FormatBlockCommand(frame->document(), tagName));
273     return true;
274 }
275
276 bool execInsertHorizontalRule(Frame* frame, bool userInterface, const String& value)
277 {
278     RefPtr<HTMLElement> hr = new HTMLElement(hrTag, frame->document());
279     hr->setId(value);
280     RefPtr<DocumentFragment> fragment = new DocumentFragment(frame->document());
281     ExceptionCode ec = 0;
282     fragment->appendChild(hr, ec);
283     if (ec)
284         return false;
285     
286     applyCommand(new ReplaceSelectionCommand(frame->document(), fragment.release(),
287         false, false, false, true, EditActionUnspecified));
288     return true;
289 }
290
291 bool execInsertHTML(Frame* frame, bool userInterface, const String& value)
292 {
293     Document* document = frame->document();
294     applyCommand(new ReplaceSelectionCommand(frame->document(), createFragmentFromMarkup(document, value, ""), false));
295     return true;
296 }
297
298 bool execInsertImage(Frame* frame, bool userInterface, const String& value)
299 {
300     // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
301     if (userInterface)
302         LOG_ERROR("A dialog box for image insertion is not yet implemented.\n");
303     
304     RefPtr<HTMLImageElement> image = new HTMLImageElement(imgTag, frame->document());
305     image->setSrc(value);
306     RefPtr<DocumentFragment> fragment = new DocumentFragment(frame->document());
307     ExceptionCode ec = 0;
308     fragment->appendChild(image, ec);
309     if (ec)
310         return false;
311     
312     applyCommand(new ReplaceSelectionCommand(frame->document(), fragment.release(), false));
313     return true;
314 }
315
316 bool execIndent(Frame* frame, bool, const String&)
317 {
318     applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Indent));
319     return true;
320 }
321
322 bool execInsertLineBreak(Frame* frame, bool, const String&)
323 {
324     TypingCommand::insertLineBreak(frame->document());
325     return true;
326 }
327
328 bool execInsertParagraph(Frame* frame, bool, const String&)
329 {
330     TypingCommand::insertParagraphSeparator(frame->document());
331     return true;
332 }
333
334 bool execInsertNewlineInQuotedContent(Frame* frame, bool, const String&)
335 {
336     TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document());
337     return true;
338 }
339
340 bool execInsertText(Frame* frame, bool, const String& value)
341 {
342     TypingCommand::insertText(frame->document(), value);
343     return true;
344 }
345
346 bool execInsertUnorderedList(Frame* frame, bool, const String& value)
347 {
348     applyCommand(new InsertListCommand(frame->document(), InsertListCommand::UnorderedList, value));
349     return true;
350 }
351
352 bool execInsertOrderedList(Frame* frame, bool, const String& value)
353 {
354     applyCommand(new InsertListCommand(frame->document(), InsertListCommand::OrderedList, value));
355     return true;
356 }
357
358 bool execItalic(Frame* frame, bool, const String&)
359 {
360     bool isItalic = selectionStartHasStyle(frame, CSS_PROP_FONT_STYLE, "italic");
361     return execStyleChange(frame, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
362 }
363
364 bool execJustifyCenter(Frame* frame, bool, const String&)
365 {
366     return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "center");
367 }
368
369 bool execJustifyFull(Frame* frame, bool, const String&)
370 {
371     return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "justify");
372 }
373
374 bool execJustifyLeft(Frame* frame, bool, const String&)
375 {
376     return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "left");
377 }
378
379 bool execJustifyRight(Frame* frame, bool, const String&)
380 {
381     return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "right");
382 }
383
384 bool execOutdent(Frame* frame, bool, const String&)
385 {
386     applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Outdent));
387     return true;
388 }
389
390 bool execPaste(Frame* frame, bool, const String&)
391 {
392     frame->pasteFromPasteboard();
393     return true;
394 }
395
396 bool execPasteAndMatchStyle(Frame* frame, bool, const String&)
397 {
398     frame->pasteAndMatchStyle();
399     return true;
400 }
401
402 bool execPrint(Frame* frame, bool, const String&)
403 {
404     frame->print();
405     return true;
406 }
407
408 bool execRedo(Frame* frame, bool, const String&)
409 {
410     frame->redo();
411     return true;
412 }
413
414 bool execRemoveFormat(Frame* frame, bool userInterface, const String& value)
415 {
416     applyCommand(new ReplaceSelectionCommand(frame->document(),
417         createFragmentFromText(frame->selectionController()->toRange().get(), frame->selectionController()->toString()),
418         false, false, false, true, EditActionUnspecified));
419     return true;
420 }
421
422 bool execSelectAll(Frame* frame, bool, const String&)
423 {
424     frame->selectAll();
425     return true;
426 }
427
428 bool execStrikethrough(Frame* frame, bool, const String&)
429 {
430     bool isStrikethrough = selectionStartHasStyle(frame,  CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "line-through");
431     return execStyleChange(frame, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, isStrikethrough ? "none" : "line-through");
432 }
433
434 bool execSubscript(Frame* frame, bool, const String&)
435 {
436     return execStyleChange(frame,  CSS_PROP_VERTICAL_ALIGN, "sub");
437 }
438
439 bool execSuperscript(Frame* frame, bool, const String&)
440 {
441     return execStyleChange(frame,  CSS_PROP_VERTICAL_ALIGN, "super");
442 }
443
444 bool execTranspose(Frame* frame, bool, const String&)
445 {
446     frame->transpose();
447     return true;
448 }
449
450 bool execUnderline(Frame* frame, bool, const String&)
451 {
452     bool isUnderlined = selectionStartHasStyle(frame,  CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline");
453     return execStyleChange(frame,  CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, isUnderlined ? "none" : "underline");
454 }
455
456 bool execUndo(Frame* frame, bool, const String&)
457 {
458     frame->undo();
459     return true;
460 }
461
462 bool execUnlink(Frame* frame, bool, const String&)
463 {
464     applyCommand(new UnlinkCommand(frame->document()));
465     return true;
466 }
467
468 bool execUnselect(Frame* frame, bool, const String&)
469 {
470     frame->selectionController()->clear();
471     return true;
472 }
473
474 // =============================================================================================
475 //
476 // queryCommandEnabled implementations
477 //
478 // It's a bit difficult to get a clear notion of the difference between
479 // "supported" and "enabled" from reading the Microsoft documentation, but
480 // what little I could glean from that seems to make some sense.
481 //     Supported = The command is supported by this object.
482 //     Enabled =   The command is available and enabled.
483
484 bool enabled(Frame*)
485 {
486     return true;
487 }
488
489 bool enabledAnyCaret(Frame* frame)
490 {
491     return frame->selectionController()->isCaret() && frame->selectionController()->isContentEditable();
492 }
493
494 bool enabledAnySelection(Frame* frame)
495 {
496     return frame->selectionController()->isCaretOrRange();
497 }
498
499 bool enabledAnyEditableSelection(Frame* frame)
500 {
501     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentEditable();
502 }
503
504 bool enabledAnyRichlyEditableSelection(Frame* frame)
505 {
506     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
507 }
508
509 bool enabledPaste(Frame* frame)
510 {
511     return supportsPasteCommand && frame->canPaste();
512 }
513
514 bool enabledPasteAndMatchStyle(Frame* frame)
515 {
516     return supportsPasteCommand && frame->canPaste();
517 }
518
519 bool enabledAnyRangeSelection(Frame* frame)
520 {
521     return frame->selectionController()->isRange();
522 }
523
524 bool enabledAnyEditableRangeSelection(Frame* frame)
525 {
526     return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
527 }
528
529 bool enabledAnyRichlyEditableRangeSelection(Frame* frame)
530 {
531     return frame->selectionController()->isRange() && frame->selectionController()->isContentRichlyEditable();
532 }
533
534 bool enabledRedo(Frame* frame)
535 {
536     return frame->canRedo();
537 }
538
539 bool enabledUndo(Frame* frame)
540 {
541     return frame->canUndo();
542 }
543
544 // =============================================================================================
545 //
546 // queryCommandIndeterm/State implementations
547 //
548 // It's a bit difficult to get a clear notion of what these methods are supposed
549 // to do from reading the Microsoft documentation, but my current guess is this:
550 //
551 //     queryCommandState and queryCommandIndeterm work in concert to return
552 //     the two bits of information that are needed to tell, for instance,
553 //     if the text of a selection is bold. The answer can be "yes", "no", or
554 //     "partially".
555 //
556 // If this is so, then queryCommandState should return "yes" in the case where
557 // all the text is bold and "no" for non-bold or partially-bold text.
558 // Then, queryCommandIndeterm should return "no" in the case where
559 // all the text is either all bold or not-bold and and "yes" for partially-bold text.
560
561 Frame::TriState stateNone(Frame*)
562 {
563     return Frame::falseTriState;
564 }
565
566 Frame::TriState stateBold(Frame* frame)
567 {
568     return stateStyle(frame, CSS_PROP_FONT_WEIGHT, "bold");
569 }
570
571 Frame::TriState stateItalic(Frame* frame)
572 {
573     return stateStyle(frame, CSS_PROP_FONT_STYLE, "italic");
574 }
575
576 Frame::TriState stateUnorderedList(Frame* frame)
577 {
578     return frame->editor()->selectionUnorderedListState();
579 }
580
581 Frame::TriState stateOrderedList(Frame* frame)
582 {
583     return frame->editor()->selectionOrderedListState();
584 }
585
586 Frame::TriState stateStrikethrough(Frame* frame)
587 {
588     return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "line-through");
589 }
590
591 Frame::TriState stateSubscript(Frame* frame)
592 {
593     return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "sub");
594 }
595
596 Frame::TriState stateSuperscript(Frame* frame)
597 {
598     return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "super");
599 }
600
601 Frame::TriState stateUnderline(Frame* frame)
602 {
603     return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "underline");
604 }
605
606 // =============================================================================================
607 //
608 // queryCommandValue implementations
609 //
610
611 String valueNull(Frame*)
612 {
613     return String();
614 }
615
616 String valueBackColor(Frame* frame)
617 {
618     return valueStyle(frame, CSS_PROP_BACKGROUND_COLOR);
619 }
620
621 String valueFontName(Frame* frame)
622 {
623     return valueStyle(frame, CSS_PROP_FONT_FAMILY);
624 }
625
626 String valueFontSize(Frame* frame)
627 {
628     return valueStyle(frame, CSS_PROP_FONT_SIZE);
629 }
630
631 String valueFontSizeDelta(Frame* frame)
632 {
633     return valueStyle(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA);
634 }
635
636 String valueForeColor(Frame* frame)
637 {
638     return valueStyle(frame, CSS_PROP_COLOR);
639 }
640
641 // =============================================================================================
642
643 CommandMap* createCommandDictionary()
644 {
645     struct EditorCommand { const char* name; CommandImp imp; };
646
647     static const EditorCommand commands[] = {
648
649         { "BackColor", { execBackColor, enabledAnyRichlyEditableRangeSelection, stateNone, valueBackColor } },
650         { "Bold", { execBold, enabledAnyRichlyEditableSelection, stateBold, valueNull } },
651         { "Copy", { execCopy, enabledAnyRangeSelection, stateNone, valueNull } },
652         { "CreateLink", { execCreateLink, enabledAnyRichlyEditableRangeSelection, stateNone, valueNull } },
653         { "Cut", { execCut, enabledAnyEditableRangeSelection, stateNone, valueNull } },
654         { "Delete", { execDelete, enabledAnyEditableSelection, stateNone, valueNull } },
655         { "FindString", { execFindString, enabled, stateNone, valueNull } },
656         { "FontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
657         { "FontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
658         { "FontSizeDelta", { execFontSizeDelta, enabledAnySelection, stateNone, valueFontSizeDelta } },
659         { "ForeColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
660         { "FormatBlock", { execFormatBlock, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
661         { "ForwardDelete", { execForwardDelete, enabledAnyEditableSelection, stateNone, valueNull } },
662         { "HiliteColor", { execBackColor, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
663         { "Indent", { execIndent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
664         { "InsertHorizontalRule", { execInsertHorizontalRule, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
665         { "InsertHTML", { execInsertHTML, enabledAnyEditableSelection, stateNone, valueNull } },
666         { "InsertImage", { execInsertImage, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
667         { "InsertLineBreak", { execInsertLineBreak, enabledAnyEditableSelection, stateNone, valueNull } },
668         { "InsertOrderedList", { execInsertOrderedList, enabledAnyRichlyEditableSelection, stateOrderedList, valueNull } },
669         { "InsertParagraph", { execInsertParagraph, enabledAnyEditableSelection, stateNone, valueNull } },
670         { "InsertNewlineInQuotedContent", { execInsertNewlineInQuotedContent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
671         { "InsertText", { execInsertText, enabledAnyEditableSelection, stateNone, valueNull } },
672         { "InsertUnorderedList", { execInsertUnorderedList, enabledAnyRichlyEditableSelection, stateUnorderedList, valueNull } },
673         { "Italic", { execItalic, enabledAnyRichlyEditableSelection, stateItalic, valueNull } },
674         { "JustifyCenter", { execJustifyCenter, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
675         { "JustifyFull", { execJustifyFull, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
676         { "JustifyLeft", { execJustifyLeft, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
677         { "JustifyNone", { execJustifyLeft, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
678         { "JustifyRight", { execJustifyRight, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
679         { "Outdent", { execOutdent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
680         { "Paste", { execPaste, enabledPaste, stateNone, valueNull } },
681         { "PasteAndMatchStyle", { execPasteAndMatchStyle, enabledPasteAndMatchStyle, stateNone, valueNull } },
682         { "Print", { execPrint, enabled, stateNone, valueNull } },
683         { "Redo", { execRedo, enabledRedo, stateNone, valueNull } },
684         { "RemoveFormat", { execRemoveFormat, enabledAnyEditableRangeSelection, stateNone, valueNull } },
685         { "SelectAll", { execSelectAll, enabled, stateNone, valueNull } },
686         { "Strikethrough", { execStrikethrough, enabledAnyRichlyEditableSelection, stateStrikethrough, valueNull } },
687         { "Subscript", { execSubscript, enabledAnyRichlyEditableSelection, stateSubscript, valueNull } },
688         { "Superscript", { execSuperscript, enabledAnyRichlyEditableSelection, stateSuperscript, valueNull } },
689         { "Transpose", { execTranspose, enabledAnyCaret, stateNone, valueNull } },
690         { "Underline", { execUnderline, enabledAnyRichlyEditableSelection, stateUnderline, valueNull } },
691         { "Undo", { execUndo, enabledUndo, stateNone, valueNull } },
692         { "Unlink", { execUnlink, enabledAnyRichlyEditableRangeSelection, stateNone, valueNull } },
693         { "Unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
694
695         //
696         // The "unsupported" commands are listed here since they appear in the Microsoft
697         // documentation used as the basis for the list.
698         //
699
700         // 2D-Position (not supported)
701         // AbsolutePosition (not supported)
702         // BlockDirLTR (not supported)
703         // BlockDirRTL (not supported)
704         // BrowseMode (not supported)
705         // ClearAuthenticationCache (not supported)
706         // CreateBookmark (not supported)
707         // DirLTR (not supported)
708         // DirRTL (not supported)
709         // EditMode (not supported)
710         // InlineDirLTR (not supported)
711         // InlineDirRTL (not supported)
712         // InsertButton (not supported)
713         // InsertFieldSet (not supported)
714         // InsertIFrame (not supported)
715         // InsertInputButton (not supported)
716         // InsertInputCheckbox (not supported)
717         // InsertInputFileUpload (not supported)
718         // InsertInputHidden (not supported)
719         // InsertInputImage (not supported)
720         // InsertInputPassword (not supported)
721         // InsertInputRadio (not supported)
722         // InsertInputReset (not supported)
723         // InsertInputSubmit (not supported)
724         // InsertInputText (not supported)
725         // InsertMarquee (not supported)
726         // InsertSelectDropDown (not supported)
727         // InsertSelectListBox (not supported)
728         // InsertTextArea (not supported)
729         // LiveResize (not supported)
730         // MultipleSelection (not supported)
731         // Open (not supported)
732         // Overwrite (not supported)
733         // PlayImage (not supported)
734         // Refresh (not supported)
735         // RemoveParaFormat (not supported)
736         // SaveAs (not supported)
737         // SizeToControl (not supported)
738         // SizeToControlHeight (not supported)
739         // SizeToControlWidth (not supported)
740         // Stop (not supported)
741         // StopImage (not supported)
742         // Unbookmark (not supported)
743     };
744
745     CommandMap* commandMap = new CommandMap;
746
747     const int numCommands = sizeof(commands) / sizeof(commands[0]);
748     for (int i = 0; i < numCommands; ++i) {
749         StringImpl *name = new StringImpl(commands[i].name);
750         name->ref();
751         commandMap->set(name, &commands[i].imp);
752     }
753 #ifndef NDEBUG
754     supportsPasteCommand = true;
755 #endif
756     return commandMap;
757 }
758
759 } // anonymous namespace
760
761 } // namespace WebCore