2009-03-17 Darin Adler <darin@apple.com>
[WebKit-https.git] / WebCore / editing / Editor.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
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 "CSSValueKeywords.h"
36 #include "ClipboardEvent.h"
37 #include "DeleteButtonController.h"
38 #include "DeleteSelectionCommand.h"
39 #include "DocLoader.h"
40 #include "DocumentFragment.h"
41 #include "EditorClient.h"
42 #include "EventHandler.h"
43 #include "EventNames.h"
44 #include "FocusController.h"
45 #include "Frame.h"
46 #include "FrameTree.h"
47 #include "FrameView.h"
48 #include "HTMLInputElement.h"
49 #include "HTMLTextAreaElement.h"
50 #include "HitTestResult.h"
51 #include "IndentOutdentCommand.h"
52 #include "InsertListCommand.h"
53 #include "KeyboardEvent.h"
54 #include "ModifySelectionListLevel.h"
55 #include "Page.h"
56 #include "Pasteboard.h"
57 #include "RemoveFormatCommand.h"
58 #include "RenderBlock.h"
59 #include "RenderPart.h"
60 #include "ReplaceSelectionCommand.h"
61 #include "Sound.h"
62 #include "Text.h"
63 #include "TextIterator.h"
64 #include "TypingCommand.h"
65 #include "htmlediting.h"
66 #include "markup.h"
67 #include "visible_units.h"
68 #include <wtf/UnusedParam.h>
69
70 namespace WebCore {
71
72 using namespace std;
73 using namespace HTMLNames;
74
75 // When an event handler has moved the selection outside of a text control
76 // we should use the target control's selection for this editing operation.
77 VisibleSelection Editor::selectionForCommand(Event* event)
78 {
79     VisibleSelection selection = m_frame->selection()->selection();
80     if (!event)
81         return selection;
82     // If the target is a text control, and the current selection is outside of its shadow tree,
83     // then use the saved selection for that text control.
84     Node* target = event->target()->toNode();
85     Node* selectionStart = selection.start().node();
86     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
87         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
88             return static_cast<HTMLInputElement*>(target)->selection();
89         if (target->hasTagName(textareaTag))
90             return static_cast<HTMLTextAreaElement*>(target)->selection();
91     }
92     return selection;
93 }
94
95 EditorClient* Editor::client() const
96 {
97     if (Page* page = m_frame->page())
98         return page->editorClient();
99     return 0;
100 }
101
102 void Editor::handleKeyboardEvent(KeyboardEvent* event)
103 {
104     if (EditorClient* c = client())
105         c->handleKeyboardEvent(event);
106 }
107
108 void Editor::handleInputMethodKeydown(KeyboardEvent* event)
109 {
110     if (EditorClient* c = client())
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(eventNames().beforecutEvent, ClipboardNumb);
132 }
133
134 bool Editor::canDHTMLCopy()
135 {
136     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb);
137 }
138
139 bool Editor::canDHTMLPaste()
140 {
141     return !dispatchCPPEvent(eventNames().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::isSelectTrailingWhitespaceEnabled()
219 {
220     return client() && client()->isSelectTrailingWhitespaceEnabled();
221 }
222
223 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
224 {
225     if (!canEdit())
226         return false;
227
228     if (m_frame->selection()->isRange()) {
229         if (isTypingAction) {
230             TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity);
231             revealSelectionAfterEditingOperation();
232         } else {
233             if (killRing)
234                 addToKillRing(selectedRange().get(), false);
235             deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
236             // Implicitly calls revealSelectionAfterEditingOperation().
237         }
238     } else {        
239         switch (direction) {
240             case SelectionController::FORWARD:
241             case SelectionController::RIGHT:
242                 TypingCommand::forwardDeleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
243                 break;
244             case SelectionController::BACKWARD:
245             case SelectionController::LEFT:
246                 TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
247                 break;
248         }
249         revealSelectionAfterEditingOperation();
250     }
251
252     // FIXME: We should to move this down into deleteKeyPressed.
253     // clear the "start new kill ring sequence" setting, because it was set to true
254     // when the selection was updated by deleting the range
255     if (killRing)
256         setStartNewKillRingSequence(false);
257
258     return true;
259 }
260
261 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
262 {
263     if (m_frame->selection()->isNone())
264         return;
265     
266     applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));
267 }
268
269 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
270 {
271     String text = pasteboard->plainText(m_frame);
272     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
273         replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
274 }
275
276 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
277 {
278     RefPtr<Range> range = selectedRange();
279     bool chosePlainText;
280     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
281     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
282         replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
283 }
284
285 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
286 {
287     return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
288 }
289
290 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
291 {
292     if (!client())
293         return false;
294         
295     Node* child = fragment->firstChild();
296     if (child && fragment->lastChild() == child && child->isCharacterDataNode())
297         return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
298
299     return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
300 }
301
302 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
303 {
304     if (m_frame->selection()->isNone() || !fragment)
305         return;
306     
307     applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
308     revealSelectionAfterEditingOperation();
309 }
310
311 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
312 {
313     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); 
314 }
315
316 PassRefPtr<Range> Editor::selectedRange()
317 {
318     if (!m_frame)
319         return 0;
320     return m_frame->selection()->toNormalizedRange();
321 }
322
323 bool Editor::shouldDeleteRange(Range* range) const
324 {
325     ExceptionCode ec;
326     if (!range || range->collapsed(ec))
327         return false;
328     
329     if (!canDeleteRange(range))
330         return false;
331
332     return client() && client()->shouldDeleteRange(range);
333 }
334
335 bool Editor::tryDHTMLCopy()
336 {   
337     if (m_frame->selection()->isInPasswordField())
338         return false;
339
340     // Must be done before oncopy adds types and data to the pboard,
341     // also done for security, as it erases data from the last copy/paste.
342     Pasteboard::generalPasteboard()->clear();
343
344     return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);
345 }
346
347 bool Editor::tryDHTMLCut()
348 {
349     if (m_frame->selection()->isInPasswordField())
350         return false;
351
352     // Must be done before oncut adds types and data to the pboard,
353     // also done for security, as it erases data from the last copy/paste.
354     Pasteboard::generalPasteboard()->clear();
355
356     return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable);
357 }
358
359 bool Editor::tryDHTMLPaste()
360 {
361     return !dispatchCPPEvent(eventNames().pasteEvent, ClipboardReadable);
362 }
363
364 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
365 {
366     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
367 }
368
369 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
370 {
371     return client() && client()->shouldInsertText(text, range, action);
372 }
373
374 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
375 {
376     return client() && client()->shouldShowDeleteInterface(element);
377 }
378
379 void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
380 {
381     if (client())
382         client()->respondToChangedSelection();
383     m_deleteButtonController->respondToChangedSelection(oldSelection);
384 }
385
386 void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
387 {
388     if (AXObjectCache::accessibilityEnabled()) {
389         Node* node = endingSelection.start().node();
390         if (node)
391             m_frame->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
392     }
393     
394     if (client())
395         client()->respondToChangedContents();  
396 }
397
398 const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
399 {
400 #if !PLATFORM(QT)
401     hasMultipleFonts = false;
402
403     if (!m_frame->selection()->isRange()) {
404         Node* nodeToRemove;
405         RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
406
407         const SimpleFontData* result = 0;
408         if (style)
409             result = style->font().primaryFont();
410         
411         if (nodeToRemove) {
412             ExceptionCode ec;
413             nodeToRemove->remove(ec);
414             ASSERT(ec == 0);
415         }
416
417         return result;
418     }
419
420     const SimpleFontData* font = 0;
421
422     RefPtr<Range> range = m_frame->selection()->toNormalizedRange();
423     Node* startNode = range->editingStartPosition().node();
424     if (startNode) {
425         Node* pastEnd = range->pastLastNode();
426         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
427         // unreproducible case where this didn't happen, so check for nil also.
428         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
429             RenderObject *renderer = n->renderer();
430             if (!renderer)
431                 continue;
432             // FIXME: Are there any node types that have renderers, but that we should be skipping?
433             const SimpleFontData* f = renderer->style()->font().primaryFont();
434             if (!font)
435                 font = f;
436             else if (font != f) {
437                 hasMultipleFonts = true;
438                 break;
439             }
440         }
441     }
442
443     return font;
444 #else
445     return 0;
446 #endif
447 }
448
449 WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbeddings) const
450 {
451     hasNestedOrMultipleEmbeddings = true;
452
453     if (m_frame->selection()->isNone())
454         return NaturalWritingDirection;
455
456     Position pos = m_frame->selection()->selection().start().downstream();
457
458     Node* node = pos.node();
459     if (!node)
460         return NaturalWritingDirection;
461
462     Position end;
463     if (m_frame->selection()->isRange()) {
464         end = m_frame->selection()->selection().end().upstream();
465
466         Node* pastLast = Range::create(m_frame->document(), rangeCompliantEquivalent(pos), rangeCompliantEquivalent(end))->pastLastNode();
467         for (Node* n = node; n && n != pastLast; n = n->traverseNextNode()) {
468             if (!n->isStyledElement())
469                 continue;
470
471             RefPtr<CSSComputedStyleDeclaration> style = computedStyle(n);
472             RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
473             if (!unicodeBidi)
474                 continue;
475
476             ASSERT(unicodeBidi->isPrimitiveValue());
477             int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
478             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
479                 return NaturalWritingDirection;
480         }
481     }
482
483     if (m_frame->selection()->isCaret()) {
484         if (CSSMutableStyleDeclaration *typingStyle = m_frame->typingStyle()) {
485             RefPtr<CSSValue> unicodeBidi = typingStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
486             if (unicodeBidi) {
487                 ASSERT(unicodeBidi->isPrimitiveValue());
488                 int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
489                 if (unicodeBidiValue == CSSValueEmbed) {
490                     RefPtr<CSSValue> direction = typingStyle->getPropertyCSSValue(CSSPropertyDirection);
491                     ASSERT(!direction || direction->isPrimitiveValue());
492                     if (direction) {
493                         hasNestedOrMultipleEmbeddings = false;
494                         return static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
495                     }
496                 } else if (unicodeBidiValue == CSSValueNormal) {
497                     hasNestedOrMultipleEmbeddings = false;
498                     return NaturalWritingDirection;
499                 }
500             }
501         }
502         node = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
503     }
504
505     // The selection is either a caret with no typing attributes or a range in which no embedding is added, so just use the start position
506     // to decide.
507     Node* block = enclosingBlock(node);
508     WritingDirection foundDirection = NaturalWritingDirection;
509
510     for (; node != block; node = node->parent()) {
511         if (!node->isStyledElement())
512             continue;
513
514         RefPtr<CSSComputedStyleDeclaration> style = computedStyle(node);
515         RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
516         if (!unicodeBidi)
517             continue;
518
519         ASSERT(unicodeBidi->isPrimitiveValue());
520         int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
521         if (unicodeBidiValue == CSSValueNormal)
522             continue;
523
524         if (unicodeBidiValue == CSSValueBidiOverride)
525             return NaturalWritingDirection;
526
527         ASSERT(unicodeBidiValue == CSSValueEmbed);
528         RefPtr<CSSValue> direction = style->getPropertyCSSValue(CSSPropertyDirection);
529         if (!direction)
530             continue;
531
532         ASSERT(direction->isPrimitiveValue());
533         int directionValue = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent();
534         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
535             continue;
536
537         if (foundDirection != NaturalWritingDirection)
538             return NaturalWritingDirection;
539
540         // In the range case, make sure that the embedding element persists until the end of the range.
541         if (m_frame->selection()->isRange() && !end.node()->isDescendantOf(node))
542             return NaturalWritingDirection;
543
544         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
545     }
546     hasNestedOrMultipleEmbeddings = false;
547     return foundDirection;
548 }
549
550 bool Editor::hasBidiSelection() const
551 {
552     if (m_frame->selection()->isNone())
553         return false;
554
555     Node* startNode;
556     if (m_frame->selection()->isRange()) {
557         startNode = m_frame->selection()->selection().start().downstream().node();
558         Node* endNode = m_frame->selection()->selection().end().upstream().node();
559         if (enclosingBlock(startNode) != enclosingBlock(endNode))
560             return false;
561     } else
562         startNode = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
563
564     RenderObject* renderer = startNode->renderer();
565     while (renderer && !renderer->isRenderBlock())
566         renderer = renderer->parent();
567
568     if (!renderer)
569         return false;
570
571     RenderStyle* style = renderer->style();
572     if (style->direction() == RTL)
573         return true;
574
575     return toRenderBlock(renderer)->containsNonZeroBidiLevel();
576 }
577
578 TriState Editor::selectionUnorderedListState() const
579 {
580     if (m_frame->selection()->isCaret()) {
581         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag))
582             return TrueTriState;
583     } else if (m_frame->selection()->isRange()) {
584         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag);
585         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag);
586         if (startNode && endNode && startNode == endNode)
587             return TrueTriState;
588     }
589
590     return FalseTriState;
591 }
592
593 TriState Editor::selectionOrderedListState() const
594 {
595     if (m_frame->selection()->isCaret()) {
596         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag))
597             return TrueTriState;
598     } else if (m_frame->selection()->isRange()) {
599         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag);
600         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag);
601         if (startNode && endNode && startNode == endNode)
602             return TrueTriState;
603     }
604
605     return FalseTriState;
606 }
607
608 PassRefPtr<Node> Editor::insertOrderedList()
609 {
610     if (!canEditRichly())
611         return 0;
612         
613     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
614     revealSelectionAfterEditingOperation();
615     return newList;
616 }
617
618 PassRefPtr<Node> Editor::insertUnorderedList()
619 {
620     if (!canEditRichly())
621         return 0;
622         
623     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
624     revealSelectionAfterEditingOperation();
625     return newList;
626 }
627
628 bool Editor::canIncreaseSelectionListLevel()
629 {
630     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
631 }
632
633 bool Editor::canDecreaseSelectionListLevel()
634 {
635     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
636 }
637
638 PassRefPtr<Node> Editor::increaseSelectionListLevel()
639 {
640     if (!canEditRichly() || m_frame->selection()->isNone())
641         return 0;
642     
643     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
644     revealSelectionAfterEditingOperation();
645     return newList;
646 }
647
648 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
649 {
650     if (!canEditRichly() || m_frame->selection()->isNone())
651         return 0;
652     
653     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
654     revealSelectionAfterEditingOperation();
655     return newList;
656 }
657
658 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
659 {
660     if (!canEditRichly() || m_frame->selection()->isNone())
661         return 0;
662     
663     PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
664     revealSelectionAfterEditingOperation();
665     return newList;
666 }
667
668 void Editor::decreaseSelectionListLevel()
669 {
670     if (!canEditRichly() || m_frame->selection()->isNone())
671         return;
672     
673     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
674     revealSelectionAfterEditingOperation();
675 }
676
677 void Editor::removeFormattingAndStyle()
678 {
679     applyCommand(RemoveFormatCommand::create(m_frame->document()));
680 }
681
682 void Editor::clearLastEditCommand() 
683 {
684     m_lastEditCommand.clear();
685 }
686
687 // Returns whether caller should continue with "the default processing", which is the same as 
688 // the event handler NOT setting the return value to false
689 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
690 {
691     Node* target = m_frame->selection()->start().element();
692     if (!target)
693         target = m_frame->document()->body();
694     if (!target)
695         return true;
696     target = target->shadowAncestorNode();
697     
698     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
699
700     ExceptionCode ec = 0;
701     RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
702     target->dispatchEvent(evt, ec);
703     bool noDefaultProcessing = evt->defaultPrevented();
704
705     // invalidate clipboard here for security
706     clipboard->setAccessPolicy(ClipboardNumb);
707     
708     return !noDefaultProcessing;
709 }
710
711 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
712 {
713     switch (m_frame->selection()->selectionType()) {
714         case VisibleSelection::NoSelection:
715             // do nothing
716             break;
717         case VisibleSelection::CaretSelection:
718             m_frame->computeAndSetTypingStyle(style, editingAction);
719             break;
720         case VisibleSelection::RangeSelection:
721             if (style)
722                 applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction));
723             break;
724     }
725 }
726     
727 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
728 {   
729     return client()->shouldApplyStyle(style, range);
730 }
731     
732 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
733 {
734     switch (m_frame->selection()->selectionType()) {
735         case VisibleSelection::NoSelection:
736             // do nothing
737             break;
738         case VisibleSelection::CaretSelection:
739         case VisibleSelection::RangeSelection:
740             if (style)
741                 applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
742             break;
743     }
744 }
745
746 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
747 {
748     if (!style || style->length() == 0 || !canEditRichly())
749         return;
750
751     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
752         applyStyle(style, editingAction);
753 }
754
755 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
756 {
757     if (!style || style->length() == 0 || !canEditRichly())
758         return;
759     
760     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
761         applyParagraphStyle(style, editingAction);
762 }
763
764 bool Editor::clientIsEditable() const
765 {
766     return client() && client()->isEditable();
767 }
768
769 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
770 {
771     Node* nodeToRemove;
772     RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
773     if (!selectionStyle)
774         return false;
775     
776     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
777     
778     bool match = true;
779     CSSMutableStyleDeclaration::const_iterator end = mutableStyle->end();
780     for (CSSMutableStyleDeclaration::const_iterator it = mutableStyle->begin(); it != end; ++it) {
781         int propertyID = (*it).id();
782         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
783             match = false;
784             break;
785         }
786     }
787     
788     if (nodeToRemove) {
789         ExceptionCode ec = 0;
790         nodeToRemove->remove(ec);
791         ASSERT(ec == 0);
792     }
793     
794     return match;
795 }
796
797 static void updateState(CSSMutableStyleDeclaration* desiredStyle, CSSComputedStyleDeclaration* computedStyle, bool& atStart, TriState& state)
798 {
799     CSSMutableStyleDeclaration::const_iterator end = desiredStyle->end();
800     for (CSSMutableStyleDeclaration::const_iterator it = desiredStyle->begin(); it != end; ++it) {
801         int propertyID = (*it).id();
802         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
803         String computedProperty = computedStyle->getPropertyValue(propertyID);
804         TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
805             ? TrueTriState : FalseTriState;
806         if (atStart) {
807             state = propertyState;
808             atStart = false;
809         } else if (state != propertyState) {
810             state = MixedTriState;
811             break;
812         }
813     }
814 }
815
816 TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
817 {
818     bool atStart = true;
819     TriState state = FalseTriState;
820
821     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
822
823     if (!m_frame->selection()->isRange()) {
824         Node* nodeToRemove;
825         RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
826         if (!selectionStyle)
827             return FalseTriState;
828         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
829         if (nodeToRemove) {
830             ExceptionCode ec = 0;
831             nodeToRemove->remove(ec);
832             ASSERT(ec == 0);
833         }
834     } else {
835         for (Node* node = m_frame->selection()->start().node(); node; node = node->traverseNextNode()) {
836             RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
837             if (nodeStyle)
838                 updateState(mutableStyle.get(), nodeStyle.get(), atStart, state);
839             if (state == MixedTriState)
840                 break;
841             if (node == m_frame->selection()->end().node())
842                 break;
843         }
844     }
845
846     return state;
847 }
848 void Editor::indent()
849 {
850     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
851 }
852
853 void Editor::outdent()
854 {
855     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent));
856 }
857
858 static void dispatchEditableContentChangedEvents(const EditCommand& command)
859 {
860     Element* startRoot = command.startingRootEditableElement();
861     Element* endRoot = command.endingRootEditableElement();
862     ExceptionCode ec;
863     if (startRoot)
864         startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
865     if (endRoot && endRoot != startRoot)
866         endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
867 }
868
869 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
870 {
871     dispatchEditableContentChangedEvents(*cmd);
872     
873     VisibleSelection newSelection(cmd->endingSelection());
874     // Don't clear the typing style with this selection change.  We do those things elsewhere if necessary.
875     changeSelectionAfterCommand(newSelection, false, false, cmd.get());
876         
877     if (!cmd->preservesTypingStyle())
878         m_frame->setTypingStyle(0);
879     
880     // Command will be equal to last edit command only in the case of typing
881     if (m_lastEditCommand.get() == cmd)
882         ASSERT(cmd->isTypingCommand());
883     else {
884         // Only register a new undo command if the command passed in is
885         // different from the last command
886         m_lastEditCommand = cmd;
887         if (client())
888             client()->registerCommandForUndo(m_lastEditCommand);
889     }
890     respondToChangedContents(newSelection);    
891 }
892
893 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
894 {
895     dispatchEditableContentChangedEvents(*cmd);
896     
897     VisibleSelection newSelection(cmd->startingSelection());
898     changeSelectionAfterCommand(newSelection, true, true, cmd.get());
899     
900     m_lastEditCommand = 0;
901     if (client())
902         client()->registerCommandForRedo(cmd);
903     respondToChangedContents(newSelection);    
904 }
905
906 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
907 {
908     dispatchEditableContentChangedEvents(*cmd);
909     
910     VisibleSelection newSelection(cmd->endingSelection());
911     changeSelectionAfterCommand(newSelection, true, true, cmd.get());
912     
913     m_lastEditCommand = 0;
914     if (client())
915         client()->registerCommandForUndo(cmd);
916     respondToChangedContents(newSelection);    
917 }
918
919 Editor::Editor(Frame* frame)
920     : m_frame(frame)
921     , m_deleteButtonController(new DeleteButtonController(frame))
922     , m_ignoreCompositionSelectionChange(false)
923     , m_shouldStartNewKillRingSequence(false)
924     // This is off by default, since most editors want this behavior (this matches IE but not FF).
925     , m_shouldStyleWithCSS(false)
926
927 }
928
929 Editor::~Editor()
930 {
931 }
932
933 void Editor::clear()
934 {
935     m_compositionNode = 0;
936     m_customCompositionUnderlines.clear();
937     m_shouldStyleWithCSS = false;
938 }
939
940 bool Editor::insertText(const String& text, Event* triggeringEvent)
941 {
942     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
943 }
944
945 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
946 {
947     if (text.isEmpty())
948         return false;
949
950     VisibleSelection selection = selectionForCommand(triggeringEvent);
951     if (!selection.isContentEditable())
952         return false;
953     RefPtr<Range> range = selection.toNormalizedRange();
954
955     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
956         return true;
957
958     // Get the selection to use for the event that triggered this insertText.
959     // If the event handler changed the selection, we may want to use a different selection
960     // that is contained in the event target.
961     selection = selectionForCommand(triggeringEvent);
962     if (selection.isContentEditable()) {
963         if (Node* selectionStart = selection.start().node()) {
964             RefPtr<Document> document = selectionStart->document();
965             
966             // Insert the text
967             TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
968
969             // Reveal the current selection 
970             if (Frame* editedFrame = document->frame())
971                 if (Page* page = editedFrame->page())
972                     page->focusController()->focusedOrMainFrame()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
973         }
974     }
975
976     return true;
977 }
978
979 bool Editor::insertLineBreak()
980 {
981     if (!canEdit())
982         return false;
983
984     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
985         return true;
986
987     TypingCommand::insertLineBreak(m_frame->document());
988     revealSelectionAfterEditingOperation();
989     return true;
990 }
991
992 bool Editor::insertParagraphSeparator()
993 {
994     if (!canEdit())
995         return false;
996
997     if (!canEditRichly())
998         return insertLineBreak();
999
1000     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
1001         return true;
1002
1003     TypingCommand::insertParagraphSeparator(m_frame->document());
1004     revealSelectionAfterEditingOperation();
1005     return true;
1006 }
1007
1008 void Editor::cut()
1009 {
1010     if (tryDHTMLCut())
1011         return; // DHTML did the whole operation
1012     if (!canCut()) {
1013         systemBeep();
1014         return;
1015     }
1016     RefPtr<Range> selection = selectedRange();
1017     if (shouldDeleteRange(selection.get())) {
1018         Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
1019         didWriteSelectionToPasteboard();
1020         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1021     }
1022 }
1023
1024 void Editor::copy()
1025 {
1026     if (tryDHTMLCopy())
1027         return; // DHTML did the whole operation
1028     if (!canCopy()) {
1029         systemBeep();
1030         return;
1031     }
1032     
1033     Document* document = m_frame->document();
1034     if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
1035         Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
1036     else
1037         Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
1038     
1039     didWriteSelectionToPasteboard();
1040 }
1041
1042 #if !PLATFORM(MAC)
1043
1044 void Editor::paste()
1045 {
1046     ASSERT(m_frame->document());
1047     if (tryDHTMLPaste())
1048         return;     // DHTML did the whole operation
1049     if (!canPaste())
1050         return;
1051     DocLoader* loader = m_frame->document()->docLoader();
1052     loader->setAllowStaleResources(true);
1053     if (m_frame->selection()->isContentRichlyEditable())
1054         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
1055     else
1056         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1057     loader->setAllowStaleResources(false);
1058 }
1059
1060 #endif
1061
1062 void Editor::pasteAsPlainText()
1063 {
1064    if (!canPaste())
1065         return;
1066    pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1067 }
1068
1069 void Editor::performDelete()
1070 {
1071     if (!canDelete()) {
1072         systemBeep();
1073         return;
1074     }
1075
1076     addToKillRing(selectedRange().get(), false);
1077     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1078
1079     // clear the "start new kill ring sequence" setting, because it was set to true
1080     // when the selection was updated by deleting the range
1081     setStartNewKillRingSequence(false);
1082 }
1083
1084 void Editor::copyURL(const KURL& url, const String& title)
1085 {
1086     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
1087 }
1088
1089 void Editor::copyImage(const HitTestResult& result)
1090 {
1091     KURL url = result.absoluteLinkURL();
1092     if (url.isEmpty())
1093         url = result.absoluteImageURL();
1094
1095     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
1096 }
1097
1098 bool Editor::isContinuousSpellCheckingEnabled()
1099 {
1100     return client() && client()->isContinuousSpellCheckingEnabled();
1101 }
1102
1103 void Editor::toggleContinuousSpellChecking()
1104 {
1105     if (client())
1106         client()->toggleContinuousSpellChecking();
1107 }
1108
1109 bool Editor::isGrammarCheckingEnabled()
1110 {
1111     return client() && client()->isGrammarCheckingEnabled();
1112 }
1113
1114 void Editor::toggleGrammarChecking()
1115 {
1116     if (client())
1117         client()->toggleGrammarChecking();
1118 }
1119
1120 int Editor::spellCheckerDocumentTag()
1121 {
1122     return client() ? client()->spellCheckerDocumentTag() : 0;
1123 }
1124
1125 bool Editor::shouldEndEditing(Range* range)
1126 {
1127     return client() && client()->shouldEndEditing(range);
1128 }
1129
1130 bool Editor::shouldBeginEditing(Range* range)
1131 {
1132     return client() && client()->shouldBeginEditing(range);
1133 }
1134
1135 void Editor::clearUndoRedoOperations()
1136 {
1137     if (client())
1138         client()->clearUndoRedoOperations();
1139 }
1140
1141 bool Editor::canUndo()
1142 {
1143     return client() && client()->canUndo();
1144 }
1145
1146 void Editor::undo()
1147 {
1148     if (client())
1149         client()->undo();
1150 }
1151
1152 bool Editor::canRedo()
1153 {
1154     return client() && client()->canRedo();
1155 }
1156
1157 void Editor::redo()
1158 {
1159     if (client())
1160         client()->redo();
1161 }
1162
1163 void Editor::didBeginEditing()
1164 {
1165     if (client())
1166         client()->didBeginEditing();
1167 }
1168
1169 void Editor::didEndEditing()
1170 {
1171     if (client())
1172         client()->didEndEditing();
1173 }
1174
1175 void Editor::didWriteSelectionToPasteboard()
1176 {
1177     if (client())
1178         client()->didWriteSelectionToPasteboard();
1179 }
1180
1181 void Editor::toggleBold()
1182 {
1183     command("ToggleBold").execute();
1184 }
1185
1186 void Editor::toggleUnderline()
1187 {
1188     command("ToggleUnderline").execute();
1189 }
1190
1191 void Editor::setBaseWritingDirection(WritingDirection direction)
1192 {
1193     Node* focusedNode = frame()->document()->focusedNode();
1194     if (focusedNode && (focusedNode->hasTagName(textareaTag)
1195                         || focusedNode->hasTagName(inputTag) && (static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::TEXT
1196                                                                 || static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::SEARCH))) {
1197         if (direction == NaturalWritingDirection)
1198             return;
1199         static_cast<HTMLElement*>(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
1200         frame()->document()->updateRendering();
1201         return;
1202     }
1203
1204     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
1205     style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
1206     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1207 }
1208
1209 void Editor::selectComposition()
1210 {
1211     RefPtr<Range> range = compositionRange();
1212     if (!range)
1213         return;
1214     
1215     // The composition can start inside a composed character sequence, so we have to override checks.
1216     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
1217     VisibleSelection selection;
1218     selection.setWithoutValidation(range->startPosition(), range->endPosition());
1219     m_frame->selection()->setSelection(selection, false, false);
1220 }
1221
1222 void Editor::confirmComposition()
1223 {
1224     if (!m_compositionNode)
1225         return;
1226     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
1227 }
1228
1229 void Editor::confirmCompositionWithoutDisturbingSelection()
1230 {
1231     if (!m_compositionNode)
1232         return;
1233     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
1234 }
1235
1236 void Editor::confirmComposition(const String& text)
1237 {
1238     confirmComposition(text, false);
1239 }
1240
1241 void Editor::confirmComposition(const String& text, bool preserveSelection)
1242 {
1243     setIgnoreCompositionSelectionChange(true);
1244
1245     VisibleSelection oldSelection = m_frame->selection()->selection();
1246
1247     selectComposition();
1248
1249     if (m_frame->selection()->isNone()) {
1250         setIgnoreCompositionSelectionChange(false);
1251         return;
1252     }
1253     
1254     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1255     // will delete the old composition with an optimized replace operation.
1256     if (text.isEmpty())
1257         TypingCommand::deleteSelection(m_frame->document(), false);
1258
1259     m_compositionNode = 0;
1260     m_customCompositionUnderlines.clear();
1261
1262     insertText(text, 0);
1263
1264     if (preserveSelection)
1265         m_frame->selection()->setSelection(oldSelection, false, false);
1266
1267     setIgnoreCompositionSelectionChange(false);
1268 }
1269
1270 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
1271 {
1272     setIgnoreCompositionSelectionChange(true);
1273
1274     selectComposition();
1275
1276     if (m_frame->selection()->isNone()) {
1277         setIgnoreCompositionSelectionChange(false);
1278         return;
1279     }
1280     
1281     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1282     // will delete the old composition with an optimized replace operation.
1283     if (text.isEmpty())
1284         TypingCommand::deleteSelection(m_frame->document(), false);
1285
1286     m_compositionNode = 0;
1287     m_customCompositionUnderlines.clear();
1288
1289     if (!text.isEmpty()) {
1290         TypingCommand::insertText(m_frame->document(), text, true, true);
1291
1292         Node* baseNode = m_frame->selection()->base().node();
1293         unsigned baseOffset = m_frame->selection()->base().m_offset;
1294         Node* extentNode = m_frame->selection()->extent().node();
1295         unsigned extentOffset = m_frame->selection()->extent().m_offset;
1296
1297         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
1298             m_compositionNode = static_cast<Text*>(baseNode);
1299             m_compositionStart = baseOffset;
1300             m_compositionEnd = extentOffset;
1301             m_customCompositionUnderlines = underlines;
1302             size_t numUnderlines = m_customCompositionUnderlines.size();
1303             for (size_t i = 0; i < numUnderlines; ++i) {
1304                 m_customCompositionUnderlines[i].startOffset += baseOffset;
1305                 m_customCompositionUnderlines[i].endOffset += baseOffset;
1306             }
1307             if (baseNode->renderer())
1308                 baseNode->renderer()->repaint();
1309
1310             unsigned start = min(baseOffset + selectionStart, extentOffset);
1311             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
1312             RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);                
1313             m_frame->selection()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
1314         }
1315     }
1316
1317     setIgnoreCompositionSelectionChange(false);
1318 }
1319
1320 void Editor::ignoreSpelling()
1321 {
1322     if (!client())
1323         return;
1324         
1325     RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange();
1326     if (selectedRange)
1327         frame()->document()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
1328
1329     String text = frame()->selectedText();
1330     ASSERT(text.length() != 0);
1331     client()->ignoreWordInSpellDocument(text);
1332 }
1333
1334 void Editor::learnSpelling()
1335 {
1336     if (!client())
1337         return;
1338         
1339     // FIXME: We don't call this on the Mac, and it should remove misppelling markers around the 
1340     // learned word, see <rdar://problem/5396072>.
1341
1342     String text = frame()->selectedText();
1343     ASSERT(text.length() != 0);
1344     client()->learnWord(text);
1345 }
1346
1347 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll)
1348 {
1349     ASSERT_ARG(client, client);
1350     ASSERT_ARG(searchRange, searchRange);
1351     
1352     WordAwareIterator it(searchRange);
1353     firstMisspellingOffset = 0;
1354     
1355     String firstMisspelling;
1356     int currentChunkOffset = 0;
1357
1358     while (!it.atEnd()) {
1359         const UChar* chars = it.characters();
1360         int len = it.length();
1361         
1362         // Skip some work for one-space-char hunks
1363         if (!(len == 1 && chars[0] == ' ')) {
1364             
1365             int misspellingLocation = -1;
1366             int misspellingLength = 0;
1367             client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
1368
1369             // 5490627 shows that there was some code path here where the String constructor below crashes.
1370             // We don't know exactly what combination of bad input caused this, so we're making this much
1371             // more robust against bad input on release builds.
1372             ASSERT(misspellingLength >= 0);
1373             ASSERT(misspellingLocation >= -1);
1374             ASSERT(misspellingLength == 0 || misspellingLocation >= 0);
1375             ASSERT(misspellingLocation < len);
1376             ASSERT(misspellingLength <= len);
1377             ASSERT(misspellingLocation + misspellingLength <= len);
1378             
1379             if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
1380                 
1381                 // Remember first-encountered misspelling and its offset
1382                 if (!firstMisspelling) {
1383                     firstMisspellingOffset = currentChunkOffset + misspellingLocation;
1384                     firstMisspelling = String(chars + misspellingLocation, misspellingLength);
1385                 }
1386                 
1387                 // Mark this instance if we're marking all instances. Otherwise bail out because we found the first one.
1388                 if (!markAll)
1389                     break;
1390                 
1391                 // Compute range of misspelled word
1392                 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
1393                 
1394                 // Store marker for misspelled word
1395                 ExceptionCode ec = 0;
1396                 misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1397                 ASSERT(ec == 0);
1398             }
1399         }
1400         
1401         currentChunkOffset += len;
1402         it.advance();
1403     }
1404     
1405     return firstMisspelling;
1406 }
1407
1408 #ifndef BUILDING_ON_TIGER
1409
1410 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
1411 {
1412     ASSERT_ARG(arbitraryRange, arbitraryRange);
1413     
1414     ExceptionCode ec = 0;
1415     
1416     // Expand range to paragraph boundaries
1417     RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
1418     setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
1419     setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
1420     
1421     // Compute offset from start of expanded range to start of original range
1422     RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
1423     offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
1424     
1425     // Fill in out parameter with string representing entire paragraph range.
1426     // Someday we might have a caller that doesn't use this, but for now all callers do.
1427     paragraphString = plainText(paragraphRange.get());
1428
1429     return paragraphRange;
1430 }
1431
1432 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, Range *searchRange, int startOffset, int endOffset, bool markAll)
1433 {
1434     // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1435     // Optionally add a DocumentMarker for each detail in the range.
1436     int earliestDetailLocationSoFar = -1;
1437     int earliestDetailIndex = -1;
1438     for (unsigned i = 0; i < grammarDetails.size(); i++) {
1439         const GrammarDetail* detail = &grammarDetails[i];
1440         ASSERT(detail->length > 0 && detail->location >= 0);
1441         
1442         int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
1443         
1444         // Skip this detail if it starts before the original search range
1445         if (detailStartOffsetInParagraph < startOffset)
1446             continue;
1447         
1448         // Skip this detail if it starts after the original search range
1449         if (detailStartOffsetInParagraph >= endOffset)
1450             continue;
1451         
1452         if (markAll) {
1453             RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
1454             ExceptionCode ec = 0;
1455             badGrammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
1456             ASSERT(ec == 0);
1457         }
1458         
1459         // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
1460         if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
1461             earliestDetailIndex = i;
1462             earliestDetailLocationSoFar = detail->location;
1463         }
1464     }
1465     
1466     return earliestDetailIndex;
1467 }
1468     
1469 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
1470 {
1471     ASSERT_ARG(client, client);
1472     ASSERT_ARG(searchRange, searchRange);
1473     
1474     // Initialize out parameters; these will be updated if we find something to return.
1475     outGrammarDetail.location = -1;
1476     outGrammarDetail.length = 0;
1477     outGrammarDetail.guesses.clear();
1478     outGrammarDetail.userDescription = "";
1479     outGrammarPhraseOffset = 0;
1480     
1481     String firstBadGrammarPhrase;
1482
1483     // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
1484     // Determine the character offset from the start of the paragraph to the start of the original search range,
1485     // since we will want to ignore results in this area.
1486     int searchRangeStartOffset;
1487     String paragraphString;
1488     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
1489         
1490     // Determine the character offset from the start of the paragraph to the end of the original search range, 
1491     // since we will want to ignore results in this area also.
1492     int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
1493         
1494     // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
1495     int startOffset = 0;
1496     while (startOffset < searchRangeEndOffset) {
1497         Vector<GrammarDetail> grammarDetails;
1498         int badGrammarPhraseLocation = -1;
1499         int badGrammarPhraseLength = 0;
1500         client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
1501         
1502         if (badGrammarPhraseLength == 0) {
1503             ASSERT(badGrammarPhraseLocation == -1);
1504             return String();
1505         }
1506
1507         ASSERT(badGrammarPhraseLocation >= 0);
1508         badGrammarPhraseLocation += startOffset;
1509
1510         
1511         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1512         int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
1513         if (badGrammarIndex >= 0) {
1514             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
1515             outGrammarDetail = grammarDetails[badGrammarIndex];
1516         }
1517
1518         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
1519         // kept going so we could mark all instances).
1520         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
1521             outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
1522             firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
1523             
1524             // Found one. We're done now, unless we're marking each instance.
1525             if (!markAll)
1526                 break;
1527         }
1528
1529         // These results were all between the start of the paragraph and the start of the search range; look
1530         // beyond this phrase.
1531         startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
1532     }
1533     
1534     return firstBadGrammarPhrase;
1535 }
1536     
1537 #endif /* not BUILDING_ON_TIGER */
1538
1539 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1540
1541 static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Range* searchRange, bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
1542 {
1543     ASSERT_ARG(client, client);
1544     ASSERT_ARG(searchRange, searchRange);
1545     
1546     String firstFoundItem;
1547     String misspelledWord;
1548     String badGrammarPhrase;
1549     ExceptionCode ec = 0;
1550     
1551     // Initialize out parameters; these will be updated if we find something to return.
1552     outIsSpelling = true;
1553     outFirstFoundOffset = 0;
1554     outGrammarDetail.location = -1;
1555     outGrammarDetail.length = 0;
1556     outGrammarDetail.guesses.clear();
1557     outGrammarDetail.userDescription = "";
1558     
1559     // Expand the search range to encompass entire paragraphs, since text checking needs that much context.
1560     // Determine the character offset from the start of the paragraph to the start of the original search range,
1561     // since we will want to ignore results in this area.
1562     RefPtr<Range> paragraphRange = searchRange->cloneRange(ec);
1563     setStart(paragraphRange.get(), startOfParagraph(searchRange->startPosition()));
1564     int totalRangeLength = TextIterator::rangeLength(paragraphRange.get());
1565     setEnd(paragraphRange.get(), endOfParagraph(searchRange->startPosition()));
1566     
1567     RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->startPosition());
1568     int searchRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
1569     int totalLengthProcessed = 0;
1570     
1571     bool firstIteration = true;
1572     bool lastIteration = false;
1573     while (totalLengthProcessed < totalRangeLength) {
1574         // Iterate through the search range by paragraphs, checking each one for spelling and grammar.
1575         int currentLength = TextIterator::rangeLength(paragraphRange.get());
1576         int currentStartOffset = firstIteration ? searchRangeStartOffset : 0;
1577         int currentEndOffset = currentLength;
1578         if (inSameParagraph(paragraphRange->startPosition(), searchRange->endPosition())) {
1579             // Determine the character offset from the end of the original search range to the end of the paragraph,
1580             // since we will want to ignore results in this area.
1581             RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->endPosition());
1582             currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get());
1583             lastIteration = true;
1584         }
1585         if (currentStartOffset < currentEndOffset) {
1586             String paragraphString = plainText(paragraphRange.get());
1587             if (paragraphString.length() > 0) {
1588                 bool foundGrammar = false;
1589                 int spellingLocation = 0;
1590                 int grammarPhraseLocation = 0;
1591                 int grammarDetailLocation = 0;
1592                 unsigned grammarDetailIndex = 0;
1593                 
1594                 Vector<TextCheckingResult> results;
1595                 client->checkSpellingAndGrammarOfParagraph(paragraphString.characters(), paragraphString.length(), checkGrammar, results);
1596                 
1597                 for (unsigned i = 0; i < results.size(); i++) {
1598                     const TextCheckingResult* result = &results[i];
1599                     if (result->resultType == 1 && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) {
1600                         ASSERT(result->length > 0 && result->location >= 0);
1601                         spellingLocation = result->location;
1602                         misspelledWord = paragraphString.substring(result->location, result->length);
1603                         ASSERT(misspelledWord.length() != 0);
1604                         break;
1605                     } else if (checkGrammar && result->resultType == 2 && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
1606                         ASSERT(result->length > 0 && result->location >= 0);
1607                         // We can't stop after the first grammar result, since there might still be a spelling result after
1608                         // it begins but before the first detail in it, but we can stop if we find a second grammar result.
1609                         if (foundGrammar) break;
1610                         for (unsigned j = 0; j < result->details.size(); j++) {
1611                             const GrammarDetail* detail = &result->details[j];
1612                             ASSERT(detail->length > 0 && detail->location >= 0);
1613                             if (result->location + detail->location >= currentStartOffset && result->location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result->location + detail->location < grammarDetailLocation)) {
1614                                 grammarDetailIndex = j;
1615                                 grammarDetailLocation = result->location + detail->location;
1616                                 foundGrammar = true;
1617                             }
1618                         }
1619                         if (foundGrammar) {
1620                             grammarPhraseLocation = result->location;
1621                             outGrammarDetail = result->details[grammarDetailIndex];
1622                             badGrammarPhrase = paragraphString.substring(result->location, result->length);
1623                             ASSERT(badGrammarPhrase.length() != 0);
1624                         }
1625                     }
1626                 }
1627
1628                 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
1629                     int spellingOffset = spellingLocation - currentStartOffset;
1630                     if (!firstIteration) {
1631                         RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
1632                         spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
1633                     }
1634                     outIsSpelling = true;
1635                     outFirstFoundOffset = spellingOffset;
1636                     firstFoundItem = misspelledWord;
1637                     break;
1638                 } else if (checkGrammar && !badGrammarPhrase.isEmpty()) {
1639                     int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
1640                     if (!firstIteration) {
1641                         RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
1642                         grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
1643                     }
1644                     outIsSpelling = false;
1645                     outFirstFoundOffset = grammarPhraseOffset;
1646                     firstFoundItem = badGrammarPhrase;
1647                     break;
1648                 }
1649             }
1650         }
1651         if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
1652             break;
1653         setStart(paragraphRange.get(), startOfNextParagraph(paragraphRange->endPosition()));
1654         setEnd(paragraphRange.get(), endOfParagraph(paragraphRange->startPosition()));
1655         firstIteration = false;
1656         totalLengthProcessed += currentLength;
1657     }
1658     return firstFoundItem;
1659 }
1660
1661 #endif
1662
1663 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
1664 {
1665     ExceptionCode ec = 0;
1666
1667     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
1668     // then we wrap and search from the doc start to (approximately) where we started.
1669     
1670     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
1671     // repeated "check spelling" commands work.
1672     VisibleSelection selection(frame()->selection()->selection());
1673     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
1674     bool startedWithSelection = false;
1675     if (selection.start().node()) {
1676         startedWithSelection = true;
1677         if (startBeforeSelection) {
1678             VisiblePosition start(selection.visibleStart());
1679             // We match AppKit's rule: Start 1 character before the selection.
1680             VisiblePosition oneBeforeStart = start.previous();
1681             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
1682         } else
1683             setStart(spellingSearchRange.get(), selection.visibleEnd());
1684     }
1685
1686     Position position = spellingSearchRange->startPosition();
1687     if (!isEditablePosition(position)) {
1688         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
1689         // selection is editable.
1690         // This can happen in Mail for a mix of non-editable and editable content (like Stationary), 
1691         // when spell checking the whole document before sending the message.
1692         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
1693
1694         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
1695         if (position.isNull())
1696             return;
1697         
1698         Position rangeCompliantPosition = rangeCompliantEquivalent(position);
1699         spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.m_offset, ec);
1700         startedWithSelection = false;   // won't need to wrap
1701     }
1702     
1703     // topNode defines the whole range we want to operate on 
1704     Node* topNode = highestEditableRoot(position);
1705     spellingSearchRange->setEnd(topNode, maxDeepOffset(topNode), ec);
1706
1707     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
1708     // at a word boundary. Going back by one char and then forward by a word does the trick.
1709     if (startedWithSelection) {
1710         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
1711         if (oneBeforeStart.isNotNull()) {
1712             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
1713         } // else we were already at the start of the editable node
1714     }
1715     
1716     if (spellingSearchRange->collapsed(ec))
1717         return;       // nothing to search in
1718     
1719     // Get the spell checker if it is available
1720     if (!client())
1721         return;
1722         
1723     // We go to the end of our first range instead of the start of it, just to be sure
1724     // we don't get foiled by any word boundary problems at the start.  It means we might
1725     // do a tiny bit more searching.
1726     Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
1727     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
1728     
1729     int misspellingOffset = 0;
1730 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1731     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
1732     String misspelledWord;
1733     String badGrammarPhrase;
1734     int grammarPhraseOffset = 0;
1735     bool isSpelling = true;
1736     int foundOffset = 0;
1737     GrammarDetail grammarDetail;
1738     String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
1739     if (isSpelling) {
1740         misspelledWord = foundItem;
1741         misspellingOffset = foundOffset;
1742     } else {
1743         badGrammarPhrase = foundItem;
1744         grammarPhraseOffset = foundOffset;
1745     }
1746 #else
1747     String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
1748     
1749     String badGrammarPhrase;
1750
1751 #ifndef BUILDING_ON_TIGER
1752     int grammarPhraseOffset = 0;
1753     GrammarDetail grammarDetail;
1754
1755     // Search for bad grammar that occurs prior to the next misspelled word (if any)
1756     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
1757     if (!misspelledWord.isEmpty()) {
1758         // Stop looking at start of next misspelled word
1759         CharacterIterator chars(grammarSearchRange.get());
1760         chars.advance(misspellingOffset);
1761         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
1762     }
1763     
1764     if (isGrammarCheckingEnabled())
1765         badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
1766 #endif
1767 #endif
1768     
1769     // 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
1770     // block rather than at a selection).
1771     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
1772         spellingSearchRange->setStart(topNode, 0, ec);
1773         // going until the end of the very first chunk we tested is far enough
1774         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
1775         
1776 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1777         grammarSearchRange = spellingSearchRange->cloneRange(ec);
1778         foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
1779         if (isSpelling) {
1780             misspelledWord = foundItem;
1781             misspellingOffset = foundOffset;
1782         } else {
1783             badGrammarPhrase = foundItem;
1784             grammarPhraseOffset = foundOffset;
1785         }
1786 #else
1787         misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
1788
1789 #ifndef BUILDING_ON_TIGER
1790         grammarSearchRange = spellingSearchRange->cloneRange(ec);
1791         if (!misspelledWord.isEmpty()) {
1792             // Stop looking at start of next misspelled word
1793             CharacterIterator chars(grammarSearchRange.get());
1794             chars.advance(misspellingOffset);
1795             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
1796         }
1797         if (isGrammarCheckingEnabled())
1798             badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
1799 #endif
1800 #endif
1801     }
1802     
1803     if (!badGrammarPhrase.isEmpty()) {
1804 #ifdef BUILDING_ON_TIGER
1805         ASSERT_NOT_REACHED();
1806 #else
1807         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
1808         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
1809         // panel, and store a marker so we draw the green squiggle later.
1810         
1811         ASSERT(badGrammarPhrase.length() > 0);
1812         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
1813         
1814         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
1815         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
1816         frame()->selection()->setSelection(VisibleSelection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
1817         frame()->revealSelection();
1818         
1819         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
1820         frame()->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
1821 #endif        
1822     } else if (!misspelledWord.isEmpty()) {
1823         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
1824         // a marker so we draw the red squiggle later.
1825         
1826         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
1827         frame()->selection()->setSelection(VisibleSelection(misspellingRange.get(), DOWNSTREAM));
1828         frame()->revealSelection();
1829         
1830         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
1831         frame()->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1832     }
1833 }
1834
1835 bool Editor::isSelectionMisspelled()
1836 {
1837     String selectedString = frame()->selectedText();
1838     int length = selectedString.length();
1839     if (length == 0)
1840         return false;
1841
1842     if (!client())
1843         return false;
1844     
1845     int misspellingLocation = -1;
1846     int misspellingLength = 0;
1847     client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
1848     
1849     // The selection only counts as misspelled if the selected text is exactly one misspelled word
1850     if (misspellingLength != length)
1851         return false;
1852     
1853     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
1854     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
1855     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
1856     // or a grammar error.
1857     client()->updateSpellingUIWithMisspelledWord(selectedString);
1858     
1859     return true;
1860 }
1861
1862 #ifndef BUILDING_ON_TIGER
1863 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
1864 {
1865     if (!client)
1866         return false;
1867
1868     ExceptionCode ec;
1869     if (!range || range->collapsed(ec))
1870         return false;
1871     
1872     // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
1873     // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
1874     // or overlapping the range; the ranges must exactly match.
1875     guessesVector.clear();
1876     int grammarPhraseOffset;
1877     
1878     GrammarDetail grammarDetail;
1879     String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);    
1880     
1881     // No bad grammar in these parts at all.
1882     if (badGrammarPhrase.isEmpty())
1883         return false;
1884     
1885     // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
1886     if (grammarPhraseOffset > 0)
1887         return false;
1888     
1889     ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
1890     
1891     // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
1892     if (grammarDetail.location + grammarPhraseOffset != 0)
1893         return false;
1894     
1895     // Bad grammar at start of range, but end of bad grammar is before or after end of range
1896     if (grammarDetail.length != TextIterator::rangeLength(range))
1897         return false;
1898     
1899     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
1900     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
1901     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
1902     // or a grammar error.
1903     client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
1904     
1905     return true;
1906 }
1907 #endif
1908
1909 bool Editor::isSelectionUngrammatical()
1910 {
1911 #ifdef BUILDING_ON_TIGER
1912     return false;
1913 #else
1914     Vector<String> ignoredGuesses;
1915     return isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), ignoredGuesses);
1916 #endif
1917 }
1918
1919 Vector<String> Editor::guessesForUngrammaticalSelection()
1920 {
1921 #ifdef BUILDING_ON_TIGER
1922     return Vector<String>();
1923 #else
1924     Vector<String> guesses;
1925     // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
1926     isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), guesses);
1927     return guesses;
1928 #endif
1929 }
1930
1931 Vector<String> Editor::guessesForMisspelledSelection()
1932 {
1933     String selectedString = frame()->selectedText();
1934     ASSERT(selectedString.length() != 0);
1935
1936     Vector<String> guesses;
1937     if (client())
1938         client()->getGuessesForWord(selectedString, guesses);
1939     return guesses;
1940 }
1941
1942 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1943
1944 static Vector<String> guessesForMisspelledOrUngrammaticalRange(EditorClient* client, Range *range, bool checkGrammar, bool& misspelled, bool& ungrammatical)
1945 {
1946     Vector<String> guesses;
1947     ExceptionCode ec;
1948     misspelled = false;
1949     ungrammatical = false;
1950     
1951     if (!client || !range || range->collapsed(ec))
1952         return guesses;
1953
1954     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
1955     int rangeStartOffset;
1956     String paragraphString;
1957     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(range, rangeStartOffset, paragraphString);
1958     int rangeLength = TextIterator::rangeLength(range);
1959     if (rangeLength == 0 || paragraphString.length() == 0)
1960         return guesses;
1961
1962     Vector<TextCheckingResult> results;
1963     client->checkSpellingAndGrammarOfParagraph(paragraphString.characters(), paragraphString.length(), checkGrammar, results);
1964     
1965     for (unsigned i = 0; i < results.size(); i++) {
1966         const TextCheckingResult* result = &results[i];
1967         if (result->resultType == 1 && result->location == rangeStartOffset && result->length == rangeLength) {
1968             String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength);
1969             ASSERT(misspelledWord.length() != 0);
1970             client->getGuessesForWord(misspelledWord, guesses);
1971             client->updateSpellingUIWithMisspelledWord(misspelledWord);
1972             misspelled = true;
1973             return guesses;
1974         }
1975     }
1976     
1977     if (!checkGrammar)
1978         return guesses;
1979         
1980     for (unsigned i = 0; i < results.size(); i++) {
1981         const TextCheckingResult* result = &results[i];
1982         if (result->resultType == 2 && result->location <= rangeStartOffset && result->location + result->length >= rangeStartOffset + rangeLength) {
1983             for (unsigned j = 0; j < result->details.size(); j++) {
1984                 const GrammarDetail* detail = &result->details[j];
1985                 ASSERT(detail->length > 0 && detail->location >= 0);
1986                 if (result->location + detail->location == rangeStartOffset && detail->length == rangeLength) {
1987                     String badGrammarPhrase = paragraphString.substring(result->location, result->length);
1988                     ASSERT(badGrammarPhrase.length() != 0);
1989                     for (unsigned k = 0; k < detail->guesses.size(); k++)
1990                         guesses.append(detail->guesses[k]);
1991                     client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail);
1992                     ungrammatical = true;
1993                     return guesses;
1994                 }
1995             }
1996         }
1997     }
1998     return guesses;
1999 }
2000
2001 #endif
2002
2003 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
2004 {
2005 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2006     return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammatical);
2007 #else
2008     misspelled = isSelectionMisspelled();
2009     if (misspelled) {
2010         ungrammatical = false;
2011         return guessesForMisspelledSelection();
2012     }
2013     if (isGrammarCheckingEnabled() && isSelectionUngrammatical()) {
2014         ungrammatical = true;
2015         return guessesForUngrammaticalSelection();
2016     }
2017     ungrammatical = false;
2018     return Vector<String>();
2019 #endif
2020 }
2021
2022 void Editor::showSpellingGuessPanel()
2023 {
2024     if (!client()) {
2025         LOG_ERROR("No NSSpellChecker");
2026         return;
2027     }
2028
2029 #ifndef BUILDING_ON_TIGER
2030     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
2031     // to match rest of OS X.
2032     if (client()->spellingUIIsShowing()) {
2033         client()->showSpellingUI(false);
2034         return;
2035     }
2036 #endif
2037     
2038     advanceToNextMisspelling(true);
2039     client()->showSpellingUI(true);
2040 }
2041
2042 bool Editor::spellingPanelIsShowing()
2043 {
2044     if (!client())
2045         return false;
2046     return client()->spellingUIIsShowing();
2047 }
2048
2049 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
2050 {
2051     if (!isContinuousSpellCheckingEnabled())
2052         return;
2053     
2054 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2055     VisibleSelection adjacentWords = VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary));
2056     if (isGrammarCheckingEnabled()) {
2057         VisibleSelection selectedSentence = VisibleSelection(startOfSentence(p), endOfSentence(p));
2058         markMisspellingsAndBadGrammar(adjacentWords, true, selectedSentence);
2059     } else {
2060         markMisspellingsAndBadGrammar(adjacentWords, false, adjacentWords);
2061     }
2062 #else
2063     // Check spelling of one word
2064     markMisspellings(VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
2065     
2066     if (!isGrammarCheckingEnabled())
2067         return;
2068     
2069     // Check grammar of entire sentence
2070     markBadGrammar(VisibleSelection(startOfSentence(p), endOfSentence(p)));
2071 #endif
2072 }
2073
2074 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange)
2075 {
2076     // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
2077     // all we need to do is mark every instance.
2078     int ignoredOffset;
2079     findFirstMisspellingInRange(client, searchRange, ignoredOffset, true);
2080 }
2081
2082 #ifndef BUILDING_ON_TIGER
2083 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
2084 {
2085     // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
2086     // do is mark every instance.
2087     GrammarDetail ignoredGrammarDetail;
2088     int ignoredOffset;
2089     findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
2090 }
2091 #endif
2092     
2093 static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection& selection, bool checkSpelling)
2094 {
2095     // This function is called with a selection already expanded to word boundaries.
2096     // Might be nice to assert that here.
2097     
2098     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
2099     // grammar checking can only be on if spell checking is also on.
2100     if (!editor->isContinuousSpellCheckingEnabled())
2101         return;
2102     
2103     RefPtr<Range> searchRange(selection.toNormalizedRange());
2104     if (!searchRange)
2105         return;
2106     
2107     // If we're not in an editable node, bail.
2108     Node* editableNode = searchRange->startContainer();
2109     if (!editableNode || !editableNode->isContentEditable())
2110         return;
2111     
2112     // Get the spell checker if it is available
2113     if (!editor->client())
2114         return;
2115     
2116     if (checkSpelling)
2117         markAllMisspellingsInRange(editor->client(), searchRange.get());
2118     else {
2119 #ifdef BUILDING_ON_TIGER
2120         ASSERT_NOT_REACHED();
2121 #else
2122         if (editor->isGrammarCheckingEnabled())
2123             markAllBadGrammarInRange(editor->client(), searchRange.get());
2124 #endif
2125     }    
2126 }
2127
2128 void Editor::markMisspellings(const VisibleSelection& selection)
2129 {
2130     markMisspellingsOrBadGrammar(this, selection, true);
2131 }
2132     
2133 void Editor::markBadGrammar(const VisibleSelection& selection)
2134 {
2135 #ifndef BUILDING_ON_TIGER
2136     markMisspellingsOrBadGrammar(this, selection, false);
2137 #else
2138     UNUSED_PARAM(selection);
2139 #endif
2140 }
2141
2142 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2143
2144 static void markAllMisspellingsAndBadGrammarInRanges(EditorClient* client, Range *spellingRange, bool markGrammar, Range *grammarRange)
2145 {
2146     // This function is called with selections already expanded to word boundaries.
2147     ExceptionCode ec;
2148     if (!client || !spellingRange || (markGrammar && !grammarRange))
2149         return;
2150     
2151     // If we're not in an editable node, bail.
2152     Node* editableNode = spellingRange->startContainer();
2153     if (!editableNode || !editableNode->isContentEditable())
2154         return;
2155     
2156     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
2157     int spellingRangeStartOffset = 0;
2158     int spellingRangeEndOffset = 0;
2159     int grammarRangeStartOffset = 0;
2160     int grammarRangeEndOffset = 0;
2161     String paragraphString;
2162     
2163     if (markGrammar) {
2164         // The spelling range should be contained in the paragraph-aligned extension of the grammar range.
2165         RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(grammarRange, grammarRangeStartOffset, paragraphString);
2166         RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
2167         spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
2168         grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange);
2169     } else {
2170         RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(spellingRange, spellingRangeStartOffset, paragraphString);
2171     }
2172     spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
2173     if (paragraphString.length() == 0 || (spellingRangeStartOffset >= spellingRangeEndOffset && (!markGrammar || grammarRangeStartOffset >= grammarRangeEndOffset)))
2174         return;
2175     
2176     Vector<TextCheckingResult> results;
2177     client->checkSpellingAndGrammarOfParagraph(paragraphString.characters(), paragraphString.length(), markGrammar, results);
2178     
2179     for (unsigned i = 0; i < results.size(); i++) {
2180         const TextCheckingResult* result = &results[i];
2181         if (result->resultType == 1 && result->location >= spellingRangeStartOffset && result->location + result->length <= spellingRangeEndOffset) {
2182             ASSERT(result->length > 0 && result->location >= 0);
2183             RefPtr<Range> misspellingRange = TextIterator::subrange(spellingRange, result->location - spellingRangeStartOffset, result->length);
2184             misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
2185         } else if (markGrammar && result->resultType == 2 && result->location < grammarRangeEndOffset && result->location + result->length > grammarRangeStartOffset) {
2186             ASSERT(result->length > 0 && result->location >= 0);
2187             for (unsigned j = 0; j < result->details.size(); j++) {
2188                 const GrammarDetail* detail = &result->details[j];
2189                 ASSERT(detail->length > 0 && detail->location >= 0);
2190                 if (result->location + detail->location >= grammarRangeStartOffset && result->location + detail->location + detail->length <= grammarRangeEndOffset) {
2191                     RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarRange, result->location + detail->location - grammarRangeStartOffset, detail->length);
2192                     grammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
2193                 }
2194             }
2195         }
2196     }
2197 }
2198
2199 #endif
2200
2201 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
2202 {
2203 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2204     if (!isContinuousSpellCheckingEnabled())
2205         return;
2206     markAllMisspellingsAndBadGrammarInRanges(client(), spellingSelection.toNormalizedRange().get(), markGrammar && isGrammarCheckingEnabled(), grammarSelection.toNormalizedRange().get());
2207 #else
2208     markMisspellings(spellingSelection);
2209     if (markGrammar)
2210         markBadGrammar(grammarSelection);
2211 #endif
2212 }
2213
2214 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
2215 {
2216     Document* document = m_frame->documentAtPoint(windowPoint);
2217     if (!document)
2218         return 0;
2219     
2220     Frame* frame = document->frame();
2221     ASSERT(frame);
2222     FrameView* frameView = frame->view();
2223     if (!frameView)
2224         return 0;
2225     IntPoint framePoint = frameView->windowToContents(windowPoint);
2226     VisibleSelection selection(frame->visiblePositionForPoint(framePoint));
2227     return avoidIntersectionWithNode(selection.toNormalizedRange().get(), m_deleteButtonController->containerElement());
2228 }
2229
2230 void Editor::revealSelectionAfterEditingOperation()
2231 {
2232     if (m_ignoreCompositionSelectionChange)
2233         return;
2234
2235     m_frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
2236 }
2237
2238 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
2239 {
2240     if (m_ignoreCompositionSelectionChange == ignore)
2241         return;
2242
2243     m_ignoreCompositionSelectionChange = ignore;
2244     if (!ignore)
2245         revealSelectionAfterEditingOperation();
2246 }
2247
2248 PassRefPtr<Range> Editor::compositionRange() const
2249 {
2250     if (!m_compositionNode)
2251         return 0;
2252     unsigned length = m_compositionNode->length();
2253     unsigned start = min(m_compositionStart, length);
2254     unsigned end = min(max(start, m_compositionEnd), length);
2255     if (start >= end)
2256         return 0;
2257     return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
2258 }
2259
2260 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
2261 {
2262     if (!m_compositionNode)
2263         return false;
2264     Position start = m_frame->selection()->start();
2265     if (start.node() != m_compositionNode)
2266         return false;
2267     Position end = m_frame->selection()->end();
2268     if (end.node() != m_compositionNode)
2269         return false;
2270
2271     if (static_cast<unsigned>(start.m_offset) < m_compositionStart)
2272         return false;
2273     if (static_cast<unsigned>(end.m_offset) > m_compositionEnd)
2274         return false;
2275
2276     selectionStart = start.m_offset - m_compositionStart;
2277     selectionEnd = start.m_offset - m_compositionEnd;
2278     return true;
2279 }
2280
2281 void Editor::transpose()
2282 {
2283     if (!canEdit())
2284         return;
2285
2286      VisibleSelection selection = m_frame->selection()->selection();
2287      if (!selection.isCaret())
2288          return;
2289
2290     // Make a selection that goes back one character and forward two characters.
2291     VisiblePosition caret = selection.visibleStart();
2292     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
2293     VisiblePosition previous = next.previous();
2294     if (next == previous)
2295         return;
2296     previous = previous.previous();
2297     if (!inSameParagraph(next, previous))
2298         return;
2299     RefPtr<Range> range = makeRange(previous, next);
2300     if (!range)
2301         return;
2302     VisibleSelection newSelection(range.get(), DOWNSTREAM);
2303
2304     // Transpose the two characters.
2305     String text = plainText(range.get());
2306     if (text.length() != 2)
2307         return;
2308     String transposed = text.right(1) + text.left(1);
2309
2310     // Select the two characters.
2311     if (newSelection != m_frame->selection()->selection()) {
2312         if (!m_frame->shouldChangeSelection(newSelection))
2313             return;
2314         m_frame->selection()->setSelection(newSelection);
2315     }
2316
2317     // Insert the transposed characters.
2318     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
2319         return;
2320     replaceSelectionWithText(transposed, false, false);
2321 }
2322
2323 void Editor::addToKillRing(Range* range, bool prepend)
2324 {
2325     if (m_shouldStartNewKillRingSequence)
2326         startNewKillRingSequence();
2327
2328     String text = m_frame->displayStringModifiedByEncoding(plainText(range));
2329     if (prepend)
2330         prependToKillRing(text);
2331     else
2332         appendToKillRing(text);
2333     m_shouldStartNewKillRingSequence = false;
2334 }
2335
2336 #if !PLATFORM(MAC)
2337
2338 void Editor::appendToKillRing(const String&)
2339 {
2340 }
2341
2342 void Editor::prependToKillRing(const String&)
2343 {
2344 }
2345
2346 String Editor::yankFromKillRing()
2347 {
2348     return String();
2349 }
2350
2351 void Editor::startNewKillRingSequence()
2352 {
2353 }
2354
2355 void Editor::setKillRingToYankedState()
2356 {
2357 }
2358
2359 #endif
2360
2361 bool Editor::insideVisibleArea(const IntPoint& point) const
2362 {
2363     if (m_frame->excludeFromTextSearch())
2364         return false;
2365     
2366     // Right now, we only check the visibility of a point for disconnected frames. For all other
2367     // frames, we assume visibility.
2368     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
2369     if (!frame->isDisconnected())
2370         return true;
2371     
2372     RenderPart* renderer = frame->ownerRenderer();
2373     RenderBlock* container = renderer->containingBlock();
2374     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
2375         return true;
2376
2377     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
2378     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
2379                                     rectInPageCoords.width(), rectInPageCoords.height());
2380
2381     return rectInFrameCoords.contains(point);
2382 }
2383
2384 bool Editor::insideVisibleArea(Range* range) const
2385 {
2386     if (!range)
2387         return true;
2388
2389     if (m_frame->excludeFromTextSearch())
2390         return false;
2391     
2392     // Right now, we only check the visibility of a range for disconnected frames. For all other
2393     // frames, we assume visibility.
2394     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
2395     if (!frame->isDisconnected())
2396         return true;
2397     
2398     RenderPart* renderer = frame->ownerRenderer();
2399     RenderBlock* container = renderer->containingBlock();
2400     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
2401         return true;
2402
2403     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
2404     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
2405                                     rectInPageCoords.width(), rectInPageCoords.height());
2406     IntRect resultRect = range->boundingBox();
2407     
2408     return rectInFrameCoords.contains(resultRect);
2409 }
2410
2411 PassRefPtr<Range> Editor::firstVisibleRange(const String& target, bool caseFlag)
2412 {
2413     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
2414     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
2415     ExceptionCode ec = 0;
2416
2417     while (!insideVisibleArea(resultRange.get())) {
2418         searchRange->setStartAfter(resultRange->endContainer(), ec);
2419         if (searchRange->startContainer() == searchRange->endContainer())
2420             return Range::create(m_frame->document());
2421         resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
2422     }
2423     
2424     return resultRange;
2425 }
2426
2427 PassRefPtr<Range> Editor::lastVisibleRange(const String& target, bool caseFlag)
2428 {
2429     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
2430     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
2431     ExceptionCode ec = 0;
2432
2433     while (!insideVisibleArea(resultRange.get())) {
2434         searchRange->setEndBefore(resultRange->startContainer(), ec);
2435         if (searchRange->startContainer() == searchRange->endContainer())
2436             return Range::create(m_frame->document());
2437         resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
2438     }
2439     
2440     return resultRange;
2441 }
2442
2443 PassRefPtr<Range> Editor::nextVisibleRange(Range* currentRange, const String& target, bool forward, bool caseFlag, bool wrapFlag)
2444 {
2445     if (m_frame->excludeFromTextSearch())
2446         return Range::create(m_frame->document());
2447
2448     RefPtr<Range> resultRange = currentRange;
2449     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
2450     ExceptionCode ec = 0;
2451     
2452     for ( ; !insideVisibleArea(resultRange.get()); resultRange = findPlainText(searchRange.get(), target, forward, caseFlag)) {
2453         if (resultRange->collapsed(ec)) {
2454             if (!resultRange->startContainer()->isInShadowTree())
2455                 break;
2456             searchRange = rangeOfContents(m_frame->document());
2457             if (forward)
2458                 searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
2459             else
2460                 searchRange->setEndBefore(resultRange->startContainer()->shadowAncestorNode(), ec);
2461             continue;
2462         }
2463
2464         if (forward)
2465             searchRange->setStartAfter(resultRange->endContainer(), ec);
2466         else
2467             searchRange->setEndBefore(resultRange->startContainer(), ec);
2468
2469         Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
2470         if (searchRange->collapsed(ec) && shadowTreeRoot) {
2471             if (forward)
2472                 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
2473             else
2474                 searchRange->setStartBefore(shadowTreeRoot, ec);
2475         }
2476         
2477         if (searchRange->startContainer()->isDocumentNode() && searchRange->endContainer()->isDocumentNode())
2478             break;
2479     }
2480     
2481     if (insideVisibleArea(resultRange.get()))
2482         return resultRange;
2483     
2484     if (!wrapFlag)
2485         return Range::create(m_frame->document());
2486
2487     if (forward)
2488         return firstVisibleRange(target, caseFlag);
2489
2490     return lastVisibleRange(target, caseFlag);
2491 }
2492
2493 void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle, EditCommand* cmd)
2494 {
2495     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
2496     // because there is work that it must do in this situation.
2497     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
2498     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
2499     bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
2500     if (selectionDidNotChangeDOMPosition || m_frame->shouldChangeSelection(newSelection))
2501         m_frame->selection()->setSelection(newSelection, closeTyping, clearTypingStyle);
2502         
2503     // Some kinds of deletes and line break insertions change the selection's position within the document without 
2504     // changing its position within the DOM.  For example when you press return in the following (the caret is marked by ^): 
2505     // <div contentEditable="true"><div>^Hello</div></div>
2506     // WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't
2507     // change the caret's DOM position (["hello", 0]).  In these situations the above SelectionController::setSelection call
2508     // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and 
2509     // starts a new kill ring sequence, but we want to do these things (matches AppKit).
2510     if (selectionDidNotChangeDOMPosition && cmd->isTypingCommand())
2511         client()->respondToChangedSelection();
2512 }
2513
2514 } // namespace WebCore