2 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "CSSPropertyNames.h"
30 #include "CreateLinkCommand.h"
32 #include "DocumentFragment.h"
34 #include "FormatBlockCommand.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"
49 using namespace HTMLNames;
55 bool supportsPasteCommand = false;
58 bool (*execFn)(Frame*, bool userInterface, const String& value);
59 bool (*enabledFn)(Frame*);
60 Frame::TriState (*stateFn)(Frame*);
61 String (*valueFn)(Frame*);
64 typedef HashMap<StringImpl*, const CommandImp*, CaseInsensitiveHash<StringImpl*> > CommandMap;
66 CommandMap* createCommandDictionary();
68 const CommandImp* commandImp(const String& command)
70 static CommandMap* commandDictionary = createCommandDictionary();
71 return commandDictionary->get(command.impl());
74 } // anonymous namespace
76 bool JSEditor::execCommand(const String& command, bool userInterface, const String& value)
78 const CommandImp* cmd = commandImp(command);
81 Frame* frame = m_document->frame();
84 m_document->updateLayoutIgnorePendingStylesheets();
85 return cmd->enabledFn(frame) && cmd->execFn(frame, userInterface, value);
88 bool JSEditor::queryCommandEnabled(const String& command)
90 const CommandImp* cmd = commandImp(command);
93 Frame* frame = m_document->frame();
96 m_document->updateLayoutIgnorePendingStylesheets();
97 return cmd->enabledFn(frame);
100 bool JSEditor::queryCommandIndeterm(const String& command)
102 const CommandImp* cmd = commandImp(command);
105 Frame* frame = m_document->frame();
108 m_document->updateLayoutIgnorePendingStylesheets();
109 return cmd->stateFn(frame) == Frame::mixedTriState;
112 bool JSEditor::queryCommandState(const String& command)
114 const CommandImp* cmd = commandImp(command);
117 Frame* frame = m_document->frame();
120 m_document->updateLayoutIgnorePendingStylesheets();
121 return cmd->stateFn(frame) != Frame::falseTriState;
124 bool JSEditor::queryCommandSupported(const String& command)
126 if (!supportsPasteCommand && command.lower() == "paste")
128 return commandImp(command) != 0;
131 String JSEditor::queryCommandValue(const String& command)
133 const CommandImp* cmd = commandImp(command);
136 Frame* frame = m_document->frame();
139 m_document->updateLayoutIgnorePendingStylesheets();
140 return cmd->valueFn(frame);
143 void JSEditor::setSupportsPasteCommand(bool flag)
145 supportsPasteCommand = flag;
148 // =============================================================================================
150 // Private stuff, all inside an anonymous namespace.
154 bool execStyleChange(Frame* frame, int propertyID, const String& propertyValue)
156 RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
157 style->setProperty(propertyID, propertyValue);
158 frame->applyStyle(style.get());
162 bool execStyleChange(Frame* frame, int propertyID, const char* propertyValue)
164 return execStyleChange(frame, propertyID, String(propertyValue));
167 Frame::TriState stateStyle(Frame* frame, int propertyID, const char* desiredValue)
169 RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
170 style->setProperty(propertyID, desiredValue);
171 return frame->selectionHasStyle(style.get());
174 bool selectionStartHasStyle(Frame* frame, int propertyID, const char* desiredValue)
176 RefPtr<CSSMutableStyleDeclaration> style = new CSSMutableStyleDeclaration;
177 style->setProperty(propertyID, desiredValue);
178 return frame->selectionStartHasStyle(style.get());
181 String valueStyle(Frame* frame, int propertyID)
183 return frame->selectionStartStylePropertyValue(propertyID);
186 // =============================================================================================
188 // execCommand implementations
191 bool execBackColor(Frame* frame, bool, const String& value)
193 return execStyleChange(frame, CSS_PROP_BACKGROUND_COLOR, value);
196 bool execBold(Frame* frame, bool, const String&)
198 bool isBold = selectionStartHasStyle(frame, CSS_PROP_FONT_WEIGHT, "bold");
199 return execStyleChange(frame, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
202 bool execCopy(Frame* frame, bool, const String&)
204 frame->copyToPasteboard();
208 bool execCreateLink(Frame* frame, bool userInterface, const String& value)
210 // FIXME: If userInterface is true, we should display a dialog box to let the user enter a url.
212 LOG_ERROR("A dialog box for link creation is not yet implemented.\n");
217 applyCommand(new CreateLinkCommand(frame->document(), value));
221 bool execCut(Frame* frame, bool, const String&)
223 frame->cutToPasteboard();
227 bool execDelete(Frame* frame, bool, const String&)
229 TypingCommand::deleteKeyPressed(frame->document(), frame->selectionGranularity() == WordGranularity);
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)
236 return frame->findString(value, true, false, true);
239 bool execForwardDelete(Frame* frame, bool, const String&)
241 TypingCommand::forwardDeleteKeyPressed(frame->document());
245 bool execFontName(Frame* frame, bool, const String& value)
247 return execStyleChange(frame, CSS_PROP_FONT_FAMILY, value);
250 bool execFontSize(Frame* frame, bool, const String& value)
252 return execStyleChange(frame, CSS_PROP_FONT_SIZE, value);
255 bool execFontSizeDelta(Frame* frame, bool, const String& value)
257 return execStyleChange(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA, value);
260 bool execForeColor(Frame* frame, bool, const String& value)
262 return execStyleChange(frame, CSS_PROP_COLOR, value);
265 bool execFormatBlock(Frame* frame, bool, const String& value)
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))
272 applyCommand(new FormatBlockCommand(frame->document(), tagName));
276 bool execInsertHorizontalRule(Frame* frame, bool userInterface, const String& value)
278 RefPtr<HTMLElement> hr = new HTMLElement(hrTag, frame->document());
280 RefPtr<DocumentFragment> fragment = new DocumentFragment(frame->document());
281 ExceptionCode ec = 0;
282 fragment->appendChild(hr, ec);
286 applyCommand(new ReplaceSelectionCommand(frame->document(), fragment.release(),
287 false, false, false, true, EditActionUnspecified));
291 bool execInsertHTML(Frame* frame, bool userInterface, const String& value)
293 Document* document = frame->document();
294 applyCommand(new ReplaceSelectionCommand(frame->document(), createFragmentFromMarkup(document, value, ""), false));
298 bool execInsertImage(Frame* frame, bool userInterface, const String& value)
300 // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
302 LOG_ERROR("A dialog box for image insertion is not yet implemented.\n");
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);
312 applyCommand(new ReplaceSelectionCommand(frame->document(), fragment.release(), false));
316 bool execIndent(Frame* frame, bool, const String&)
318 applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Indent));
322 bool execInsertLineBreak(Frame* frame, bool, const String&)
324 TypingCommand::insertLineBreak(frame->document());
328 bool execInsertParagraph(Frame* frame, bool, const String&)
330 TypingCommand::insertParagraphSeparator(frame->document());
334 bool execInsertNewlineInQuotedContent(Frame* frame, bool, const String&)
336 TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document());
340 bool execInsertText(Frame* frame, bool, const String& value)
342 TypingCommand::insertText(frame->document(), value);
346 bool execInsertUnorderedList(Frame* frame, bool, const String& value)
348 applyCommand(new InsertListCommand(frame->document(), InsertListCommand::UnorderedList, value));
352 bool execInsertOrderedList(Frame* frame, bool, const String& value)
354 applyCommand(new InsertListCommand(frame->document(), InsertListCommand::OrderedList, value));
358 bool execItalic(Frame* frame, bool, const String&)
360 bool isItalic = selectionStartHasStyle(frame, CSS_PROP_FONT_STYLE, "italic");
361 return execStyleChange(frame, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
364 bool execJustifyCenter(Frame* frame, bool, const String&)
366 return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "center");
369 bool execJustifyFull(Frame* frame, bool, const String&)
371 return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "justify");
374 bool execJustifyLeft(Frame* frame, bool, const String&)
376 return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "left");
379 bool execJustifyRight(Frame* frame, bool, const String&)
381 return execStyleChange(frame, CSS_PROP_TEXT_ALIGN, "right");
384 bool execOutdent(Frame* frame, bool, const String&)
386 applyCommand(new IndentOutdentCommand(frame->document(), IndentOutdentCommand::Outdent));
390 bool execPaste(Frame* frame, bool, const String&)
392 frame->pasteFromPasteboard();
396 bool execPasteAndMatchStyle(Frame* frame, bool, const String&)
398 frame->pasteAndMatchStyle();
402 bool execPrint(Frame* frame, bool, const String&)
408 bool execRedo(Frame* frame, bool, const String&)
414 bool execRemoveFormat(Frame* frame, bool userInterface, const String& value)
416 frame->editor()->removeFormattingAndStyle();
420 bool execSelectAll(Frame* frame, bool, const String&)
426 bool execStrikethrough(Frame* frame, bool, const String&)
428 bool isStrikethrough = selectionStartHasStyle(frame, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "line-through");
429 return execStyleChange(frame, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, isStrikethrough ? "none" : "line-through");
432 bool execSubscript(Frame* frame, bool, const String&)
434 return execStyleChange(frame, CSS_PROP_VERTICAL_ALIGN, "sub");
437 bool execSuperscript(Frame* frame, bool, const String&)
439 return execStyleChange(frame, CSS_PROP_VERTICAL_ALIGN, "super");
442 bool execTranspose(Frame* frame, bool, const String&)
448 bool execUnderline(Frame* frame, bool, const String&)
450 bool isUnderlined = selectionStartHasStyle(frame, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline");
451 return execStyleChange(frame, CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, isUnderlined ? "none" : "underline");
454 bool execUndo(Frame* frame, bool, const String&)
460 bool execUnlink(Frame* frame, bool, const String&)
462 applyCommand(new UnlinkCommand(frame->document()));
466 bool execUnselect(Frame* frame, bool, const String&)
468 frame->selectionController()->clear();
472 // =============================================================================================
474 // queryCommandEnabled implementations
476 // It's a bit difficult to get a clear notion of the difference between
477 // "supported" and "enabled" from reading the Microsoft documentation, but
478 // what little I could glean from that seems to make some sense.
479 // Supported = The command is supported by this object.
480 // Enabled = The command is available and enabled.
487 bool enabledAnyCaret(Frame* frame)
489 return frame->selectionController()->isCaret() && frame->selectionController()->isContentEditable();
492 bool enabledAnySelection(Frame* frame)
494 return frame->selectionController()->isCaretOrRange();
497 bool enabledAnyEditableSelection(Frame* frame)
499 return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentEditable();
502 bool enabledAnyRichlyEditableSelection(Frame* frame)
504 return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
507 bool enabledPaste(Frame* frame)
509 return supportsPasteCommand && frame->canPaste();
512 bool enabledPasteAndMatchStyle(Frame* frame)
514 return supportsPasteCommand && frame->canPaste();
517 bool enabledAnyRangeSelection(Frame* frame)
519 return frame->selectionController()->isRange();
522 bool enabledAnyEditableRangeSelection(Frame* frame)
524 return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
527 bool enabledAnyRichlyEditableRangeSelection(Frame* frame)
529 return frame->selectionController()->isRange() && frame->selectionController()->isContentRichlyEditable();
532 bool enabledRedo(Frame* frame)
534 return frame->canRedo();
537 bool enabledUndo(Frame* frame)
539 return frame->canUndo();
542 // =============================================================================================
544 // queryCommandIndeterm/State implementations
546 // It's a bit difficult to get a clear notion of what these methods are supposed
547 // to do from reading the Microsoft documentation, but my current guess is this:
549 // queryCommandState and queryCommandIndeterm work in concert to return
550 // the two bits of information that are needed to tell, for instance,
551 // if the text of a selection is bold. The answer can be "yes", "no", or
554 // If this is so, then queryCommandState should return "yes" in the case where
555 // all the text is bold and "no" for non-bold or partially-bold text.
556 // Then, queryCommandIndeterm should return "no" in the case where
557 // all the text is either all bold or not-bold and and "yes" for partially-bold text.
559 Frame::TriState stateNone(Frame*)
561 return Frame::falseTriState;
564 Frame::TriState stateBold(Frame* frame)
566 return stateStyle(frame, CSS_PROP_FONT_WEIGHT, "bold");
569 Frame::TriState stateItalic(Frame* frame)
571 return stateStyle(frame, CSS_PROP_FONT_STYLE, "italic");
574 Frame::TriState stateUnorderedList(Frame* frame)
576 return frame->editor()->selectionUnorderedListState();
579 Frame::TriState stateOrderedList(Frame* frame)
581 return frame->editor()->selectionOrderedListState();
584 Frame::TriState stateStrikethrough(Frame* frame)
586 return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "line-through");
589 Frame::TriState stateSubscript(Frame* frame)
591 return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "sub");
594 Frame::TriState stateSuperscript(Frame* frame)
596 return stateStyle(frame, CSS_PROP_VERTICAL_ALIGN, "super");
599 Frame::TriState stateUnderline(Frame* frame)
601 return stateStyle(frame, CSS_PROP_TEXT_DECORATION, "underline");
604 // =============================================================================================
606 // queryCommandValue implementations
609 String valueNull(Frame*)
614 String valueBackColor(Frame* frame)
616 return valueStyle(frame, CSS_PROP_BACKGROUND_COLOR);
619 String valueFontName(Frame* frame)
621 return valueStyle(frame, CSS_PROP_FONT_FAMILY);
624 String valueFontSize(Frame* frame)
626 return valueStyle(frame, CSS_PROP_FONT_SIZE);
629 String valueFontSizeDelta(Frame* frame)
631 return valueStyle(frame, CSS_PROP__WEBKIT_FONT_SIZE_DELTA);
634 String valueForeColor(Frame* frame)
636 return valueStyle(frame, CSS_PROP_COLOR);
639 // =============================================================================================
641 CommandMap* createCommandDictionary()
643 struct EditorCommand { const char* name; CommandImp imp; };
645 static const EditorCommand commands[] = {
647 { "BackColor", { execBackColor, enabledAnyRichlyEditableRangeSelection, stateNone, valueBackColor } },
648 { "Bold", { execBold, enabledAnyRichlyEditableSelection, stateBold, valueNull } },
649 { "Copy", { execCopy, enabledAnyRangeSelection, stateNone, valueNull } },
650 { "CreateLink", { execCreateLink, enabledAnyRichlyEditableRangeSelection, stateNone, valueNull } },
651 { "Cut", { execCut, enabledAnyEditableRangeSelection, stateNone, valueNull } },
652 { "Delete", { execDelete, enabledAnyEditableSelection, stateNone, valueNull } },
653 { "FindString", { execFindString, enabled, stateNone, valueNull } },
654 { "FontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
655 { "FontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
656 { "FontSizeDelta", { execFontSizeDelta, enabledAnySelection, stateNone, valueFontSizeDelta } },
657 { "ForeColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
658 { "FormatBlock", { execFormatBlock, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
659 { "ForwardDelete", { execForwardDelete, enabledAnyEditableSelection, stateNone, valueNull } },
660 { "HiliteColor", { execBackColor, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
661 { "Indent", { execIndent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
662 { "InsertHorizontalRule", { execInsertHorizontalRule, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
663 { "InsertHTML", { execInsertHTML, enabledAnyEditableSelection, stateNone, valueNull } },
664 { "InsertImage", { execInsertImage, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
665 { "InsertLineBreak", { execInsertLineBreak, enabledAnyEditableSelection, stateNone, valueNull } },
666 { "InsertOrderedList", { execInsertOrderedList, enabledAnyRichlyEditableSelection, stateOrderedList, valueNull } },
667 { "InsertParagraph", { execInsertParagraph, enabledAnyEditableSelection, stateNone, valueNull } },
668 { "InsertNewlineInQuotedContent", { execInsertNewlineInQuotedContent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
669 { "InsertText", { execInsertText, enabledAnyEditableSelection, stateNone, valueNull } },
670 { "InsertUnorderedList", { execInsertUnorderedList, enabledAnyRichlyEditableSelection, stateUnorderedList, valueNull } },
671 { "Italic", { execItalic, enabledAnyRichlyEditableSelection, stateItalic, valueNull } },
672 { "JustifyCenter", { execJustifyCenter, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
673 { "JustifyFull", { execJustifyFull, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
674 { "JustifyLeft", { execJustifyLeft, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
675 { "JustifyNone", { execJustifyLeft, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
676 { "JustifyRight", { execJustifyRight, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
677 { "Outdent", { execOutdent, enabledAnyRichlyEditableSelection, stateNone, valueNull } },
678 { "Paste", { execPaste, enabledPaste, stateNone, valueNull } },
679 { "PasteAndMatchStyle", { execPasteAndMatchStyle, enabledPasteAndMatchStyle, stateNone, valueNull } },
680 { "Print", { execPrint, enabled, stateNone, valueNull } },
681 { "Redo", { execRedo, enabledRedo, stateNone, valueNull } },
682 { "RemoveFormat", { execRemoveFormat, enabledAnyEditableRangeSelection, stateNone, valueNull } },
683 { "SelectAll", { execSelectAll, enabled, stateNone, valueNull } },
684 { "Strikethrough", { execStrikethrough, enabledAnyRichlyEditableSelection, stateStrikethrough, valueNull } },
685 { "Subscript", { execSubscript, enabledAnyRichlyEditableSelection, stateSubscript, valueNull } },
686 { "Superscript", { execSuperscript, enabledAnyRichlyEditableSelection, stateSuperscript, valueNull } },
687 { "Transpose", { execTranspose, enabledAnyCaret, stateNone, valueNull } },
688 { "Underline", { execUnderline, enabledAnyRichlyEditableSelection, stateUnderline, valueNull } },
689 { "Undo", { execUndo, enabledUndo, stateNone, valueNull } },
690 { "Unlink", { execUnlink, enabledAnyRichlyEditableRangeSelection, stateNone, valueNull } },
691 { "Unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
694 // The "unsupported" commands are listed here since they appear in the Microsoft
695 // documentation used as the basis for the list.
698 // 2D-Position (not supported)
699 // AbsolutePosition (not supported)
700 // BlockDirLTR (not supported)
701 // BlockDirRTL (not supported)
702 // BrowseMode (not supported)
703 // ClearAuthenticationCache (not supported)
704 // CreateBookmark (not supported)
705 // DirLTR (not supported)
706 // DirRTL (not supported)
707 // EditMode (not supported)
708 // InlineDirLTR (not supported)
709 // InlineDirRTL (not supported)
710 // InsertButton (not supported)
711 // InsertFieldSet (not supported)
712 // InsertIFrame (not supported)
713 // InsertInputButton (not supported)
714 // InsertInputCheckbox (not supported)
715 // InsertInputFileUpload (not supported)
716 // InsertInputHidden (not supported)
717 // InsertInputImage (not supported)
718 // InsertInputPassword (not supported)
719 // InsertInputRadio (not supported)
720 // InsertInputReset (not supported)
721 // InsertInputSubmit (not supported)
722 // InsertInputText (not supported)
723 // InsertMarquee (not supported)
724 // InsertSelectDropDown (not supported)
725 // InsertSelectListBox (not supported)
726 // InsertTextArea (not supported)
727 // LiveResize (not supported)
728 // MultipleSelection (not supported)
729 // Open (not supported)
730 // Overwrite (not supported)
731 // PlayImage (not supported)
732 // Refresh (not supported)
733 // RemoveParaFormat (not supported)
734 // SaveAs (not supported)
735 // SizeToControl (not supported)
736 // SizeToControlHeight (not supported)
737 // SizeToControlWidth (not supported)
738 // Stop (not supported)
739 // StopImage (not supported)
740 // Unbookmark (not supported)
743 CommandMap* commandMap = new CommandMap;
745 const int numCommands = sizeof(commands) / sizeof(commands[0]);
746 for (int i = 0; i < numCommands; ++i) {
747 StringImpl *name = new StringImpl(commands[i].name);
749 commandMap->set(name, &commands[i].imp);
752 supportsPasteCommand = true;
757 } // anonymous namespace
759 } // namespace WebCore