2010-09-08 MORITA Hajime <morrita@google.com>
[WebKit.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 "CSSMutableStyleDeclaration.h"
34 #include "CSSProperty.h"
35 #include "CSSPropertyNames.h"
36 #include "CSSValueKeywords.h"
37 #include "CharacterNames.h"
38 #include "ClipboardEvent.h"
39 #include "CompositionEvent.h"
40 #include "CreateLinkCommand.h"
41 #include "DeleteButtonController.h"
42 #include "DeleteSelectionCommand.h"
43 #include "CachedResourceLoader.h"
44 #include "DocumentFragment.h"
45 #include "EditorClient.h"
46 #include "EventHandler.h"
47 #include "EventNames.h"
48 #include "FocusController.h"
49 #include "Frame.h"
50 #include "FrameTree.h"
51 #include "FrameView.h"
52 #include "HTMLInputElement.h"
53 #include "HTMLTextAreaElement.h"
54 #include "HitTestResult.h"
55 #include "IndentOutdentCommand.h"
56 #include "InsertListCommand.h"
57 #include "KeyboardEvent.h"
58 #include "KillRing.h"
59 #include "ModifySelectionListLevel.h"
60 #include "Page.h"
61 #include "Pasteboard.h"
62 #include "RemoveFormatCommand.h"
63 #include "RenderBlock.h"
64 #include "RenderPart.h"
65 #include "ReplaceSelectionCommand.h"
66 #include "Settings.h"
67 #include "Sound.h"
68 #include "Text.h"
69 #include "TextEvent.h"
70 #include "TextIterator.h"
71 #include "TypingCommand.h"
72 #include "UserTypingGestureIndicator.h"
73 #include "htmlediting.h"
74 #include "markup.h"
75 #include "visible_units.h"
76 #include <wtf/UnusedParam.h>
77
78 namespace WebCore {
79
80 using namespace std;
81 using namespace HTMLNames;
82
83 // When an event handler has moved the selection outside of a text control
84 // we should use the target control's selection for this editing operation.
85 VisibleSelection Editor::selectionForCommand(Event* event)
86 {
87     VisibleSelection selection = m_frame->selection()->selection();
88     if (!event)
89         return selection;
90     // If the target is a text control, and the current selection is outside of its shadow tree,
91     // then use the saved selection for that text control.
92     Node* target = event->target()->toNode();
93     Node* selectionStart = selection.start().node();
94     if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
95         if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
96             return static_cast<HTMLInputElement*>(target)->selection();
97         if (target->hasTagName(textareaTag))
98             return static_cast<HTMLTextAreaElement*>(target)->selection();
99     }
100     return selection;
101 }
102
103 // Function considers Mac editing behavior a fallback when Page or Settings is not available.
104 EditingBehavior Editor::behavior() const
105 {
106     if (!m_frame || !m_frame->settings())
107         return EditingBehavior(EditingMacBehavior);
108
109     return EditingBehavior(m_frame->settings()->editingBehaviorType());
110 }
111
112 EditorClient* Editor::client() const
113 {
114     if (Page* page = m_frame->page())
115         return page->editorClient();
116     return 0;
117 }
118
119 void Editor::handleKeyboardEvent(KeyboardEvent* event)
120 {
121     if (EditorClient* c = client())
122         c->handleKeyboardEvent(event);
123 }
124
125 void Editor::handleInputMethodKeydown(KeyboardEvent* event)
126 {
127     if (EditorClient* c = client())
128         c->handleInputMethodKeydown(event);
129 }
130
131 bool Editor::handleTextEvent(TextEvent* event)
132 {
133     // Default event handling for Drag and Drop will be handled by DragController
134     // so we leave the event for it.
135     if (event->isDrop())
136         return false;
137
138     if (event->isPaste()) {
139         if (event->pastingFragment())
140             replaceSelectionWithFragment(event->pastingFragment(), false, event->shouldSmartReplace(), event->shouldMatchStyle());
141         else 
142             replaceSelectionWithText(event->data(), false, event->shouldSmartReplace());
143         return true;
144     }
145
146     String data = event->data();
147     if (data == "\n") {
148         if (event->isLineBreak())
149             return insertLineBreak();
150         return insertParagraphSeparator();
151     }
152
153     return insertTextWithoutSendingTextEvent(data, false, event);
154 }
155
156 bool Editor::canEdit() const
157 {
158     return m_frame->selection()->isContentEditable();
159 }
160
161 bool Editor::canEditRichly() const
162 {
163     return m_frame->selection()->isContentRichlyEditable();
164 }
165
166 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items.  They
167 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
168 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
169 // normally selectable to implement copy/paste (like divs, or a document body).
170
171 bool Editor::canDHTMLCut()
172 {
173     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, ClipboardNumb);
174 }
175
176 bool Editor::canDHTMLCopy()
177 {
178     return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb);
179 }
180
181 bool Editor::canDHTMLPaste()
182 {
183     return !dispatchCPPEvent(eventNames().beforepasteEvent, ClipboardNumb);
184 }
185
186 bool Editor::canCut() const
187 {
188     return canCopy() && canDelete();
189 }
190
191 static HTMLImageElement* imageElementFromImageDocument(Document* document)
192 {
193     if (!document)
194         return 0;
195     if (!document->isImageDocument())
196         return 0;
197     
198     HTMLElement* body = document->body();
199     if (!body)
200         return 0;
201     
202     Node* node = body->firstChild();
203     if (!node)
204         return 0;    
205     if (!node->hasTagName(imgTag))
206         return 0;
207     return static_cast<HTMLImageElement*>(node);
208 }
209
210 bool Editor::canCopy() const
211 {
212     if (imageElementFromImageDocument(m_frame->document()))
213         return true;
214     SelectionController* selection = m_frame->selection();
215     return selection->isRange() && !selection->isInPasswordField();
216 }
217
218 bool Editor::canPaste() const
219 {
220     return canEdit();
221 }
222
223 bool Editor::canDelete() const
224 {
225     SelectionController* selection = m_frame->selection();
226     return selection->isRange() && selection->isContentEditable();
227 }
228
229 bool Editor::canDeleteRange(Range* range) const
230 {
231     ExceptionCode ec = 0;
232     Node* startContainer = range->startContainer(ec);
233     Node* endContainer = range->endContainer(ec);
234     if (!startContainer || !endContainer)
235         return false;
236     
237     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
238         return false;
239     
240     if (range->collapsed(ec)) {
241         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
242         VisiblePosition previous = start.previous();
243         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
244         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
245             return false;
246     }
247     return true;
248 }
249
250 bool Editor::smartInsertDeleteEnabled()
251 {   
252     return client() && client()->smartInsertDeleteEnabled();
253 }
254     
255 bool Editor::canSmartCopyOrDelete()
256 {
257     return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
258 }
259
260 bool Editor::isSelectTrailingWhitespaceEnabled()
261 {
262     return client() && client()->isSelectTrailingWhitespaceEnabled();
263 }
264
265 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
266 {
267     if (!canEdit())
268         return false;
269
270     if (m_frame->selection()->isRange()) {
271         if (isTypingAction) {
272             TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity);
273             revealSelectionAfterEditingOperation();
274         } else {
275             if (killRing)
276                 addToKillRing(selectedRange().get(), false);
277             deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
278             // Implicitly calls revealSelectionAfterEditingOperation().
279         }
280     } else {
281         switch (direction) {
282         case SelectionController::DirectionForward:
283         case SelectionController::DirectionRight:
284             TypingCommand::forwardDeleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
285             break;
286         case SelectionController::DirectionBackward:
287         case SelectionController::DirectionLeft:
288             TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
289             break;
290         }
291         revealSelectionAfterEditingOperation();
292     }
293
294     // FIXME: We should to move this down into deleteKeyPressed.
295     // clear the "start new kill ring sequence" setting, because it was set to true
296     // when the selection was updated by deleting the range
297     if (killRing)
298         setStartNewKillRingSequence(false);
299
300     return true;
301 }
302
303 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
304 {
305     if (m_frame->selection()->isNone())
306         return;
307     
308     applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));
309 }
310
311 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace)
312 {
313     Node* target = findEventTargetFromSelection();
314     if (!target)
315         return;
316     ExceptionCode ec = 0;
317     target->dispatchEvent(TextEvent::createForPlainTextPaste(m_frame->domWindow(), pastingText, smartReplace), ec);
318 }
319
320 void Editor::pasteAsFragment(PassRefPtr<DocumentFragment> pastingFragment, bool smartReplace, bool matchStyle)
321 {
322     Node* target = findEventTargetFromSelection();
323     if (!target)
324         return;
325     ExceptionCode ec = 0;
326     target->dispatchEvent(TextEvent::createForFragmentPaste(m_frame->domWindow(), pastingFragment, smartReplace, matchStyle), ec);
327 }
328
329 void Editor::pasteAsPlainTextBypassingDHTML()
330 {
331     pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
332 }
333
334 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
335 {
336     String text = pasteboard->plainText(m_frame);
337     if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
338         pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard));
339 }
340
341 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
342 {
343     RefPtr<Range> range = selectedRange();
344     bool chosePlainText;
345     RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
346     if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
347         pasteAsFragment(fragment, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
348 }
349
350 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
351 {
352     return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
353 }
354
355 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
356 {
357     if (!client())
358         return false;
359         
360     Node* child = fragment->firstChild();
361     if (child && fragment->lastChild() == child && child->isCharacterDataNode())
362         return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
363
364     return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
365 }
366
367 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
368 {
369     if (m_frame->selection()->isNone() || !fragment)
370         return;
371     
372     applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
373     revealSelectionAfterEditingOperation();
374 }
375
376 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
377 {
378     replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); 
379 }
380
381 PassRefPtr<Range> Editor::selectedRange()
382 {
383     if (!m_frame)
384         return 0;
385     return m_frame->selection()->toNormalizedRange();
386 }
387
388 bool Editor::shouldDeleteRange(Range* range) const
389 {
390     ExceptionCode ec;
391     if (!range || range->collapsed(ec))
392         return false;
393     
394     if (!canDeleteRange(range))
395         return false;
396
397     return client() && client()->shouldDeleteRange(range);
398 }
399
400 bool Editor::tryDHTMLCopy()
401 {   
402     if (m_frame->selection()->isInPasswordField())
403         return false;
404
405     if (canCopy())
406         // Must be done before oncopy adds types and data to the pboard,
407         // also done for security, as it erases data from the last copy/paste.
408         Pasteboard::generalPasteboard()->clear();
409
410     return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);
411 }
412
413 bool Editor::tryDHTMLCut()
414 {
415     if (m_frame->selection()->isInPasswordField())
416         return false;
417     
418     if (canCut())
419         // Must be done before oncut adds types and data to the pboard,
420         // also done for security, as it erases data from the last copy/paste.
421         Pasteboard::generalPasteboard()->clear();
422
423     return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable);
424 }
425
426 bool Editor::tryDHTMLPaste()
427 {
428     return !dispatchCPPEvent(eventNames().pasteEvent, ClipboardReadable);
429 }
430
431 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
432 {
433     pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
434 }
435
436 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
437 {
438     return client() && client()->shouldInsertText(text, range, action);
439 }
440
441 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
442 {
443     return client() && client()->shouldShowDeleteInterface(element);
444 }
445
446 void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
447 {
448     if (client())
449         client()->respondToChangedSelection();
450     m_deleteButtonController->respondToChangedSelection(oldSelection);
451 }
452
453 void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
454 {
455     if (AXObjectCache::accessibilityEnabled()) {
456         Node* node = endingSelection.start().node();
457         if (node)
458             m_frame->document()->axObjectCache()->postNotification(node->renderer(), AXObjectCache::AXValueChanged, false);
459     }
460     
461     if (client())
462         client()->respondToChangedContents();  
463 }
464
465 const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
466 {
467 #if !PLATFORM(QT)
468     hasMultipleFonts = false;
469
470     if (!m_frame->selection()->isRange()) {
471         Node* nodeToRemove;
472         RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
473
474         const SimpleFontData* result = 0;
475         if (style)
476             result = style->font().primaryFont();
477         
478         if (nodeToRemove) {
479             ExceptionCode ec;
480             nodeToRemove->remove(ec);
481             ASSERT(!ec);
482         }
483
484         return result;
485     }
486
487     const SimpleFontData* font = 0;
488
489     RefPtr<Range> range = m_frame->selection()->toNormalizedRange();
490     Node* startNode = range->editingStartPosition().node();
491     if (startNode) {
492         Node* pastEnd = range->pastLastNode();
493         // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
494         // unreproducible case where this didn't happen, so check for nil also.
495         for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
496             RenderObject* renderer = n->renderer();
497             if (!renderer)
498                 continue;
499             // FIXME: Are there any node types that have renderers, but that we should be skipping?
500             const SimpleFontData* f = renderer->style()->font().primaryFont();
501             if (!font)
502                 font = f;
503             else if (font != f) {
504                 hasMultipleFonts = true;
505                 break;
506             }
507         }
508     }
509
510     return font;
511 #else
512     return 0;
513 #endif
514 }
515
516 WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbeddings) const
517 {
518     hasNestedOrMultipleEmbeddings = true;
519
520     if (m_frame->selection()->isNone())
521         return NaturalWritingDirection;
522
523     Position pos = m_frame->selection()->selection().start().downstream();
524
525     Node* node = pos.node();
526     if (!node)
527         return NaturalWritingDirection;
528
529     Position end;
530     if (m_frame->selection()->isRange()) {
531         end = m_frame->selection()->selection().end().upstream();
532
533         Node* pastLast = Range::create(m_frame->document(), rangeCompliantEquivalent(pos), rangeCompliantEquivalent(end))->pastLastNode();
534         for (Node* n = node; n && n != pastLast; n = n->traverseNextNode()) {
535             if (!n->isStyledElement())
536                 continue;
537
538             RefPtr<CSSComputedStyleDeclaration> style = computedStyle(n);
539             RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
540             if (!unicodeBidi)
541                 continue;
542
543             ASSERT(unicodeBidi->isPrimitiveValue());
544             int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
545             if (unicodeBidiValue == CSSValueEmbed || unicodeBidiValue == CSSValueBidiOverride)
546                 return NaturalWritingDirection;
547         }
548     }
549
550     if (m_frame->selection()->isCaret()) {
551         if (CSSMutableStyleDeclaration *typingStyle = m_frame->typingStyle()) {
552             RefPtr<CSSValue> unicodeBidi = typingStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
553             if (unicodeBidi) {
554                 ASSERT(unicodeBidi->isPrimitiveValue());
555                 int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
556                 if (unicodeBidiValue == CSSValueEmbed) {
557                     RefPtr<CSSValue> direction = typingStyle->getPropertyCSSValue(CSSPropertyDirection);
558                     ASSERT(!direction || direction->isPrimitiveValue());
559                     if (direction) {
560                         hasNestedOrMultipleEmbeddings = false;
561                         return static_cast<CSSPrimitiveValue*>(direction.get())->getIdent() == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
562                     }
563                 } else if (unicodeBidiValue == CSSValueNormal) {
564                     hasNestedOrMultipleEmbeddings = false;
565                     return NaturalWritingDirection;
566                 }
567             }
568         }
569         node = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
570     }
571
572     // 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
573     // to decide.
574     Node* block = enclosingBlock(node);
575     WritingDirection foundDirection = NaturalWritingDirection;
576
577     for (; node != block; node = node->parent()) {
578         if (!node->isStyledElement())
579             continue;
580
581         RefPtr<CSSComputedStyleDeclaration> style = computedStyle(node);
582         RefPtr<CSSValue> unicodeBidi = style->getPropertyCSSValue(CSSPropertyUnicodeBidi);
583         if (!unicodeBidi)
584             continue;
585
586         ASSERT(unicodeBidi->isPrimitiveValue());
587         int unicodeBidiValue = static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent();
588         if (unicodeBidiValue == CSSValueNormal)
589             continue;
590
591         if (unicodeBidiValue == CSSValueBidiOverride)
592             return NaturalWritingDirection;
593
594         ASSERT(unicodeBidiValue == CSSValueEmbed);
595         RefPtr<CSSValue> direction = style->getPropertyCSSValue(CSSPropertyDirection);
596         if (!direction)
597             continue;
598
599         ASSERT(direction->isPrimitiveValue());
600         int directionValue = static_cast<CSSPrimitiveValue*>(direction.get())->getIdent();
601         if (directionValue != CSSValueLtr && directionValue != CSSValueRtl)
602             continue;
603
604         if (foundDirection != NaturalWritingDirection)
605             return NaturalWritingDirection;
606
607         // In the range case, make sure that the embedding element persists until the end of the range.
608         if (m_frame->selection()->isRange() && !end.node()->isDescendantOf(node))
609             return NaturalWritingDirection;
610
611         foundDirection = directionValue == CSSValueLtr ? LeftToRightWritingDirection : RightToLeftWritingDirection;
612     }
613     hasNestedOrMultipleEmbeddings = false;
614     return foundDirection;
615 }
616
617 bool Editor::hasBidiSelection() const
618 {
619     if (m_frame->selection()->isNone())
620         return false;
621
622     Node* startNode;
623     if (m_frame->selection()->isRange()) {
624         startNode = m_frame->selection()->selection().start().downstream().node();
625         Node* endNode = m_frame->selection()->selection().end().upstream().node();
626         if (enclosingBlock(startNode) != enclosingBlock(endNode))
627             return false;
628     } else
629         startNode = m_frame->selection()->selection().visibleStart().deepEquivalent().node();
630
631     RenderObject* renderer = startNode->renderer();
632     while (renderer && !renderer->isRenderBlock())
633         renderer = renderer->parent();
634
635     if (!renderer)
636         return false;
637
638     RenderStyle* style = renderer->style();
639     if (style->direction() == RTL)
640         return true;
641
642     return toRenderBlock(renderer)->containsNonZeroBidiLevel();
643 }
644
645 TriState Editor::selectionUnorderedListState() const
646 {
647     if (m_frame->selection()->isCaret()) {
648         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag))
649             return TrueTriState;
650     } else if (m_frame->selection()->isRange()) {
651         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag);
652         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag);
653         if (startNode && endNode && startNode == endNode)
654             return TrueTriState;
655     }
656
657     return FalseTriState;
658 }
659
660 TriState Editor::selectionOrderedListState() const
661 {
662     if (m_frame->selection()->isCaret()) {
663         if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag))
664             return TrueTriState;
665     } else if (m_frame->selection()->isRange()) {
666         Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag);
667         Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag);
668         if (startNode && endNode && startNode == endNode)
669             return TrueTriState;
670     }
671
672     return FalseTriState;
673 }
674
675 PassRefPtr<Node> Editor::insertOrderedList()
676 {
677     if (!canEditRichly())
678         return 0;
679         
680     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
681     revealSelectionAfterEditingOperation();
682     return newList;
683 }
684
685 PassRefPtr<Node> Editor::insertUnorderedList()
686 {
687     if (!canEditRichly())
688         return 0;
689         
690     RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
691     revealSelectionAfterEditingOperation();
692     return newList;
693 }
694
695 bool Editor::canIncreaseSelectionListLevel()
696 {
697     return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
698 }
699
700 bool Editor::canDecreaseSelectionListLevel()
701 {
702     return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
703 }
704
705 PassRefPtr<Node> Editor::increaseSelectionListLevel()
706 {
707     if (!canEditRichly() || m_frame->selection()->isNone())
708         return 0;
709     
710     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
711     revealSelectionAfterEditingOperation();
712     return newList;
713 }
714
715 PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
716 {
717     if (!canEditRichly() || m_frame->selection()->isNone())
718         return 0;
719     
720     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
721     revealSelectionAfterEditingOperation();
722     return newList.release();
723 }
724
725 PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
726 {
727     if (!canEditRichly() || m_frame->selection()->isNone())
728         return 0;
729     
730     RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
731     revealSelectionAfterEditingOperation();
732     return newList.release();
733 }
734
735 void Editor::decreaseSelectionListLevel()
736 {
737     if (!canEditRichly() || m_frame->selection()->isNone())
738         return;
739     
740     DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
741     revealSelectionAfterEditingOperation();
742 }
743
744 void Editor::removeFormattingAndStyle()
745 {
746     applyCommand(RemoveFormatCommand::create(m_frame->document()));
747 }
748
749 void Editor::clearLastEditCommand() 
750 {
751     m_lastEditCommand.clear();
752 }
753
754 // Returns whether caller should continue with "the default processing", which is the same as 
755 // the event handler NOT setting the return value to false
756 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
757 {
758     Node* target = findEventTargetFromSelection();
759     if (!target)
760         return true;
761     
762     RefPtr<Clipboard> clipboard = newGeneralClipboard(policy, m_frame);
763
764     ExceptionCode ec = 0;
765     RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
766     target->dispatchEvent(evt, ec);
767     bool noDefaultProcessing = evt->defaultPrevented();
768
769     // invalidate clipboard here for security
770     clipboard->setAccessPolicy(ClipboardNumb);
771     
772     return !noDefaultProcessing;
773 }
774
775 Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const
776 {
777     Node* target = selection.start().element();
778     if (!target)
779         target = m_frame->document()->body();
780     if (!target)
781         return 0;
782     return target->shadowAncestorNode();
783
784 }
785
786 Node* Editor::findEventTargetFromSelection() const
787 {
788     return findEventTargetFrom(m_frame->selection()->selection());
789 }
790
791 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
792 {
793     switch (m_frame->selection()->selectionType()) {
794     case VisibleSelection::NoSelection:
795         // do nothing
796         break;
797     case VisibleSelection::CaretSelection:
798         m_frame->computeAndSetTypingStyle(style, editingAction);
799         break;
800     case VisibleSelection::RangeSelection:
801         if (style)
802             applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction));
803         break;
804     }
805 }
806     
807 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
808 {   
809     return client()->shouldApplyStyle(style, range);
810 }
811     
812 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
813 {
814     switch (m_frame->selection()->selectionType()) {
815     case VisibleSelection::NoSelection:
816         // do nothing
817         break;
818     case VisibleSelection::CaretSelection:
819     case VisibleSelection::RangeSelection:
820         if (style)
821             applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
822         break;
823     }
824 }
825
826 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
827 {
828     if (!style || !style->length() || !canEditRichly())
829         return;
830
831     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
832         applyStyle(style, editingAction);
833 }
834
835 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
836 {
837     if (!style || !style->length() || !canEditRichly())
838         return;
839     
840     if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toNormalizedRange().get()))
841         applyParagraphStyle(style, editingAction);
842 }
843
844 bool Editor::clientIsEditable() const
845 {
846     return client() && client()->isEditable();
847 }
848
849 // CSS properties that only has a visual difference when applied to text.
850 static const int textOnlyProperties[] = {
851     CSSPropertyTextDecoration,
852     CSSPropertyWebkitTextDecorationsInEffect,
853     CSSPropertyFontStyle,
854     CSSPropertyFontWeight,
855     CSSPropertyColor,
856 };
857
858 static TriState triStateOfStyleInComputedStyle(CSSStyleDeclaration* desiredStyle, CSSComputedStyleDeclaration* computedStyle, bool ignoreTextOnlyProperties = false)
859 {
860     RefPtr<CSSMutableStyleDeclaration> diff = getPropertiesNotInComputedStyle(desiredStyle, computedStyle);
861
862     if (ignoreTextOnlyProperties)
863         diff->removePropertiesInSet(textOnlyProperties, sizeof(textOnlyProperties) / sizeof(textOnlyProperties[0]));
864
865     if (!diff->length())
866         return TrueTriState;
867     if (diff->length() == desiredStyle->length())
868         return FalseTriState;
869     return MixedTriState;
870 }
871
872 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
873 {
874     Node* nodeToRemove;
875     RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
876     if (!selectionStyle)
877         return false;
878     TriState state = triStateOfStyleInComputedStyle(style, selectionStyle.get());
879     if (nodeToRemove) {
880         ExceptionCode ec = 0;
881         nodeToRemove->remove(ec);
882         ASSERT(!ec);
883     }
884     return state == TrueTriState;
885 }
886
887 TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
888 {
889     TriState state = FalseTriState;
890
891     if (!m_frame->selection()->isRange()) {
892         Node* nodeToRemove;
893         RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
894         if (!selectionStyle)
895             return FalseTriState;
896         state = triStateOfStyleInComputedStyle(style, selectionStyle.get());
897         if (nodeToRemove) {
898             ExceptionCode ec = 0;
899             nodeToRemove->remove(ec);
900             ASSERT(!ec);
901         }
902     } else {
903         for (Node* node = m_frame->selection()->start().node(); node; node = node->traverseNextNode()) {
904             RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
905             if (nodeStyle) {
906                 TriState nodeState = triStateOfStyleInComputedStyle(style, nodeStyle.get(), !node->isTextNode());
907                 if (node == m_frame->selection()->start().node())
908                     state = nodeState;
909                 else if (state != nodeState && node->isTextNode()) {
910                     state = MixedTriState;
911                     break;
912                 }
913             }
914             if (node == m_frame->selection()->end().node())
915                 break;
916         }
917     }
918
919     return state;
920 }
921
922 static bool hasTransparentBackgroundColor(CSSStyleDeclaration* style)
923 {
924     RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
925     if (!cssValue)
926         return true;
927
928     if (!cssValue->isPrimitiveValue())
929         return false;
930     CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(cssValue.get());
931
932     if (value->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
933         return !alphaChannel(value->getRGBA32Value());
934
935     return value->getIdent() == CSSValueTransparent;
936 }
937
938 String Editor::selectionStartCSSPropertyValue(int propertyID)
939 {
940     Node* nodeToRemove;
941     RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
942     if (!selectionStyle)
943         return String();
944
945     String value = selectionStyle->getPropertyValue(propertyID);
946
947     if (nodeToRemove) {
948         ExceptionCode ec = 0;
949         nodeToRemove->remove(ec);
950         ASSERT(!ec);
951     }
952
953     // If background color is transparent, traverse parent nodes until we hit a different value or document root
954     // Also, if the selection is a range, ignore the background color at the start of selection,
955     // and find the background color of the common ancestor.
956     if (propertyID == CSSPropertyBackgroundColor && (m_frame->selection()->isRange() || hasTransparentBackgroundColor(selectionStyle.get()))) {
957         RefPtr<Range> range(m_frame->selection()->toNormalizedRange());
958         ExceptionCode ec = 0;
959         for (Node* ancestor = range->commonAncestorContainer(ec); ancestor; ancestor = ancestor->parentNode()) {
960             selectionStyle = computedStyle(ancestor);
961             if (!hasTransparentBackgroundColor(selectionStyle.get())) {
962                 value = selectionStyle->getPropertyValue(CSSPropertyBackgroundColor);
963                 break;
964             }
965         }
966     }
967
968     return value;
969 }
970
971 void Editor::indent()
972 {
973     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
974 }
975
976 void Editor::outdent()
977 {
978     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent));
979 }
980
981 static void dispatchEditableContentChangedEvents(const EditCommand& command)
982 {
983     Element* startRoot = command.startingRootEditableElement();
984     Element* endRoot = command.endingRootEditableElement();
985     ExceptionCode ec;
986     if (startRoot)
987         startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
988     if (endRoot && endRoot != startRoot)
989         endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
990 }
991
992 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
993 {
994     m_frame->document()->updateLayout();
995     
996     dispatchEditableContentChangedEvents(*cmd);
997     
998     VisibleSelection newSelection(cmd->endingSelection());
999     // Don't clear the typing style with this selection change.  We do those things elsewhere if necessary.
1000     changeSelectionAfterCommand(newSelection, false, false);
1001         
1002     if (!cmd->preservesTypingStyle())
1003         m_frame->setTypingStyle(0);
1004     
1005     // Command will be equal to last edit command only in the case of typing
1006     if (m_lastEditCommand.get() == cmd)
1007         ASSERT(cmd->isTypingCommand());
1008     else {
1009         // Only register a new undo command if the command passed in is
1010         // different from the last command
1011         m_lastEditCommand = cmd;
1012         if (client())
1013             client()->registerCommandForUndo(m_lastEditCommand);
1014     }
1015     respondToChangedContents(newSelection);    
1016 }
1017
1018 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
1019 {
1020     m_frame->document()->updateLayout();
1021     
1022     dispatchEditableContentChangedEvents(*cmd);
1023     
1024     VisibleSelection newSelection(cmd->startingSelection());
1025     changeSelectionAfterCommand(newSelection, true, true);
1026     
1027     m_lastEditCommand = 0;
1028     if (client())
1029         client()->registerCommandForRedo(cmd);
1030     respondToChangedContents(newSelection);    
1031 }
1032
1033 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
1034 {
1035     m_frame->document()->updateLayout();
1036     
1037     dispatchEditableContentChangedEvents(*cmd);
1038     
1039     VisibleSelection newSelection(cmd->endingSelection());
1040     changeSelectionAfterCommand(newSelection, true, true);
1041     
1042     m_lastEditCommand = 0;
1043     if (client())
1044         client()->registerCommandForUndo(cmd);
1045     respondToChangedContents(newSelection);    
1046 }
1047
1048 Editor::Editor(Frame* frame)
1049     : m_frame(frame)
1050     , m_deleteButtonController(adoptPtr(new DeleteButtonController(frame)))
1051     , m_ignoreCompositionSelectionChange(false)
1052     , m_shouldStartNewKillRingSequence(false)
1053     // This is off by default, since most editors want this behavior (this matches IE but not FF).
1054     , m_shouldStyleWithCSS(false)
1055     , m_killRing(adoptPtr(new KillRing))
1056     , m_correctionPanelTimer(this, &Editor::correctionPanelTimerFired)
1057 {
1058 }
1059
1060 Editor::~Editor()
1061 {
1062 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
1063     if (client())
1064         client()->dismissCorrectionPanel(true);
1065 #endif
1066 }
1067
1068 void Editor::clear()
1069 {
1070     m_compositionNode = 0;
1071     m_customCompositionUnderlines.clear();
1072     m_shouldStyleWithCSS = false;
1073 }
1074
1075 bool Editor::insertText(const String& text, Event* triggeringEvent)
1076 {
1077     return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
1078 }
1079
1080 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
1081 {
1082     if (text.isEmpty())
1083         return false;
1084
1085     VisibleSelection selection = selectionForCommand(triggeringEvent);
1086     if (!selection.isContentEditable())
1087         return false;
1088     RefPtr<Range> range = selection.toNormalizedRange();
1089
1090     if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
1091         return true;
1092
1093     // Get the selection to use for the event that triggered this insertText.
1094     // If the event handler changed the selection, we may want to use a different selection
1095     // that is contained in the event target.
1096     selection = selectionForCommand(triggeringEvent);
1097     if (selection.isContentEditable()) {
1098         if (Node* selectionStart = selection.start().node()) {
1099             RefPtr<Document> document = selectionStart->document();
1100             
1101             // Insert the text
1102             TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
1103
1104             // Reveal the current selection 
1105             if (Frame* editedFrame = document->frame())
1106                 if (Page* page = editedFrame->page())
1107                     page->focusController()->focusedOrMainFrame()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1108         }
1109     }
1110
1111     return true;
1112 }
1113
1114 bool Editor::insertLineBreak()
1115 {
1116     if (!canEdit())
1117         return false;
1118
1119     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
1120         return true;
1121
1122     TypingCommand::insertLineBreak(m_frame->document());
1123     revealSelectionAfterEditingOperation();
1124     return true;
1125 }
1126
1127 bool Editor::insertParagraphSeparator()
1128 {
1129     if (!canEdit())
1130         return false;
1131
1132     if (!canEditRichly())
1133         return insertLineBreak();
1134
1135     if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
1136         return true;
1137
1138     TypingCommand::insertParagraphSeparator(m_frame->document());
1139     revealSelectionAfterEditingOperation();
1140     return true;
1141 }
1142
1143 void Editor::cut()
1144 {
1145     if (tryDHTMLCut())
1146         return; // DHTML did the whole operation
1147     if (!canCut()) {
1148         systemBeep();
1149         return;
1150     }
1151     RefPtr<Range> selection = selectedRange();
1152     if (shouldDeleteRange(selection.get())) {
1153         if (isNodeInTextFormControl(m_frame->selection()->start().node()))
1154             Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText());
1155         else
1156             Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
1157         didWriteSelectionToPasteboard();
1158         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1159     }
1160 }
1161
1162 void Editor::copy()
1163 {
1164     if (tryDHTMLCopy())
1165         return; // DHTML did the whole operation
1166     if (!canCopy()) {
1167         systemBeep();
1168         return;
1169     }
1170
1171     if (isNodeInTextFormControl(m_frame->selection()->start().node()))
1172         Pasteboard::generalPasteboard()->writePlainText(m_frame->selectedText());
1173     else {
1174         Document* document = m_frame->document();
1175         if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
1176             Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
1177         else
1178             Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
1179     }
1180
1181     didWriteSelectionToPasteboard();
1182 }
1183
1184 #if !PLATFORM(MAC)
1185
1186 void Editor::paste()
1187 {
1188     ASSERT(m_frame->document());
1189     if (tryDHTMLPaste())
1190         return; // DHTML did the whole operation
1191     if (!canPaste())
1192         return;
1193     CachedResourceLoader* loader = m_frame->document()->cachedResourceLoader();
1194     loader->setAllowStaleResources(true);
1195     if (m_frame->selection()->isContentRichlyEditable())
1196         pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
1197     else
1198         pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1199     loader->setAllowStaleResources(false);
1200 }
1201
1202 #endif
1203
1204 void Editor::pasteAsPlainText()
1205 {
1206     if (tryDHTMLPaste())
1207         return;
1208     if (!canPaste())
1209         return;
1210     pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1211 }
1212
1213 void Editor::performDelete()
1214 {
1215     if (!canDelete()) {
1216         systemBeep();
1217         return;
1218     }
1219
1220     addToKillRing(selectedRange().get(), false);
1221     deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
1222
1223     // clear the "start new kill ring sequence" setting, because it was set to true
1224     // when the selection was updated by deleting the range
1225     setStartNewKillRingSequence(false);
1226 }
1227
1228 void Editor::copyURL(const KURL& url, const String& title)
1229 {
1230     Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
1231 }
1232
1233 void Editor::copyImage(const HitTestResult& result)
1234 {
1235     KURL url = result.absoluteLinkURL();
1236     if (url.isEmpty())
1237         url = result.absoluteImageURL();
1238
1239     Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
1240 }
1241
1242 bool Editor::isContinuousSpellCheckingEnabled()
1243 {
1244     return client() && client()->isContinuousSpellCheckingEnabled();
1245 }
1246
1247 void Editor::toggleContinuousSpellChecking()
1248 {
1249     if (client())
1250         client()->toggleContinuousSpellChecking();
1251 }
1252
1253 bool Editor::isGrammarCheckingEnabled()
1254 {
1255     return client() && client()->isGrammarCheckingEnabled();
1256 }
1257
1258 void Editor::toggleGrammarChecking()
1259 {
1260     if (client())
1261         client()->toggleGrammarChecking();
1262 }
1263
1264 int Editor::spellCheckerDocumentTag()
1265 {
1266     return client() ? client()->spellCheckerDocumentTag() : 0;
1267 }
1268
1269 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1270
1271 void Editor::uppercaseWord()
1272 {
1273     if (client())
1274         client()->uppercaseWord();
1275 }
1276
1277 void Editor::lowercaseWord()
1278 {
1279     if (client())
1280         client()->lowercaseWord();
1281 }
1282
1283 void Editor::capitalizeWord()
1284 {
1285     if (client())
1286         client()->capitalizeWord();
1287 }
1288
1289 void Editor::showSubstitutionsPanel()
1290 {
1291     if (!client()) {
1292         LOG_ERROR("No NSSpellChecker");
1293         return;
1294     }
1295
1296     if (client()->substitutionsPanelIsShowing()) {
1297         client()->showSubstitutionsPanel(false);
1298         return;
1299     }
1300     client()->showSubstitutionsPanel(true);
1301 }
1302
1303 bool Editor::substitutionsPanelIsShowing()
1304 {
1305     if (!client())
1306         return false;
1307     return client()->substitutionsPanelIsShowing();
1308 }
1309
1310 void Editor::toggleSmartInsertDelete()
1311 {
1312     if (client())
1313         client()->toggleSmartInsertDelete();
1314 }
1315
1316 bool Editor::isAutomaticQuoteSubstitutionEnabled()
1317 {
1318     return client() && client()->isAutomaticQuoteSubstitutionEnabled();
1319 }
1320
1321 void Editor::toggleAutomaticQuoteSubstitution()
1322 {
1323     if (client())
1324         client()->toggleAutomaticQuoteSubstitution();
1325 }
1326
1327 bool Editor::isAutomaticLinkDetectionEnabled()
1328 {
1329     return client() && client()->isAutomaticLinkDetectionEnabled();
1330 }
1331
1332 void Editor::toggleAutomaticLinkDetection()
1333 {
1334     if (client())
1335         client()->toggleAutomaticLinkDetection();
1336 }
1337
1338 bool Editor::isAutomaticDashSubstitutionEnabled()
1339 {
1340     return client() && client()->isAutomaticDashSubstitutionEnabled();
1341 }
1342
1343 void Editor::toggleAutomaticDashSubstitution()
1344 {
1345     if (client())
1346         client()->toggleAutomaticDashSubstitution();
1347 }
1348
1349 bool Editor::isAutomaticTextReplacementEnabled()
1350 {
1351     return client() && client()->isAutomaticTextReplacementEnabled();
1352 }
1353
1354 void Editor::toggleAutomaticTextReplacement()
1355 {
1356     if (client())
1357         client()->toggleAutomaticTextReplacement();
1358 }
1359
1360 bool Editor::isAutomaticSpellingCorrectionEnabled()
1361 {
1362     return client() && client()->isAutomaticSpellingCorrectionEnabled();
1363 }
1364
1365 void Editor::toggleAutomaticSpellingCorrection()
1366 {
1367     if (client())
1368         client()->toggleAutomaticSpellingCorrection();
1369 }
1370
1371 #endif
1372
1373 bool Editor::shouldEndEditing(Range* range)
1374 {
1375     return client() && client()->shouldEndEditing(range);
1376 }
1377
1378 bool Editor::shouldBeginEditing(Range* range)
1379 {
1380     return client() && client()->shouldBeginEditing(range);
1381 }
1382
1383 void Editor::clearUndoRedoOperations()
1384 {
1385     if (client())
1386         client()->clearUndoRedoOperations();
1387 }
1388
1389 bool Editor::canUndo()
1390 {
1391     return client() && client()->canUndo();
1392 }
1393
1394 void Editor::undo()
1395 {
1396     if (client())
1397         client()->undo();
1398 }
1399
1400 bool Editor::canRedo()
1401 {
1402     return client() && client()->canRedo();
1403 }
1404
1405 void Editor::redo()
1406 {
1407     if (client())
1408         client()->redo();
1409 }
1410
1411 void Editor::didBeginEditing()
1412 {
1413     if (client())
1414         client()->didBeginEditing();
1415 }
1416
1417 void Editor::didEndEditing()
1418 {
1419     if (client())
1420         client()->didEndEditing();
1421 }
1422
1423 void Editor::didWriteSelectionToPasteboard()
1424 {
1425     if (client())
1426         client()->didWriteSelectionToPasteboard();
1427 }
1428
1429 void Editor::toggleBold()
1430 {
1431     command("ToggleBold").execute();
1432 }
1433
1434 void Editor::toggleUnderline()
1435 {
1436     command("ToggleUnderline").execute();
1437 }
1438
1439 void Editor::setBaseWritingDirection(WritingDirection direction)
1440 {
1441     Node* focusedNode = frame()->document()->focusedNode();
1442     if (focusedNode && (focusedNode->hasTagName(textareaTag)
1443                         || (focusedNode->hasTagName(inputTag) && (static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::TEXT
1444                                                                 || static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::SEARCH)))) {
1445         if (direction == NaturalWritingDirection)
1446             return;
1447         static_cast<HTMLElement*>(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
1448         frame()->document()->updateStyleIfNeeded();
1449         return;
1450     }
1451
1452     RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
1453     style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
1454     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1455 }
1456
1457 void Editor::selectComposition()
1458 {
1459     RefPtr<Range> range = compositionRange();
1460     if (!range)
1461         return;
1462     
1463     // The composition can start inside a composed character sequence, so we have to override checks.
1464     // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
1465     VisibleSelection selection;
1466     selection.setWithoutValidation(range->startPosition(), range->endPosition());
1467     m_frame->selection()->setSelection(selection, false, false);
1468 }
1469
1470 void Editor::confirmComposition()
1471 {
1472     if (!m_compositionNode)
1473         return;
1474     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
1475 }
1476
1477 void Editor::confirmCompositionWithoutDisturbingSelection()
1478 {
1479     if (!m_compositionNode)
1480         return;
1481     confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
1482 }
1483
1484 void Editor::confirmComposition(const String& text)
1485 {
1486     confirmComposition(text, false);
1487 }
1488
1489 void Editor::confirmComposition(const String& text, bool preserveSelection)
1490 {
1491     UserTypingGestureIndicator typingGestureIndicator(m_frame);
1492
1493     setIgnoreCompositionSelectionChange(true);
1494
1495     VisibleSelection oldSelection = m_frame->selection()->selection();
1496
1497     selectComposition();
1498
1499     if (m_frame->selection()->isNone()) {
1500         setIgnoreCompositionSelectionChange(false);
1501         return;
1502     }
1503     
1504     // Dispatch a compositionend event to the focused node.
1505     // We should send this event before sending a TextEvent as written in Section 6.2.2 and 6.2.3 of
1506     // the DOM Event specification.
1507     Node* target = m_frame->document()->focusedNode();
1508     if (target) {
1509         RefPtr<CompositionEvent> event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
1510         ExceptionCode ec = 0;
1511         target->dispatchEvent(event, ec);
1512     }
1513
1514     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1515     // will delete the old composition with an optimized replace operation.
1516     if (text.isEmpty())
1517         TypingCommand::deleteSelection(m_frame->document(), false);
1518
1519     m_compositionNode = 0;
1520     m_customCompositionUnderlines.clear();
1521
1522     insertText(text, 0);
1523
1524     if (preserveSelection) {
1525         m_frame->selection()->setSelection(oldSelection, false, false);
1526         // An open typing command that disagrees about current selection would cause issues with typing later on.
1527         TypingCommand::closeTyping(m_lastEditCommand.get());
1528     }
1529
1530     setIgnoreCompositionSelectionChange(false);
1531 }
1532
1533 void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
1534 {
1535     UserTypingGestureIndicator typingGestureIndicator(m_frame);
1536
1537     setIgnoreCompositionSelectionChange(true);
1538
1539     selectComposition();
1540
1541     if (m_frame->selection()->isNone()) {
1542         setIgnoreCompositionSelectionChange(false);
1543         return;
1544     }
1545
1546     Node* target = m_frame->document()->focusedNode();
1547     if (target) {
1548         // Dispatch an appropriate composition event to the focused node.
1549         // We check the composition status and choose an appropriate composition event since this
1550         // function is used for three purposes:
1551         // 1. Starting a new composition.
1552         //    Send a compositionstart event when this function creates a new composition node, i.e.
1553         //    m_compositionNode == 0 && !text.isEmpty().
1554         // 2. Updating the existing composition node.
1555         //    Send a compositionupdate event when this function updates the existing composition
1556         //    node, i.e. m_compositionNode != 0 && !text.isEmpty().
1557         // 3. Canceling the ongoing composition.
1558         //    Send a compositionend event when function deletes the existing composition node, i.e.
1559         //    m_compositionNode != 0 && test.isEmpty().
1560         RefPtr<CompositionEvent> event;
1561         if (!m_compositionNode) {
1562             // We should send a compositionstart event only when the given text is not empty because this
1563             // function doesn't create a composition node when the text is empty.
1564             if (!text.isEmpty())
1565                 event = CompositionEvent::create(eventNames().compositionstartEvent, m_frame->domWindow(), text);
1566         } else {
1567             if (!text.isEmpty())
1568                 event = CompositionEvent::create(eventNames().compositionupdateEvent, m_frame->domWindow(), text);
1569             else
1570               event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
1571         }
1572         ExceptionCode ec = 0;
1573         if (event.get())
1574             target->dispatchEvent(event, ec);
1575     }
1576
1577     // If text is empty, then delete the old composition here.  If text is non-empty, InsertTextCommand::input
1578     // will delete the old composition with an optimized replace operation.
1579     if (text.isEmpty())
1580         TypingCommand::deleteSelection(m_frame->document(), false);
1581
1582     m_compositionNode = 0;
1583     m_customCompositionUnderlines.clear();
1584
1585     if (!text.isEmpty()) {
1586         TypingCommand::insertText(m_frame->document(), text, true, true);
1587
1588         // Find out what node has the composition now.
1589         Position base = m_frame->selection()->base().downstream();
1590         Position extent = m_frame->selection()->extent();
1591         Node* baseNode = base.node();
1592         unsigned baseOffset = base.deprecatedEditingOffset();
1593         Node* extentNode = extent.node();
1594         unsigned extentOffset = extent.deprecatedEditingOffset();
1595
1596         if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
1597             m_compositionNode = static_cast<Text*>(baseNode);
1598             m_compositionStart = baseOffset;
1599             m_compositionEnd = extentOffset;
1600             m_customCompositionUnderlines = underlines;
1601             size_t numUnderlines = m_customCompositionUnderlines.size();
1602             for (size_t i = 0; i < numUnderlines; ++i) {
1603                 m_customCompositionUnderlines[i].startOffset += baseOffset;
1604                 m_customCompositionUnderlines[i].endOffset += baseOffset;
1605             }
1606             if (baseNode->renderer())
1607                 baseNode->renderer()->repaint();
1608
1609             unsigned start = min(baseOffset + selectionStart, extentOffset);
1610             unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
1611             RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);                
1612             m_frame->selection()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
1613         }
1614     }
1615
1616     setIgnoreCompositionSelectionChange(false);
1617 }
1618
1619 void Editor::ignoreSpelling()
1620 {
1621     if (!client())
1622         return;
1623         
1624     RefPtr<Range> selectedRange = frame()->selection()->toNormalizedRange();
1625     if (selectedRange)
1626         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
1627
1628     String text = frame()->selectedText();
1629     ASSERT(text.length());
1630     client()->ignoreWordInSpellDocument(text);
1631 }
1632
1633 void Editor::learnSpelling()
1634 {
1635     if (!client())
1636         return;
1637         
1638     // FIXME: We don't call this on the Mac, and it should remove misspelling markers around the 
1639     // learned word, see <rdar://problem/5396072>.
1640
1641     String text = frame()->selectedText();
1642     ASSERT(text.length());
1643     client()->learnWord(text);
1644 }
1645
1646 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange)
1647 {
1648     ASSERT_ARG(client, client);
1649     ASSERT_ARG(searchRange, searchRange);
1650     
1651     WordAwareIterator it(searchRange);
1652     firstMisspellingOffset = 0;
1653     
1654     String firstMisspelling;
1655     int currentChunkOffset = 0;
1656
1657     while (!it.atEnd()) {
1658         const UChar* chars = it.characters();
1659         int len = it.length();
1660         
1661         // Skip some work for one-space-char hunks
1662         if (!(len == 1 && chars[0] == ' ')) {
1663             
1664             int misspellingLocation = -1;
1665             int misspellingLength = 0;
1666             client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
1667
1668             // 5490627 shows that there was some code path here where the String constructor below crashes.
1669             // We don't know exactly what combination of bad input caused this, so we're making this much
1670             // more robust against bad input on release builds.
1671             ASSERT(misspellingLength >= 0);
1672             ASSERT(misspellingLocation >= -1);
1673             ASSERT(!misspellingLength || misspellingLocation >= 0);
1674             ASSERT(misspellingLocation < len);
1675             ASSERT(misspellingLength <= len);
1676             ASSERT(misspellingLocation + misspellingLength <= len);
1677             
1678             if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
1679                 
1680                 // Compute range of misspelled word
1681                 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
1682
1683                 // Remember first-encountered misspelling and its offset.
1684                 if (!firstMisspelling) {
1685                     firstMisspellingOffset = currentChunkOffset + misspellingLocation;
1686                     firstMisspelling = String(chars + misspellingLocation, misspellingLength);
1687                     firstMisspellingRange = misspellingRange;
1688                 }
1689
1690                 // Store marker for misspelled word.
1691                 ExceptionCode ec = 0;
1692                 misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
1693                 ASSERT(!ec);
1694
1695                 // Bail out if we're marking only the first misspelling, and not all instances.
1696                 if (!markAll)
1697                     break;
1698             }
1699         }
1700         
1701         currentChunkOffset += len;
1702         it.advance();
1703     }
1704     
1705     return firstMisspelling;
1706 }
1707
1708 #ifndef BUILDING_ON_TIGER
1709
1710 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
1711 {
1712     ASSERT_ARG(arbitraryRange, arbitraryRange);
1713     
1714     ExceptionCode ec = 0;
1715     
1716     // Expand range to paragraph boundaries
1717     RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
1718     setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
1719     setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
1720     
1721     // Compute offset from start of expanded range to start of original range
1722     RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
1723     offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
1724     
1725     // Fill in out parameter with string representing entire paragraph range.
1726     // Someday we might have a caller that doesn't use this, but for now all callers do.
1727     paragraphString = plainText(paragraphRange.get());
1728
1729     return paragraphRange;
1730 }
1731
1732 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, Range *searchRange, int startOffset, int endOffset, bool markAll)
1733 {
1734     // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1735     // Optionally add a DocumentMarker for each detail in the range.
1736     int earliestDetailLocationSoFar = -1;
1737     int earliestDetailIndex = -1;
1738     for (unsigned i = 0; i < grammarDetails.size(); i++) {
1739         const GrammarDetail* detail = &grammarDetails[i];
1740         ASSERT(detail->length > 0 && detail->location >= 0);
1741         
1742         int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
1743         
1744         // Skip this detail if it starts before the original search range
1745         if (detailStartOffsetInParagraph < startOffset)
1746             continue;
1747         
1748         // Skip this detail if it starts after the original search range
1749         if (detailStartOffsetInParagraph >= endOffset)
1750             continue;
1751         
1752         if (markAll) {
1753             RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
1754             ExceptionCode ec = 0;
1755             badGrammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
1756             ASSERT(!ec);
1757         }
1758         
1759         // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
1760         if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
1761             earliestDetailIndex = i;
1762             earliestDetailLocationSoFar = detail->location;
1763         }
1764     }
1765     
1766     return earliestDetailIndex;
1767 }
1768     
1769 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
1770 {
1771     ASSERT_ARG(client, client);
1772     ASSERT_ARG(searchRange, searchRange);
1773     
1774     // Initialize out parameters; these will be updated if we find something to return.
1775     outGrammarDetail.location = -1;
1776     outGrammarDetail.length = 0;
1777     outGrammarDetail.guesses.clear();
1778     outGrammarDetail.userDescription = "";
1779     outGrammarPhraseOffset = 0;
1780     
1781     String firstBadGrammarPhrase;
1782
1783     // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
1784     // Determine the character offset from the start of the paragraph to the start of the original search range,
1785     // since we will want to ignore results in this area.
1786     int searchRangeStartOffset;
1787     String paragraphString;
1788     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
1789         
1790     // Determine the character offset from the start of the paragraph to the end of the original search range, 
1791     // since we will want to ignore results in this area also.
1792     int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
1793         
1794     // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
1795     int startOffset = 0;
1796     while (startOffset < searchRangeEndOffset) {
1797         Vector<GrammarDetail> grammarDetails;
1798         int badGrammarPhraseLocation = -1;
1799         int badGrammarPhraseLength = 0;
1800         client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
1801         
1802         if (!badGrammarPhraseLength) {
1803             ASSERT(badGrammarPhraseLocation == -1);
1804             return String();
1805         }
1806
1807         ASSERT(badGrammarPhraseLocation >= 0);
1808         badGrammarPhraseLocation += startOffset;
1809
1810         
1811         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
1812         int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
1813         if (badGrammarIndex >= 0) {
1814             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
1815             outGrammarDetail = grammarDetails[badGrammarIndex];
1816         }
1817
1818         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
1819         // kept going so we could mark all instances).
1820         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
1821             outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
1822             firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
1823             
1824             // Found one. We're done now, unless we're marking each instance.
1825             if (!markAll)
1826                 break;
1827         }
1828
1829         // These results were all between the start of the paragraph and the start of the search range; look
1830         // beyond this phrase.
1831         startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
1832     }
1833     
1834     return firstBadGrammarPhrase;
1835 }
1836     
1837 #endif /* not BUILDING_ON_TIGER */
1838
1839 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1840
1841 static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Range* searchRange, bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
1842 {
1843     ASSERT_ARG(client, client);
1844     ASSERT_ARG(searchRange, searchRange);
1845     
1846     String firstFoundItem;
1847     String misspelledWord;
1848     String badGrammarPhrase;
1849     ExceptionCode ec = 0;
1850     
1851     // Initialize out parameters; these will be updated if we find something to return.
1852     outIsSpelling = true;
1853     outFirstFoundOffset = 0;
1854     outGrammarDetail.location = -1;
1855     outGrammarDetail.length = 0;
1856     outGrammarDetail.guesses.clear();
1857     outGrammarDetail.userDescription = "";
1858     
1859     // Expand the search range to encompass entire paragraphs, since text checking needs that much context.
1860     // Determine the character offset from the start of the paragraph to the start of the original search range,
1861     // since we will want to ignore results in this area.
1862     RefPtr<Range> paragraphRange = searchRange->cloneRange(ec);
1863     setStart(paragraphRange.get(), startOfParagraph(searchRange->startPosition()));
1864     int totalRangeLength = TextIterator::rangeLength(paragraphRange.get());
1865     setEnd(paragraphRange.get(), endOfParagraph(searchRange->startPosition()));
1866     
1867     RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->startPosition());
1868     int searchRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
1869     int totalLengthProcessed = 0;
1870     
1871     bool firstIteration = true;
1872     bool lastIteration = false;
1873     while (totalLengthProcessed < totalRangeLength) {
1874         // Iterate through the search range by paragraphs, checking each one for spelling and grammar.
1875         int currentLength = TextIterator::rangeLength(paragraphRange.get());
1876         int currentStartOffset = firstIteration ? searchRangeStartOffset : 0;
1877         int currentEndOffset = currentLength;
1878         if (inSameParagraph(paragraphRange->startPosition(), searchRange->endPosition())) {
1879             // Determine the character offset from the end of the original search range to the end of the paragraph,
1880             // since we will want to ignore results in this area.
1881             RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->endPosition());
1882             currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get());
1883             lastIteration = true;
1884         }
1885         if (currentStartOffset < currentEndOffset) {
1886             String paragraphString = plainText(paragraphRange.get());
1887             if (paragraphString.length() > 0) {
1888                 bool foundGrammar = false;
1889                 int spellingLocation = 0;
1890                 int grammarPhraseLocation = 0;
1891                 int grammarDetailLocation = 0;
1892                 unsigned grammarDetailIndex = 0;
1893                 
1894                 Vector<TextCheckingResult> results;
1895                 uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
1896                 client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);
1897                 
1898                 for (unsigned i = 0; i < results.size(); i++) {
1899                     const TextCheckingResult* result = &results[i];
1900                     if (result->type == TextCheckingTypeSpelling && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) {
1901                         ASSERT(result->length > 0 && result->location >= 0);
1902                         spellingLocation = result->location;
1903                         misspelledWord = paragraphString.substring(result->location, result->length);
1904                         ASSERT(misspelledWord.length());
1905                         break;
1906                     }
1907                     if (checkGrammar && result->type == TextCheckingTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
1908                         ASSERT(result->length > 0 && result->location >= 0);
1909                         // We can't stop after the first grammar result, since there might still be a spelling result after
1910                         // it begins but before the first detail in it, but we can stop if we find a second grammar result.
1911                         if (foundGrammar)
1912                             break;
1913                         for (unsigned j = 0; j < result->details.size(); j++) {
1914                             const GrammarDetail* detail = &result->details[j];
1915                             ASSERT(detail->length > 0 && detail->location >= 0);
1916                             if (result->location + detail->location >= currentStartOffset && result->location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result->location + detail->location < grammarDetailLocation)) {
1917                                 grammarDetailIndex = j;
1918                                 grammarDetailLocation = result->location + detail->location;
1919                                 foundGrammar = true;
1920                             }
1921                         }
1922                         if (foundGrammar) {
1923                             grammarPhraseLocation = result->location;
1924                             outGrammarDetail = result->details[grammarDetailIndex];
1925                             badGrammarPhrase = paragraphString.substring(result->location, result->length);
1926                             ASSERT(badGrammarPhrase.length());
1927                         }
1928                     }
1929                 }
1930
1931                 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
1932                     int spellingOffset = spellingLocation - currentStartOffset;
1933                     if (!firstIteration) {
1934                         RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
1935                         spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
1936                     }
1937                     outIsSpelling = true;
1938                     outFirstFoundOffset = spellingOffset;
1939                     firstFoundItem = misspelledWord;
1940                     break;
1941                 }
1942                 if (checkGrammar && !badGrammarPhrase.isEmpty()) {
1943                     int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
1944                     if (!firstIteration) {
1945                         RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
1946                         grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
1947                     }
1948                     outIsSpelling = false;
1949                     outFirstFoundOffset = grammarPhraseOffset;
1950                     firstFoundItem = badGrammarPhrase;
1951                     break;
1952                 }
1953             }
1954         }
1955         if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
1956             break;
1957         VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition());
1958         setStart(paragraphRange.get(), newParagraphStart);
1959         setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart));
1960         firstIteration = false;
1961         totalLengthProcessed += currentLength;
1962     }
1963     return firstFoundItem;
1964 }
1965
1966 #endif
1967
1968 void Editor::advanceToNextMisspelling(bool startBeforeSelection)
1969 {
1970     ExceptionCode ec = 0;
1971
1972     // The basic approach is to search in two phases - from the selection end to the end of the doc, and
1973     // then we wrap and search from the doc start to (approximately) where we started.
1974     
1975     // Start at the end of the selection, search to edge of document.  Starting at the selection end makes
1976     // repeated "check spelling" commands work.
1977     VisibleSelection selection(frame()->selection()->selection());
1978     RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
1979     bool startedWithSelection = false;
1980     if (selection.start().node()) {
1981         startedWithSelection = true;
1982         if (startBeforeSelection) {
1983             VisiblePosition start(selection.visibleStart());
1984             // We match AppKit's rule: Start 1 character before the selection.
1985             VisiblePosition oneBeforeStart = start.previous();
1986             setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
1987         } else
1988             setStart(spellingSearchRange.get(), selection.visibleEnd());
1989     }
1990
1991     Position position = spellingSearchRange->startPosition();
1992     if (!isEditablePosition(position)) {
1993         // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
1994         // selection is editable.
1995         // This can happen in Mail for a mix of non-editable and editable content (like Stationary), 
1996         // when spell checking the whole document before sending the message.
1997         // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
1998
1999         position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
2000         if (position.isNull())
2001             return;
2002         
2003         Position rangeCompliantPosition = rangeCompliantEquivalent(position);
2004         spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.deprecatedEditingOffset(), ec);
2005         startedWithSelection = false; // won't need to wrap
2006     }
2007     
2008     // topNode defines the whole range we want to operate on 
2009     Node* topNode = highestEditableRoot(position);
2010     // FIXME: lastOffsetForEditing() is wrong here if editingIgnoresContent(highestEditableRoot()) returns true (e.g. a <table>)
2011     spellingSearchRange->setEnd(topNode, lastOffsetForEditing(topNode), ec);
2012
2013     // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
2014     // at a word boundary. Going back by one char and then forward by a word does the trick.
2015     if (startedWithSelection) {
2016         VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
2017         if (oneBeforeStart.isNotNull())
2018             setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
2019         // else we were already at the start of the editable node
2020     }
2021     
2022     if (spellingSearchRange->collapsed(ec))
2023         return; // nothing to search in
2024     
2025     // Get the spell checker if it is available
2026     if (!client())
2027         return;
2028         
2029     // We go to the end of our first range instead of the start of it, just to be sure
2030     // we don't get foiled by any word boundary problems at the start.  It means we might
2031     // do a tiny bit more searching.
2032     Node* searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
2033     int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
2034     
2035     int misspellingOffset = 0;
2036 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2037     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
2038     String misspelledWord;
2039     String badGrammarPhrase;
2040     int grammarPhraseOffset = 0;
2041     bool isSpelling = true;
2042     int foundOffset = 0;
2043     GrammarDetail grammarDetail;
2044     String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
2045     if (isSpelling) {
2046         misspelledWord = foundItem;
2047         misspellingOffset = foundOffset;
2048     } else {
2049         badGrammarPhrase = foundItem;
2050         grammarPhraseOffset = foundOffset;
2051     }
2052 #else
2053     RefPtr<Range> firstMisspellingRange;
2054     String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
2055     String badGrammarPhrase;
2056
2057 #ifndef BUILDING_ON_TIGER
2058     int grammarPhraseOffset = 0;
2059     GrammarDetail grammarDetail;
2060
2061     // Search for bad grammar that occurs prior to the next misspelled word (if any)
2062     RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
2063     if (!misspelledWord.isEmpty()) {
2064         // Stop looking at start of next misspelled word
2065         CharacterIterator chars(grammarSearchRange.get());
2066         chars.advance(misspellingOffset);
2067         grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
2068     }
2069     
2070     if (isGrammarCheckingEnabled())
2071         badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
2072 #endif
2073 #endif
2074     
2075     // 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
2076     // block rather than at a selection).
2077     if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
2078         spellingSearchRange->setStart(topNode, 0, ec);
2079         // going until the end of the very first chunk we tested is far enough
2080         spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
2081         
2082 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2083         grammarSearchRange = spellingSearchRange->cloneRange(ec);
2084         foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
2085         if (isSpelling) {
2086             misspelledWord = foundItem;
2087             misspellingOffset = foundOffset;
2088         } else {
2089             badGrammarPhrase = foundItem;
2090             grammarPhraseOffset = foundOffset;
2091         }
2092 #else
2093         misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
2094
2095 #ifndef BUILDING_ON_TIGER
2096         grammarSearchRange = spellingSearchRange->cloneRange(ec);
2097         if (!misspelledWord.isEmpty()) {
2098             // Stop looking at start of next misspelled word
2099             CharacterIterator chars(grammarSearchRange.get());
2100             chars.advance(misspellingOffset);
2101             grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
2102         }
2103         if (isGrammarCheckingEnabled())
2104             badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
2105 #endif
2106 #endif
2107     }
2108     
2109     if (!badGrammarPhrase.isEmpty()) {
2110 #ifdef BUILDING_ON_TIGER
2111         ASSERT_NOT_REACHED();
2112 #else
2113         // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
2114         // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
2115         // panel, and store a marker so we draw the green squiggle later.
2116         
2117         ASSERT(badGrammarPhrase.length() > 0);
2118         ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
2119         
2120         // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
2121         RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
2122         frame()->selection()->setSelection(VisibleSelection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
2123         frame()->revealSelection();
2124         
2125         client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
2126         frame()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
2127 #endif        
2128     } else if (!misspelledWord.isEmpty()) {
2129         // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
2130         // a marker so we draw the red squiggle later.
2131         
2132         RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
2133         frame()->selection()->setSelection(VisibleSelection(misspellingRange.get(), DOWNSTREAM));
2134         frame()->revealSelection();
2135         
2136         client()->updateSpellingUIWithMisspelledWord(misspelledWord);
2137         frame()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
2138     }
2139 }
2140
2141 bool Editor::isSelectionMisspelled()
2142 {
2143     String selectedString = frame()->selectedText();
2144     int length = selectedString.length();
2145     if (!length)
2146         return false;
2147
2148     if (!client())
2149         return false;
2150     
2151     int misspellingLocation = -1;
2152     int misspellingLength = 0;
2153     client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
2154     
2155     // The selection only counts as misspelled if the selected text is exactly one misspelled word
2156     if (misspellingLength != length)
2157         return false;
2158     
2159     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
2160     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
2161     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
2162     // or a grammar error.
2163     client()->updateSpellingUIWithMisspelledWord(selectedString);
2164     
2165     return true;
2166 }
2167
2168 #ifndef BUILDING_ON_TIGER
2169 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
2170 {
2171     if (!client)
2172         return false;
2173
2174     ExceptionCode ec;
2175     if (!range || range->collapsed(ec))
2176         return false;
2177     
2178     // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
2179     // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
2180     // or overlapping the range; the ranges must exactly match.
2181     guessesVector.clear();
2182     int grammarPhraseOffset;
2183     
2184     GrammarDetail grammarDetail;
2185     String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);    
2186     
2187     // No bad grammar in these parts at all.
2188     if (badGrammarPhrase.isEmpty())
2189         return false;
2190     
2191     // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
2192     if (grammarPhraseOffset > 0)
2193         return false;
2194     
2195     ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
2196     
2197     // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
2198     if (grammarDetail.location + grammarPhraseOffset)
2199         return false;
2200     
2201     // Bad grammar at start of range, but end of bad grammar is before or after end of range
2202     if (grammarDetail.length != TextIterator::rangeLength(range))
2203         return false;
2204     
2205     // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
2206     // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
2207     // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
2208     // or a grammar error.
2209     client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
2210     
2211     return true;
2212 }
2213 #endif
2214
2215 bool Editor::isSelectionUngrammatical()
2216 {
2217 #ifdef BUILDING_ON_TIGER
2218     return false;
2219 #else
2220     Vector<String> ignoredGuesses;
2221     return isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), ignoredGuesses);
2222 #endif
2223 }
2224
2225 Vector<String> Editor::guessesForUngrammaticalSelection()
2226 {
2227 #ifdef BUILDING_ON_TIGER
2228     return Vector<String>();
2229 #else
2230     Vector<String> guesses;
2231     // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
2232     isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), guesses);
2233     return guesses;
2234 #endif
2235 }
2236
2237 Vector<String> Editor::guessesForMisspelledSelection()
2238 {
2239     String selectedString = frame()->selectedText();
2240     ASSERT(selectedString.length());
2241
2242     Vector<String> guesses;
2243     if (client())
2244         client()->getGuessesForWord(selectedString, guesses);
2245     return guesses;
2246 }
2247
2248 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2249
2250 static Vector<String> guessesForMisspelledOrUngrammaticalRange(EditorClient* client, Range *range, bool checkGrammar, bool& misspelled, bool& ungrammatical)
2251 {
2252     Vector<String> guesses;
2253     ExceptionCode ec;
2254     misspelled = false;
2255     ungrammatical = false;
2256     
2257     if (!client || !range || range->collapsed(ec))
2258         return guesses;
2259
2260     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
2261     int rangeStartOffset;
2262     String paragraphString;
2263     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(range, rangeStartOffset, paragraphString);
2264     int rangeLength = TextIterator::rangeLength(range);
2265     if (!rangeLength || !paragraphString.length())
2266         return guesses;
2267
2268     Vector<TextCheckingResult> results;
2269     uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
2270     client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);
2271     
2272     for (unsigned i = 0; i < results.size(); i++) {
2273         const TextCheckingResult* result = &results[i];
2274         if (result->type == TextCheckingTypeSpelling && result->location == rangeStartOffset && result->length == rangeLength) {
2275             String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength);
2276             ASSERT(misspelledWord.length());
2277             client->getGuessesForWord(misspelledWord, guesses);
2278             client->updateSpellingUIWithMisspelledWord(misspelledWord);
2279             misspelled = true;
2280             return guesses;
2281         }
2282     }
2283     
2284     if (!checkGrammar)
2285         return guesses;
2286         
2287     for (unsigned i = 0; i < results.size(); i++) {
2288         const TextCheckingResult* result = &results[i];
2289         if (result->type == TextCheckingTypeGrammar && result->location <= rangeStartOffset && result->location + result->length >= rangeStartOffset + rangeLength) {
2290             for (unsigned j = 0; j < result->details.size(); j++) {
2291                 const GrammarDetail* detail = &result->details[j];
2292                 ASSERT(detail->length > 0 && detail->location >= 0);
2293                 if (result->location + detail->location == rangeStartOffset && detail->length == rangeLength) {
2294                     String badGrammarPhrase = paragraphString.substring(result->location, result->length);
2295                     ASSERT(badGrammarPhrase.length());
2296                     for (unsigned k = 0; k < detail->guesses.size(); k++)
2297                         guesses.append(detail->guesses[k]);
2298                     client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail);
2299                     ungrammatical = true;
2300                     return guesses;
2301                 }
2302             }
2303         }
2304     }
2305     return guesses;
2306 }
2307
2308 #endif
2309
2310 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
2311 {
2312 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2313     return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammatical);
2314 #else
2315     misspelled = isSelectionMisspelled();
2316     if (misspelled) {
2317         ungrammatical = false;
2318         return guessesForMisspelledSelection();
2319     }
2320     if (isGrammarCheckingEnabled() && isSelectionUngrammatical()) {
2321         ungrammatical = true;
2322         return guessesForUngrammaticalSelection();
2323     }
2324     ungrammatical = false;
2325     return Vector<String>();
2326 #endif
2327 }
2328
2329 void Editor::showSpellingGuessPanel()
2330 {
2331     if (!client()) {
2332         LOG_ERROR("No NSSpellChecker");
2333         return;
2334     }
2335
2336 #ifndef BUILDING_ON_TIGER
2337     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
2338     // to match rest of OS X.
2339     if (client()->spellingUIIsShowing()) {
2340         client()->showSpellingUI(false);
2341         return;
2342     }
2343 #endif
2344     
2345     advanceToNextMisspelling(true);
2346     client()->showSpellingUI(true);
2347 }
2348
2349 bool Editor::spellingPanelIsShowing()
2350 {
2351     if (!client())
2352         return false;
2353     return client()->spellingUIIsShowing();
2354 }
2355
2356 void Editor::clearMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
2357 {
2358     RefPtr<Range> selectedRange = movingSelection.toNormalizedRange();
2359     if (selectedRange) {
2360         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
2361         frame()->document()->markers()->removeMarkers(selectedRange.get(), DocumentMarker::Grammar);
2362     }
2363 }
2364
2365 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelection)
2366 {
2367     bool markSpelling = isContinuousSpellCheckingEnabled();
2368     bool markGrammar = markSpelling && isGrammarCheckingEnabled();
2369
2370     if (markSpelling) {
2371         RefPtr<Range> unusedFirstMisspellingRange;
2372         markMisspellings(movingSelection, unusedFirstMisspellingRange);
2373     }
2374
2375     if (markGrammar)
2376         markBadGrammar(movingSelection);
2377 }
2378
2379 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
2380 {
2381 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2382     TextCheckingOptions textCheckingOptions = 0;
2383     if (isContinuousSpellCheckingEnabled())
2384         textCheckingOptions |= MarkSpelling;
2385
2386     if (isAutomaticQuoteSubstitutionEnabled()
2387         || isAutomaticLinkDetectionEnabled()
2388         || isAutomaticDashSubstitutionEnabled()
2389         || isAutomaticTextReplacementEnabled()
2390         || ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled()))
2391         textCheckingOptions |= PerformReplacement;
2392
2393     if (!textCheckingOptions & (MarkSpelling | PerformReplacement))
2394         return;
2395
2396     if (isGrammarCheckingEnabled())
2397         textCheckingOptions |= MarkGrammar;
2398
2399     VisibleSelection adjacentWords = VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary));
2400     if (textCheckingOptions & MarkGrammar) {
2401         VisibleSelection selectedSentence = VisibleSelection(startOfSentence(p), endOfSentence(p));
2402         markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), selectedSentence.toNormalizedRange().get());
2403     } else {
2404         markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
2405     }
2406 #else
2407     if (!isContinuousSpellCheckingEnabled())
2408         return;
2409     
2410     // Check spelling of one word
2411     RefPtr<Range> misspellingRange;
2412     markMisspellings(VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)), misspellingRange);
2413
2414     // Autocorrect the misspelled word.
2415     if (!misspellingRange)
2416         return;
2417     
2418     // Get the misspelled word.
2419     const String misspelledWord = plainText(misspellingRange.get());
2420     String autocorrectedString = client()->getAutoCorrectSuggestionForMisspelledWord(misspelledWord);
2421
2422     // If autocorrected word is non empty, replace the misspelled word by this word.
2423     if (!autocorrectedString.isEmpty()) {
2424         VisibleSelection newSelection(misspellingRange.get(), DOWNSTREAM);
2425         if (newSelection != frame()->selection()->selection()) {
2426             if (!frame()->shouldChangeSelection(newSelection))
2427                 return;
2428             frame()->selection()->setSelection(newSelection);
2429         }
2430
2431         if (!frame()->editor()->shouldInsertText(autocorrectedString, misspellingRange.get(), EditorInsertActionTyped))
2432             return;
2433         frame()->editor()->replaceSelectionWithText(autocorrectedString, false, false);
2434
2435         // Reset the charet one character further.
2436         frame()->selection()->moveTo(frame()->selection()->end());
2437         frame()->selection()->modify(SelectionController::AlterationMove, SelectionController::DirectionForward, CharacterGranularity);
2438     }
2439
2440     if (!isGrammarCheckingEnabled())
2441         return;
2442     
2443     // Check grammar of entire sentence
2444     markBadGrammar(VisibleSelection(startOfSentence(p), endOfSentence(p)));
2445 #endif
2446 }
2447
2448 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange, RefPtr<Range>& firstMisspellingRange)
2449 {
2450     // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
2451     // all we need to do is mark every instance.
2452     int ignoredOffset;
2453     findFirstMisspellingInRange(client, searchRange, ignoredOffset, true, firstMisspellingRange);
2454 }
2455
2456 #ifndef BUILDING_ON_TIGER
2457 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
2458 {
2459     // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
2460     // do is mark every instance.
2461     GrammarDetail ignoredGrammarDetail;
2462     int ignoredOffset;
2463     findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
2464 }
2465 #endif
2466     
2467 static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
2468 {
2469     // This function is called with a selection already expanded to word boundaries.
2470     // Might be nice to assert that here.
2471     
2472     // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
2473     // grammar checking can only be on if spell checking is also on.
2474     if (!editor->isContinuousSpellCheckingEnabled())
2475         return;
2476     
2477     RefPtr<Range> searchRange(selection.toNormalizedRange());
2478     if (!searchRange)
2479         return;
2480     
2481     // If we're not in an editable node, bail.
2482     Node* editableNode = searchRange->startContainer();
2483     if (!editableNode || !editableNode->isContentEditable())
2484         return;
2485
2486     if (!editor->spellCheckingEnabledInFocusedNode())
2487         return;
2488
2489     // Get the spell checker if it is available
2490     if (!editor->client())
2491         return;
2492     
2493     if (checkSpelling)
2494         markAllMisspellingsInRange(editor->client(), searchRange.get(), firstMisspellingRange);
2495     else {
2496 #ifdef BUILDING_ON_TIGER
2497         ASSERT_NOT_REACHED();
2498 #else
2499         if (editor->isGrammarCheckingEnabled())
2500             markAllBadGrammarInRange(editor->client(), searchRange.get());
2501 #endif
2502     }    
2503 }
2504
2505 bool Editor::spellCheckingEnabledInFocusedNode() const
2506 {
2507     // Ascend the DOM tree to find a "spellcheck" attribute.
2508     // When we find a "spellcheck" attribute, retrieve its value and return false if its value is "false".
2509     const Node* node = frame()->document()->focusedNode();
2510     while (node) {
2511         if (node->isElementNode()) {
2512             const WTF::AtomicString& value = static_cast<const Element*>(node)->getAttribute(spellcheckAttr);
2513             if (equalIgnoringCase(value, "true"))
2514                 return true;
2515             if (equalIgnoringCase(value, "false"))
2516                 return false;
2517         }
2518         node = node->parent();
2519     }
2520     return true;
2521 }
2522
2523 void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
2524 {
2525     markMisspellingsOrBadGrammar(this, selection, true, firstMisspellingRange);
2526 }
2527     
2528 void Editor::markBadGrammar(const VisibleSelection& selection)
2529 {
2530 #ifndef BUILDING_ON_TIGER
2531     RefPtr<Range> firstMisspellingRange;
2532     markMisspellingsOrBadGrammar(this, selection, false, firstMisspellingRange);
2533 #else
2534     UNUSED_PARAM(selection);
2535 #endif
2536 }
2537
2538 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2539
2540 static inline bool isAmbiguousBoundaryCharacter(UChar character)
2541 {
2542     // These are characters that can behave as word boundaries, but can appear within words.
2543     // If they are just typed, i.e. if they are immediately followed by a caret, we want to delay text checking until the next character has been typed.
2544     // FIXME: this is required until 6853027 is fixed and text checking can do this for us.
2545     return character == '\'' || character == rightSingleQuotationMark || character == hebrewPunctuationGershayim;
2546 }
2547
2548 void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCheckingOptions, Range* spellingRange, Range* grammarRange)
2549 {
2550     bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
2551     bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
2552     bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
2553     bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
2554
2555     // This function is called with selections already expanded to word boundaries.
2556     ExceptionCode ec = 0;
2557     if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange))
2558         return;
2559
2560     // If we're not in an editable node, bail.
2561     Node* editableNode = spellingRange->startContainer();
2562     if (!editableNode || !editableNode->isContentEditable())
2563         return;
2564
2565     if (!spellCheckingEnabledInFocusedNode())
2566         return;
2567
2568     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
2569     int spellingRangeStartOffset = 0;
2570     int spellingRangeEndOffset = 0;
2571     int grammarRangeStartOffset = 0;
2572     int grammarRangeEndOffset = 0;
2573     int offsetDueToReplacement = 0;
2574     int paragraphLength = 0;
2575     int selectionOffset = 0;
2576     int ambiguousBoundaryOffset = -1;
2577     bool selectionChanged = false;
2578     bool restoreSelectionAfterChange = false;
2579     bool adjustSelectionForParagraphBoundaries = false;
2580     String paragraphString;
2581     RefPtr<Range> paragraphRange;
2582
2583     if (shouldMarkGrammar) {
2584         // The spelling range should be contained in the paragraph-aligned extension of the grammar range.
2585         paragraphRange = paragraphAlignedRangeForRange(grammarRange, grammarRangeStartOffset, paragraphString);
2586         RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
2587         spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
2588         grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange);
2589     } else {
2590         paragraphRange = paragraphAlignedRangeForRange(spellingRange, spellingRangeStartOffset, paragraphString);
2591     }
2592     spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
2593     paragraphLength = paragraphString.length();
2594     if (paragraphLength <= 0 || (spellingRangeStartOffset >= spellingRangeEndOffset && (!shouldMarkGrammar || grammarRangeStartOffset >= grammarRangeEndOffset)))
2595         return;
2596
2597     if (shouldPerformReplacement) {
2598         if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
2599             // Attempt to save the caret position so we can restore it later if needed
2600             RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), paragraphRange->startPosition());
2601             Position caretPosition = m_frame->selection()->end();
2602             offsetAsRange->setEnd(caretPosition.containerNode(), caretPosition.computeOffsetInContainerNode(), ec);
2603             if (!ec) {
2604                 selectionOffset = TextIterator::rangeLength(offsetAsRange.get());
2605                 restoreSelectionAfterChange = true;
2606                 if (selectionOffset > 0 && (selectionOffset > paragraphLength || paragraphString[selectionOffset - 1] == newlineCharacter))
2607                     adjustSelectionForParagraphBoundaries = true;
2608                 if (selectionOffset > 0 && selectionOffset <= paragraphLength && isAmbiguousBoundaryCharacter(paragraphString[selectionOffset - 1]))
2609                     ambiguousBoundaryOffset = selectionOffset - 1;
2610             }
2611         }
2612     }
2613
2614     Vector<TextCheckingResult> results;
2615     uint64_t checkingTypes = 0;
2616     if (shouldMarkSpelling)
2617         checkingTypes |= TextCheckingTypeSpelling;
2618     if (shouldMarkGrammar)
2619         checkingTypes |= TextCheckingTypeGrammar;
2620     if (shouldShowCorrectionPanel)
2621         checkingTypes |= TextCheckingTypeCorrection;
2622     if (shouldPerformReplacement) {
2623         if (isAutomaticLinkDetectionEnabled())
2624             checkingTypes |= TextCheckingTypeLink;
2625         if (isAutomaticQuoteSubstitutionEnabled())
2626             checkingTypes |= TextCheckingTypeQuote;
2627         if (isAutomaticDashSubstitutionEnabled())
2628             checkingTypes |= TextCheckingTypeDash;
2629         if (isAutomaticTextReplacementEnabled())
2630             checkingTypes |= TextCheckingTypeReplacement;
2631         if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
2632             checkingTypes |= TextCheckingTypeCorrection;
2633     }
2634     client()->checkTextOfParagraph(paragraphString.characters(), paragraphLength, checkingTypes, results);
2635
2636 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
2637     // If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
2638     if (shouldShowCorrectionPanel)
2639         shouldMarkSpelling = false;
2640 #endif
2641
2642     for (unsigned i = 0; i < results.size(); i++) {
2643         const TextCheckingResult* result = &results[i];
2644         int resultLocation = result->location + offsetDueToReplacement;
2645         int resultLength = result->length;
2646         if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingRangeStartOffset && resultLocation + resultLength <= spellingRangeEndOffset) {
2647             ASSERT(resultLength > 0 && resultLocation >= 0);
2648             RefPtr<Range> misspellingRange = TextIterator::subrange(spellingRange, resultLocation - spellingRangeStartOffset, resultLength);
2649             misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
2650         } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && resultLocation < grammarRangeEndOffset && resultLocation + resultLength > grammarRangeStartOffset) {
2651             ASSERT(resultLength > 0 && resultLocation >= 0);
2652             for (unsigned j = 0; j < result->details.size(); j++) {
2653                 const GrammarDetail* detail = &result->details[j];
2654                 ASSERT(detail->length > 0 && detail->location >= 0);
2655                 if (resultLocation + detail->location >= grammarRangeStartOffset && resultLocation + detail->location + detail->length <= grammarRangeEndOffset) {
2656                     RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarRange, resultLocation + detail->location - grammarRangeStartOffset, detail->length);
2657                     grammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
2658                 }
2659             }
2660         } else if ((shouldPerformReplacement || shouldShowCorrectionPanel) && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingRangeStartOffset
2661                     && (result->type == TextCheckingTypeLink
2662                     || result->type == TextCheckingTypeQuote
2663                     || result->type == TextCheckingTypeDash
2664                     || result->type == TextCheckingTypeReplacement
2665                     || result->type == TextCheckingTypeCorrection)) {
2666             // In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation.
2667             ASSERT(resultLength > 0 && resultLocation >= 0);
2668             int replacementLength = result->replacement.length();
2669             bool doReplacement = (replacementLength > 0);
2670             RefPtr<Range> rangeToReplace = TextIterator::subrange(paragraphRange.get(), resultLocation, resultLength);
2671             VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);
2672         
2673             // avoid correcting text after an ambiguous boundary character has been typed
2674             // FIXME: this is required until 6853027 is fixed and text checking can do this for us
2675             if (ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset)
2676                 doReplacement = false;
2677
2678             // adding links should be done only immediately after they are typed
2679             if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1)
2680                 doReplacement = false;
2681
2682             // Don't correct spelling in an already-corrected word.
2683             if (doReplacement && result->type == TextCheckingTypeCorrection) {
2684                 Node* node = rangeToReplace->startContainer();
2685                 int startOffset = rangeToReplace->startOffset();
2686                 int endOffset = startOffset + replacementLength;
2687                 Vector<DocumentMarker> markers = node->document()->markers()->markersForNode(node);
2688                 size_t markerCount = markers.size();
2689                 for (size_t i = 0; i < markerCount; ++i) {
2690                     const DocumentMarker& marker = markers[i];
2691                     if ((marker.type == DocumentMarker::Replacement || marker.type == DocumentMarker::RejectedCorrection) && static_cast<int>(marker.startOffset) < endOffset && static_cast<int>(marker.endOffset) > startOffset) {
2692                         doReplacement = false;
2693                         break;
2694                     }
2695                     if (static_cast<int>(marker.startOffset) >= endOffset)
2696                         break;
2697                 }
2698             }
2699             if (doReplacement && !shouldShowCorrectionPanel && selectionToReplace != m_frame->selection()->selection()) {
2700                 if (m_frame->shouldChangeSelection(selectionToReplace)) {
2701                     m_frame->selection()->setSelection(selectionToReplace);
2702                     selectionChanged = true;
2703                 } else {
2704                     doReplacement = false;
2705                 }
2706             }
2707
2708             String replacedString;
2709             if (doReplacement) {
2710                 if (result->type == TextCheckingTypeLink) {
2711                     restoreSelectionAfterChange = false;
2712                     if (canEditRichly())
2713                         applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
2714                 } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
2715                     if (result->type == TextCheckingTypeCorrection)
2716                         replacedString = plainText(rangeToReplace.get());
2717 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
2718                     if (shouldShowCorrectionPanel && resultLocation + resultLength == spellingRangeEndOffset && result->type == TextCheckingTypeCorrection) {
2719                         // We only show the correction panel on the last word.
2720                         Vector<FloatQuad> textQuads;
2721                         rangeToReplace->textQuads(textQuads);
2722                         Vector<FloatQuad>::const_iterator end = textQuads.end();
2723                         FloatRect totalBoundingBox;
2724                         for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
2725                             totalBoundingBox.unite(it->boundingBox());
2726                         m_rangeToBeReplacedByCorrection = rangeToReplace;
2727                         m_stringToBeReplacedByCorrection = replacedString;
2728                         client()->showCorrectionPanel(totalBoundingBox, m_stringToBeReplacedByCorrection, result->replacement, this);
2729                         doReplacement = false;
2730                     }
2731 #endif
2732                     if (doReplacement) {
2733                         replaceSelectionWithText(result->replacement, false, false);
2734                         spellingRangeEndOffset += replacementLength - resultLength;
2735                         offsetDueToReplacement += replacementLength - resultLength;
2736                         if (resultLocation < selectionOffset)
2737                             selectionOffset += replacementLength - resultLength;
2738                         if (result->type == TextCheckingTypeCorrection) {
2739 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
2740                             if (client())
2741                                 client()->dismissCorrectionPanel(true);
2742 #endif
2743                             // Add a marker so that corrections can easily be undone and won't be re-corrected.
2744                             RefPtr<Range> replacedRange = TextIterator::subrange(paragraphRange.get(), resultLocation, replacementLength);
2745                             replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
2746                         }
2747                     }
2748                 }
2749             }
2750         }
2751     }
2752
2753     if (selectionChanged) {
2754         // Restore the caret position if we have made any replacements
2755         setEnd(paragraphRange.get(), endOfParagraph(startOfNextParagraph(paragraphRange->startPosition())));
2756         int newLength = TextIterator::rangeLength(paragraphRange.get());
2757         if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= newLength) {
2758             RefPtr<Range> selectionRange = TextIterator::subrange(paragraphRange.get(), 0, selectionOffset);
2759             m_frame->selection()->moveTo(selectionRange->endPosition(), DOWNSTREAM);
2760             if (adjustSelectionForParagraphBoundaries)
2761                 m_frame->selection()->modify(SelectionController::AlterationMove, SelectionController::DirectionForward, CharacterGranularity);
2762         } else {
2763             // If this fails for any reason, the fallback is to go one position beyond the last replacement
2764             m_frame->selection()->moveTo(m_frame->selection()->end());
2765             m_frame->selection()->modify(SelectionController::AlterationMove, SelectionController::DirectionForward, CharacterGranularity);
2766         }
2767     }
2768 }
2769
2770 void Editor::changeBackToReplacedString(const String& replacedString)
2771 {
2772     if (replacedString.isEmpty())
2773         return;
2774
2775     RefPtr<Range> selection = selectedRange();
2776     if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
2777         return;
2778         
2779     String paragraphString;
2780     int selectionOffset;
2781     RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(selection.get(), selectionOffset, paragraphString);
2782     replaceSelectionWithText(replacedString, false, false);
2783     RefPtr<Range> changedRange = TextIterator::subrange(paragraphRange.get(), selectionOffset, replacedString.length());
2784     changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
2785 }
2786
2787 #endif
2788
2789 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection)
2790 {
2791 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2792     if (!isContinuousSpellCheckingEnabled())
2793         return;
2794     TextCheckingOptions textCheckingOptions = MarkSpelling;
2795     if (markGrammar && isGrammarCheckingEnabled())
2796         textCheckingOptions |= MarkGrammar;
2797     markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get());
2798 #else
2799     RefPtr<Range> firstMisspellingRange;
2800     markMisspellings(spellingSelection, firstMisspellingRange);
2801     if (markGrammar)
2802         markBadGrammar(grammarSelection);
2803 #endif
2804 }
2805
2806 void Editor::correctionPanelTimerFired(Timer<Editor>*)
2807 {
2808 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
2809     VisibleSelection selection(frame()->selection()->selection());
2810     VisiblePosition start(selection.start(), selection.affinity());
2811     VisiblePosition p = startOfWord(start, LeftWordIfOnBoundary);
2812     VisibleSelection adjacentWords = VisibleSelection(p, start);
2813     markAllMisspellingsAndBadGrammarInRanges(MarkSpelling | ShowCorrectionPanel, adjacentWords.toNormalizedRange().get(), 0);
2814 #endif
2815 }
2816
2817 void Editor::handleRejectedCorrection()
2818 {
2819     Range* replacedRange = m_rangeToBeReplacedByCorrection.get();
2820     if (!replacedRange || m_frame->document() != replacedRange->ownerDocument())
2821         return;
2822
2823     replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_stringToBeReplacedByCorrection);
2824 }
2825
2826 void Editor::startCorrectionPanelTimer()
2827 {
2828 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
2829     static const double correctionPanelTimerInterval = 0.3;
2830     if (client())
2831         client()->dismissCorrectionPanel(true);
2832     if (isAutomaticSpellingCorrectionEnabled())
2833         m_correctionPanelTimer.startOneShot(correctionPanelTimerInterval);
2834 #endif
2835 }
2836
2837 void Editor::handleCancelOperation()
2838 {
2839 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
2840     if (client())
2841         client()->dismissCorrectionPanel(false);
2842 #endif
2843 }
2844
2845 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
2846 {
2847     Document* document = m_frame->documentAtPoint(windowPoint);
2848     if (!document)
2849         return 0;
2850     
2851     Frame* frame = document->frame();
2852     ASSERT(frame);
2853     FrameView* frameView = frame->view();
2854     if (!frameView)
2855         return 0;
2856     IntPoint framePoint = frameView->windowToContents(windowPoint);
2857     VisibleSelection selection(frame->visiblePositionForPoint(framePoint));
2858     return avoidIntersectionWithNode(selection.toNormalizedRange().get(), m_deleteButtonController->containerElement());
2859 }
2860
2861 void Editor::revealSelectionAfterEditingOperation()
2862 {
2863     if (m_ignoreCompositionSelectionChange)
2864         return;
2865
2866     m_frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
2867 }
2868
2869 void Editor::setIgnoreCompositionSelectionChange(bool ignore)
2870 {
2871     if (m_ignoreCompositionSelectionChange == ignore)
2872         return;
2873
2874     m_ignoreCompositionSelectionChange = ignore;
2875     if (!ignore)
2876         revealSelectionAfterEditingOperation();
2877 }
2878
2879 PassRefPtr<Range> Editor::compositionRange() const
2880 {
2881     if (!m_compositionNode)
2882         return 0;
2883     unsigned length = m_compositionNode->length();
2884     unsigned start = min(m_compositionStart, length);
2885     unsigned end = min(max(start, m_compositionEnd), length);
2886     if (start >= end)
2887         return 0;
2888     return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
2889 }
2890
2891 bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
2892 {
2893     if (!m_compositionNode)
2894         return false;
2895     Position start = m_frame->selection()->start();
2896     if (start.node() != m_compositionNode)
2897         return false;
2898     Position end = m_frame->selection()->end();
2899     if (end.node() != m_compositionNode)
2900         return false;
2901
2902     if (static_cast<unsigned>(start.deprecatedEditingOffset()) < m_compositionStart)
2903         return false;
2904     if (static_cast<unsigned>(end.deprecatedEditingOffset()) > m_compositionEnd)
2905         return false;
2906
2907     selectionStart = start.deprecatedEditingOffset() - m_compositionStart;
2908     selectionEnd = start.deprecatedEditingOffset() - m_compositionEnd;
2909     return true;
2910 }
2911
2912 void Editor::transpose()
2913 {
2914     if (!canEdit())
2915         return;
2916
2917      VisibleSelection selection = m_frame->selection()->selection();
2918      if (!selection.isCaret())
2919          return;
2920
2921     // Make a selection that goes back one character and forward two characters.
2922     VisiblePosition caret = selection.visibleStart();
2923     VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
2924     VisiblePosition previous = next.previous();
2925     if (next == previous)
2926         return;
2927     previous = previous.previous();
2928     if (!inSameParagraph(next, previous))
2929         return;
2930     RefPtr<Range> range = makeRange(previous, next);
2931     if (!range)
2932         return;
2933     VisibleSelection newSelection(range.get(), DOWNSTREAM);
2934
2935     // Transpose the two characters.
2936     String text = plainText(range.get());
2937     if (text.length() != 2)
2938         return;
2939     String transposed = text.right(1) + text.left(1);
2940
2941     // Select the two characters.
2942     if (newSelection != m_frame->selection()->selection()) {
2943         if (!m_frame->shouldChangeSelection(newSelection))
2944             return;
2945         m_frame->selection()->setSelection(newSelection);
2946     }
2947
2948     // Insert the transposed characters.
2949     if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
2950         return;
2951     replaceSelectionWithText(transposed, false, false);
2952 }
2953
2954 void Editor::addToKillRing(Range* range, bool prepend)
2955 {
2956     if (m_shouldStartNewKillRingSequence)
2957         killRing()->startNewSequence();
2958
2959     String text = plainText(range);
2960     if (prepend)
2961         killRing()->prepend(text);
2962     else
2963         killRing()->append(text);
2964     m_shouldStartNewKillRingSequence = false;
2965 }
2966
2967 bool Editor::insideVisibleArea(const IntPoint& point) const
2968 {
2969     if (m_frame->excludeFromTextSearch())
2970         return false;
2971     
2972     // Right now, we only check the visibility of a point for disconnected frames. For all other
2973     // frames, we assume visibility.
2974     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
2975     if (!frame->isDisconnected())
2976         return true;
2977     
2978     RenderPart* renderer = frame->ownerRenderer();
2979     if (!renderer)
2980         return false;
2981
2982     RenderBlock* container = renderer->containingBlock();
2983     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
2984         return true;
2985
2986     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
2987     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
2988                                     rectInPageCoords.width(), rectInPageCoords.height());
2989
2990     return rectInFrameCoords.contains(point);
2991 }
2992
2993 bool Editor::insideVisibleArea(Range* range) const
2994 {
2995     if (!range)
2996         return true;
2997
2998     if (m_frame->excludeFromTextSearch())
2999         return false;
3000     
3001     // Right now, we only check the visibility of a range for disconnected frames. For all other
3002     // frames, we assume visibility.
3003     Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
3004     if (!frame->isDisconnected())
3005         return true;
3006     
3007     RenderPart* renderer = frame->ownerRenderer();
3008     if (!renderer)
3009         return false;
3010
3011     RenderBlock* container = renderer->containingBlock();
3012     if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
3013         return true;
3014
3015     IntRect rectInPageCoords = container->overflowClipRect(0, 0);
3016     IntRect rectInFrameCoords = IntRect(renderer->x() * -1, renderer->y() * -1,
3017                                     rectInPageCoords.width(), rectInPageCoords.height());
3018     IntRect resultRect = range->boundingBox();
3019     
3020     return rectInFrameCoords.contains(resultRect);
3021 }
3022
3023 PassRefPtr<Range> Editor::firstVisibleRange(const String& target, bool caseFlag)
3024 {
3025     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
3026     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
3027     ExceptionCode ec = 0;
3028
3029     while (!insideVisibleArea(resultRange.get())) {
3030         searchRange->setStartAfter(resultRange->endContainer(), ec);
3031         if (searchRange->startContainer() == searchRange->endContainer())
3032             return Range::create(m_frame->document());
3033         resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
3034     }
3035     
3036     return resultRange;
3037 }
3038
3039 PassRefPtr<Range> Editor::lastVisibleRange(const String& target, bool caseFlag)
3040 {
3041     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
3042     RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
3043     ExceptionCode ec = 0;
3044
3045     while (!insideVisibleArea(resultRange.get())) {
3046         searchRange->setEndBefore(resultRange->startContainer(), ec);
3047         if (searchRange->startContainer() == searchRange->endContainer())
3048             return Range::create(m_frame->document());
3049         resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
3050     }
3051     
3052     return resultRange;
3053 }
3054
3055 PassRefPtr<Range> Editor::nextVisibleRange(Range* currentRange, const String& target, bool forward, bool caseFlag, bool wrapFlag)
3056 {
3057     if (m_frame->excludeFromTextSearch())
3058         return Range::create(m_frame->document());
3059
3060     RefPtr<Range> resultRange = currentRange;
3061     RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
3062     ExceptionCode ec = 0;
3063     
3064     for ( ; !insideVisibleArea(resultRange.get()); resultRange = findPlainText(searchRange.get(), target, forward, caseFlag)) {
3065         if (resultRange->collapsed(ec)) {
3066             if (!resultRange->startContainer()->isInShadowTree())
3067                 break;
3068             searchRange = rangeOfContents(m_frame->document());
3069             if (forward)
3070                 searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
3071             else
3072                 searchRange->setEndBefore(resultRange->startContainer()->shadowAncestorNode(), ec);
3073             continue;
3074         }
3075
3076         if (forward)
3077             searchRange->setStartAfter(resultRange->endContainer(), ec);
3078         else
3079             searchRange->setEndBefore(resultRange->startContainer(), ec);
3080
3081         Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
3082         if (searchRange->collapsed(ec) && shadowTreeRoot) {
3083             if (forward)
3084                 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
3085             else
3086                 searchRange->setStartBefore(shadowTreeRoot, ec);
3087         }
3088         
3089         if (searchRange->startContainer()->isDocumentNode() && searchRange->endContainer()->isDocumentNode())
3090             break;
3091     }
3092     
3093     if (insideVisibleArea(resultRange.get()))
3094         return resultRange;
3095     
3096     if (!wrapFlag)
3097         return Range::create(m_frame->document());
3098
3099     if (forward)
3100         return firstVisibleRange(target, caseFlag);
3101
3102     return lastVisibleRange(target, caseFlag);
3103 }
3104
3105 void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle)
3106 {
3107     // If the new selection is orphaned, then don't update the selection.
3108     if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
3109         return;
3110
3111     // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
3112     // because there is work that it must do in this situation.
3113     // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
3114     // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
3115     bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
3116     if (selectionDidNotChangeDOMPosition || m_frame->shouldChangeSelection(newSelection))
3117         m_frame->selection()->setSelection(newSelection, closeTyping, clearTypingStyle);
3118         
3119     // Some editing operations change the selection visually without affecting its position within the DOM.
3120     // For example when you press return in the following (the caret is marked by ^): 
3121     // <div contentEditable="true"><div>^Hello</div></div>
3122     // WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't
3123     // change the caret's DOM position (["hello", 0]).  In these situations the above SelectionController::setSelection call
3124     // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and 
3125     // starts a new kill ring sequence, but we want to do these things (matches AppKit).
3126     if (selectionDidNotChangeDOMPosition)
3127         client()->respondToChangedSelection();
3128 }
3129
3130 } // namespace WebCore