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