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