Reviewed by Justin Garcia.
[WebKit-https.git] / WebCore / editing / Editor.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2007 Trolltech ASA
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "Editor.h"
29
30 #include "AXObjectCache.h"
31 #include "ApplyStyleCommand.h"
32 #include "CSSComputedStyleDeclaration.h"
33 #include "CSSProperty.h"
34 #include "CSSPropertyNames.h"
35 #include "CharacterData.h"
36 #include "Clipboard.h"
37 #include "ClipboardEvent.h"
38 #include "DeleteButtonController.h"
39 #include "DeleteSelectionCommand.h"
40 #include "DocLoader.h"
41 #include "Document.h"
42 #include "DocumentFragment.h"
43 #include "EditCommand.h"
44 #include "Editor.h"
45 #include "EditorClient.h"
46 #include "Event.h"
47 #include "EventHandler.h"
48 #include "EventNames.h"
49 #include "FocusController.h"
50 #include "FrameView.h"
51 #include "HTMLElement.h"
52 #include "HTMLInputElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLTextAreaElement.h"
55 #include "HitTestResult.h"
56 #include "IndentOutdentCommand.h"
57 #include "InsertListCommand.h"
58 #include "KeyboardEvent.h"
59 #include "KURL.h"
60 #include "ModifySelectionListLevel.h"
61 #include "Page.h"
62 #include "Pasteboard.h"
63 #include "Range.h"
64 #include "ReplaceSelectionCommand.h"
65 #include "SelectionController.h"
66 #include "Sound.h"
67 #include "Text.h"
68 #include "TextIterator.h"
69 #include "TypingCommand.h"
70 #include "htmlediting.h"
71 #include "markup.h"
72 #include "visible_units.h"
73
74 namespace WebCore {
75
76 class FontData;
77
78 using namespace std;
79 using namespace EventNames;
80 using namespace HTMLNames;
81
82 // When an event handler has moved the selection outside of a text control
83 // we should use the target control's selection for this editing operation.
84 static Selection selectionForEvent(Frame* frame, Event* event)
85 {
86     Page* page = frame->page();
87     if (!page)
88         return Selection();
89     Selection selection = page->selection();
90     if (!event)
91         return selection;
92     Node* target = event->target()->toNode();
93     Node* selectionStart = selection.start().node();
94     
95     // If the target is a text control, and the current selection is outside of its shadow tree,
96     // then use the saved selection for that text control.
97     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
98         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
99             return static_cast<HTMLInputElement*>(target)->selection();
100         if (target->hasTagName(textareaTag))
101             return static_cast<HTMLTextAreaElement*>(target)->selection();
102     }
103     return selection;
104 }
105
106 EditorClient* Editor::client() const
107 {
108     if (Page* page = m_frame->page())
109         return page->editorClient();
110     return 0;
111 }
112
113 void Editor::handleKeypress(KeyboardEvent* event)
114 {
115     if (EditorClient* c = client())
116         if (selectionForEvent(m_frame, event).isContentEditable())
117             c->handleKeypress(event);
118 }
119
120 void Editor::handleInputMethodKeypress(KeyboardEvent* event)
121 {
122     if (EditorClient* c = client())
123         if (selectionForEvent(m_frame, event).isContentEditable())
124             c->handleInputMethodKeypress(event);
125 }
126
127 bool Editor::canEdit() const
128 {
129     return m_frame->selectionController()->isContentEditable();
130 }
131
132 bool Editor::canEditRichly() const
133 {
134     return m_frame->selectionController()->isContentRichlyEditable();
135 }
136
137 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
138 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
139 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
140 // normally selectable to implement copy/paste (like divs, or a document body).
141
142 bool Editor::canDHTMLCut()
143 {
144     return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecutEvent, ClipboardNumb);
145 }
146
147 bool Editor::canDHTMLCopy()
148 {
149     return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecopyEvent, ClipboardNumb);
150 }
151
152 bool Editor::canDHTMLPaste()
153 {
154     return !dispatchCPPEvent(beforepasteEvent, ClipboardNumb);
155 }
156
157 bool Editor::canCut() const
158 {
159     return canCopy() && canDelete();
160 }
161
162 static Node* imageNodeFromImageDocument(Document* document)
163 {
164     if (!document)
165         return 0;
166     
167     if (!document->isImageDocument())
168         return 0;
169     
170     HTMLElement* body = document->body();
171     if (!body)
172         return 0;
173     
174     Node* node = body->firstChild();
175     if (!node)
176         return 0;
177     
178     if (!node->hasTagName(imgTag))
179         return 0;
180     
181     return node;
182 }
183
184 bool Editor::canCopy() const
185 {
186     if (imageNodeFromImageDocument(m_frame->document()))
187         return true;
188         
189     SelectionController* selectionController = m_frame->selectionController();
190     return selectionController->isRange() && !selectionController->isInPasswordField();
191 }
192
193 bool Editor::canPaste() const
194 {
195     return canEdit();
196 }
197
198 bool Editor::canDelete() const
199 {
200     SelectionController* selectionController = m_frame->selectionController();
201     return selectionController->isRange() && selectionController->isContentEditable();
202 }
203
204 bool Editor::canDeleteRange(Range* range) const
205 {
206     ExceptionCode ec = 0;
207     Node* startContainer = range->startContainer(ec);
208     Node* endContainer = range->endContainer(ec);
209     if (!startContainer || !endContainer)
210         return false;
211     
212     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
213         return false;
214     
215     if (range->collapsed(ec)) {
216         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
217         VisiblePosition previous = start.previous();
218         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
219         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
220             return false;
221     }
222     return true;
223 }
224
225 bool Editor::smartInsertDeleteEnabled()
226 {   
227     return client() && client()->smartInsertDeleteEnabled();
228 }
229     
230 bool Editor::canSmartCopyOrDelete()
231 {
232     return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
233 }
234
235 void Editor::deleteRange(Range* range, bool killRing, bool prepend, bool smartDeleteOK, EditorDeleteAction deletionAction, TextGranularity granularity)
236 {
237     if (killRing)
238         addToKillRing(range, prepend);
239
240     SelectionController* selectionController = m_frame->selectionController();
241     bool smartDelete = smartDeleteOK && canSmartCopyOrDelete();
242     switch (deletionAction) {
243         case deleteSelectionAction:
244             if (!selectionController->setSelectedRange(range, DOWNSTREAM, true))
245                 return;
246             deleteSelectionWithSmartDelete(smartDelete);
247             break;
248         case deleteKeyAction:
249             if (!selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity)))
250                 return;
251             if (m_frame->document()) {
252                 TypingCommand::deleteKeyPressed(m_frame->document(), smartDelete, granularity);
253                 revealSelectionAfterEditingOperation();
254             }
255             break;
256         case forwardDeleteKeyAction:
257             if (!selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity)))
258                 return;
259             if (m_frame->document()) {
260                 TypingCommand::forwardDeleteKeyPressed(m_frame->document(), smartDelete, granularity);
261                 revealSelectionAfterEditingOperation();
262             }
263             break;
264     }
265
266     // clear the "start new kill ring sequence" setting, because it was set to true
267     // when the selection was updated by deleting the range
268     if (killRing)
269         setStartNewKillRingSequence(false);
270 }
271
272 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
273 {
274     // Delete the selection, if there is one.
275     // If not, make a selection using the passed-in direction and granularity.
276
277     if (!canEdit())
278         return false;
279
280     RefPtr<Range> range;
281     EditorDeleteAction deletionAction = deleteSelectionAction;
282
283     bool smartDeleteOK = false;
284     
285     if (m_frame->selectionController()->isRange()) {
286         range = selectedRange();
287         smartDeleteOK = true;
288         if (isTypingAction)
289             deletionAction = deleteKeyAction;
290     } else {
291         SelectionController selectionController;
292         selectionController.setSelection(m_frame->selectionController()->selection());
293         selectionController.modify(SelectionController::EXTEND, direction, granularity);
294         if (killRing && selectionController.isCaret() && granularity != CharacterGranularity)
295             selectionController.modify(SelectionController::EXTEND, direction, CharacterGranularity);
296
297         range = selectionController.toRange();
298         
299         switch (direction) {
300             case SelectionController::FORWARD:
301             case SelectionController::RIGHT:
302                 deletionAction = forwardDeleteKeyAction;
303                 break;
304             case SelectionController::BACKWARD:
305             case SelectionController::LEFT:
306                 deletionAction = deleteKeyAction;
307                 break;
308         }
309     }
310
311     deleteRange(range.get(), killRing, false, smartDeleteOK, deletionAction, granularity);
312
313     return true;
314 }
315
316 void Editor::deleteSelectionWithSmartDelete()
317 {
318     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
319 }
320
321 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
322 {
323     if (m_frame->selectionController()->isNone())
324         return;
325     
326     applyCommand(new DeleteSelectionCommand(m_frame->document(), smartDelete));
327 }
328
329 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
330 {
331     String text = pasteboard->plainText(m_frame);
332     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
333         replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
334 }
335
336 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
337 {
338     RefPtr<Range> range = selectedRange();
339     bool chosePlainText;
340     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
341     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
342         replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
343 }
344
345 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
346 {
347     return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
348 }
349
350 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
351 {
352     if (!client())
353         return false;
354         
355     Node* child = fragment->firstChild();
356     if (child && fragment->lastChild() == child && child->isCharacterDataNode())
357         return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
358
359     return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
360 }
361
362 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
363 {
364     if (m_frame->selectionController()->isNone() || !fragment)
365         return;
366     
367     applyCommand(new ReplaceSelectionCommand(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
368     revealSelectionAfterEditingOperation();
369 }
370
371 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
372 {
373     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); 
374 }
375
376 PassRefPtr<Range> Editor::selectedRange()
377 {
378     if (!m_frame)
379         return 0;
380     return m_frame->selectionController()->toRange();
381 }
382
383 bool Editor::shouldDeleteRange(Range* range) const
384 {
385     ExceptionCode ec;
386     if (!range || range->collapsed(ec))
387         return false;
388     
389     if (!canDeleteRange(range))
390         return false;
391
392     return client() && client()->shouldDeleteRange(range);
393 }
394
395 bool Editor::tryDHTMLCopy()
396 {   
397     if (m_frame->selectionController()->isInPasswordField())
398         return false;
399
400     // Must be done before oncopy adds types and data to the pboard,
401     // also done for security, as it erases data from the last copy/paste.
402     Pasteboard::generalPasteboard()->clear();
403
404     return !dispatchCPPEvent(copyEvent, ClipboardWritable);
405 }
406
407 bool Editor::tryDHTMLCut()
408 {
409     if (m_frame->selectionController()->isInPasswordField())
410         return false;
411
412     // Must be done before oncut adds types and data to the pboard,
413     // also done for security, as it erases data from the last copy/paste.
414     Pasteboard::generalPasteboard()->clear();
415
416     return !dispatchCPPEvent(cutEvent, ClipboardWritable);
417 }
418
419 bool Editor::tryDHTMLPaste()
420 {
421     return !dispatchCPPEvent(pasteEvent, ClipboardReadable);
422 }
423
424 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
425 {
426     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
427 }
428
429 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
430 {
431     return client() && client()->shouldInsertText(text, range, action);
432 }
433
434 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
435 {
436     return client() && client()->shouldShowDeleteInterface(element);
437 }
438
439 void Editor::respondToChangedSelection(const Selection& oldSelection)
440 {
441     if (client())
442         client()->respondToChangedSelection();
443     m_deleteButtonController->respondToChangedSelection(oldSelection);
444 }
445
446 void Editor::respondToChangedContents(const Selection& endingSelection)
447 {
448     if (AXObjectCache::accessibilityEnabled()) {
449         Node* node = endingSelection.start().node();
450         if (node)
451             m_frame->renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
452     }
453     
454     if (client())
455         client()->respondToChangedContents();  
456 }
457
458 const FontData* Editor::fontForSelection(bool& hasMultipleFonts) const
459 {
460 #if !PLATFORM(QT)
461     hasMultipleFonts = false;
462
463     if (!m_frame->selectionController()->isRange()) {
464         Node* nodeToRemove;
465         RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
466
467         const FontData* result = 0;
468         if (style)
469             result = style->font().primaryFont();
470         
471         if (nodeToRemove) {
472             ExceptionCode ec;
473             nodeToRemove->remove(ec);
474             ASSERT(ec == 0);
475         }
476
477         return result;
478     }
479
480     const FontData* font = 0;
481
482     RefPtr<Range> range = m_frame->selectionController()->toRange();
483     Node* startNode = range->editingStartPosition().node();
484     if (startNode) {
485         Node* pastEnd = range->pastEndNode();
486         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
487         // unreproducible case where this didn't happen, so check for nil also.
488         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
489             RenderObject *renderer = n->renderer();
490             if (!renderer)
491                 continue;
492             // FIXME: Are there any node types that have renderers, but that we should be skipping?
493             const FontData* f = renderer->style()->font().primaryFont();
494             if (!font)
495                 font = f;
496             else if (font != f) {
497                 hasMultipleFonts = true;
498                 break;
499             }
500         }
501     }
502
503     return font;
504 #else
505     return 0;
506 #endif
507 }
508
509 Frame::TriState Editor::selectionUnorderedListState() const
510 {
511     if (m_frame->selectionController()->isCaret()) {
512         Node* selectionNode = m_frame->selectionController()->selection().start().node();
513         if (enclosingNodeWithTag(selectionNode, ulTag))
514             return Frame::trueTriState;
515     } else if (m_frame->selectionController()->isRange()) {
516         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
517         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
518         if (startNode && endNode && startNode == endNode)
519             return Frame::trueTriState;
520     }
521
522     return Frame::falseTriState;
523 }
524
525 Frame::TriState Editor::selectionOrderedListState() const
526 {
527     if (m_frame->selectionController()->isCaret()) {
528         Node* selectionNode = m_frame->selectionController()->selection().start().node();
529         if (enclosingNodeWithTag(selectionNode, olTag))
530             return Frame::trueTriState;
531     } else if (m_frame->selectionController()->isRange()) {
532         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
533         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
534         if (startNode && endNode && startNode == endNode)
535             return Frame::trueTriState;
536     }
537
538     return Frame::falseTriState;
539 }
540
541 PassRefPtr<Node> Editor::insertOrderedList()
542 {
543     if (!canEditRichly())
544         return 0;
545         
546     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
547     revealSelectionAfterEditingOperation();
548     return newList;
549 }
550
551 PassRefPtr<Node> Editor::insertUnorderedList()
552 {
553     if (!canEditRichly())
554         return 0;
555         
556     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
557     revealSelectionAfterEditingOperation();
558     return newList;
559 }
560
561 bool Editor::canIncreaseSelectionListLevel()
562 {
563     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
564 }
565
566 bool Editor::canDecreaseSelectionListLevel()
567 {
568     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
569 }
570
571 PassRefPtr<Node> Editor::increaseSelectionListLevel()
572 {
573     if (!canEditRichly() || m_frame->selectionController()->isNone())
574         return 0;
575     
576     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
577     revealSelectionAfterEditingOperation();
578     return newList;
579 }
580
581 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
582 {
583     if (!canEditRichly() || m_frame->selectionController()->isNone())
584         return 0;
585     
586     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
587     revealSelectionAfterEditingOperation();
588     return newList;
589 }
590
591 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
592 {
593     if (!canEditRichly() || m_frame->selectionController()->isNone())
594         return 0;
595     
596     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
597     revealSelectionAfterEditingOperation();
598     return newList;
599 }
600
601 void Editor::decreaseSelectionListLevel()
602 {
603     if (!canEditRichly() || m_frame->selectionController()->isNone())
604         return;
605     
606     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
607     revealSelectionAfterEditingOperation();
608 }
609
610 void Editor::removeFormattingAndStyle()
611 {
612     Document* document = m_frame->document();
613     
614     // Make a plain text string from the selection to remove formatting like tables and lists.
615     String string = plainText(m_frame->selectionController()->selection().toRange().get());
616
617     // Get the default style for this editable root, it's the style that we'll give the
618     // content that we're operating on.
619     Node* root = m_frame->selectionController()->rootEditableElement();
620     RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(root);
621     RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle->copyInheritableProperties();
622     
623     // Delete the selected content.
624     // FIXME: We should be able to leave this to insertText, but its delete operation
625     // doesn't preserve the style we're about to set.
626     deleteSelectionWithSmartDelete(false);
627     // Normally, deleting a fully selected anchor and then inserting text will re-create
628     // the removed anchor, but we don't want that behavior here. 
629     setRemovedAnchor(0);
630     // Insert the content with the default style.
631     m_frame->setTypingStyle(defaultStyle.get());
632     TypingCommand::insertText(document, string, true);
633 }
634
635 void Editor::setLastEditCommand(PassRefPtr<EditCommand> lastEditCommand) 
636 {
637     m_lastEditCommand = lastEditCommand;
638 }
639
640 // Returns whether caller should continue with "the default processing", which is the same as 
641 // the event handler NOT setting the return value to false
642 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
643 {
644     Node* target = m_frame->selectionController()->start().element();
645     if (!target && m_frame->document())
646         target = m_frame->document()->body();
647     if (!target)
648         return true;
649     target = target->shadowAncestorNode();
650     
651     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
652
653     ExceptionCode ec = 0;
654     RefPtr<Event> evt = new ClipboardEvent(eventType, true, true, clipboard.get());
655     EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
656     bool noDefaultProcessing = evt->defaultPrevented();
657
658     // invalidate clipboard here for security
659     clipboard->setAccessPolicy(ClipboardNumb);
660     
661     return !noDefaultProcessing;
662 }
663
664 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
665 {
666     switch (m_frame->selectionController()->state()) {
667         case Selection::NONE:
668             // do nothing
669             break;
670         case Selection::CARET: {
671             m_frame->computeAndSetTypingStyle(style, editingAction);
672             break;
673         }
674         case Selection::RANGE:
675             if (m_frame->document() && style)
676                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction));
677             break;
678     }
679 }
680     
681 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
682 {   
683     return client()->shouldApplyStyle(style, range);
684 }
685     
686 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
687 {
688     switch (m_frame->selectionController()->state()) {
689         case Selection::NONE:
690             // do nothing
691             break;
692         case Selection::CARET:
693         case Selection::RANGE:
694             if (m_frame->document() && style)
695                 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
696             break;
697     }
698 }
699
700 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
701 {
702     if (!style || style->length() == 0 || !canEditRichly())
703         return;
704
705     if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
706         applyStyle(style, editingAction);
707 }
708
709 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
710 {
711     if (!style || style->length() == 0 || !canEditRichly())
712         return;
713     
714     if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
715         applyParagraphStyle(style, editingAction);
716 }
717
718 bool Editor::clientIsEditable() const
719 {
720     return client() && client()->isEditable();
721 }
722
723 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
724 {
725     Node* nodeToRemove;
726     RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
727     if (!selectionStyle)
728         return false;
729     
730     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
731     
732     bool match = true;
733     DeprecatedValueListConstIterator<CSSProperty> end;
734     for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
735         int propertyID = (*it).id();
736         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
737             match = false;
738             break;
739         }
740     }
741     
742     if (nodeToRemove) {
743         ExceptionCode ec = 0;
744         nodeToRemove->remove(ec);
745         ASSERT(ec == 0);
746     }
747     
748     return match;
749 }
750
751 void Editor::indent()
752 {
753     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Indent));
754 }
755
756 void Editor::outdent()
757 {
758     applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Outdent));
759 }
760
761 static void dispatchEditableContentChangedEvents(const EditCommand& command)
762 {
763     Element* startRoot = command.startingRootEditableElement();
764     Element* endRoot = command.endingRootEditableElement();
765     ExceptionCode ec;
766     if (startRoot)
767         startRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
768     if (endRoot && endRoot != startRoot)
769         endRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
770 }
771
772 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
773 {
774     dispatchEditableContentChangedEvents(*cmd);
775     
776     // FIXME: We shouldn't tell setSelection to clear the typing style or removed anchor here.
777     // If we didn't, we wouldn't have to save/restore the removedAnchor, and we wouldn't have to have
778     // the typing style stored in two places (the Frame and commands).
779     RefPtr<Node> anchor = removedAnchor();
780     
781     Selection newSelection(cmd->endingSelection());
782     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
783     // because there is work that it must do in this situation.
784     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
785         m_frame->selectionController()->setSelection(newSelection, false);
786     
787     setRemovedAnchor(anchor);
788     
789     // Now set the typing style from the command. Clear it when done.
790     // This helps make the case work where you completely delete a piece
791     // of styled text and then type a character immediately after.
792     // That new character needs to take on the style of the just-deleted text.
793     // FIXME: Improve typing style.
794     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
795     if (cmd->typingStyle()) {
796         m_frame->setTypingStyle(cmd->typingStyle());
797         cmd->setTypingStyle(0);
798     }
799     
800     // Command will be equal to last edit command only in the case of typing
801     if (m_lastEditCommand.get() == cmd)
802         ASSERT(cmd->isTypingCommand());
803     else {
804         // Only register a new undo command if the command passed in is
805         // different from the last command
806         m_lastEditCommand = cmd;
807         if (client())
808             client()->registerCommandForUndo(m_lastEditCommand);
809     }
810     respondToChangedContents(newSelection);    
811 }
812
813 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
814 {
815     dispatchEditableContentChangedEvents(*cmd);
816     
817     Selection newSelection(cmd->startingSelection());
818     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
819     // because there is work that it must do in this situation.
820     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
821         m_frame->selectionController()->setSelection(newSelection, true);
822     
823     m_lastEditCommand = 0;
824     if (client())
825         client()->registerCommandForRedo(cmd);
826     respondToChangedContents(newSelection);    
827 }
828
829 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
830 {
831     dispatchEditableContentChangedEvents(*cmd);
832     
833     Selection newSelection(cmd->endingSelection());
834     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
835     // because there is work that it must do in this situation.
836     if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
837         m_frame->selectionController()->setSelection(newSelection, true);
838     
839     m_lastEditCommand = 0;
840     if (client())
841         client()->registerCommandForUndo(cmd);
842     respondToChangedContents(newSelection);    
843 }
844
845 // Execute command functions
846
847 static bool execCopy(Frame* frame, Event*)
848 {
849     frame->editor()->copy();
850     return true;
851 }
852
853 static bool execCut(Frame* frame, Event*)
854 {
855     frame->editor()->cut();
856     return true;
857 }
858
859 static bool execDelete(Frame* frame, Event*)
860 {
861     frame->editor()->performDelete();
862     return true;
863 }
864
865 static bool execDeleteWordBackward(Frame* frame, Event*)
866 {
867     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
868     return true;
869 }
870
871 static bool execDeleteWordForward(Frame* frame, Event*)
872 {
873     frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
874     return true;
875 }
876
877 static bool execBackwardDelete(Frame* frame, Event*)
878 {
879     frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
880     return true;
881 }
882
883 static bool execForwardDelete(Frame* frame, Event*)
884 {
885     frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
886     return true;
887 }
888
889 static bool execMoveBackward(Frame* frame, Event*)
890 {
891     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
892     return true;
893 }
894
895 static bool execMoveBackwardAndModifySelection(Frame* frame, Event*)
896 {
897     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
898     return true;
899 }
900
901 static bool execMoveUpByPageAndModifyCaret(Frame* frame, Event*)
902 {
903     RenderObject* renderer = frame->document()->focusedNode()->renderer();
904     if (renderer->style()->overflowY() == OSCROLL
905         || renderer->style()->overflowY() == OAUTO
906         || renderer->isTextArea()) {
907         int height = -(frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP);
908         bool handledScroll = renderer->scroll(ScrollUp, ScrollByPage);
909         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
910         return handledScroll || handledCaretMove;
911     }
912     return false;
913 }
914
915 static bool execMoveDown(Frame* frame, Event*)
916 {
917     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
918     return true;
919 }
920
921 static bool execMoveDownAndModifySelection(Frame* frame, Event*)
922 {
923     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
924     return true;
925 }
926
927 static bool execMoveForward(Frame* frame, Event*)
928 {
929     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
930     return true;
931 }
932
933 static bool execMoveForwardAndModifySelection(Frame* frame, Event*)
934 {
935     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
936     return true;
937 }
938
939 static bool execMoveDownByPageAndModifyCaret(Frame* frame, Event*)
940 {
941     RenderObject* renderer = frame->document()->focusedNode()->renderer();
942     if (renderer->style()->overflowY() == OSCROLL
943         || renderer->style()->overflowY() == OAUTO
944         || renderer->isTextArea()) {
945         int height = frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP;
946         bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
947         bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
948         return handledScroll || handledCaretMove;
949     }
950     return false;
951 }
952
953 static bool execMoveLeft(Frame* frame, Event*)
954 {
955     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
956     return true;
957 }
958
959 static bool execMoveLeftAndModifySelection(Frame* frame, Event*)
960 {
961     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
962     return true;
963 }
964
965 static bool execMoveRight(Frame* frame, Event*)
966 {
967     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
968     return true;
969 }
970
971 static bool execMoveRightAndModifySelection(Frame* frame, Event*)
972 {
973     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
974     return true;
975 }
976
977 static bool execMoveToBeginningOfDocument(Frame* frame, Event*)
978 {
979     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
980     return true;
981 }
982
983 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*)
984 {
985     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
986     return true;
987 }
988
989 static bool execMoveToBeginningOfSentence(Frame* frame, Event*)
990 {
991     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
992     return true;
993 }
994
995 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*)
996 {
997     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
998     return true;
999 }
1000
1001 static bool execMoveToBeginningOfLine(Frame* frame, Event*)
1002 {
1003     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
1004     return true;
1005 }
1006
1007 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*)
1008 {
1009     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
1010     return true;
1011 }
1012
1013 static bool execMoveToBeginningOfParagraph(Frame* frame, Event*)
1014 {
1015     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
1016     return true;
1017 }
1018
1019 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*)
1020 {
1021     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
1022     return true;
1023 }
1024
1025 static bool execMoveToEndOfDocument(Frame* frame, Event*)
1026 {
1027     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
1028     return true;
1029 }
1030
1031 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*)
1032 {
1033     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
1034     return true;
1035 }
1036
1037 static bool execMoveToEndOfSentence(Frame* frame, Event*)
1038 {
1039     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
1040     return true;
1041 }
1042
1043 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*)
1044 {
1045     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
1046     return true;
1047 }
1048
1049 static bool execMoveToEndOfLine(Frame* frame, Event*)
1050 {
1051     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
1052     return true;
1053 }
1054
1055 static bool execMoveToEndOfLineAndModifySelection(Frame* frame, Event*)
1056 {
1057     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
1058     return true;
1059 }
1060
1061 static bool execMoveToEndOfParagraph(Frame* frame, Event*)
1062 {
1063     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
1064     return true;
1065 }
1066
1067 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*)
1068 {
1069     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
1070     return true;
1071 }
1072
1073 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame, Event*)
1074 {
1075     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
1076     return true;
1077 }
1078
1079 static bool execMoveParagraphForwardAndModifySelection(Frame* frame, Event*)
1080 {
1081     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
1082     return true;
1083 }
1084
1085 static bool execMoveUp(Frame* frame, Event*)
1086 {
1087     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
1088     return true;
1089 }
1090
1091 static bool execMoveUpAndModifySelection(Frame* frame, Event*)
1092 {
1093     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
1094     return true;
1095 }
1096
1097 static bool execMoveWordBackward(Frame* frame, Event*)
1098 {
1099     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
1100     return true;
1101 }
1102
1103 static bool execMoveWordBackwardAndModifySelection(Frame* frame, Event*)
1104 {
1105     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
1106     return true;
1107 }
1108
1109 static bool execMoveWordForward(Frame* frame, Event*)
1110 {
1111     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
1112     return true;
1113 }
1114
1115 static bool execMoveWordForwardAndModifySelection(Frame* frame, Event*)
1116 {
1117     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
1118     return true;
1119 }
1120
1121 static bool execMoveWordLeft(Frame* frame, Event*)
1122 {
1123     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
1124     return true;
1125 }
1126
1127 static bool execMoveWordLeftAndModifySelection(Frame* frame, Event*)
1128 {
1129     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
1130     return true;
1131 }
1132
1133 static bool execMoveWordRight(Frame* frame, Event*)
1134 {
1135     frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
1136     return true;
1137 }
1138
1139 static bool execMoveWordRightAndModifySelection(Frame* frame, Event*)
1140 {
1141     frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
1142     return true;
1143 }
1144
1145 static bool execPaste(Frame* frame, Event*)
1146 {
1147     frame->editor()->paste();
1148     return true;
1149 }
1150
1151 static bool execSelectAll(Frame* frame, Event*)
1152 {
1153     frame->selectionController()->selectAll();
1154     return true;
1155 }
1156
1157 static bool execToggleBold(Frame* frame, Event*)
1158 {
1159     ExceptionCode ec;
1160     
1161     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
1162     style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
1163     if (frame->editor()->selectionStartHasStyle(style.get()))
1164         style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
1165     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
1166     return true;
1167 }
1168
1169 static bool execToggleItalic(Frame* frame, Event*)
1170 {
1171     ExceptionCode ec;
1172     
1173     RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
1174     style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
1175     if (frame->editor()->selectionStartHasStyle(style.get()))
1176         style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
1177     frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
1178     return true;
1179 }
1180
1181 static bool execRedo(Frame* frame, Event*)
1182 {
1183     frame->editor()->redo();
1184     return true;
1185 }
1186
1187 static bool execUndo(Frame* frame, Event*)
1188 {
1189     frame->editor()->undo();
1190     return true;
1191 }
1192
1193 static bool execTranspose(Frame* frame, Event*)
1194 {
1195     frame->editor()->transpose();
1196     return true;
1197 }
1198
1199 static inline Frame* targetFrame(Frame* frame, Event* evt)
1200 {
1201     Node* node = evt ? evt->target()->toNode() : 0;
1202     if (!node)
1203         return frame;
1204     return node->document()->frame();
1205 }
1206
1207 static bool execInsertTab(Frame* frame, Event* evt)
1208 {
1209     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, false);
1210 }
1211
1212 static bool execInsertBacktab(Frame* frame, Event* evt)
1213 {
1214     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, true);
1215 }
1216
1217 static bool execInsertNewline(Frame* frame, Event* evt)
1218 {
1219     Frame* targetFrame = WebCore::targetFrame(frame, evt);
1220     return targetFrame->eventHandler()->handleTextInputEvent("\n", evt, !targetFrame->editor()->canEditRichly());
1221 }
1222
1223 static bool execInsertLineBreak(Frame* frame, Event* evt)
1224 {
1225     return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\n", evt, true);
1226 }
1227
1228 // Enabled functions
1229
1230 static bool enabled(Frame*, Event*)
1231 {
1232     return true;
1233 }
1234
1235 static bool canPaste(Frame* frame, Event*)
1236 {
1237     return frame->editor()->canPaste();
1238 }
1239
1240 static bool hasEditableSelection(Frame* frame, Event* evt)
1241 {
1242     if (evt)
1243         return selectionForEvent(frame, evt).isContentEditable();
1244     return frame->selectionController()->isContentEditable();
1245 }
1246
1247 static bool hasEditableRangeSelection(Frame* frame, Event*)
1248 {
1249     return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
1250 }
1251
1252 static bool hasRangeSelection(Frame* frame, Event*)
1253 {
1254     return frame->selectionController()->isRange();
1255 }
1256
1257 static bool hasRichlyEditableSelection(Frame* frame, Event*)
1258 {
1259     return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
1260 }
1261
1262 static bool canRedo(Frame* frame, Event*)
1263 {
1264     return frame->editor()->canRedo();
1265 }
1266
1267 static bool canUndo(Frame* frame, Event*)
1268 {
1269     return frame->editor()->canUndo();
1270 }
1271
1272 struct Command {
1273     bool (*enabled)(Frame*, Event*);
1274     bool (*exec)(Frame*, Event*);
1275 };
1276
1277 typedef HashMap<RefPtr<AtomicStringImpl>, const Command*> CommandMap;
1278
1279 static CommandMap* createCommandMap()
1280 {
1281     struct CommandEntry { const char* name; Command command; };
1282     
1283     static const CommandEntry commands[] = {
1284         { "BackwardDelete", { hasEditableSelection, execBackwardDelete } },
1285         { "Copy", { hasRangeSelection, execCopy } },
1286         { "Cut", { hasEditableRangeSelection, execCut } },
1287         { "Delete", { hasEditableSelection, execDelete } },
1288         { "DeleteWordBackward", { hasEditableSelection, execDeleteWordBackward } },
1289         { "DeleteWordForward", { hasEditableSelection, execDeleteWordForward} },
1290         { "ForwardDelete", { hasEditableSelection, execForwardDelete } },
1291         { "InsertBacktab", { hasEditableSelection, execInsertBacktab } },
1292         { "InsertTab", { hasEditableSelection, execInsertTab } },
1293         { "InsertLineBreak", { hasEditableSelection, execInsertLineBreak } },        
1294         { "InsertNewline", { hasEditableSelection, execInsertNewline } },        
1295         { "MoveBackward", { hasEditableSelection, execMoveBackward } },
1296         { "MoveBackwardAndModifySelection", { hasEditableSelection, execMoveBackwardAndModifySelection } },
1297         { "MoveUpByPageAndModifyCaret", { hasEditableSelection, execMoveUpByPageAndModifyCaret } },
1298         { "MoveDown", { hasEditableSelection, execMoveDown } },
1299         { "MoveDownAndModifySelection", { hasEditableSelection, execMoveDownAndModifySelection } },
1300         { "MoveForward", { hasEditableSelection, execMoveForward } },
1301         { "MoveForwardAndModifySelection", { hasEditableSelection, execMoveForwardAndModifySelection } },
1302         { "MoveDownByPageAndModifyCaret", { hasEditableSelection, execMoveDownByPageAndModifyCaret } },
1303         { "MoveLeft", { hasEditableSelection, execMoveLeft } },
1304         { "MoveLeftAndModifySelection", { hasEditableSelection, execMoveLeftAndModifySelection } },
1305         { "MoveRight", { hasEditableSelection, execMoveRight } },
1306         { "MoveRightAndModifySelection", { hasEditableSelection, execMoveRightAndModifySelection } },
1307         { "MoveToBeginningOfDocument", { hasEditableSelection, execMoveToBeginningOfDocument } },
1308         { "MoveToBeginningOfDocumentAndModifySelection", { hasEditableSelection, execMoveToBeginningOfDocumentAndModifySelection } },
1309         { "MoveToBeginningOfSentence", { hasEditableSelection, execMoveToBeginningOfSentence } },
1310         { "MoveToBeginningOfSentenceAndModifySelection", { hasEditableSelection, execMoveToBeginningOfSentenceAndModifySelection } },
1311         { "MoveToBeginningOfLine", { hasEditableSelection, execMoveToBeginningOfLine } },
1312         { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfLineAndModifySelection } },
1313         { "MoveToBeginningOfParagraph", { hasEditableSelection, execMoveToBeginningOfParagraph } },
1314         { "MoveToBeginningOfParagraphAndModifySelection", { hasEditableSelection, execMoveToBeginningOfParagraphAndModifySelection } },
1315         { "MoveToEndOfDocument", { hasEditableSelection, execMoveToEndOfDocument } },
1316         { "MoveToEndOfDocumentAndModifySelection", { hasEditableSelection, execMoveToEndOfDocumentAndModifySelection } },
1317         { "MoveToEndOfSentence", { hasEditableSelection, execMoveToEndOfSentence } },
1318         { "MoveToEndOfSentenceAndModifySelection", { hasEditableSelection, execMoveToEndOfSentenceAndModifySelection } },
1319         { "MoveToEndOfLine", { hasEditableSelection, execMoveToEndOfLine } },
1320         { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfLineAndModifySelection } },
1321         { "MoveToEndOfParagraph", { hasEditableSelection, execMoveToEndOfParagraph } },
1322         { "MoveToEndOfParagraphAndModifySelection", { hasEditableSelection, execMoveToEndOfParagraphAndModifySelection } },
1323         { "MoveParagraphBackwardAndModifySelection", { hasEditableSelection, execMoveParagraphBackwardAndModifySelection } },
1324         { "MoveParagraphForwardAndModifySelection", { hasEditableSelection, execMoveParagraphForwardAndModifySelection } },
1325         { "MoveUp", { hasEditableSelection, execMoveUp } },
1326         { "MoveUpAndModifySelection", { hasEditableSelection, execMoveUpAndModifySelection } },
1327         { "MoveWordBackward", { hasEditableSelection, execMoveWordBackward } },
1328         { "MoveWordBackwardAndModifySelection", { hasEditableSelection, execMoveWordBackwardAndModifySelection } },
1329         { "MoveWordForward", { hasEditableSelection, execMoveWordForward } },
1330         { "MoveWordForwardAndModifySelection", { hasEditableSelection, execMoveWordForwardAndModifySelection } },
1331         { "MoveWordLeft", { hasEditableSelection, execMoveWordLeft } },
1332         { "MoveWordLeftAndModifySelection", { hasEditableSelection, execMoveWordLeftAndModifySelection } },
1333         { "MoveWordRight", { hasEditableSelection, execMoveWordRight } },
1334         { "MoveWordRightAndModifySelection", { hasEditableSelection, execMoveWordRightAndModifySelection } },
1335         { "Paste", { canPaste, execPaste } },
1336         { "Redo", { canRedo, execRedo } },
1337         { "SelectAll", { enabled, execSelectAll } },
1338         { "ToggleBold", { hasRichlyEditableSelection, execToggleBold } },
1339         { "ToggleItalic", { hasRichlyEditableSelection, execToggleItalic } },
1340         { "Transpose", { hasEditableSelection, execTranspose } },
1341         { "Undo", { canUndo, execUndo } }
1342     };
1343
1344     CommandMap* commandMap = new CommandMap;
1345
1346     const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
1347     for (unsigned i = 0; i < numCommands; i++)
1348         commandMap->set(AtomicString(commands[i].name).impl(), &commands[i].command);
1349
1350     return commandMap;
1351 }
1352
1353 // =============================================================================
1354 //
1355 // public editing commands
1356 //
1357 // =============================================================================
1358
1359 Editor::Editor(Frame* frame)
1360     : m_frame(frame)
1361     , m_deleteButtonController(new DeleteButtonController(frame))
1362     , m_ignoreCompositionSelectionChange(false)
1363
1364 }
1365
1366 Editor::~Editor()
1367 {
1368 }
1369
1370 void Editor::clear()
1371 {
1372     m_compositionNode = 0;
1373     m_customCompositionUnderlines.clear();
1374 }
1375
1376 bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
1377 {
1378     if (!m_frame->document())
1379         return false;
1380
1381     static CommandMap* commandMap;
1382     if (!commandMap)
1383         commandMap = createCommandMap();
1384     
1385     const Command* c = commandMap->get(command.impl());
1386     if (!c)
1387         return false;
1388     
1389     bool handled = false;
1390     
1391     if (c->enabled(m_frame, triggeringEvent)) {
1392         m_frame->document()->updateLayoutIgnorePendingStylesheets();
1393         handled = c->exec(m_frame, triggeringEvent);
1394     }
1395     
1396     return handled;
1397 }
1398
1399 bool Editor::insertText(const String& text, Event* triggeringEvent)
1400 {
1401     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
1402 }
1403
1404 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
1405 {
1406     if (text.isEmpty())
1407         return false;
1408
1409     Selection selection = selectionForEvent(m_frame, triggeringEvent);
1410     if (!selection.isContentEditable())
1411         return false;
1412     RefPtr<Range> range = selection.toRange();
1413
1414     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
1415         return true;
1416
1417     // Get the selection to use for the event that triggered this insertText.
1418     // If the event handler changed the selection, we may want to use a different selection
1419     // that is contained in the event target.
1420     selection = selectionForEvent(m_frame, triggeringEvent);
1421     if (selection.isContentEditable()) {
1422         if (Node* selectionStart = selection.start().node()) {
1423             RefPtr<Document> document = selectionStart->document();
1424             
1425             // Insert the text
1426             TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
1427
1428             // Reveal the current selection 
1429             if (Frame* editedFrame = document->frame())
1430                 if (Page* page = editedFrame->page())
1431                     page->focusController()->focusedOrMainFrame()->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1432         }
1433     }
1434
1435     return true;
1436 }
1437
1438 bool Editor::insertLineBreak()
1439 {
1440     if (!canEdit())
1441         return false;
1442
1443     if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
1444         return true;
1445
1446     TypingCommand::insertLineBreak(m_frame->document());
1447     revealSelectionAfterEditingOperation();
1448     return true;
1449 }
1450
1451 bool Editor::insertParagraphSeparator()
1452 {
1453     if (!canEdit())
1454         return false;
1455
1456     if (!canEditRichly())
1457         return insertLineBreak();
1458
1459     if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
1460         return true;
1461
1462     TypingCommand::insertParagraphSeparator(m_frame->document());
1463     revealSelectionAfterEditingOperation();
1464     return true;
1465 }
1466
1467 void Editor::cut()
1468 {
1469     if (tryDHTMLCut())
1470         return; // DHTML did the whole operation
1471     if (!canCut()) {
1472         systemBeep();
1473         return;
1474     }
1475     RefPtr<Range> selection = selectedRange();
1476     if (shouldDeleteRange(selection.get())) {
1477         Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
1478         didWriteSelectionToPasteboard();
1479         deleteSelectionWithSmartDelete();
1480     }
1481 }
1482
1483 void Editor::copy()
1484 {
1485     if (tryDHTMLCopy())
1486         return; // DHTML did the whole operation
1487     if (!canCopy()) {
1488         systemBeep();
1489         return;
1490     }
1491     
1492     Document* document = m_frame->document();
1493     if (Node* node = imageNodeFromImageDocument(document))
1494         Pasteboard::generalPasteboard()->writeImage(node, document->URL(), document->title());
1495     else
1496         Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
1497     
1498     didWriteSelectionToPasteboard();
1499 }
1500
1501 void Editor::paste()
1502 {
1503     ASSERT(m_frame->document());
1504     DocLoader* loader = m_frame->document()->docLoader();
1505 #if PLATFORM(MAC)
1506     // using the platform independent code below requires moving all of
1507     // WEBHTMLView: _documentFragmentFromPasteboard over to PasteboardMac.
1508     loader->setAllowStaleResources(true);
1509     m_frame->issuePasteCommand();
1510     loader->setAllowStaleResources(false);
1511 #else
1512     if (tryDHTMLPaste())
1513         return;     // DHTML did the whole operation
1514     if (!canPaste())
1515         return;
1516     loader->setAllowStaleResources(true);
1517     if (m_frame->selectionController()->isContentRichlyEditable())
1518         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
1519     else
1520         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1521     loader->setAllowStaleResources(false);
1522 #endif
1523 }
1524
1525 void Editor::pasteAsPlainText()
1526 {
1527    if (!canPaste())
1528         return;
1529    pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1530 }
1531
1532 void Editor::performDelete()
1533 {
1534     if (!canDelete()) {
1535         systemBeep();
1536         return;
1537     }
1538     deleteRange(selectedRange().get(), true, false, true, deleteSelectionAction, CharacterGranularity);
1539 }
1540
1541 void Editor::copyURL(const KURL& url, const String& title)
1542 {
1543     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
1544 }
1545
1546 void Editor::copyImage(const HitTestResult& result)
1547 {
1548     KURL url = result.absoluteLinkURL();
1549     if (url.isEmpty())
1550         url = result.absoluteImageURL();
1551
1552     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
1553 }
1554
1555 bool Editor::isContinuousSpellCheckingEnabled()
1556 {
1557     return client() && client()->isContinuousSpellCheckingEnabled();
1558 }
1559
1560 void Editor::toggleContinuousSpellChecking()
1561 {
1562     if (client())
1563         client()->toggleContinuousSpellChecking();
1564 }
1565
1566 bool Editor::isGrammarCheckingEnabled()
1567 {
1568     return client() && client()->isGrammarCheckingEnabled();
1569 }
1570
1571 void Editor::toggleGrammarChecking()
1572 {
1573     if (client())
1574         client()->toggleGrammarChecking();
1575 }
1576
1577 int Editor::spellCheckerDocumentTag()
1578 {
1579     return client() ? client()->spellCheckerDocumentTag() : 0;
1580 }
1581
1582 bool Editor::shouldEndEditing(Range* range)
1583 {
1584     return client() && client()->shouldEndEditing(range);
1585 }
1586
1587 bool Editor::shouldBeginEditing(Range* range)
1588 {
1589     return client() && client()->shouldBeginEditing(range);
1590 }
1591
1592 void Editor::clearUndoRedoOperations()
1593 {
1594     if (client())
1595         client()->clearUndoRedoOperations();
1596 }
1597
1598 bool Editor::canUndo()
1599 {
1600     return client() && client()->canUndo();
1601 }
1602
1603 void Editor::undo()
1604 {
1605     if (client())
1606         client()->undo();
1607 }
1608
1609 bool Editor::canRedo()
1610 {
1611     return client() && client()->canRedo();
1612 }
1613
1614 void Editor::redo()
1615 {
1616     if (client())
1617         client()->redo();
1618 }
1619
1620 void Editor::didBeginEditing()
1621 {
1622     if (client())
1623         client()->didBeginEditing();
1624 }
1625
1626 void Editor::didEndEditing()
1627 {
1628     if (client())
1629         client()->didEndEditing();
1630 }
1631
1632 void Editor::didWriteSelectionToPasteboard()
1633 {
1634     if (client())
1635         client()->didWriteSelectionToPasteboard();
1636 }
1637
1638 void Editor::toggleBold()
1639 {
1640     execToggleBold(frame(), 0);
1641 }
1642
1643 void Editor::toggleUnderline()
1644 {
1645     ExceptionCode ec = 0;
1646
1647     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
1648     style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline", false, ec);
1649     if (selectionStartHasStyle(style.get()))
1650         style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", false, ec);
1651     applyStyleToSelection(style.get(), EditActionUnderline);
1652 }
1653
1654 void Editor::setBaseWritingDirection(String direction)
1655 {
1656     ExceptionCode ec = 0;
1657
1658     RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
1659     style->setProperty(CSS_PROP_DIRECTION, direction, false, ec);
1660     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1661 }
1662
1663 void Editor::selectComposition()
1664 {
1665     RefPtr<Range> range = compositionRange();
1666     if (!range)
1667         return;
1668     
1669     // The composition can start inside a composed character sequence, so we have to override checks.
1670     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
1671     Selection selection;
1672     selection.setWithoutValidation(range->startPosition(), range->endPosition());
1673     m_frame->selectionController()->setSelection(selection, false, false);
1674 }
1675
1676 void Editor::confirmComposition()
1677 {
1678     if (!m_compositionNode)
1679         return;
1680     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
1681 }
1682
1683 void Editor::confirmCompositionWithoutDisturbingSelection()
1684 {
1685     if (!m_compositionNode)
1686         return;
1687     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
1688 }
1689
1690 void Editor::confirmComposition(const String& text)
1691 {
1692     confirmComposition(text, false);
1693 }
1694
1695 void Editor::confirmComposition(const String& text, bool preserveSelection)
1696 {
1697     setIgnoreCompositionSelectionChange(true);
1698
1699     Selection oldSelection = m_frame->selectionController()->selection();
1700
1701     selectComposition();
1702
1703     if (m_frame->selectionController()->isNone()) {
1704         setIgnoreCompositionSelectionChange(false);
1705         return;
1706     }
1707     
1708     // If there is a composition to replace, remove it with a deletion that will be part of the
1709     // same Undo step as the next and previous insertions.
1710     TypingCommand::deleteSelection(m_frame->document(), false);
1711
1712     m_compositionNode = 0;
1713     m_customCompositionUnderlines.clear();
1714
1715     insertText(text, 0);
1716
1717     if (preserveSelection)
1718         m_frame->selectionController()->setSelection(oldSelection, false, false);
1719
1720     setIgnoreCompositionSelectionChange(false);
1721 }
1722
1723 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
1724 {
1725     setIgnoreCompositionSelectionChange(true);
1726
1727     selectComposition();
1728
1729     if (m_frame->selectionController()->isNone()) {
1730         setIgnoreCompositionSelectionChange(false);
1731         return;
1732     }
1733     
1734     // If there is a composition to replace, remove it with a deletion that will be part of the
1735     // same Undo step as the next and previous insertions.
1736     TypingCommand::deleteSelection(m_frame->document(), false);
1737
1738     m_compositionNode = 0;
1739     m_customCompositionUnderlines.clear();
1740
1741     if (!text.isEmpty()) {
1742         TypingCommand::insertText(m_frame->document(), text, true, true);
1743
1744         Node* baseNode = m_frame->selectionController()->base().node();
1745         unsigned baseOffset = m_frame->selectionController()->base().offset();
1746         Node* extentNode = m_frame->selectionController()->extent().node();
1747         unsigned extentOffset = m_frame->selectionController()->extent().offset();
1748
1749         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
1750             m_compositionNode = static_cast<Text*>(baseNode);
1751             m_compositionStart = baseOffset;
1752             m_compositionEnd = extentOffset;
1753             m_customCompositionUnderlines = underlines;
1754             size_t numUnderlines = m_customCompositionUnderlines.size();
1755             for (size_t i = 0; i < numUnderlines; ++i) {
1756                 m_customCompositionUnderlines[i].startOffset += baseOffset;
1757                 m_customCompositionUnderlines[i].endOffset += baseOffset;
1758             }
1759             if (baseNode->renderer())
1760                 baseNode->renderer()->repaint();
1761
1762             unsigned start = min(baseOffset + selectionStart, extentOffset);
1763             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
1764             RefPtr<Range> selectedRange = new Range(baseNode->document(), baseNode, start, baseNode, end);                
1765             m_frame->selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
1766         }
1767     }
1768
1769     setIgnoreCompositionSelectionChange(false);
1770 }
1771
1772 void Editor::ignoreSpelling()
1773 {
1774     if (!client())
1775         return;
1776
1777     String text = frame()->selectedText();
1778     ASSERT(text.length() != 0);
1779     client()->ignoreWordInSpellDocument(text);
1780 }
1781
1782 void Editor::learnSpelling()
1783 {
1784     if (!client())
1785         return;
1786
1787     String text = frame()->selectedText();
1788     ASSERT(text.length() != 0);
1789     client()->learnWord(text);
1790 }
1791
1792 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll)
1793 {
1794     ASSERT_ARG(client, client);
1795     ASSERT_ARG(searchRange, searchRange);
1796     
1797     WordAwareIterator it(searchRange);
1798     firstMisspellingOffset = 0;
1799     
1800     String firstMisspelling;
1801     int currentChunkOffset = 0;
1802
1803     while (!it.atEnd()) {
1804         const UChar* chars = it.characters();
1805         int len = it.length();
1806         
1807         // Skip some work for one-space-char hunks
1808         if (!(len == 1 && chars[0] == ' ')) {
1809             
1810             int misspellingLocation = -1;
1811             int misspellingLength = 0;
1812             client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
1813
1814             // 5490627 shows that there was some code path here where the String constructor below crashes.
1815             // We don't know exactly what combination of bad input caused this, so we're making this much
1816             // more robust against bad input on release builds.
1817             ASSERT(misspellingLength >= 0);
1818             ASSERT(misspellingLocation >= -1);
1819             ASSERT(misspellingLength == 0 || misspellingLocation >= 0);
1820             ASSERT(misspellingLocation < len);
1821             ASSERT(misspellingLength <= len);
1822             ASSERT(misspellingLocation + misspellingLength <= len);
1823             
1824             if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
1825                 
1826                 // Remember first-encountered misspelling and its offset
1827                 if (!firstMisspelling) {
1828                     firstMisspellingOffset = currentChunkOffset + misspellingLocation;
1829                     firstMisspelling = String(chars + misspellingLocation, misspellingLength);
1830                 }
1831                 
1832                 // Mark this instance if we're marking all instances. Otherwise bail out because we found the first one.
1833                 if (!markAll)
1834                     break;
1835                 
1836                 // Compute range of misspelled word
1837                 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
1838                 
1839                 // Store marker for misspelled word
1840                 ExceptionCode ec = 0;
1841                 misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1842                 ASSERT(ec == 0);
1843             }
1844         }
1845         
1846         currentChunkOffset += len;
1847         it.advance();
1848     }
1849     
1850     return firstMisspelling;
1851 }
1852
1853 #ifndef BUILDING_ON_TIGER
1854
1855 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
1856 {
1857     ASSERT_ARG(arbitraryRange, arbitraryRange);
1858     
1859     ExceptionCode ec = 0;
1860     
1861     // Expand range to paragraph boundaries
1862     RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
1863     setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
1864     setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
1865     
1866     // Compute offset from start of expanded range to start of original range
1867     RefPtr<Range> offsetAsRange = new Range(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
1868     offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
1869     
1870     // Fill in out parameter with string representing entire paragraph range.
1871     // Someday we might have a caller that doesn't use this, but for now all callers do.
1872     paragraphString = plainText(paragraphRange.get());
1873
1874     return paragraphRange;
1875 }
1876
1877 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int badGrammarPhraseLength, Range *searchRange, int startOffset, int endOffset, bool markAll)
1878 {
1879     // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1880     // Optionally add a DocumentMarker for each detail in the range.
1881     int earliestDetailLocationSoFar = -1;
1882     int earliestDetailIndex = -1;
1883     for (unsigned i = 0; i < grammarDetails.size(); i++) {
1884         const GrammarDetail* detail = &grammarDetails[i];
1885         ASSERT(detail->length > 0 && detail->location >= 0);
1886         
1887         int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
1888         
1889         // Skip this detail if it starts before the original search range
1890         if (detailStartOffsetInParagraph < startOffset)
1891             continue;
1892         
1893         // Skip this detail if it starts after the original search range
1894         if (detailStartOffsetInParagraph >= endOffset)
1895             continue;
1896         
1897         if (markAll) {
1898             RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
1899             ExceptionCode ec = 0;
1900             badGrammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
1901             ASSERT(ec == 0);
1902         }
1903         
1904         // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
1905         if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
1906             earliestDetailIndex = i;
1907             earliestDetailLocationSoFar = detail->location;
1908         }
1909     }
1910     
1911     return earliestDetailIndex;
1912 }
1913     
1914 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
1915 {
1916     ASSERT_ARG(client, client);
1917     ASSERT_ARG(searchRange, searchRange);
1918     
1919     // Initialize out parameters; these will be updated if we find something to return.
1920     outGrammarDetail.location = -1;
1921     outGrammarDetail.length = 0;
1922     outGrammarDetail.guesses.clear();
1923     outGrammarDetail.userDescription = "";
1924     outGrammarPhraseOffset = 0;
1925     
1926     String firstBadGrammarPhrase;
1927
1928     // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
1929     // Determine the character offset from the start of the paragraph to the start of the original search range,
1930     // since we will want to ignore results in this area.
1931     int searchRangeStartOffset;
1932     String paragraphString;
1933     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
1934         
1935     // Determine the character offset from the start of the paragraph to the end of the original search range, 
1936     // since we will want to ignore results in this area also.
1937     int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
1938         
1939     // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
1940     int startOffset = 0;
1941     while (startOffset < searchRangeEndOffset) {
1942         Vector<GrammarDetail> grammarDetails;
1943         int badGrammarPhraseLocation = -1;
1944         int badGrammarPhraseLength = 0;
1945         client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
1946         
1947         if (badGrammarPhraseLength == 0) {
1948             ASSERT(badGrammarPhraseLocation == -1);
1949             return String();
1950         }
1951
1952         ASSERT(badGrammarPhraseLocation >= 0);
1953         badGrammarPhraseLocation += startOffset;
1954
1955         
1956         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1957         int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
1958         if (badGrammarIndex >= 0) {
1959             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
1960             outGrammarDetail = grammarDetails[badGrammarIndex];
1961         }
1962
1963         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
1964         // kept going so we could mark all instances).
1965         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
1966             outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
1967             firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
1968             
1969             // Found one. We're done now, unless we're marking each instance.
1970             if (!markAll)
1971                 break;
1972         }
1973
1974         // These results were all between the start of the paragraph and the start of the search range; look
1975         // beyond this phrase.
1976         startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
1977     }
1978     
1979     return firstBadGrammarPhrase;
1980 }
1981     
1982 #endif /* not BUILDING_ON_TIGER */
1983
1984 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
1985 {
1986     ExceptionCode ec = 0;
1987
1988     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
1989     // then we wrap and search from the doc start to (approximately) where we started.
1990     
1991     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
1992     // repeated "check spelling" commands work.
1993     Selection selection(frame()->selectionController()->selection());
1994     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
1995     bool startedWithSelection = false;
1996     if (selection.start().node()) {
1997         startedWithSelection = true;
1998         if (startBeforeSelection) {
1999             VisiblePosition start(selection.visibleStart());
2000             // We match AppKit's rule: Start 1 character before the selection.
2001             VisiblePosition oneBeforeStart = start.previous();
2002             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
2003         } else
2004             setStart(spellingSearchRange.get(), selection.visibleEnd());
2005     }
2006
2007     Position position = spellingSearchRange->startPosition();
2008     if (!isEditablePosition(position)) {
2009         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
2010         // selection is editable.
2011         // This can happen in Mail for a mix of non-editable and editable content (like Stationary), 
2012         // when spell checking the whole document before sending the message.
2013         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
2014
2015         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
2016         if (position.isNull())
2017             return;
2018         
2019         Position rangeCompliantPosition = rangeCompliantEquivalent(position);
2020         spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.offset(), ec);
2021         startedWithSelection = false;   // won't need to wrap
2022     }
2023     
2024     // topNode defines the whole range we want to operate on 
2025     Node* topNode = highestEditableRoot(position);
2026     spellingSearchRange->setEnd(topNode, maxDeepOffset(topNode), ec);
2027
2028     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
2029     // at a word boundary. Going back by one char and then forward by a word does the trick.
2030     if (startedWithSelection) {
2031         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
2032         if (oneBeforeStart.isNotNull()) {
2033             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
2034         } // else we were already at the start of the editable node
2035     }
2036     
2037     if (spellingSearchRange->collapsed(ec))
2038         return;       // nothing to search in
2039     
2040     // Get the spell checker if it is available
2041     if (!client())
2042         return;
2043         
2044     // We go to the end of our first range instead of the start of it, just to be sure
2045     // we don't get foiled by any word boundary problems at the start.  It means we might
2046     // do a tiny bit more searching.
2047     Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
2048     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
2049     
2050     int misspellingOffset;
2051     String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
2052     
2053     String badGrammarPhrase;
2054
2055 #ifndef BUILDING_ON_TIGER
2056     int grammarPhraseOffset = 0;
2057     GrammarDetail grammarDetail;
2058
2059     // Search for bad grammar that occurs prior to the next misspelled word (if any)
2060     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
2061     if (!misspelledWord.isEmpty()) {
2062         // Stop looking at start of next misspelled word
2063         CharacterIterator chars(grammarSearchRange.get());
2064         chars.advance(misspellingOffset);
2065         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
2066     }
2067     
2068     if (isGrammarCheckingEnabled())
2069         badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
2070 #endif
2071     
2072     // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
2073     // block rather than at a selection).
2074     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
2075         spellingSearchRange->setStart(topNode, 0, ec);
2076         // going until the end of the very first chunk we tested is far enough
2077         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
2078         
2079         misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
2080
2081 #ifndef BUILDING_ON_TIGER
2082         grammarSearchRange = spellingSearchRange->cloneRange(ec);
2083         if (!misspelledWord.isEmpty()) {
2084             // Stop looking at start of next misspelled word
2085             CharacterIterator chars(grammarSearchRange.get());
2086             chars.advance(misspellingOffset);
2087             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
2088         }
2089         if (isGrammarCheckingEnabled())
2090             badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
2091 #endif
2092     }
2093     
2094     if (!badGrammarPhrase.isEmpty()) {
2095 #ifdef BUILDING_ON_TIGER
2096         ASSERT_NOT_REACHED();
2097 #else
2098         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
2099         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
2100         // panel, and store a marker so we draw the green squiggle later.
2101         
2102         ASSERT(badGrammarPhrase.length() > 0);
2103         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
2104         
2105         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
2106         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
2107         frame()->selectionController()->setSelection(Selection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
2108         frame()->revealSelection();
2109         
2110         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
2111         frame()->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
2112 #endif        
2113     } else if (!misspelledWord.isEmpty()) {
2114         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
2115         // a marker so we draw the red squiggle later.
2116         
2117         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
2118         frame()->selectionController()->setSelection(Selection(misspellingRange.get(), DOWNSTREAM));
2119         frame()->revealSelection();
2120         
2121         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
2122         frame()->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
2123     }
2124 }
2125
2126 bool Editor::isSelectionMisspelled()
2127 {
2128     String selectedString = frame()->selectedText();
2129     int length = selectedString.length();
2130     if (length == 0)
2131         return false;
2132
2133     if (!client())
2134         return false;
2135     
2136     int misspellingLocation = -1;
2137     int misspellingLength = 0;
2138     client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
2139     
2140     // The selection only counts as misspelled if the selected text is exactly one misspelled word
2141     if (misspellingLength != length)
2142         return false;
2143     
2144     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
2145     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
2146     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
2147     // or a grammar error.
2148     client()->updateSpellingUIWithMisspelledWord(selectedString);
2149     
2150     return true;
2151 }
2152
2153 #ifndef BUILDING_ON_TIGER
2154 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
2155 {
2156     if (!client)
2157         return false;
2158
2159     ExceptionCode ec;
2160     if (!range || range->collapsed(ec))
2161         return false;
2162     
2163     // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
2164     // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
2165     // or overlapping the range; the ranges must exactly match.
2166     guessesVector.clear();
2167     int grammarPhraseOffset;
2168     
2169     GrammarDetail grammarDetail;
2170     String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);    
2171     
2172     // No bad grammar in these parts at all.
2173     if (badGrammarPhrase.isEmpty())
2174         return false;
2175     
2176     // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
2177     if (grammarPhraseOffset > 0)
2178         return false;
2179     
2180     ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
2181     
2182     // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
2183     if (grammarDetail.location + grammarPhraseOffset != 0)
2184         return false;
2185     
2186     // Bad grammar at start of range, but end of bad grammar is before or after end of range
2187     if (grammarDetail.length != TextIterator::rangeLength(range))
2188         return false;
2189     
2190     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
2191     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
2192     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
2193     // or a grammar error.
2194     client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
2195     
2196     return true;
2197 }
2198 #endif
2199
2200 bool Editor::isSelectionUngrammatical()
2201 {
2202 #ifdef BUILDING_ON_TIGER
2203     return false;
2204 #else
2205     Vector<String> ignoredGuesses;
2206     return isRangeUngrammatical(client(), frame()->selectionController()->toRange().get(), ignoredGuesses);
2207 #endif
2208 }
2209
2210 Vector<String> Editor::guessesForUngrammaticalSelection()
2211 {
2212 #ifdef BUILDING_ON_TIGER
2213     return Vector<String>();
2214 #else
2215     Vector<String> guesses;
2216     // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
2217     isRangeUngrammatical(client(), frame()->selectionController()->toRange().get(), guesses);
2218     return guesses;
2219 #endif
2220 }
2221
2222 Vector<String> Editor::guessesForMisspelledSelection()
2223 {
2224     String selectedString = frame()->selectedText();
2225     ASSERT(selectedString.length() != 0);
2226
2227     Vector<String> guesses;
2228     if (client())
2229         client()->getGuessesForWord(selectedString, guesses);
2230     return guesses;
2231 }
2232
2233 void Editor::showSpellingGuessPanel()
2234 {
2235     if (!client()) {
2236         LOG_ERROR("No NSSpellChecker");
2237         return;
2238     }
2239
2240 #ifndef BUILDING_ON_TIGER
2241     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
2242     // to match rest of OS X.
2243     if (client()->spellingUIIsShowing()) {
2244         client()->showSpellingUI(false);
2245         return;
2246     }
2247 #endif
2248     
2249     advanceToNextMisspelling(true);
2250     client()->showSpellingUI(true);
2251 }
2252
2253 bool Editor::spellingPanelIsShowing()
2254 {
2255     if (!client())
2256         return false;
2257     return client()->spellingUIIsShowing();
2258 }
2259
2260 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
2261 {
2262     if (!isContinuousSpellCheckingEnabled())
2263         return;
2264     
2265     // Check spelling of one word
2266     markMisspellings(Selection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
2267     
2268     if (!isGrammarCheckingEnabled())
2269         return;
2270     
2271     // Check grammar of entire sentence
2272     markBadGrammar(Selection(startOfSentence(p), endOfSentence(p)));
2273 }
2274
2275 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange)
2276 {
2277     // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
2278     // all we need to do is mark every instance.
2279     int ignoredOffset;
2280     findFirstMisspellingInRange(client, searchRange, ignoredOffset, true);
2281 }
2282
2283 #ifndef BUILDING_ON_TIGER
2284 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
2285 {
2286     // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
2287     // do is mark every instance.
2288     GrammarDetail ignoredGrammarDetail;
2289     int ignoredOffset;
2290     findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
2291 }
2292 #endif
2293     
2294 static void markMisspellingsOrBadGrammar(Editor* editor, const Selection& selection, bool checkSpelling)
2295 {
2296     // This function is called with a selection already expanded to word boundaries.
2297     // Might be nice to assert that here.
2298     
2299     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
2300     // grammar checking can only be on if spell checking is also on.
2301     if (!editor->isContinuousSpellCheckingEnabled())
2302         return;
2303     
2304     RefPtr<Range> searchRange(selection.toRange());
2305     if (!searchRange || searchRange->isDetached())
2306         return;
2307     
2308     // If we're not in an editable node, bail.
2309     int exception = 0;
2310     Node *editableNode = searchRange->startContainer(exception);
2311     if (!editableNode->isContentEditable())
2312         return;
2313     
2314     // Get the spell checker if it is available
2315     if (!editor->client())
2316         return;
2317     
2318     if (checkSpelling)
2319         markAllMisspellingsInRange(editor->client(), searchRange.get());
2320     else {
2321 #ifdef BUILDING_ON_TIGER
2322         ASSERT_NOT_REACHED();
2323 #else
2324         if (editor->isGrammarCheckingEnabled())
2325             markAllBadGrammarInRange(editor->client(), searchRange.get());
2326 #endif
2327     }    
2328 }
2329
2330 void Editor::markMisspellings(const Selection& selection)
2331 {
2332     markMisspellingsOrBadGrammar(this, selection, true);
2333 }
2334     
2335 void Editor::markBadGrammar(const Selection& selection)
2336 {
2337 #ifndef BUILDING_ON_TIGER
2338     markMisspellingsOrBadGrammar(this, selection, false);
2339 #endif
2340 }
2341
2342 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
2343 {
2344     Document* document = m_frame->documentAtPoint(windowPoint);
2345     if (!document)
2346         return 0;
2347     
2348     Frame* frame = document->frame();
2349     ASSERT(frame);
2350     FrameView* frameView = frame->view();
2351     if (!frameView)
2352         return 0;
2353     IntPoint framePoint = frameView->windowToContents(windowPoint);
2354     Selection selection(frame->visiblePositionForPoint(framePoint));
2355     return avoidIntersectionWithNode(selection.toRange().get(), deleteButtonController() ? deleteButtonController()->containerElement() : 0);
2356 }
2357
2358 void Editor::revealSelectionAfterEditingOperation()
2359 {
2360     if (m_ignoreCompositionSelectionChange)
2361         return;
2362
2363     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
2364 }
2365
2366 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
2367 {
2368     if (m_ignoreCompositionSelectionChange == ignore)
2369         return;
2370
2371     m_ignoreCompositionSelectionChange = ignore;
2372     if (!ignore)
2373         revealSelectionAfterEditingOperation();
2374 }
2375
2376 PassRefPtr<Range> Editor::compositionRange() const
2377 {
2378     if (!m_compositionNode)
2379         return 0;
2380     unsigned length = m_compositionNode->length();
2381     unsigned start = min(m_compositionStart, length);
2382     unsigned end = min(max(start, m_compositionEnd), length);
2383     if (start >= end)
2384         return 0;
2385     return new Range(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
2386 }
2387
2388 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
2389 {
2390     if (!m_compositionNode)
2391         return false;
2392     Position start = m_frame->selectionController()->start();
2393     if (start.node() != m_compositionNode)
2394         return false;
2395     Position end = m_frame->selectionController()->end();
2396     if (end.node() != m_compositionNode)
2397         return false;
2398
2399     if (static_cast<unsigned>(start.offset()) < m_compositionStart)
2400         return false;
2401     if (static_cast<unsigned>(end.offset()) > m_compositionEnd)
2402         return false;
2403
2404     selectionStart = start.offset() - m_compositionStart;
2405     selectionEnd = start.offset() - m_compositionEnd;
2406     return true;
2407 }
2408
2409 void Editor::transpose()
2410 {
2411     if (!canEdit())
2412         return;
2413
2414      Selection selection = m_frame->selectionController()->selection();
2415      if (!selection.isCaret())
2416          return;
2417
2418     // Make a selection that goes back one character and forward two characters.
2419     VisiblePosition caret = selection.visibleStart();
2420     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
2421     VisiblePosition previous = next.previous();
2422     if (next == previous)
2423         return;
2424     previous = previous.previous();
2425     if (!inSameParagraph(next, previous))
2426         return;
2427     RefPtr<Range> range = makeRange(previous, next);
2428     if (!range)
2429         return;
2430     Selection newSelection(range.get(), DOWNSTREAM);
2431
2432     // Transpose the two characters.
2433     String text = plainText(range.get());
2434     if (text.length() != 2)
2435         return;
2436     String transposed = text.right(1) + text.left(1);
2437
2438     // Select the two characters.
2439     if (newSelection != m_frame->selectionController()->selection()) {
2440         if (!m_frame->shouldChangeSelection(newSelection))
2441             return;
2442         m_frame->selectionController()->setSelection(newSelection);
2443     }
2444
2445     // Insert the transposed characters.
2446     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
2447         return;
2448     replaceSelectionWithText(transposed, false, false);
2449 }
2450
2451 } // namespace WebCore