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