WebCore:
[WebKit-https.git] / WebCore / editing / Editor.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 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 "ClipboardEvent.h"
36 #include "DeleteButtonController.h"
37 #include "DeleteSelectionCommand.h"
38 #include "DocLoader.h"
39 #include "DocumentFragment.h"
40 #include "EditorClient.h"
41 #include "EventHandler.h"
42 #include "EventNames.h"
43 #include "FocusController.h"
44 #include "Frame.h"
45 #include "FrameView.h"
46 #include "HTMLInputElement.h"
47 #include "HTMLTextAreaElement.h"
48 #include "HitTestResult.h"
49 #include "IndentOutdentCommand.h"
50 #include "InsertListCommand.h"
51 #include "KeyboardEvent.h"
52 #include "ModifySelectionListLevel.h"
53 #include "Page.h"
54 #include "Pasteboard.h"
55 #include "RemoveFormatCommand.h"
56 #include "ReplaceSelectionCommand.h"
57 #include "Sound.h"
58 #include "Text.h"
59 #include "TextIterator.h"
60 #include "TypingCommand.h"
61 #include "htmlediting.h"
62 #include "markup.h"
63 #include "visible_units.h"
64
65 namespace WebCore {
66
67 using namespace std;
68 using namespace EventNames;
69 using namespace HTMLNames;
70
71 // When an event handler has moved the selection outside of a text control
72 // we should use the target control's selection for this editing operation.
73 Selection Editor::selectionForCommand(Event* event)
74 {
75     Selection selection = m_frame->selection()->selection();
76     if (!event)
77         return selection;
78     // If the target is a text control, and the current selection is outside of its shadow tree,
79     // then use the saved selection for that text control.
80     Node* target = event->target()->toNode();
81     Node* selectionStart = selection.start().node();
82     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
83         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
84             return static_cast<HTMLInputElement*>(target)->selection();
85         if (target->hasTagName(textareaTag))
86             return static_cast<HTMLTextAreaElement*>(target)->selection();
87     }
88     return selection;
89 }
90
91 EditorClient* Editor::client() const
92 {
93     if (Page* page = m_frame->page())
94         return page->editorClient();
95     return 0;
96 }
97
98 void Editor::handleKeyboardEvent(KeyboardEvent* event)
99 {
100     if (EditorClient* c = client())
101         if (selectionForCommand(event).isContentEditable())
102             c->handleKeyboardEvent(event);
103 }
104
105 void Editor::handleInputMethodKeydown(KeyboardEvent* event)
106 {
107     if (EditorClient* c = client())
108         if (selectionForCommand(event).isContentEditable())
109             c->handleInputMethodKeydown(event);
110 }
111
112 bool Editor::canEdit() const
113 {
114     return m_frame->selection()->isContentEditable();
115 }
116
117 bool Editor::canEditRichly() const
118 {
119     return m_frame->selection()->isContentRichlyEditable();
120 }
121
122 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
123 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
124 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
125 // normally selectable to implement copy/paste (like divs, or a document body).
126
127 bool Editor::canDHTMLCut()
128 {
129     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(beforecutEvent, ClipboardNumb);
130 }
131
132 bool Editor::canDHTMLCopy()
133 {
134     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(beforecopyEvent, ClipboardNumb);
135 }
136
137 bool Editor::canDHTMLPaste()
138 {
139     return !dispatchCPPEvent(beforepasteEvent, ClipboardNumb);
140 }
141
142 bool Editor::canCut() const
143 {
144     return canCopy() && canDelete();
145 }
146
147 static HTMLImageElement* imageElementFromImageDocument(Document* document)
148 {
149     if (!document)
150         return 0;
151     if (!document->isImageDocument())
152         return 0;
153     
154     HTMLElement* body = document->body();
155     if (!body)
156         return 0;
157     
158     Node* node = body->firstChild();
159     if (!node)
160         return 0;    
161     if (!node->hasTagName(imgTag))
162         return 0;
163     return static_cast<HTMLImageElement*>(node);
164 }
165
166 bool Editor::canCopy() const
167 {
168     if (imageElementFromImageDocument(m_frame->document()))
169         return true;
170     SelectionController* selection = m_frame->selection();
171     return selection->isRange() && !selection->isInPasswordField();
172 }
173
174 bool Editor::canPaste() const
175 {
176     return canEdit();
177 }
178
179 bool Editor::canDelete() const
180 {
181     SelectionController* selection = m_frame->selection();
182     return selection->isRange() && selection->isContentEditable();
183 }
184
185 bool Editor::canDeleteRange(Range* range) const
186 {
187     ExceptionCode ec = 0;
188     Node* startContainer = range->startContainer(ec);
189     Node* endContainer = range->endContainer(ec);
190     if (!startContainer || !endContainer)
191         return false;
192     
193     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
194         return false;
195     
196     if (range->collapsed(ec)) {
197         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
198         VisiblePosition previous = start.previous();
199         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
200         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
201             return false;
202     }
203     return true;
204 }
205
206 bool Editor::smartInsertDeleteEnabled()
207 {   
208     return client() && client()->smartInsertDeleteEnabled();
209 }
210     
211 bool Editor::canSmartCopyOrDelete()
212 {
213     return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
214 }
215
216 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
217 {
218     // Delete the selection, if there is one.
219     // If not, make a selection using the passed-in direction and granularity.
220
221     if (!canEdit())
222         return false;
223
224     if (m_frame->selection()->isRange()) {
225         if (killRing)
226             addToKillRing(selectedRange().get(), false);
227         if (isTypingAction) {
228             if (m_frame->document()) {
229                 TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity);
230                 revealSelectionAfterEditingOperation();
231             }
232         } else {
233             deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
234             // Implicitly calls revealSelectionAfterEditingOperation().
235         }
236     } else {
237         SelectionController selectionToDelete;
238         selectionToDelete.setSelection(m_frame->selection()->selection());
239         selectionToDelete.modify(SelectionController::EXTEND, direction, granularity);
240         if (killRing && selectionToDelete.isCaret() && granularity != CharacterGranularity)
241             selectionToDelete.modify(SelectionController::EXTEND, direction, CharacterGranularity);
242
243         RefPtr<Range> range = selectionToDelete.toRange();
244
245         if (killRing)
246             addToKillRing(range.get(), false);
247
248         if (!m_frame->selection()->setSelectedRange(range.get(), DOWNSTREAM, (granularity != CharacterGranularity)))
249             return true;
250
251         switch (direction) {
252             case SelectionController::FORWARD:
253             case SelectionController::RIGHT:
254                 if (m_frame->document())
255                     TypingCommand::forwardDeleteKeyPressed(m_frame->document(), false, granularity);
256                 break;
257             case SelectionController::BACKWARD:
258             case SelectionController::LEFT:
259                 if (m_frame->document())
260                     TypingCommand::deleteKeyPressed(m_frame->document(), false, granularity);
261                 break;
262         }
263         revealSelectionAfterEditingOperation();
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     return true;
272 }
273
274 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
275 {
276     if (m_frame->selection()->isNone())
277         return;
278     
279     applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));
280 }
281
282 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
283 {
284     String text = pasteboard->plainText(m_frame);
285     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
286         replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
287 }
288
289 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
290 {
291     RefPtr<Range> range = selectedRange();
292     bool chosePlainText;
293     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
294     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
295         replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
296 }
297
298 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
299 {
300     return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
301 }
302
303 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
304 {
305     if (!client())
306         return false;
307         
308     Node* child = fragment->firstChild();
309     if (child && fragment->lastChild() == child && child->isCharacterDataNode())
310         return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
311
312     return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
313 }
314
315 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
316 {
317     if (m_frame->selection()->isNone() || !fragment)
318         return;
319     
320     applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
321     revealSelectionAfterEditingOperation();
322 }
323
324 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
325 {
326     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); 
327 }
328
329 PassRefPtr<Range> Editor::selectedRange()
330 {
331     if (!m_frame)
332         return 0;
333     return m_frame->selection()->toRange();
334 }
335
336 bool Editor::shouldDeleteRange(Range* range) const
337 {
338     ExceptionCode ec;
339     if (!range || range->collapsed(ec))
340         return false;
341     
342     if (!canDeleteRange(range))
343         return false;
344
345     return client() && client()->shouldDeleteRange(range);
346 }
347
348 bool Editor::tryDHTMLCopy()
349 {   
350     if (m_frame->selection()->isInPasswordField())
351         return false;
352
353     // Must be done before oncopy adds types and data to the pboard,
354     // also done for security, as it erases data from the last copy/paste.
355     Pasteboard::generalPasteboard()->clear();
356
357     return !dispatchCPPEvent(copyEvent, ClipboardWritable);
358 }
359
360 bool Editor::tryDHTMLCut()
361 {
362     if (m_frame->selection()->isInPasswordField())
363         return false;
364
365     // Must be done before oncut adds types and data to the pboard,
366     // also done for security, as it erases data from the last copy/paste.
367     Pasteboard::generalPasteboard()->clear();
368
369     return !dispatchCPPEvent(cutEvent, ClipboardWritable);
370 }
371
372 bool Editor::tryDHTMLPaste()
373 {
374     return !dispatchCPPEvent(pasteEvent, ClipboardReadable);
375 }
376
377 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
378 {
379     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
380 }
381
382 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
383 {
384     return client() && client()->shouldInsertText(text, range, action);
385 }
386
387 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
388 {
389     return client() && client()->shouldShowDeleteInterface(element);
390 }
391
392 void Editor::respondToChangedSelection(const Selection& oldSelection)
393 {
394     if (client())
395         client()->respondToChangedSelection();
396     m_deleteButtonController->respondToChangedSelection(oldSelection);
397 }
398
399 void Editor::respondToChangedContents(const Selection& endingSelection)
400 {
401     if (AXObjectCache::accessibilityEnabled()) {
402         Node* node = endingSelection.start().node();
403         if (node)
404             m_frame->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
405     }
406     
407     if (client())
408         client()->respondToChangedContents();  
409 }
410
411 const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
412 {
413 #if !PLATFORM(QT)
414     hasMultipleFonts = false;
415
416     if (!m_frame->selection()->isRange()) {
417         Node* nodeToRemove;
418         RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
419
420         const SimpleFontData* result = 0;
421         if (style)
422             result = style->font().primaryFont();
423         
424         if (nodeToRemove) {
425             ExceptionCode ec;
426             nodeToRemove->remove(ec);
427             ASSERT(ec == 0);
428         }
429
430         return result;
431     }
432
433     const SimpleFontData* font = 0;
434
435     RefPtr<Range> range = m_frame->selection()->toRange();
436     Node* startNode = range->editingStartPosition().node();
437     if (startNode) {
438         Node* pastEnd = range->pastLastNode();
439         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
440         // unreproducible case where this didn't happen, so check for nil also.
441         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
442             RenderObject *renderer = n->renderer();
443             if (!renderer)
444                 continue;
445             // FIXME: Are there any node types that have renderers, but that we should be skipping?
446             const SimpleFontData* f = renderer->style()->font().primaryFont();
447             if (!font)
448                 font = f;
449             else if (font != f) {
450                 hasMultipleFonts = true;
451                 break;
452             }
453         }
454     }
455
456     return font;
457 #else
458     return 0;
459 #endif
460 }
461
462 TriState Editor::selectionUnorderedListState() const
463 {
464     if (m_frame->selection()->isCaret()) {
465         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag))
466             return TrueTriState;
467     } else if (m_frame->selection()->isRange()) {
468         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag);
469         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag);
470         if (startNode && endNode && startNode == endNode)
471             return TrueTriState;
472     }
473
474     return FalseTriState;
475 }
476
477 TriState Editor::selectionOrderedListState() const
478 {
479     if (m_frame->selection()->isCaret()) {
480         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag))
481             return TrueTriState;
482     } else if (m_frame->selection()->isRange()) {
483         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag);
484         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag);
485         if (startNode && endNode && startNode == endNode)
486             return TrueTriState;
487     }
488
489     return FalseTriState;
490 }
491
492 PassRefPtr<Node> Editor::insertOrderedList()
493 {
494     if (!canEditRichly())
495         return 0;
496         
497     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
498     revealSelectionAfterEditingOperation();
499     return newList;
500 }
501
502 PassRefPtr<Node> Editor::insertUnorderedList()
503 {
504     if (!canEditRichly())
505         return 0;
506         
507     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
508     revealSelectionAfterEditingOperation();
509     return newList;
510 }
511
512 bool Editor::canIncreaseSelectionListLevel()
513 {
514     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
515 }
516
517 bool Editor::canDecreaseSelectionListLevel()
518 {
519     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
520 }
521
522 PassRefPtr<Node> Editor::increaseSelectionListLevel()
523 {
524     if (!canEditRichly() || m_frame->selection()->isNone())
525         return 0;
526     
527     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
528     revealSelectionAfterEditingOperation();
529     return newList;
530 }
531
532 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
533 {
534     if (!canEditRichly() || m_frame->selection()->isNone())
535         return 0;
536     
537     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
538     revealSelectionAfterEditingOperation();
539     return newList;
540 }
541
542 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
543 {
544     if (!canEditRichly() || m_frame->selection()->isNone())
545         return 0;
546     
547     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
548     revealSelectionAfterEditingOperation();
549     return newList;
550 }
551
552 void Editor::decreaseSelectionListLevel()
553 {
554     if (!canEditRichly() || m_frame->selection()->isNone())
555         return;
556     
557     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
558     revealSelectionAfterEditingOperation();
559 }
560
561 void Editor::removeFormattingAndStyle()
562 {
563     applyCommand(RemoveFormatCommand::create(m_frame->document()));
564 }
565
566 void Editor::clearLastEditCommand() 
567 {
568     m_lastEditCommand.clear();
569 }
570
571 // Returns whether caller should continue with "the default processing", which is the same as 
572 // the event handler NOT setting the return value to false
573 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
574 {
575     Node* target = m_frame->selection()->start().element();
576     if (!target && m_frame->document())
577         target = m_frame->document()->body();
578     if (!target)
579         return true;
580     target = target->shadowAncestorNode();
581     
582     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
583
584     ExceptionCode ec = 0;
585     RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
586     EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
587     bool noDefaultProcessing = evt->defaultPrevented();
588
589     // invalidate clipboard here for security
590     clipboard->setAccessPolicy(ClipboardNumb);
591     
592     return !noDefaultProcessing;
593 }
594
595 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
596 {
597     switch (m_frame->selection()->state()) {
598         case Selection::NONE:
599             // do nothing
600             break;
601         case Selection::CARET:
602             m_frame->computeAndSetTypingStyle(style, editingAction);
603             break;
604         case Selection::RANGE:
605             if (m_frame->document() && style)
606                 applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction));
607             break;
608     }
609 }
610     
611 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
612 {   
613     return client()->shouldApplyStyle(style, range);
614 }
615     
616 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
617 {
618     switch (m_frame->selection()->state()) {
619         case Selection::NONE:
620             // do nothing
621             break;
622         case Selection::CARET:
623         case Selection::RANGE:
624             if (m_frame->document() && style)
625                 applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
626             break;
627     }
628 }
629
630 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
631 {
632     if (!style || style->length() == 0 || !canEditRichly())
633         return;
634
635     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toRange().get()))
636         applyStyle(style, editingAction);
637 }
638
639 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
640 {
641     if (!style || style->length() == 0 || !canEditRichly())
642         return;
643     
644     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toRange().get()))
645         applyParagraphStyle(style, editingAction);
646 }
647
648 bool Editor::clientIsEditable() const
649 {
650     return client() && client()->isEditable();
651 }
652
653 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
654 {
655     Node* nodeToRemove;
656     RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
657     if (!selectionStyle)
658         return false;
659     
660     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
661     
662     bool match = true;
663     DeprecatedValueListConstIterator<CSSProperty> end;
664     for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
665         int propertyID = (*it).id();
666         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
667             match = false;
668             break;
669         }
670     }
671     
672     if (nodeToRemove) {
673         ExceptionCode ec = 0;
674         nodeToRemove->remove(ec);
675         ASSERT(ec == 0);
676     }
677     
678     return match;
679 }
680
681 static void updateState(CSSMutableStyleDeclaration* desiredStyle, CSSComputedStyleDeclaration* computedStyle, bool& atStart, TriState& state)
682 {
683     DeprecatedValueListConstIterator<CSSProperty> end;
684     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
685         int propertyID = (*it).id();
686         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
687         String computedProperty = computedStyle->getPropertyValue(propertyID);
688         TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
689             ? TrueTriState : FalseTriState;
690         if (atStart) {
691             state = propertyState;
692             atStart = false;
693         } else if (state != propertyState) {
694             state = MixedTriState;
695             break;
696         }
697     }
698 }
699
700 TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
701 {
702     bool atStart = true;
703     TriState state = FalseTriState;
704
705     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
706
707     if (!m_frame->selection()->isRange()) {
708         Node* nodeToRemove;
709         RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
710         if (!selectionStyle)
711             return FalseTriState;
712         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
713         if (nodeToRemove) {
714             ExceptionCode ec = 0;
715             nodeToRemove->remove(ec);
716             ASSERT(ec == 0);
717         }
718     } else {
719         for (Node* node = m_frame->selection()->start().node(); node; node = node->traverseNextNode()) {
720             RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
721             if (nodeStyle)
722                 updateState(mutableStyle.get(), nodeStyle.get(), atStart, state);
723             if (state == MixedTriState)
724                 break;
725             if (node == m_frame->selection()->end().node())
726                 break;
727         }
728     }
729
730     return state;
731 }
732 void Editor::indent()
733 {
734     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
735 }
736
737 void Editor::outdent()
738 {
739     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent));
740 }
741
742 static void dispatchEditableContentChangedEvents(const EditCommand& command)
743 {
744     Element* startRoot = command.startingRootEditableElement();
745     Element* endRoot = command.endingRootEditableElement();
746     ExceptionCode ec;
747     if (startRoot)
748         startRoot->dispatchEvent(Event::create(webkitEditableContentChangedEvent, false, false), ec, true);
749     if (endRoot && endRoot != startRoot)
750         endRoot->dispatchEvent(Event::create(webkitEditableContentChangedEvent, false, false), ec, true);
751 }
752
753 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
754 {
755     dispatchEditableContentChangedEvents(*cmd);
756     
757     Selection newSelection(cmd->endingSelection());
758     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
759     // because there is work that it must do in this situation.
760     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
761     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
762     // Don't clear the typing style or removedAnchor with this selection change.  We do those things elsewhere if necessary.
763     if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
764         m_frame->selection()->setSelection(newSelection, false, false);
765         
766     if (!cmd->preservesTypingStyle())
767         m_frame->setTypingStyle(0);
768     
769     // Command will be equal to last edit command only in the case of typing
770     if (m_lastEditCommand.get() == cmd)
771         ASSERT(cmd->isTypingCommand());
772     else {
773         // Only register a new undo command if the command passed in is
774         // different from the last command
775         m_lastEditCommand = cmd;
776         if (client())
777             client()->registerCommandForUndo(m_lastEditCommand);
778     }
779     respondToChangedContents(newSelection);    
780 }
781
782 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
783 {
784     dispatchEditableContentChangedEvents(*cmd);
785     
786     Selection newSelection(cmd->startingSelection());
787     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
788     // because there is work that it must do in this situation.
789     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
790     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
791     if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
792         m_frame->selection()->setSelection(newSelection, true);
793     
794     m_lastEditCommand = 0;
795     if (client())
796         client()->registerCommandForRedo(cmd);
797     respondToChangedContents(newSelection);    
798 }
799
800 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
801 {
802     dispatchEditableContentChangedEvents(*cmd);
803     
804     Selection newSelection(cmd->endingSelection());
805     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
806     // because there is work that it must do in this situation.
807     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
808     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
809     if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
810         m_frame->selection()->setSelection(newSelection, true);
811     
812     m_lastEditCommand = 0;
813     if (client())
814         client()->registerCommandForUndo(cmd);
815     respondToChangedContents(newSelection);    
816 }
817
818 Editor::Editor(Frame* frame)
819     : m_frame(frame)
820     , m_deleteButtonController(new DeleteButtonController(frame))
821     , m_ignoreCompositionSelectionChange(false)
822     , m_shouldStartNewKillRingSequence(false)
823
824 }
825
826 Editor::~Editor()
827 {
828 }
829
830 void Editor::clear()
831 {
832     m_compositionNode = 0;
833     m_customCompositionUnderlines.clear();
834 }
835
836 bool Editor::insertText(const String& text, Event* triggeringEvent)
837 {
838     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
839 }
840
841 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
842 {
843     if (text.isEmpty())
844         return false;
845
846     Selection selection = selectionForCommand(triggeringEvent);
847     if (!selection.isContentEditable())
848         return false;
849     RefPtr<Range> range = selection.toRange();
850
851     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
852         return true;
853
854     // Get the selection to use for the event that triggered this insertText.
855     // If the event handler changed the selection, we may want to use a different selection
856     // that is contained in the event target.
857     selection = selectionForCommand(triggeringEvent);
858     if (selection.isContentEditable()) {
859         if (Node* selectionStart = selection.start().node()) {
860             RefPtr<Document> document = selectionStart->document();
861             
862             // Insert the text
863             TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
864
865             // Reveal the current selection 
866             if (Frame* editedFrame = document->frame())
867                 if (Page* page = editedFrame->page())
868                     page->focusController()->focusedOrMainFrame()->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
869         }
870     }
871
872     return true;
873 }
874
875 bool Editor::insertLineBreak()
876 {
877     if (!canEdit())
878         return false;
879
880     if (!shouldInsertText("\n", m_frame->selection()->toRange().get(), EditorInsertActionTyped))
881         return true;
882
883     TypingCommand::insertLineBreak(m_frame->document());
884     revealSelectionAfterEditingOperation();
885     return true;
886 }
887
888 bool Editor::insertParagraphSeparator()
889 {
890     if (!canEdit())
891         return false;
892
893     if (!canEditRichly())
894         return insertLineBreak();
895
896     if (!shouldInsertText("\n", m_frame->selection()->toRange().get(), EditorInsertActionTyped))
897         return true;
898
899     TypingCommand::insertParagraphSeparator(m_frame->document());
900     revealSelectionAfterEditingOperation();
901     return true;
902 }
903
904 void Editor::cut()
905 {
906     if (tryDHTMLCut())
907         return; // DHTML did the whole operation
908     if (!canCut()) {
909         systemBeep();
910         return;
911     }
912     RefPtr<Range> selection = selectedRange();
913     if (shouldDeleteRange(selection.get())) {
914         Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
915         didWriteSelectionToPasteboard();
916         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
917     }
918 }
919
920 void Editor::copy()
921 {
922     if (tryDHTMLCopy())
923         return; // DHTML did the whole operation
924     if (!canCopy()) {
925         systemBeep();
926         return;
927     }
928     
929     Document* document = m_frame->document();
930     if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
931         Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
932     else
933         Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
934     
935     didWriteSelectionToPasteboard();
936 }
937
938 #if !PLATFORM(MAC)
939
940 void Editor::paste()
941 {
942     ASSERT(m_frame->document());
943     if (tryDHTMLPaste())
944         return;     // DHTML did the whole operation
945     if (!canPaste())
946         return;
947     DocLoader* loader = m_frame->document()->docLoader();
948     loader->setAllowStaleResources(true);
949     if (m_frame->selection()->isContentRichlyEditable())
950         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
951     else
952         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
953     loader->setAllowStaleResources(false);
954 }
955
956 #endif
957
958 void Editor::pasteAsPlainText()
959 {
960    if (!canPaste())
961         return;
962    pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
963 }
964
965 void Editor::performDelete()
966 {
967     if (!canDelete()) {
968         systemBeep();
969         return;
970     }
971
972     addToKillRing(selectedRange().get(), false);
973     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
974
975     // clear the "start new kill ring sequence" setting, because it was set to true
976     // when the selection was updated by deleting the range
977     setStartNewKillRingSequence(false);
978 }
979
980 void Editor::copyURL(const KURL& url, const String& title)
981 {
982     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
983 }
984
985 void Editor::copyImage(const HitTestResult& result)
986 {
987     KURL url = result.absoluteLinkURL();
988     if (url.isEmpty())
989         url = result.absoluteImageURL();
990
991     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
992 }
993
994 bool Editor::isContinuousSpellCheckingEnabled()
995 {
996     return client() && client()->isContinuousSpellCheckingEnabled();
997 }
998
999 void Editor::toggleContinuousSpellChecking()
1000 {
1001     if (client())
1002         client()->toggleContinuousSpellChecking();
1003 }
1004
1005 bool Editor::isGrammarCheckingEnabled()
1006 {
1007     return client() && client()->isGrammarCheckingEnabled();
1008 }
1009
1010 void Editor::toggleGrammarChecking()
1011 {
1012     if (client())
1013         client()->toggleGrammarChecking();
1014 }
1015
1016 int Editor::spellCheckerDocumentTag()
1017 {
1018     return client() ? client()->spellCheckerDocumentTag() : 0;
1019 }
1020
1021 bool Editor::shouldEndEditing(Range* range)
1022 {
1023     return client() && client()->shouldEndEditing(range);
1024 }
1025
1026 bool Editor::shouldBeginEditing(Range* range)
1027 {
1028     return client() && client()->shouldBeginEditing(range);
1029 }
1030
1031 void Editor::clearUndoRedoOperations()
1032 {
1033     if (client())
1034         client()->clearUndoRedoOperations();
1035 }
1036
1037 bool Editor::canUndo()
1038 {
1039     return client() && client()->canUndo();
1040 }
1041
1042 void Editor::undo()
1043 {
1044     if (client())
1045         client()->undo();
1046 }
1047
1048 bool Editor::canRedo()
1049 {
1050     return client() && client()->canRedo();
1051 }
1052
1053 void Editor::redo()
1054 {
1055     if (client())
1056         client()->redo();
1057 }
1058
1059 void Editor::didBeginEditing()
1060 {
1061     if (client())
1062         client()->didBeginEditing();
1063 }
1064
1065 void Editor::didEndEditing()
1066 {
1067     if (client())
1068         client()->didEndEditing();
1069 }
1070
1071 void Editor::didWriteSelectionToPasteboard()
1072 {
1073     if (client())
1074         client()->didWriteSelectionToPasteboard();
1075 }
1076
1077 void Editor::toggleBold()
1078 {
1079     command("ToggleBold").execute();
1080 }
1081
1082 void Editor::toggleUnderline()
1083 {
1084     command("ToggleUnderline").execute();
1085 }
1086
1087 void Editor::setBaseWritingDirection(WritingDirection direction)
1088 {
1089     Node* focusedNode = frame()->document()->focusedNode();
1090     if (focusedNode && (focusedNode->hasTagName(textareaTag)
1091                         || focusedNode->hasTagName(inputTag) && (static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::TEXT
1092                                                                 || static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::SEARCH))) {
1093         if (direction == NaturalWritingDirection)
1094             return;
1095         static_cast<HTMLElement*>(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
1096         frame()->document()->updateRendering();
1097         return;
1098     }
1099
1100     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
1101     style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
1102     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1103 }
1104
1105 void Editor::selectComposition()
1106 {
1107     RefPtr<Range> range = compositionRange();
1108     if (!range)
1109         return;
1110     
1111     // The composition can start inside a composed character sequence, so we have to override checks.
1112     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
1113     Selection selection;
1114     selection.setWithoutValidation(range->startPosition(), range->endPosition());
1115     m_frame->selection()->setSelection(selection, false, false);
1116 }
1117
1118 void Editor::confirmComposition()
1119 {
1120     if (!m_compositionNode)
1121         return;
1122     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
1123 }
1124
1125 void Editor::confirmCompositionWithoutDisturbingSelection()
1126 {
1127     if (!m_compositionNode)
1128         return;
1129     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
1130 }
1131
1132 void Editor::confirmComposition(const String& text)
1133 {
1134     confirmComposition(text, false);
1135 }
1136
1137 void Editor::confirmComposition(const String& text, bool preserveSelection)
1138 {
1139     setIgnoreCompositionSelectionChange(true);
1140
1141     Selection oldSelection = m_frame->selection()->selection();
1142
1143     selectComposition();
1144
1145     if (m_frame->selection()->isNone()) {
1146         setIgnoreCompositionSelectionChange(false);
1147         return;
1148     }
1149     
1150     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1151     // will delete the old composition with an optimized replace operation.
1152     if (text.isEmpty())
1153         TypingCommand::deleteSelection(m_frame->document(), false);
1154
1155     m_compositionNode = 0;
1156     m_customCompositionUnderlines.clear();
1157
1158     insertText(text, 0);
1159
1160     if (preserveSelection)
1161         m_frame->selection()->setSelection(oldSelection, false, false);
1162
1163     setIgnoreCompositionSelectionChange(false);
1164 }
1165
1166 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
1167 {
1168     setIgnoreCompositionSelectionChange(true);
1169
1170     selectComposition();
1171
1172     if (m_frame->selection()->isNone()) {
1173         setIgnoreCompositionSelectionChange(false);
1174         return;
1175     }
1176     
1177     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1178     // will delete the old composition with an optimized replace operation.
1179     if (text.isEmpty())
1180         TypingCommand::deleteSelection(m_frame->document(), false);
1181
1182     m_compositionNode = 0;
1183     m_customCompositionUnderlines.clear();
1184
1185     if (!text.isEmpty()) {
1186         TypingCommand::insertText(m_frame->document(), text, true, true);
1187
1188         Node* baseNode = m_frame->selection()->base().node();
1189         unsigned baseOffset = m_frame->selection()->base().offset();
1190         Node* extentNode = m_frame->selection()->extent().node();
1191         unsigned extentOffset = m_frame->selection()->extent().offset();
1192
1193         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
1194             m_compositionNode = static_cast<Text*>(baseNode);
1195             m_compositionStart = baseOffset;
1196             m_compositionEnd = extentOffset;
1197             m_customCompositionUnderlines = underlines;
1198             size_t numUnderlines = m_customCompositionUnderlines.size();
1199             for (size_t i = 0; i < numUnderlines; ++i) {
1200                 m_customCompositionUnderlines[i].startOffset += baseOffset;
1201                 m_customCompositionUnderlines[i].endOffset += baseOffset;
1202             }
1203             if (baseNode->renderer())
1204                 baseNode->renderer()->repaint();
1205
1206             unsigned start = min(baseOffset + selectionStart, extentOffset);
1207             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
1208             RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);                
1209             m_frame->selection()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
1210         }
1211     }
1212
1213     setIgnoreCompositionSelectionChange(false);
1214 }
1215
1216 void Editor::ignoreSpelling()
1217 {
1218     if (!client())
1219         return;
1220
1221     String text = frame()->selectedText();
1222     ASSERT(text.length() != 0);
1223     client()->ignoreWordInSpellDocument(text);
1224 }
1225
1226 void Editor::learnSpelling()
1227 {
1228     if (!client())
1229         return;
1230
1231     String text = frame()->selectedText();
1232     ASSERT(text.length() != 0);
1233     client()->learnWord(text);
1234 }
1235
1236 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll)
1237 {
1238     ASSERT_ARG(client, client);
1239     ASSERT_ARG(searchRange, searchRange);
1240     
1241     WordAwareIterator it(searchRange);
1242     firstMisspellingOffset = 0;
1243     
1244     String firstMisspelling;
1245     int currentChunkOffset = 0;
1246
1247     while (!it.atEnd()) {
1248         const UChar* chars = it.characters();
1249         int len = it.length();
1250         
1251         // Skip some work for one-space-char hunks
1252         if (!(len == 1 && chars[0] == ' ')) {
1253             
1254             int misspellingLocation = -1;
1255             int misspellingLength = 0;
1256             client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
1257
1258             // 5490627 shows that there was some code path here where the String constructor below crashes.
1259             // We don't know exactly what combination of bad input caused this, so we're making this much
1260             // more robust against bad input on release builds.
1261             ASSERT(misspellingLength >= 0);
1262             ASSERT(misspellingLocation >= -1);
1263             ASSERT(misspellingLength == 0 || misspellingLocation >= 0);
1264             ASSERT(misspellingLocation < len);
1265             ASSERT(misspellingLength <= len);
1266             ASSERT(misspellingLocation + misspellingLength <= len);
1267             
1268             if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
1269                 
1270                 // Remember first-encountered misspelling and its offset
1271                 if (!firstMisspelling) {
1272                     firstMisspellingOffset = currentChunkOffset + misspellingLocation;
1273                     firstMisspelling = String(chars + misspellingLocation, misspellingLength);
1274                 }
1275                 
1276                 // Mark this instance if we're marking all instances. Otherwise bail out because we found the first one.
1277                 if (!markAll)
1278                     break;
1279                 
1280                 // Compute range of misspelled word
1281                 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
1282                 
1283                 // Store marker for misspelled word
1284                 ExceptionCode ec = 0;
1285                 misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1286                 ASSERT(ec == 0);
1287             }
1288         }
1289         
1290         currentChunkOffset += len;
1291         it.advance();
1292     }
1293     
1294     return firstMisspelling;
1295 }
1296
1297 #ifndef BUILDING_ON_TIGER
1298
1299 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
1300 {
1301     ASSERT_ARG(arbitraryRange, arbitraryRange);
1302     
1303     ExceptionCode ec = 0;
1304     
1305     // Expand range to paragraph boundaries
1306     RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
1307     setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
1308     setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
1309     
1310     // Compute offset from start of expanded range to start of original range
1311     RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
1312     offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
1313     
1314     // Fill in out parameter with string representing entire paragraph range.
1315     // Someday we might have a caller that doesn't use this, but for now all callers do.
1316     paragraphString = plainText(paragraphRange.get());
1317
1318     return paragraphRange;
1319 }
1320
1321 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int badGrammarPhraseLength, Range *searchRange, int startOffset, int endOffset, bool markAll)
1322 {
1323     // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1324     // Optionally add a DocumentMarker for each detail in the range.
1325     int earliestDetailLocationSoFar = -1;
1326     int earliestDetailIndex = -1;
1327     for (unsigned i = 0; i < grammarDetails.size(); i++) {
1328         const GrammarDetail* detail = &grammarDetails[i];
1329         ASSERT(detail->length > 0 && detail->location >= 0);
1330         
1331         int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
1332         
1333         // Skip this detail if it starts before the original search range
1334         if (detailStartOffsetInParagraph < startOffset)
1335             continue;
1336         
1337         // Skip this detail if it starts after the original search range
1338         if (detailStartOffsetInParagraph >= endOffset)
1339             continue;
1340         
1341         if (markAll) {
1342             RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
1343             ExceptionCode ec = 0;
1344             badGrammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
1345             ASSERT(ec == 0);
1346         }
1347         
1348         // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
1349         if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
1350             earliestDetailIndex = i;
1351             earliestDetailLocationSoFar = detail->location;
1352         }
1353     }
1354     
1355     return earliestDetailIndex;
1356 }
1357     
1358 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
1359 {
1360     ASSERT_ARG(client, client);
1361     ASSERT_ARG(searchRange, searchRange);
1362     
1363     // Initialize out parameters; these will be updated if we find something to return.
1364     outGrammarDetail.location = -1;
1365     outGrammarDetail.length = 0;
1366     outGrammarDetail.guesses.clear();
1367     outGrammarDetail.userDescription = "";
1368     outGrammarPhraseOffset = 0;
1369     
1370     String firstBadGrammarPhrase;
1371
1372     // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
1373     // Determine the character offset from the start of the paragraph to the start of the original search range,
1374     // since we will want to ignore results in this area.
1375     int searchRangeStartOffset;
1376     String paragraphString;
1377     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
1378         
1379     // Determine the character offset from the start of the paragraph to the end of the original search range, 
1380     // since we will want to ignore results in this area also.
1381     int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
1382         
1383     // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
1384     int startOffset = 0;
1385     while (startOffset < searchRangeEndOffset) {
1386         Vector<GrammarDetail> grammarDetails;
1387         int badGrammarPhraseLocation = -1;
1388         int badGrammarPhraseLength = 0;
1389         client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
1390         
1391         if (badGrammarPhraseLength == 0) {
1392             ASSERT(badGrammarPhraseLocation == -1);
1393             return String();
1394         }
1395
1396         ASSERT(badGrammarPhraseLocation >= 0);
1397         badGrammarPhraseLocation += startOffset;
1398
1399         
1400         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1401         int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
1402         if (badGrammarIndex >= 0) {
1403             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
1404             outGrammarDetail = grammarDetails[badGrammarIndex];
1405         }
1406
1407         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
1408         // kept going so we could mark all instances).
1409         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
1410             outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
1411             firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
1412             
1413             // Found one. We're done now, unless we're marking each instance.
1414             if (!markAll)
1415                 break;
1416         }
1417
1418         // These results were all between the start of the paragraph and the start of the search range; look
1419         // beyond this phrase.
1420         startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
1421     }
1422     
1423     return firstBadGrammarPhrase;
1424 }
1425     
1426 #endif /* not BUILDING_ON_TIGER */
1427
1428 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
1429 {
1430     ExceptionCode ec = 0;
1431
1432     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
1433     // then we wrap and search from the doc start to (approximately) where we started.
1434     
1435     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
1436     // repeated "check spelling" commands work.
1437     Selection selection(frame()->selection()->selection());
1438     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
1439     bool startedWithSelection = false;
1440     if (selection.start().node()) {
1441         startedWithSelection = true;
1442         if (startBeforeSelection) {
1443             VisiblePosition start(selection.visibleStart());
1444             // We match AppKit's rule: Start 1 character before the selection.
1445             VisiblePosition oneBeforeStart = start.previous();
1446             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
1447         } else
1448             setStart(spellingSearchRange.get(), selection.visibleEnd());
1449     }
1450
1451     Position position = spellingSearchRange->startPosition();
1452     if (!isEditablePosition(position)) {
1453         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
1454         // selection is editable.
1455         // This can happen in Mail for a mix of non-editable and editable content (like Stationary), 
1456         // when spell checking the whole document before sending the message.
1457         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
1458
1459         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
1460         if (position.isNull())
1461             return;
1462         
1463         Position rangeCompliantPosition = rangeCompliantEquivalent(position);
1464         spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.offset(), ec);
1465         startedWithSelection = false;   // won't need to wrap
1466     }
1467     
1468     // topNode defines the whole range we want to operate on 
1469     Node* topNode = highestEditableRoot(position);
1470     spellingSearchRange->setEnd(topNode, maxDeepOffset(topNode), ec);
1471
1472     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
1473     // at a word boundary. Going back by one char and then forward by a word does the trick.
1474     if (startedWithSelection) {
1475         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
1476         if (oneBeforeStart.isNotNull()) {
1477             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
1478         } // else we were already at the start of the editable node
1479     }
1480     
1481     if (spellingSearchRange->collapsed(ec))
1482         return;       // nothing to search in
1483     
1484     // Get the spell checker if it is available
1485     if (!client())
1486         return;
1487         
1488     // We go to the end of our first range instead of the start of it, just to be sure
1489     // we don't get foiled by any word boundary problems at the start.  It means we might
1490     // do a tiny bit more searching.
1491     Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
1492     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
1493     
1494     int misspellingOffset;
1495     String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
1496     
1497     String badGrammarPhrase;
1498
1499 #ifndef BUILDING_ON_TIGER
1500     int grammarPhraseOffset = 0;
1501     GrammarDetail grammarDetail;
1502
1503     // Search for bad grammar that occurs prior to the next misspelled word (if any)
1504     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
1505     if (!misspelledWord.isEmpty()) {
1506         // Stop looking at start of next misspelled word
1507         CharacterIterator chars(grammarSearchRange.get());
1508         chars.advance(misspellingOffset);
1509         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
1510     }
1511     
1512     if (isGrammarCheckingEnabled())
1513         badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
1514 #endif
1515     
1516     // 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
1517     // block rather than at a selection).
1518     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
1519         spellingSearchRange->setStart(topNode, 0, ec);
1520         // going until the end of the very first chunk we tested is far enough
1521         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
1522         
1523         misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
1524
1525 #ifndef BUILDING_ON_TIGER
1526         grammarSearchRange = spellingSearchRange->cloneRange(ec);
1527         if (!misspelledWord.isEmpty()) {
1528             // Stop looking at start of next misspelled word
1529             CharacterIterator chars(grammarSearchRange.get());
1530             chars.advance(misspellingOffset);
1531             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
1532         }
1533         if (isGrammarCheckingEnabled())
1534             badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
1535 #endif
1536     }
1537     
1538     if (!badGrammarPhrase.isEmpty()) {
1539 #ifdef BUILDING_ON_TIGER
1540         ASSERT_NOT_REACHED();
1541 #else
1542         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
1543         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
1544         // panel, and store a marker so we draw the green squiggle later.
1545         
1546         ASSERT(badGrammarPhrase.length() > 0);
1547         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
1548         
1549         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
1550         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
1551         frame()->selection()->setSelection(Selection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
1552         frame()->revealSelection();
1553         
1554         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
1555         frame()->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
1556 #endif        
1557     } else if (!misspelledWord.isEmpty()) {
1558         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
1559         // a marker so we draw the red squiggle later.
1560         
1561         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
1562         frame()->selection()->setSelection(Selection(misspellingRange.get(), DOWNSTREAM));
1563         frame()->revealSelection();
1564         
1565         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
1566         frame()->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1567     }
1568 }
1569
1570 bool Editor::isSelectionMisspelled()
1571 {
1572     String selectedString = frame()->selectedText();
1573     int length = selectedString.length();
1574     if (length == 0)
1575         return false;
1576
1577     if (!client())
1578         return false;
1579     
1580     int misspellingLocation = -1;
1581     int misspellingLength = 0;
1582     client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
1583     
1584     // The selection only counts as misspelled if the selected text is exactly one misspelled word
1585     if (misspellingLength != length)
1586         return false;
1587     
1588     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
1589     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
1590     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
1591     // or a grammar error.
1592     client()->updateSpellingUIWithMisspelledWord(selectedString);
1593     
1594     return true;
1595 }
1596
1597 #ifndef BUILDING_ON_TIGER
1598 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
1599 {
1600     if (!client)
1601         return false;
1602
1603     ExceptionCode ec;
1604     if (!range || range->collapsed(ec))
1605         return false;
1606     
1607     // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
1608     // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
1609     // or overlapping the range; the ranges must exactly match.
1610     guessesVector.clear();
1611     int grammarPhraseOffset;
1612     
1613     GrammarDetail grammarDetail;
1614     String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);    
1615     
1616     // No bad grammar in these parts at all.
1617     if (badGrammarPhrase.isEmpty())
1618         return false;
1619     
1620     // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
1621     if (grammarPhraseOffset > 0)
1622         return false;
1623     
1624     ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
1625     
1626     // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
1627     if (grammarDetail.location + grammarPhraseOffset != 0)
1628         return false;
1629     
1630     // Bad grammar at start of range, but end of bad grammar is before or after end of range
1631     if (grammarDetail.length != TextIterator::rangeLength(range))
1632         return false;
1633     
1634     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
1635     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
1636     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
1637     // or a grammar error.
1638     client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
1639     
1640     return true;
1641 }
1642 #endif
1643
1644 bool Editor::isSelectionUngrammatical()
1645 {
1646 #ifdef BUILDING_ON_TIGER
1647     return false;
1648 #else
1649     Vector<String> ignoredGuesses;
1650     return isRangeUngrammatical(client(), frame()->selection()->toRange().get(), ignoredGuesses);
1651 #endif
1652 }
1653
1654 Vector<String> Editor::guessesForUngrammaticalSelection()
1655 {
1656 #ifdef BUILDING_ON_TIGER
1657     return Vector<String>();
1658 #else
1659     Vector<String> guesses;
1660     // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
1661     isRangeUngrammatical(client(), frame()->selection()->toRange().get(), guesses);
1662     return guesses;
1663 #endif
1664 }
1665
1666 Vector<String> Editor::guessesForMisspelledSelection()
1667 {
1668     String selectedString = frame()->selectedText();
1669     ASSERT(selectedString.length() != 0);
1670
1671     Vector<String> guesses;
1672     if (client())
1673         client()->getGuessesForWord(selectedString, guesses);
1674     return guesses;
1675 }
1676
1677 void Editor::showSpellingGuessPanel()
1678 {
1679     if (!client()) {
1680         LOG_ERROR("No NSSpellChecker");
1681         return;
1682     }
1683
1684 #ifndef BUILDING_ON_TIGER
1685     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
1686     // to match rest of OS X.
1687     if (client()->spellingUIIsShowing()) {
1688         client()->showSpellingUI(false);
1689         return;
1690     }
1691 #endif
1692     
1693     advanceToNextMisspelling(true);
1694     client()->showSpellingUI(true);
1695 }
1696
1697 bool Editor::spellingPanelIsShowing()
1698 {
1699     if (!client())
1700         return false;
1701     return client()->spellingUIIsShowing();
1702 }
1703
1704 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
1705 {
1706     if (!isContinuousSpellCheckingEnabled())
1707         return;
1708     
1709     // Check spelling of one word
1710     markMisspellings(Selection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
1711     
1712     if (!isGrammarCheckingEnabled())
1713         return;
1714     
1715     // Check grammar of entire sentence
1716     markBadGrammar(Selection(startOfSentence(p), endOfSentence(p)));
1717 }
1718
1719 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange)
1720 {
1721     // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
1722     // all we need to do is mark every instance.
1723     int ignoredOffset;
1724     findFirstMisspellingInRange(client, searchRange, ignoredOffset, true);
1725 }
1726
1727 #ifndef BUILDING_ON_TIGER
1728 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
1729 {
1730     // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
1731     // do is mark every instance.
1732     GrammarDetail ignoredGrammarDetail;
1733     int ignoredOffset;
1734     findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
1735 }
1736 #endif
1737     
1738 static void markMisspellingsOrBadGrammar(Editor* editor, const Selection& selection, bool checkSpelling)
1739 {
1740     // This function is called with a selection already expanded to word boundaries.
1741     // Might be nice to assert that here.
1742     
1743     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
1744     // grammar checking can only be on if spell checking is also on.
1745     if (!editor->isContinuousSpellCheckingEnabled())
1746         return;
1747     
1748     RefPtr<Range> searchRange(selection.toRange());
1749     if (!searchRange)
1750         return;
1751     
1752     // If we're not in an editable node, bail.
1753     Node* editableNode = searchRange->startContainer();
1754     if (!editableNode || !editableNode->isContentEditable())
1755         return;
1756     
1757     // Get the spell checker if it is available
1758     if (!editor->client())
1759         return;
1760     
1761     if (checkSpelling)
1762         markAllMisspellingsInRange(editor->client(), searchRange.get());
1763     else {
1764 #ifdef BUILDING_ON_TIGER
1765         ASSERT_NOT_REACHED();
1766 #else
1767         if (editor->isGrammarCheckingEnabled())
1768             markAllBadGrammarInRange(editor->client(), searchRange.get());
1769 #endif
1770     }    
1771 }
1772
1773 void Editor::markMisspellings(const Selection& selection)
1774 {
1775     markMisspellingsOrBadGrammar(this, selection, true);
1776 }
1777     
1778 void Editor::markBadGrammar(const Selection& selection)
1779 {
1780 #ifndef BUILDING_ON_TIGER
1781     markMisspellingsOrBadGrammar(this, selection, false);
1782 #endif
1783 }
1784
1785 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
1786 {
1787     Document* document = m_frame->documentAtPoint(windowPoint);
1788     if (!document)
1789         return 0;
1790     
1791     Frame* frame = document->frame();
1792     ASSERT(frame);
1793     FrameView* frameView = frame->view();
1794     if (!frameView)
1795         return 0;
1796     IntPoint framePoint = frameView->windowToContents(windowPoint);
1797     Selection selection(frame->visiblePositionForPoint(framePoint));
1798     return avoidIntersectionWithNode(selection.toRange().get(), deleteButtonController() ? deleteButtonController()->containerElement() : 0);
1799 }
1800
1801 void Editor::revealSelectionAfterEditingOperation()
1802 {
1803     if (m_ignoreCompositionSelectionChange)
1804         return;
1805
1806     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1807 }
1808
1809 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
1810 {
1811     if (m_ignoreCompositionSelectionChange == ignore)
1812         return;
1813
1814     m_ignoreCompositionSelectionChange = ignore;
1815     if (!ignore)
1816         revealSelectionAfterEditingOperation();
1817 }
1818
1819 PassRefPtr<Range> Editor::compositionRange() const
1820 {
1821     if (!m_compositionNode)
1822         return 0;
1823     unsigned length = m_compositionNode->length();
1824     unsigned start = min(m_compositionStart, length);
1825     unsigned end = min(max(start, m_compositionEnd), length);
1826     if (start >= end)
1827         return 0;
1828     return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
1829 }
1830
1831 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
1832 {
1833     if (!m_compositionNode)
1834         return false;
1835     Position start = m_frame->selection()->start();
1836     if (start.node() != m_compositionNode)
1837         return false;
1838     Position end = m_frame->selection()->end();
1839     if (end.node() != m_compositionNode)
1840         return false;
1841
1842     if (static_cast<unsigned>(start.offset()) < m_compositionStart)
1843         return false;
1844     if (static_cast<unsigned>(end.offset()) > m_compositionEnd)
1845         return false;
1846
1847     selectionStart = start.offset() - m_compositionStart;
1848     selectionEnd = start.offset() - m_compositionEnd;
1849     return true;
1850 }
1851
1852 void Editor::transpose()
1853 {
1854     if (!canEdit())
1855         return;
1856
1857      Selection selection = m_frame->selection()->selection();
1858      if (!selection.isCaret())
1859          return;
1860
1861     // Make a selection that goes back one character and forward two characters.
1862     VisiblePosition caret = selection.visibleStart();
1863     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
1864     VisiblePosition previous = next.previous();
1865     if (next == previous)
1866         return;
1867     previous = previous.previous();
1868     if (!inSameParagraph(next, previous))
1869         return;
1870     RefPtr<Range> range = makeRange(previous, next);
1871     if (!range)
1872         return;
1873     Selection newSelection(range.get(), DOWNSTREAM);
1874
1875     // Transpose the two characters.
1876     String text = plainText(range.get());
1877     if (text.length() != 2)
1878         return;
1879     String transposed = text.right(1) + text.left(1);
1880
1881     // Select the two characters.
1882     if (newSelection != m_frame->selection()->selection()) {
1883         if (!m_frame->shouldChangeSelection(newSelection))
1884             return;
1885         m_frame->selection()->setSelection(newSelection);
1886     }
1887
1888     // Insert the transposed characters.
1889     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
1890         return;
1891     replaceSelectionWithText(transposed, false, false);
1892 }
1893
1894 void Editor::addToKillRing(Range* range, bool prepend)
1895 {
1896     if (m_shouldStartNewKillRingSequence)
1897         startNewKillRingSequence();
1898
1899     String text = plainText(range);
1900     text.replace('\\', m_frame->backslashAsCurrencySymbol());
1901     if (prepend)
1902         prependToKillRing(text);
1903     else
1904         appendToKillRing(text);
1905     m_shouldStartNewKillRingSequence = false;
1906 }
1907
1908 #if !PLATFORM(MAC)
1909
1910 void Editor::appendToKillRing(const String&)
1911 {
1912 }
1913
1914 void Editor::prependToKillRing(const String&)
1915 {
1916 }
1917
1918 String Editor::yankFromKillRing()
1919 {
1920     return String();
1921 }
1922
1923 void Editor::startNewKillRingSequence()
1924 {
1925 }
1926
1927 void Editor::setKillRingToYankedState()
1928 {
1929 }
1930
1931 #endif
1932
1933 } // namespace WebCore