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