2011-03-01  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        Remove CorrectionIndicator markers sooner.
        https://bugs.webkit.org/show_bug.cgi?id=54893
        <rdar://problem/8997524>

        See WebCore/ChangeLog for detail.

        * platform/mac-leopard/Skipped:
        * platform/mac-snowleopard/Skipped:
        * platform/mac-tiger/Skipped:
        * platform/mac-wk2/Skipped:
        * platform/mac/editing/spelling/autocorrection-simple-expected.checksum:
        * platform/mac/editing/spelling/autocorrection-simple-expected.png:
        * platform/mac/editing/spelling/autocorrection-simple-expected.txt:
        * platform/mac/editing/spelling/autocorrection-simple.html:
        * platform/mac/editing/spelling/delete-into-autocorrected-word-expected.checksum:
        * platform/mac/editing/spelling/delete-into-autocorrected-word-expected.png:
        * platform/mac/editing/spelling/removing-underline-after-accepting-autocorrection-using-punctuation-expected.checksum: Added.
        * platform/mac/editing/spelling/removing-underline-after-accepting-autocorrection-using-punctuation-expected.png: Added.
        * platform/mac/editing/spelling/removing-underline-after-accepting-autocorrection-using-punctuation-expected.txt: Copied from LayoutTests/platform/mac/editing/spelling/autocorrection-simple-expected.txt.
        * platform/mac/editing/spelling/removing-underline-after-accepting-autocorrection-using-punctuation.html: Copied from LayoutTests/platform/mac/editing/spelling/autocorrection-simple.html.
2011-03-01  Jia Pu  <jpu@apple.com>

        Reviewed by Darin Adler.

        Remove CorrectionIndicator markers sooner.
        https://bugs.webkit.org/show_bug.cgi?id=54893
        <rdar://problem/8997524>

        Test: platform/mac/editing/spelling/removing-underline-after-accepting-autocorrection-using-punctuation.html

        This patch changes the autocorrection behavior on Mac OS X. We want to remove CorrectionIndicator
        marker after any editing command if the command:
        1. is not a SpellingCorrectionCommand itself.
        2. is not the command that triggers the autocorrection.
        This is achieved by adding shouldRetainAutocorrectionIndicator() function to EditCommand. This function returns
        false for all commands derived from EditCommand, except SpellingCorrectionCommand and TypingCommand. This function
        always returns true for SpellingCorrectionCommand. For TypingCommand, the return value is determined by member
        variable m_shouldRetainAutocorrectionIndicator, which can be modified by passing option into the TypingCommand's
        public functions.

        To avoid constantly searching marker list, we use variable DocumentMarkerController::m_absentMarkerTypeCache
        to cache whether there is any marker of a particular type.

        This patch also fixes two minor existing bugs.

        1. We used to show reversion panel for word with CorrectionIndicator marker. This is incorrect because
        CorrectionIndicator marker can be removed from corrected words. Since all autocorrected words have Replacement
        marker unless the whole word is deleted, the correct behavior is to show reversion panel for word with Replacement
        marker, since all autocorrected words have such marker. However, since we don't want to show the reversion panel
        if an autocorrected word has been edited, we also check to see if the Replacement marker's description is null.

        This works as following:
        When we apply an autocorrection, we add Replacement marker to corrected word, and store original word
        as the marker's description. If the user edited the corrected word afterward, we set description to null.
        So when we decide whether to show a reversion panel, we not only check for the existence of Replacement
        marker, but also check if description is null.

        2. Fixed an assertion violation in Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(), which would
        occur when deleting the first character in an editable area.

        * dom/DocumentMarker.h: Added m_possiblyExistingMarkerTypes to allow quickly checking whether a marker type is
           completely in from the document.

        * dom/DocumentMarkerController.cpp: Most of the functions listed here are optimized for early return by checking
           the return value of possiblyHasMarkers() at beginning.
        (WebCore::DocumentMarkerController::possiblyHasMarkers):
        (WebCore::DocumentMarkerController::DocumentMarkerController):
        (WebCore::DocumentMarkerController::detach):
        (WebCore::DocumentMarkerController::removeMarkers):
        (WebCore::DocumentMarkerController::addMarker):
        (WebCore::DocumentMarkerController::copyMarkers):
        (WebCore::DocumentMarkerController::markerContainingPoint):
        (WebCore::DocumentMarkerController::renderedRectsForMarkers):
        (WebCore::DocumentMarkerController::removeMarkersFromMarkerMapVectorPair):
        (WebCore::DocumentMarkerController::repaintMarkers):
        (WebCore::DocumentMarkerController::shiftMarkers):
        (WebCore::DocumentMarkerController::setMarkersActive):
        (WebCore::DocumentMarkerController::hasMarkers):
        (WebCore::DocumentMarkerController::clearDescriptionOnMarkersIntersectingRange):
        * dom/DocumentMarkerController.h:
        * editing/EditCommand.cpp:
        (WebCore::EditCommand::apply):
        (WebCore::EditCommand::shouldRetainAutocorrectionIndicator):
        (WebCore::EditCommand::setShouldRetainAutocorrectionIndicator):
        * editing/EditCommand.h:
        * editing/Editor.cpp:
        (WebCore::Editor::respondToChangedSelection):
        (WebCore::Editor::appliedEditing):
        (WebCore::Editor::insertTextWithoutSendingTextEvent):
        (WebCore::Editor::insertLineBreak):
        (WebCore::Editor::insertParagraphSeparator):
        (WebCore::Editor::markMisspellingsAfterTypingToWord):
        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
        (WebCore::Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited):
        (WebCore::Editor::applyAutocorrectionBeforeTypingIfAppropriate):
        * editing/Editor.h:
        * editing/EditorCommand.cpp:
        (WebCore::executeInsertLineBreak):
        (WebCore::executeInsertParagraph):
        (WebCore::executeInsertText):
        * editing/SpellingCorrectionCommand.cpp:
        (WebCore::SpellingCorrectionCommand::shouldRetainAutocorrectionIndicator):
        * editing/SpellingCorrectionCommand.h:
        * editing/TypingCommand.cpp:
        (WebCore::TypingCommand::TypingCommand):
        (WebCore::TypingCommand::deleteSelection):
        (WebCore::TypingCommand::deleteKeyPressed):
        (WebCore::TypingCommand::forwardDeleteKeyPressed):
        (WebCore::TypingCommand::updateSelectionIfDifferentFromCurrentSelection):
        (WebCore::TypingCommand::insertText):
        (WebCore::TypingCommand::insertLineBreak):
        (WebCore::TypingCommand::insertParagraphSeparatorInQuotedContent):
        (WebCore::TypingCommand::insertParagraphSeparator):
        * editing/TypingCommand.h:
        (WebCore::TypingCommand::create):
        (WebCore::TypingCommand::shouldRetainAutocorrectionIndicator):
        (WebCore::TypingCommand::setShouldRetainAutocorrectionIndicator):
        * manual-tests/autocorrection/type-whitespace-to-dismiss-reversion.html:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@80023 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index 7f2c2e4..5df2c7a 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -47,18 +47,18 @@
 
 using namespace HTMLNames;
 
-TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, bool selectInsertedText, TextGranularity granularity, TextCompositionType compositionType,
-                             bool killRing)
-    : CompositeEditCommand(document), 
-      m_commandType(commandType), 
-      m_textToInsert(textToInsert), 
-      m_openForMoreTyping(true), 
-      m_selectInsertedText(selectInsertedText),
-      m_smartDelete(false),
-      m_granularity(granularity),
-      m_compositionType(compositionType),
-      m_killRing(killRing),
-      m_openedByBackwardDelete(false)
+TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, TypingCommandOptions options, TextGranularity granularity, TextCompositionType compositionType)
+    : CompositeEditCommand(document)
+    , m_commandType(commandType)
+    , m_textToInsert(textToInsert)
+    , m_openForMoreTyping(true)
+    , m_selectInsertedText(options & SelectInsertedText)
+    , m_smartDelete(false)
+    , m_granularity(granularity)
+    , m_compositionType(compositionType)
+    , m_killRing(options & KillRing)
+    , m_openedByBackwardDelete(false)
+    , m_shouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator)
 {
     updatePreservesTypingStyle(m_commandType);
 }
@@ -78,8 +78,8 @@
         static_cast<TypingCommand*>(lastEditCommand)->deleteSelection(smartDelete);
         return;
     }
-    
-    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteSelection, "", false);
+
+    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteSelection, "", 0);
     typingCommand->setSmartDelete(smartDelete);
     typingCommand->apply();
 }
@@ -97,8 +97,9 @@
         static_cast<TypingCommand*>(lastEditCommand)->deleteKeyPressed(granularity, killRing);
         return;
     }
-    
-    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteKey, "", false, granularity, killRing);
+
+    TypingCommandOptions options = killRing ? KillRing : 0;
+    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteKey, "", options, granularity);
     typingCommand->setSmartDelete(smartDelete);
     typingCommand->apply();
 }
@@ -118,7 +119,8 @@
         return;
     }
 
-    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, ForwardDeleteKey, "", false, granularity, killRing);
+    TypingCommandOptions options = killRing ? KillRing : 0;
+    RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, ForwardDeleteKey, "", options, granularity);
     typingCommand->setSmartDelete(smartDelete);
     typingCommand->apply();
 }
@@ -129,30 +131,29 @@
     VisibleSelection currentSelection = frame->selection()->selection();
     if (currentSelection == typingCommand->endingSelection())
         return;
-    
+
     typingCommand->setStartingSelection(currentSelection);
     typingCommand->setEndingSelection(currentSelection);
 }
-    
 
-void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, TextCompositionType composition)
+void TypingCommand::insertText(Document* document, const String& text, TypingCommandOptions options, TextCompositionType composition)
 {
     ASSERT(document);
-    
+
     Frame* frame = document->frame();
     ASSERT(frame);
 
-    insertText(document, text, frame->selection()->selection(), selectInsertedText, composition);
-}
-
-// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to SelectionController's current selection.
-void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, bool selectInsertedText, TextCompositionType compositionType)
-{
 #if REMOVE_MARKERS_UPON_EDITING
     if (!text.isEmpty())
         document->frame()->editor()->removeSpellAndCorrectionMarkersFromWordsToBeEdited(isSpaceOrNewline(text.characters()[0]));
 #endif
 
+    insertText(document, text, frame->selection()->selection(), options, composition);
+}
+
+// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to SelectionController's current selection.
+void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, TypingCommandOptions options, TextCompositionType compositionType)
+{
     ASSERT(document);
 
     RefPtr<Frame> frame = document->frame();
@@ -184,13 +185,14 @@
             lastTypingCommand->setStartingSelection(selectionForInsertion);
             lastTypingCommand->setEndingSelection(selectionForInsertion);
         }
-        
+
         lastTypingCommand->setCompositionType(compositionType);
-        lastTypingCommand->insertText(newText, selectInsertedText);
+        lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+        lastTypingCommand->insertText(newText, options & SelectInsertedText);
         return;
     }
 
-    RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText, compositionType);
+    RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, options, compositionType);
     if (changeSelection)  {
         cmd->setStartingSelection(selectionForInsertion);
         cmd->setEndingSelection(selectionForInsertion);
@@ -202,29 +204,31 @@
     }
 }
 
-void TypingCommand::insertLineBreak(Document *document)
+void TypingCommand::insertLineBreak(Document *document, TypingCommandOptions options)
 {
     ASSERT(document);
-    
+
     Frame* frame = document->frame();
     ASSERT(frame);
-    
+
     EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
     if (isOpenForMoreTypingCommand(lastEditCommand)) {
-        static_cast<TypingCommand*>(lastEditCommand)->insertLineBreak();
+        TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand);
+        lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+        lastTypingCommand->insertLineBreak();
         return;
     }
 
-    applyCommand(TypingCommand::create(document, InsertLineBreak));
+    applyCommand(TypingCommand::create(document, InsertLineBreak, "", options));
 }
 
 void TypingCommand::insertParagraphSeparatorInQuotedContent(Document *document)
 {
     ASSERT(document);
-    
+
     Frame* frame = document->frame();
     ASSERT(frame);
-    
+
     EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
     if (isOpenForMoreTypingCommand(lastEditCommand)) {
         static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparatorInQuotedContent();
@@ -234,20 +238,22 @@
     applyCommand(TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent));
 }
 
-void TypingCommand::insertParagraphSeparator(Document *document)
+void TypingCommand::insertParagraphSeparator(Document *document, TypingCommandOptions options)
 {
     ASSERT(document);
-    
+
     Frame* frame = document->frame();
     ASSERT(frame);
-    
+
     EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
     if (isOpenForMoreTypingCommand(lastEditCommand)) {
-        static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparator();
+        TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand);
+        lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+        lastTypingCommand->insertParagraphSeparator();
         return;
     }
 
-    applyCommand(TypingCommand::create(document, InsertParagraphSeparator));
+    applyCommand(TypingCommand::create(document, InsertParagraphSeparator, "", options));
 }
 
 bool TypingCommand::isOpenForMoreTypingCommand(const EditCommand* cmd)