WebCore:
[WebKit-https.git] / WebCore / editing / Editor.cpp
1 /*
2  * Copyright (C) 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 "Editor.h"
28
29 #include "ApplyStyleCommand.h"
30 #include "AXObjectCache.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSProperty.h"
33 #include "CSSPropertyNames.h"
34 #include "DeleteButtonController.h"
35 #include "DeleteSelectionCommand.h"
36 #include "Document.h"
37 #include "DocumentFragment.h"
38 #include "EditCommand.h"
39 #include "Editor.h"
40 #include "EditorClient.h"
41 #include "Event.h"
42 #include "EventNames.h"
43 #include "HTMLElement.h"
44 #include "HTMLNames.h"
45 #include "HitTestResult.h"
46 #include "IndentOutdentCommand.h"
47 #include "Range.h"
48 #include "ReplaceSelectionCommand.h"
49 #include "SelectionController.h"
50 #include "Sound.h"
51 #include "TypingCommand.h"
52 #include "htmlediting.h"
53 #include "markup.h"
54
55 namespace WebCore {
56
57 using namespace EventNames;
58 using namespace HTMLNames;
59
60 // implement as platform-specific
61 static Pasteboard generalPasteboard()
62 {
63     return 0;
64 }
65
66 EditorClient* Editor::client() const
67 {
68     return m_client.get();
69 }
70
71 bool Editor::canEdit() const
72 {
73     SelectionController* selectionController = m_frame->selectionController();
74     return selectionController->isCaretOrRange() && selectionController->isContentEditable();
75 }
76
77 bool Editor::canEditRichly() const
78 {
79     SelectionController* selectionController = m_frame->selectionController();
80     return canEdit() && selectionController->isContentRichlyEditable();
81 }
82
83 bool Editor::canCut() const
84 {
85     return canCopy() && canDelete();
86 }
87
88 bool Editor::canCopy() const
89 {
90     SelectionController* selectionController = m_frame->selectionController();
91     return selectionController->isRange() && !selectionController->isInPasswordField();
92 }
93
94 bool Editor::canPaste() const
95 {
96     SelectionController* selectionController = m_frame->selectionController();
97     return selectionController->isCaretOrRange() && selectionController->isContentEditable();
98 }
99
100 bool Editor::canDelete() const
101 {
102     SelectionController* selectionController = m_frame->selectionController();
103     return selectionController->isRange() && selectionController->isContentEditable();
104 }
105
106 bool Editor::canDeleteRange(Range* range) const
107 {
108     ExceptionCode ec = 0;
109     Node* startContainer = range->startContainer(ec);
110     Node* endContainer = range->endContainer(ec);
111     if (!startContainer || !endContainer)
112         return false;
113     
114     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
115         return false;
116     
117     if (range->collapsed(ec)) {
118         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
119         VisiblePosition previous = start.previous();
120         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
121         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
122             return false;
123     }
124     return true;
125 }
126
127 bool Editor::canSmartCopyOrDelete()
128 {
129     return false;
130 }
131
132 void Editor::deleteSelection()
133 {
134 }
135
136 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
137 {
138     if (m_frame->selectionController()->isNone())
139         return;
140     
141     applyCommand(new DeleteSelectionCommand(m_frame->document(), smartDelete));
142 }
143
144 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard pasteboard)
145 {
146 }
147
148 void Editor::pasteWithPasteboard(Pasteboard pasteboard, bool allowPlainText)
149 {
150 }
151
152 Range* Editor::selectedRange()
153 {
154     return 0;
155 }
156
157 bool Editor::shouldDeleteRange(Range* range) const
158 {
159     ExceptionCode ec;
160     if (!range || range->collapsed(ec))
161         return false;
162     
163     if (!canDeleteRange(range))
164         return false;
165
166     return m_client->shouldDeleteRange(range);
167  }
168
169 bool Editor::tryDHTMLCopy()
170 {
171     bool handled = false;
172     return handled;
173 }
174
175 bool Editor::tryDHTMLCut()
176 {
177     bool handled = false;
178     return handled;
179 }
180
181 bool Editor::tryDHTMLPaste()
182 {
183     bool handled = false;
184     return handled;
185 }
186
187 void Editor::writeSelectionToPasteboard(Pasteboard pasteboard)
188 {
189 }
190
191 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
192 {
193     return m_client->shouldShowDeleteInterface(element);
194 }
195
196 void Editor::respondToChangedSelection(const Selection& oldSelection)
197 {
198     m_deleteButtonController->respondToChangedSelection(oldSelection);
199 }
200
201 void Editor::respondToChangedContents(const Selection& endingSelection)
202 {
203     if (AXObjectCache::accessibilityEnabled()) {
204         Node* node = endingSelection.start().node();
205         if (node)
206             m_frame->renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
207     }
208     
209     m_client->respondToChangedContents();  
210     m_deleteButtonController->respondToChangedContents();
211 }
212
213 Frame::TriState Editor::selectionUnorderedListState() const
214 {
215     if (m_frame->selectionController()->isCaret()) {
216         Node* selectionNode = m_frame->selectionController()->selection().start().node();
217         if (enclosingNodeWithTag(selectionNode, ulTag))
218             return Frame::trueTriState;
219     } else if (m_frame->selectionController()->isRange()) {
220         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
221         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
222         if (startNode && endNode && startNode == endNode)
223             return Frame::trueTriState;
224     }
225
226     return Frame::falseTriState;
227 }
228
229 Frame::TriState Editor::selectionOrderedListState() const
230 {
231     if (m_frame->selectionController()->isCaret()) {
232         Node* selectionNode = m_frame->selectionController()->selection().start().node();
233         if (enclosingNodeWithTag(selectionNode, olTag))
234             return Frame::trueTriState;
235     } else if (m_frame->selectionController()->isRange()) {
236         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
237         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
238         if (startNode && endNode && startNode == endNode)
239             return Frame::trueTriState;
240     }
241
242     return Frame::falseTriState;
243 }
244
245 void Editor::removeFormattingAndStyle()
246 {
247     Document* document = m_frame->document();
248     
249     // Make a plain text string from the selection to remove formatting like tables and lists.
250     RefPtr<DocumentFragment> text = createFragmentFromText(m_frame->selectionController()->toRange().get(), m_frame->selectionController()->toString());
251     
252     // Put the fragment made from that string into a style span with the document's
253     // default style to make sure that it is unstyled regardless of where it is inserted.
254     Position pos(document->documentElement(), 0);
255     RefPtr<CSSComputedStyleDeclaration> computedStyle = pos.computedStyle();
256     RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle->copyInheritableProperties();
257     
258     RefPtr<Element> span = createStyleSpanElement(document);
259     span->setAttribute(styleAttr, defaultStyle->cssText());
260     
261     ExceptionCode ec;
262     
263     while (text->lastChild())
264         span->appendChild(text->lastChild(), ec);
265     
266     RefPtr<DocumentFragment> fragment = new DocumentFragment(document);
267     fragment->appendChild(span, ec);
268     
269     applyCommand(new ReplaceSelectionCommand(document, fragment, false, false, false, true, EditActionUnspecified));
270 }
271
272 void Editor::setLastEditCommand(PassRefPtr<EditCommand> lastEditCommand) 
273 {
274     m_lastEditCommand = lastEditCommand;
275 }
276
277 void Editor::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
278 {
279     switch (m_frame->selectionController()->state()) {
280         case Selection::NONE:
281             // do nothing
282             break;
283         case Selection::CARET: {
284             m_frame->computeAndSetTypingStyle(style, editingAction);
285             break;
286         }
287         case Selection::RANGE:
288             if (m_frame->document() && style)
289                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction));
290             break;
291     }
292 }
293
294 void Editor::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
295 {
296     switch (m_frame->selectionController()->state()) {
297         case Selection::NONE:
298             // do nothing
299             break;
300         case Selection::CARET:
301         case Selection::RANGE:
302             if (m_frame->document() && style)
303                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
304             break;
305     }
306 }
307
308 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
309 {
310     if (!style || style->length() == 0 || !canEditRichly())
311         return;
312
313     if (m_client->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
314         applyStyle(style, editingAction);
315 }
316
317 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
318 {
319     if (!style || style->length() == 0 || !canEditRichly())
320         return;
321     
322     if (m_client->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
323         applyParagraphStyle(style, editingAction);
324 }
325
326 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
327 {
328     Node* nodeToRemove;
329     RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
330     if (!selectionStyle)
331         return false;
332     
333     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
334     
335     bool match = true;
336     DeprecatedValueListConstIterator<CSSProperty> end;
337     for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
338         int propertyID = (*it).id();
339         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
340             match = false;
341             break;
342         }
343     }
344     
345     if (nodeToRemove) {
346         ExceptionCode ec = 0;
347         nodeToRemove->remove(ec);
348         assert(ec == 0);
349     }
350     
351     return match;
352 }
353
354 void Editor::indent()
355 {
356     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Indent));
357 }
358
359 void Editor::outdent()
360 {
361     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Outdent));
362 }
363
364 static void dispatchEditableContentChangedEvents(const EditCommand& command)
365 {
366     Element* startRoot = command.startingRootEditableElement();
367     Element* endRoot = command.endingRootEditableElement();
368     ExceptionCode ec;
369     if (startRoot)
370         startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
371     if (endRoot && endRoot != startRoot)
372         endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
373 }
374
375 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
376 {
377     dispatchEditableContentChangedEvents(*cmd);
378     
379     Selection newSelection(cmd->endingSelection());
380     if (m_frame->shouldChangeSelection(newSelection))
381         m_frame->selectionController()->setSelection(newSelection, false);
382     
383     // Now set the typing style from the command. Clear it when done.
384     // This helps make the case work where you completely delete a piece
385     // of styled text and then type a character immediately after.
386     // That new character needs to take on the style of the just-deleted text.
387     // FIXME: Improve typing style.
388     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
389     if (cmd->typingStyle()) {
390         m_frame->setTypingStyle(cmd->typingStyle());
391         cmd->setTypingStyle(0);
392     }
393     
394     // Command will be equal to last edit command only in the case of typing
395     if (m_lastEditCommand.get() == cmd)
396         ASSERT(cmd->isTypingCommand());
397     else {
398         // Only register a new undo command if the command passed in is
399         // different from the last command
400         m_lastEditCommand = cmd;
401         m_frame->registerCommandForUndo(m_lastEditCommand);
402     }
403     respondToChangedContents(newSelection);    
404 }
405
406 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
407 {
408     dispatchEditableContentChangedEvents(*cmd);
409     
410     Selection newSelection(cmd->startingSelection());
411     if (m_frame->shouldChangeSelection(newSelection))
412         m_frame->selectionController()->setSelection(newSelection, true);
413     
414     m_lastEditCommand = 0;
415     m_frame->registerCommandForRedo(cmd);
416     respondToChangedContents(newSelection);    
417 }
418
419 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
420 {
421     dispatchEditableContentChangedEvents(*cmd);
422     
423     Selection newSelection(cmd->endingSelection());
424     if (m_frame->shouldChangeSelection(newSelection))
425         m_frame->selectionController()->setSelection(newSelection, true);
426     
427     m_lastEditCommand = 0;
428     m_frame->registerCommandForUndo(cmd);
429     respondToChangedContents(newSelection);    
430 }
431
432 // Execute command functions
433
434 bool execCopy(Frame* frame)
435 {
436     frame->copyToPasteboard();
437     return true;
438 }
439
440 bool execCut(Frame* frame)
441 {
442     frame->cutToPasteboard();
443     return true;
444 }
445
446 static bool execDelete(Frame* frame)
447 {
448     TypingCommand::deleteKeyPressed(frame->document(), frame->selectionGranularity() == WordGranularity);
449     return true;
450 }
451
452 static bool execForwardDelete(Frame* frame)
453 {
454     TypingCommand::forwardDeleteKeyPressed(frame->document());
455     return true;
456 }
457
458 static bool execMoveBackward(Frame* frame)
459 {
460     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
461     return true;
462 }
463
464 static bool execMoveBackwardAndModifySelection(Frame* frame)
465 {
466     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
467     return true;
468 }
469
470 static bool execMoveDown(Frame* frame)
471 {
472     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
473     return true;
474 }
475
476 static bool execMoveDownAndModifySelection(Frame* frame)
477 {
478     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
479     return true;
480 }
481
482 static bool execMoveForward(Frame* frame)
483 {
484     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
485     return true;
486 }
487
488 static bool execMoveForwardAndModifySelection(Frame* frame)
489 {
490     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
491     return true;
492 }
493
494 static bool execMoveLeft(Frame* frame)
495 {
496     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
497     return true;
498 }
499
500 static bool execMoveLeftAndModifySelection(Frame* frame)
501 {
502     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
503     return true;
504 }
505
506 static bool execMoveRight(Frame* frame)
507 {
508     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
509     return true;
510 }
511
512 static bool execMoveRightAndModifySelection(Frame* frame)
513 {
514     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
515     return true;
516 }
517
518 static bool execMoveToBeginningOfDocument(Frame* frame)
519 {
520     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
521     return true;
522 }
523
524 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame)
525 {
526     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
527     return true;
528 }
529
530 static bool execMoveToBeginningOfSentence(Frame* frame)
531 {
532     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
533     return true;
534 }
535
536 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame)
537 {
538     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
539     return true;
540 }
541
542 static bool execMoveToBeginningOfLine(Frame* frame)
543 {
544     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
545     return true;
546 }
547
548 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame)
549 {
550     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
551     return true;
552 }
553
554 static bool execMoveToBeginningOfParagraph(Frame* frame)
555 {
556     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
557     return true;
558 }
559
560 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame)
561 {
562     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
563     return true;
564 }
565
566 static bool execMoveToEndOfDocument(Frame* frame)
567 {
568     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
569     return true;
570 }
571
572 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame)
573 {
574     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
575     return true;
576 }
577
578 static bool execMoveToEndOfSentence(Frame* frame)
579 {
580     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
581     return true;
582 }
583
584 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame)
585 {
586     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
587     return true;
588 }
589
590 static bool execMoveToEndOfLine(Frame* frame)
591 {
592     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
593     return true;
594 }
595
596 static bool execMoveToEndOfLineAndModifySelection(Frame* frame)
597 {
598     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
599     return true;
600 }
601
602 static bool execMoveToEndOfParagraph(Frame* frame)
603 {
604     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
605     return true;
606 }
607
608 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame)
609 {
610     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
611     return true;
612 }
613
614 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame)
615 {
616     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
617     return true;
618 }
619
620 static bool execMoveParagraphForwardAndModifySelection(Frame* frame)
621 {
622     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
623     return true;
624 }
625
626 static bool execMoveUp(Frame* frame)
627 {
628     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
629     return true;
630 }
631
632 static bool execMoveUpAndModifySelection(Frame* frame)
633 {
634     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
635     return true;
636 }
637
638 static bool execMoveWordBackward(Frame* frame)
639 {
640     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
641     return true;
642 }
643
644 static bool execMoveWordBackwardAndModifySelection(Frame* frame)
645 {
646     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
647     return true;
648 }
649
650 static bool execMoveWordForward(Frame* frame)
651 {
652     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
653     return true;
654 }
655
656 static bool execMoveWordForwardAndModifySelection(Frame* frame)
657 {
658     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
659     return true;
660 }
661
662 static bool execMoveWordLeft(Frame* frame)
663 {
664     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
665     return true;
666 }
667
668 static bool execMoveWordLeftAndModifySelection(Frame* frame)
669 {
670     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
671     return true;
672 }
673
674 static bool execMoveWordRight(Frame* frame)
675 {
676     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
677     return true;
678 }
679
680 static bool execMoveWordRightAndModifySelection(Frame* frame)
681 {
682     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
683     return true;
684 }
685
686 static bool execPaste(Frame* frame)
687 {
688     frame->pasteFromPasteboard();
689     return true;
690 }
691
692 static bool execSelectAll(Frame* frame)
693 {
694     frame->selectionController()->selectAll();
695     return true;
696 }
697
698 static bool execToggleBold(Frame* frame)
699 {
700     ExceptionCode ec;
701     
702     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
703     style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
704     if (frame->editor()->selectionStartHasStyle(style.get()))
705         style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
706     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
707     return true;
708 }
709
710 static bool execToggleItalic(Frame* frame)
711 {
712     ExceptionCode ec;
713     
714     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
715     style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
716     if (frame->editor()->selectionStartHasStyle(style.get()))
717         style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
718     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
719     return true;
720 }
721
722 // Enabled functions
723
724 static bool enabled(Frame*)
725 {
726     return true;
727 }
728
729 static bool canPaste(Frame* frame)
730 {
731     return frame->editor()->canPaste();
732 }
733
734 static bool hasEditableSelection(Frame* frame)
735 {
736     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentEditable();
737 }
738
739 static bool hasEditableRangeSelection(Frame* frame)
740 {
741     return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
742 }
743
744 static bool hasRangeSelection(Frame* frame)
745 {
746     return frame->selectionController()->isRange();
747 }
748
749 static bool hasRichlyEditableSelection(Frame* frame)
750 {
751     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
752 }
753
754 struct Command {
755     bool (*enabled)(Frame* frame);
756     bool (*exec)(Frame* frame);
757 };
758
759 typedef HashMap<String, const Command*> CommandMap;
760
761 static CommandMap* createCommandMap()
762 {
763     struct CommandEntry { const char* name; Command command; };
764     
765     static const CommandEntry commands[] = {
766         { "Copy", { hasRangeSelection, execCopy } },
767         { "Cut", { hasEditableRangeSelection, execCut } },
768         { "Delete", { hasEditableSelection, execDelete } },
769         { "ForwardDelete", { hasEditableSelection, execForwardDelete } },
770         { "MoveBackward", { hasEditableSelection, execMoveBackward } },
771         { "MoveBackwardAndModifySelection", { hasEditableSelection, execMoveBackwardAndModifySelection } },
772         { "MoveDown", { hasEditableSelection, execMoveDown } },
773         { "MoveDownAndModifySelection", { hasEditableSelection, execMoveDownAndModifySelection } },
774         { "MoveForward", { hasEditableSelection, execMoveForward } },
775         { "MoveForwardAndModifySelection", { hasEditableSelection, execMoveForwardAndModifySelection } },
776         { "MoveLeft", { hasEditableSelection, execMoveLeft } },
777         { "MoveLeftAndModifySelection", { hasEditableSelection, execMoveLeftAndModifySelection } },
778         { "MoveRight", { hasEditableSelection, execMoveRight } },
779         { "MoveRightAndModifySelection", { hasEditableSelection, execMoveRightAndModifySelection } },
780         { "MoveToBeginningOfDocument", { hasEditableSelection, execMoveToBeginningOfDocument } },
781         { "MoveToBeginningOfDocumentAndModifySelection", { hasEditableSelection, execMoveToBeginningOfDocumentAndModifySelection } },
782         { "MoveToBeginningOfSentence", { hasEditableSelection, execMoveToBeginningOfSentence } },
783         { "MoveToBeginningOfSentenceAndModifySelection", { hasEditableSelection, execMoveToBeginningOfSentenceAndModifySelection } },
784         { "MoveToBeginningOfLine", { hasEditableSelection, execMoveToBeginningOfLine } },
785         { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfLineAndModifySelection } },
786         { "MoveToBeginningOfParagraph", { hasEditableSelection, execMoveToBeginningOfParagraph } },
787         { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfParagraphAndModifySelection } },
788         { "MoveToEndOfDocument", { hasEditableSelection, execMoveToEndOfDocument } },
789         { "MoveToEndOfDocumentAndModifySelection", { hasEditableSelection, execMoveToEndOfDocumentAndModifySelection } },
790         { "MoveToEndOfSentence", { hasEditableSelection, execMoveToEndOfSentence } },
791         { "MoveToEndOfSentenceAndModifySelection", { hasEditableSelection, execMoveToEndOfSentenceAndModifySelection } },
792         { "MoveToEndOfLine", { hasEditableSelection, execMoveToEndOfLine } },
793         { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfLineAndModifySelection } },
794         { "MoveToEndOfParagraph", { hasEditableSelection, execMoveToEndOfParagraph } },
795         { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfParagraphAndModifySelection } },
796         { "MoveParagraphBackwardAndModifySelection", { hasEditableSelection, execMoveParagraphBackwardAndModifySelection } },
797         { "MoveParagraphForwardAndModifySelection", { hasEditableSelection, execMoveParagraphForwardAndModifySelection } },
798         { "MoveUp", { hasEditableSelection, execMoveUp } },
799         { "MoveUpAndModifySelection", { hasEditableSelection, execMoveUpAndModifySelection } },
800         { "MoveWordBackward", { hasEditableSelection, execMoveWordBackward } },
801         { "MoveWordBackwardAndModifySelection", { hasEditableSelection, execMoveWordBackwardAndModifySelection } },
802         { "MoveWordForward", { hasEditableSelection, execMoveWordForward } },
803         { "MoveWordForwardAndModifySelection", { hasEditableSelection, execMoveWordForwardAndModifySelection } },
804         { "MoveWordLeft", { hasEditableSelection, execMoveWordLeft } },
805         { "MoveWordLeftAndModifySelection", { hasEditableSelection, execMoveWordLeftAndModifySelection } },
806         { "MoveWordRight", { hasEditableSelection, execMoveWordRight } },
807         { "MoveWordRightAndModifySelection", { hasEditableSelection, execMoveWordRightAndModifySelection } },
808         { "Paste", { canPaste, execPaste } },
809         { "SelectAll", { enabled, execSelectAll } },
810         { "ToggleBold", { hasRichlyEditableSelection, execToggleBold } },
811         { "ToggleItalic", { hasRichlyEditableSelection, execToggleItalic } }
812     };
813     
814     CommandMap* commandMap = new CommandMap;
815     
816     const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
817     for (unsigned i = 0; i < numCommands; i++)
818         commandMap->set(commands[i].name, &commands[i].command);
819     return commandMap;
820 }
821
822 // =============================================================================
823 //
824 // public editing commands
825 //
826 // =============================================================================
827
828 Editor::Editor(Frame* frame, PassRefPtr<EditorClient> client)
829     : m_frame(frame)
830     , m_client(client)
831     , m_deleteButtonController(new DeleteButtonController(frame))
832
833 }
834
835 Editor::~Editor()
836 {
837 }
838
839 bool Editor::execCommand(const String& command)
840 {
841     static CommandMap* commandMap;
842     if (!commandMap)
843         commandMap = createCommandMap();
844     
845     const Command* c = commandMap->get(command);
846     ASSERT(c);
847     
848     bool handled = false;
849     
850     if (c->enabled(m_frame)) {
851         m_frame->document()->updateLayoutIgnorePendingStylesheets();
852         handled = c->exec(m_frame);
853     }
854     
855     return handled;
856 }
857
858 void Editor::cut()
859 {
860     if (tryDHTMLCut())
861         return; // DHTML did the whole operation
862     if (!canCut()) {
863         systemBeep();
864         return;
865     }
866     
867     if (shouldDeleteRange(selectedRange())) {
868         writeSelectionToPasteboard(generalPasteboard());
869         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
870     }
871 }
872
873 void Editor::copy()
874 {
875     if (tryDHTMLCopy())
876         return; // DHTML did the whole operation
877     if (!canCopy()) {
878         systemBeep();
879         return;
880     }
881     writeSelectionToPasteboard(generalPasteboard());
882 }
883
884 void Editor::paste()
885 {
886     if (tryDHTMLPaste())
887         return;     // DHTML did the whole operation
888     if (!canPaste())
889         return;
890     if (canEditRichly())
891         pasteWithPasteboard(generalPasteboard(), true);
892     else
893         pasteAsPlainTextWithPasteboard(generalPasteboard());
894 }
895
896 void Editor::performDelete()
897 {
898     if (!canDelete()) {
899         systemBeep();
900         return;
901     }
902     deleteSelection();
903 }
904
905 } // namespace WebCore