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