[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

mitz at apple.com mitz at apple.com
Wed Dec 22 12:55:55 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 1f24e24ae4cabb671948aa45328672dc461c4f8b
Author: mitz at apple.com <mitz at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Sep 2 06:43:50 2010 +0000

    Add support for autocorrection UI on Mac OS X.
    https://bugs.webkit.org/show_bug.cgi?id=44958
    <rdar://problem/7299621>
    
    Patch by Jia Pu <jpu at apple.com> on 2010-09-01
    Reviewed by Dan Bernstein.
    
    WebCore:
    
    Several new member methods are added to EditorClient for communication
    between WebCore and WebKit. A new handler, executeCancelOperation(), is
    added to EditorCommand.cpp so that WebCore can intercept the ESC key event
    to dismiss autocorrection UI. A new DocumentMarker value, RejectedCorrection,
    is added to keep track of the corrections that user has rejected, so that it
    will not be suggested again later. The autocorrection is driven by a timer.
    Every time the editor inserts a new letter, the timer is reset. If the timer
    fires, it means neither has user entered any new letter for current word, nor
    has he entered whitespace or punctuation to complete the word. In this case,
    we query for autocorrection.
    
    * WebCore.exp.in: Updated
    
    * dom/DocumentMarker.h: Added RejectedCorrection to indicate word on which user
      has rejected autocorrection.
    
    * editing/Editor.cpp:
    (WebCore::Editor::Editor): Initialize autocorrection timer.
    (WebCore::Editor::~Editor): Make sure autocorrection UI is dismissed before
      destroying Editor object.
    (WebCore::Editor::markMisspellingsAfterTypingToPosition): Adopted new signature
      of markAllMisspellingsAndBadGrammarInRanges().
    (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Consolidated all
      boolean arguments into one bitfield. This improves readability and allows us to
      pass in a bit to indicate whether we want to show autocorrection UI. Also added
      code to show autocorrection UI if it is necessary.
    (WebCore::Editor::markMisspellingsAndBadGrammar): Adopted new signature of
      markAllMisspellingsAndBadGrammarInRanges().
    (WebCore::Editor::correctionPanelTimerFired): Check to see if we should show
      autocorrection UI when user pauses during typing.
    (WebCore::Editor::handleRejectedCorrection): Update user dictionary when an autocorrection is rejected.
    (WebCore::Editor::startCorrectionPanelTimer): Start autocorrection timer.
    (WebCore::Editor::handleCancelOperation): Dismiss autocorrection UI when ESC key is pressed.
    
    * editing/Editor.h: Added autocorrection related member methods and variables.
    
    * editing/EditorCommand.cpp:
    (WebCore::executeCancelOperation): Handle ESC key event. Dismiss autocorrection UI.
    (WebCore::createCommandMap): Updated for executeCancelOperation().
    
    * editing/TypingCommand.cpp:
    (WebCore::TypingCommand::markMisspellingsAfterTyping): Reset autocorrection timer after insertion.
    
    * loader/EmptyClients.h:
    (WebCore::EmptyEditorClient::showCorrectionPanel): Dummy implementation.
    (WebCore::EmptyEditorClient::dismissCorrectionPanel): Ditto
    
    * page/EditorClient.h: Added methods for communication between WebCore and WebKit regarding autocorrection.
    
    * page/Frame.cpp:
    (WebCore::Frame::respondToChangedSelection): Remove Replacement marker where we used to only remove Spelling
      mark, because whenever we need to remove spelling underline we also should remove autocorrection underline.
    
    * platform/graphics/GraphicsContext.h: Added enum TextCheckingLineStyle to specify the underline
      for different type of text checking result. Replaced drawLineForMisspellingOrBadGrammar() with
      drawLineForTextChecking(), which allows autocorrection to have different indication from misspelling
      and grammatical error.
    
    * platform/graphics/cairo/GraphicsContextCairo.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Replaced drawLineForMisspellingOrBadGrammar() with drawLineForTextChecking().
    
    * platform/graphics/haiku/GraphicsContextHaiku.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/mac/GraphicsContextMac.mm:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/openvg/GraphicsContextOpenVG.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/qt/GraphicsContextQt.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/skia/GraphicsContextSkia.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/win/GraphicsContextCGWin.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/wince/GraphicsContextWince.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * platform/graphics/wx/GraphicsContextWx.cpp:
    (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
    
    * rendering/InlineTextBox.cpp:
    (WebCore::textCheckingLineStyleForMarkerType): Return line style for a given document marker type.
    (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):  Replaced drawLineForMisspellingOrBadGrammar() with drawLineForTextChecking().
    (WebCore::InlineTextBox::paintDocumentMarkers): Handle new marker value, RejectedCorrection.
    
    WebKit/mac:
    
    See detailed high level description in WebCore/ChangeLog.
    
    * WebCoreSupport/WebEditorClient.h: Added new member methods declared in
      EditorClient. Added m_correctionPanelTag to store the ID of current autocorrection UI object.
    
    * WebCoreSupport/WebEditorClient.mm:
    (WebEditorClient::WebEditorClient): Initialize m_correctionPanelTag.
    (WebEditorClient::~WebEditorClient): Make sure the autocorrection UI is
      dismissed before destroying the object.
    (WebEditorClient::respondToChangedSelection): Dismiss autocorrection UI whenever the selection changes.
    (WebEditorClient::showCorrectionPanel): Show autocorrection UI.
    (WebEditorClient::dismissCorrectionPanel): Dismiss autocorrection UI.
    
    WebKit2:
    
    See detailed high level description in WebCore/ChangeLog.
    
    * WebProcess/WebCoreSupport/WebEditorClient.cpp:
    (WebKit::WebEditorClient::showCorrectionPanel): Dummy implementation.
    (WebKit::WebEditorClient::dismissCorrectionPanel): Ditto
    
    * WebProcess/WebCoreSupport/WebEditorClient.h: Added new methods declared in base class.
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66643 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index a000bb0..5ee715f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,101 @@
+2010-09-01  Jia Pu  <jpu at apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        Add support for autocorrection UI on Mac OS X.
+        https://bugs.webkit.org/show_bug.cgi?id=44958
+        <rdar://problem/7299621>
+
+        Several new member methods are added to EditorClient for communication
+        between WebCore and WebKit. A new handler, executeCancelOperation(), is
+        added to EditorCommand.cpp so that WebCore can intercept the ESC key event
+        to dismiss autocorrection UI. A new DocumentMarker value, RejectedCorrection,
+        is added to keep track of the corrections that user has rejected, so that it
+        will not be suggested again later. The autocorrection is driven by a timer.
+        Every time the editor inserts a new letter, the timer is reset. If the timer
+        fires, it means neither has user entered any new letter for current word, nor
+        has he entered whitespace or punctuation to complete the word. In this case,
+        we query for autocorrection.
+
+        * WebCore.exp.in: Updated
+
+        * dom/DocumentMarker.h: Added RejectedCorrection to indicate word on which user
+          has rejected autocorrection.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::Editor): Initialize autocorrection timer.
+        (WebCore::Editor::~Editor): Make sure autocorrection UI is dismissed before
+          destroying Editor object.
+        (WebCore::Editor::markMisspellingsAfterTypingToPosition): Adopted new signature
+          of markAllMisspellingsAndBadGrammarInRanges().
+        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Consolidated all
+          boolean arguments into one bitfield. This improves readability and allows us to
+          pass in a bit to indicate whether we want to show autocorrection UI. Also added
+          code to show autocorrection UI if it is necessary.
+        (WebCore::Editor::markMisspellingsAndBadGrammar): Adopted new signature of
+          markAllMisspellingsAndBadGrammarInRanges().
+        (WebCore::Editor::correctionPanelTimerFired): Check to see if we should show
+          autocorrection UI when user pauses during typing.
+        (WebCore::Editor::handleRejectedCorrection): Update user dictionary when an autocorrection is rejected.
+        (WebCore::Editor::startCorrectionPanelTimer): Start autocorrection timer.
+        (WebCore::Editor::handleCancelOperation): Dismiss autocorrection UI when ESC key is pressed.
+
+        * editing/Editor.h: Added autocorrection related member methods and variables.
+
+        * editing/EditorCommand.cpp:
+        (WebCore::executeCancelOperation): Handle ESC key event. Dismiss autocorrection UI.
+        (WebCore::createCommandMap): Updated for executeCancelOperation().
+
+        * editing/TypingCommand.cpp:
+        (WebCore::TypingCommand::markMisspellingsAfterTyping): Reset autocorrection timer after insertion.
+
+        * loader/EmptyClients.h:
+        (WebCore::EmptyEditorClient::showCorrectionPanel): Dummy implementation.
+        (WebCore::EmptyEditorClient::dismissCorrectionPanel): Ditto
+
+        * page/EditorClient.h: Added methods for communication between WebCore and WebKit regarding autocorrection.
+
+        * page/Frame.cpp:
+        (WebCore::Frame::respondToChangedSelection): Remove Replacement marker where we used to only remove Spelling
+          mark, because whenever we need to remove spelling underline we also should remove autocorrection underline.
+
+        * platform/graphics/GraphicsContext.h: Added enum TextCheckingLineStyle to specify the underline
+          for different type of text checking result. Replaced drawLineForMisspellingOrBadGrammar() with
+          drawLineForTextChecking(), which allows autocorrection to have different indication from misspelling
+          and grammatical error.
+
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Replaced drawLineForMisspellingOrBadGrammar() with drawLineForTextChecking().
+
+        * platform/graphics/haiku/GraphicsContextHaiku.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/mac/GraphicsContextMac.mm:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/openvg/GraphicsContextOpenVG.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/qt/GraphicsContextQt.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/skia/GraphicsContextSkia.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/win/GraphicsContextCGWin.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/wince/GraphicsContextWince.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * platform/graphics/wx/GraphicsContextWx.cpp:
+        (WebCore::GraphicsContext::drawLineForTextChecking): Ditto
+
+        * rendering/InlineTextBox.cpp:
+        (WebCore::textCheckingLineStyleForMarkerType): Return line style for a given document marker type.
+        (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):  Replaced drawLineForMisspellingOrBadGrammar() with drawLineForTextChecking().
+        (WebCore::InlineTextBox::paintDocumentMarkers): Handle new marker value, RejectedCorrection.
+
 2010-09-01  Kinuko Yasuda  <kinuko at google.com>
 
         Reviewed by Adam Barth.
diff --git a/WebCore/WebCore.exp.in b/WebCore/WebCore.exp.in
index 8ad0cb5..e8b4fe7 100644
--- a/WebCore/WebCore.exp.in
+++ b/WebCore/WebCore.exp.in
@@ -620,6 +620,7 @@ __ZN7WebCore6Editor21applyStyleToSelectionEPNS_19CSSStyleDeclarationENS_10EditAc
 __ZN7WebCore6Editor21isSelectionMisspelledEv
 __ZN7WebCore6Editor23setBaseWritingDirectionENS_16WritingDirectionE
 __ZN7WebCore6Editor24advanceToNextMisspellingEb
+__ZN7WebCore6Editor24handleRejectedCorrectionEv
 __ZN7WebCore6Editor24isSelectionUngrammaticalEv
 __ZN7WebCore6Editor26decreaseSelectionListLevelEv
 __ZN7WebCore6Editor26increaseSelectionListLevelEv
diff --git a/WebCore/dom/DocumentMarker.h b/WebCore/dom/DocumentMarker.h
index 55d2e33..e6160ae 100644
--- a/WebCore/dom/DocumentMarker.h
+++ b/WebCore/dom/DocumentMarker.h
@@ -39,7 +39,8 @@ struct DocumentMarker {
         Spelling,
         Grammar,
         TextMatch,
-        Replacement
+        Replacement,
+        RejectedCorrection
     };
 
     MarkerType type;
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 855d23b..117292c 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -1053,11 +1053,16 @@ Editor::Editor(Frame* frame)
     // This is off by default, since most editors want this behavior (this matches IE but not FF).
     , m_shouldStyleWithCSS(false)
     , m_killRing(adoptPtr(new KillRing))
-{ 
+    , m_correctionPanelTimer(this, &Editor::correctionPanelTimerFired)
+{
 }
 
 Editor::~Editor()
 {
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    if (client())
+        client()->dismissCorrectionPanel(true);
+#endif
 }
 
 void Editor::clear()
@@ -2351,22 +2356,29 @@ bool Editor::spellingPanelIsShowing()
 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
 {
 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-    bool markSpelling = isContinuousSpellCheckingEnabled();
-    bool markGrammar = markSpelling && isGrammarCheckingEnabled();
-    bool performTextCheckingReplacements = isAutomaticQuoteSubstitutionEnabled() 
-                                        || isAutomaticLinkDetectionEnabled()
-                                        || isAutomaticDashSubstitutionEnabled()
-                                        || isAutomaticTextReplacementEnabled()
-                                        || (markSpelling && isAutomaticSpellingCorrectionEnabled());
-    if (!markSpelling && !performTextCheckingReplacements)
+    TextCheckingOptions textCheckingOptions = 0;
+    if (isContinuousSpellCheckingEnabled())
+        textCheckingOptions |= MarkSpelling;
+
+    if (isAutomaticQuoteSubstitutionEnabled()
+        || isAutomaticLinkDetectionEnabled()
+        || isAutomaticDashSubstitutionEnabled()
+        || isAutomaticTextReplacementEnabled()
+        || ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled()))
+        textCheckingOptions |= PerformReplacement;
+
+    if (!textCheckingOptions & (MarkSpelling | PerformReplacement))
         return;
-    
+
+    if (isGrammarCheckingEnabled())
+        textCheckingOptions |= MarkGrammar;
+
     VisibleSelection adjacentWords = VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary));
-    if (markGrammar) {
+    if (textCheckingOptions & MarkGrammar) {
         VisibleSelection selectedSentence = VisibleSelection(startOfSentence(p), endOfSentence(p));
-        markAllMisspellingsAndBadGrammarInRanges(true, adjacentWords.toNormalizedRange().get(), true, selectedSentence.toNormalizedRange().get(), performTextCheckingReplacements);
+        markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), selectedSentence.toNormalizedRange().get());
     } else {
-        markAllMisspellingsAndBadGrammarInRanges(markSpelling, adjacentWords.toNormalizedRange().get(), false, adjacentWords.toNormalizedRange().get(), performTextCheckingReplacements);
+        markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjacentWords.toNormalizedRange().get(), adjacentWords.toNormalizedRange().get());
     }
 #else
     if (!isContinuousSpellCheckingEnabled())
@@ -2510,13 +2522,18 @@ static inline bool isAmbiguousBoundaryCharacter(UChar character)
     return character == '\'' || character == rightSingleQuotationMark || character == hebrewPunctuationGershayim;
 }
 
-void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range* spellingRange, bool markGrammar, Range* grammarRange, bool performTextCheckingReplacements)
+void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCheckingOptions, Range* spellingRange, Range* grammarRange)
 {
+    bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
+    bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
+    bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
+    bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
+
     // This function is called with selections already expanded to word boundaries.
     ExceptionCode ec = 0;
-    if (!client() || !spellingRange || (markGrammar && !grammarRange))
+    if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange))
         return;
-    
+
     // If we're not in an editable node, bail.
     Node* editableNode = spellingRange->startContainer();
     if (!editableNode || !editableNode->isContentEditable())
@@ -2539,8 +2556,8 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
     bool adjustSelectionForParagraphBoundaries = false;
     String paragraphString;
     RefPtr<Range> paragraphRange;
-    
-    if (markGrammar) {
+
+    if (shouldMarkGrammar) {
         // The spelling range should be contained in the paragraph-aligned extension of the grammar range.
         paragraphRange = paragraphAlignedRangeForRange(grammarRange, grammarRangeStartOffset, paragraphString);
         RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
@@ -2551,10 +2568,10 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
     }
     spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
     paragraphLength = paragraphString.length();
-    if (paragraphLength <= 0 || (spellingRangeStartOffset >= spellingRangeEndOffset && (!markGrammar || grammarRangeStartOffset >= grammarRangeEndOffset)))
+    if (paragraphLength <= 0 || (spellingRangeStartOffset >= spellingRangeEndOffset && (!shouldMarkGrammar || grammarRangeStartOffset >= grammarRangeEndOffset)))
         return;
-    
-    if (performTextCheckingReplacements) {
+
+    if (shouldPerformReplacement) {
         if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
             // Attempt to save the caret position so we can restore it later if needed
             RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), paragraphRange->startPosition());
@@ -2570,14 +2587,16 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
             }
         }
     }
-    
+
     Vector<TextCheckingResult> results;
     uint64_t checkingTypes = 0;
-    if (markSpelling)
+    if (shouldMarkSpelling)
         checkingTypes |= TextCheckingTypeSpelling;
-    if (markGrammar)
+    if (shouldMarkGrammar)
         checkingTypes |= TextCheckingTypeGrammar;
-    if (performTextCheckingReplacements) {
+    if (shouldShowCorrectionPanel)
+        checkingTypes |= TextCheckingTypeCorrection;
+    if (shouldPerformReplacement) {
         if (isAutomaticLinkDetectionEnabled())
             checkingTypes |= TextCheckingTypeLink;
         if (isAutomaticQuoteSubstitutionEnabled())
@@ -2586,20 +2605,26 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
             checkingTypes |= TextCheckingTypeDash;
         if (isAutomaticTextReplacementEnabled())
             checkingTypes |= TextCheckingTypeReplacement;
-        if (markSpelling && isAutomaticSpellingCorrectionEnabled())
+        if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
             checkingTypes |= TextCheckingTypeCorrection;
     }
     client()->checkTextOfParagraph(paragraphString.characters(), paragraphLength, checkingTypes, results);
-    
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    // If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
+    if (shouldShowCorrectionPanel)
+        shouldMarkSpelling = false;
+#endif
+
     for (unsigned i = 0; i < results.size(); i++) {
         const TextCheckingResult* result = &results[i];
         int resultLocation = result->location + offsetDueToReplacement;
         int resultLength = result->length;
-        if (markSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingRangeStartOffset && resultLocation + resultLength <= spellingRangeEndOffset) {
+        if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingRangeStartOffset && resultLocation + resultLength <= spellingRangeEndOffset) {
             ASSERT(resultLength > 0 && resultLocation >= 0);
             RefPtr<Range> misspellingRange = TextIterator::subrange(spellingRange, resultLocation - spellingRangeStartOffset, resultLength);
             misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
-        } else if (markGrammar && result->type == TextCheckingTypeGrammar && resultLocation < grammarRangeEndOffset && resultLocation + resultLength > grammarRangeStartOffset) {
+        } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && resultLocation < grammarRangeEndOffset && resultLocation + resultLength > grammarRangeStartOffset) {
             ASSERT(resultLength > 0 && resultLocation >= 0);
             for (unsigned j = 0; j < result->details.size(); j++) {
                 const GrammarDetail* detail = &result->details[j];
@@ -2609,7 +2634,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
                     grammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
                 }
             }
-        } else if (performTextCheckingReplacements && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingRangeStartOffset
+        } else if ((shouldPerformReplacement || shouldShowCorrectionPanel) && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingRangeStartOffset
                     && (result->type == TextCheckingTypeLink
                     || result->type == TextCheckingTypeQuote
                     || result->type == TextCheckingTypeDash
@@ -2640,7 +2665,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
                 size_t markerCount = markers.size();
                 for (size_t i = 0; i < markerCount; ++i) {
                     const DocumentMarker& marker = markers[i];
-                    if (marker.type == DocumentMarker::Replacement && static_cast<int>(marker.startOffset) < endOffset && static_cast<int>(marker.endOffset) > startOffset) {
+                    if ((marker.type == DocumentMarker::Replacement || marker.type == DocumentMarker::RejectedCorrection) && static_cast<int>(marker.startOffset) < endOffset && static_cast<int>(marker.endOffset) > startOffset) {
                         doReplacement = false;
                         break;
                     }
@@ -2648,7 +2673,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
                         break;
                 }
             }
-            if (doReplacement && selectionToReplace != m_frame->selection()->selection()) {
+            if (doReplacement && !shouldShowCorrectionPanel && selectionToReplace != m_frame->selection()->selection()) {
                 if (m_frame->shouldChangeSelection(selectionToReplace)) {
                     m_frame->selection()->setSelection(selectionToReplace);
                     selectionChanged = true;
@@ -2656,30 +2681,52 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range*
                     doReplacement = false;
                 }
             }
+
+            String replacedString;
             if (doReplacement) {
                 if (result->type == TextCheckingTypeLink) {
                     restoreSelectionAfterChange = false;
                     if (canEditRichly())
                         applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
                 } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
-                    String replacedString;
                     if (result->type == TextCheckingTypeCorrection)
                         replacedString = plainText(rangeToReplace.get());
-                    replaceSelectionWithText(result->replacement, false, false);
-                    spellingRangeEndOffset += replacementLength - resultLength;
-                    offsetDueToReplacement += replacementLength - resultLength;
-                    if (resultLocation < selectionOffset)
-                        selectionOffset += replacementLength - resultLength;
-                    if (result->type == TextCheckingTypeCorrection) {
-                        // Add a marker so that corrections can easily be undone and won't be re-corrected.
-                        RefPtr<Range> replacedRange = TextIterator::subrange(paragraphRange.get(), resultLocation, replacementLength);
-                        replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+                    if (shouldShowCorrectionPanel && resultLocation + resultLength == spellingRangeEndOffset && result->type == TextCheckingTypeCorrection) {
+                        // We only show the correction panel on the last word.
+                        Vector<FloatQuad> textQuads;
+                        rangeToReplace->textQuads(textQuads);
+                        Vector<FloatQuad>::const_iterator end = textQuads.end();
+                        FloatRect totalBoundingBox;
+                        for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
+                            totalBoundingBox.unite(it->boundingBox());
+                        m_rangeToBeReplacedByCorrection = rangeToReplace;
+                        m_stringToBeReplacedByCorrection = replacedString;
+                        client()->showCorrectionPanel(totalBoundingBox, m_stringToBeReplacedByCorrection, result->replacement, this);
+                        doReplacement = false;
+                    }
+#endif
+                    if (doReplacement) {
+                        replaceSelectionWithText(result->replacement, false, false);
+                        spellingRangeEndOffset += replacementLength - resultLength;
+                        offsetDueToReplacement += replacementLength - resultLength;
+                        if (resultLocation < selectionOffset)
+                            selectionOffset += replacementLength - resultLength;
+                        if (result->type == TextCheckingTypeCorrection) {
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+                            if (client())
+                                client()->dismissCorrectionPanel(true);
+#endif
+                            // Add a marker so that corrections can easily be undone and won't be re-corrected.
+                            RefPtr<Range> replacedRange = TextIterator::subrange(paragraphRange.get(), resultLocation, replacementLength);
+                            replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
+                        }
                     }
                 }
             }
         }
     }
-    
+
     if (selectionChanged) {
         // Restore the caret position if we have made any replacements
         setEnd(paragraphRange.get(), endOfParagraph(startOfNextParagraph(paragraphRange->startPosition())));
@@ -2721,7 +2768,10 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
     if (!isContinuousSpellCheckingEnabled())
         return;
-    markAllMisspellingsAndBadGrammarInRanges(true, spellingSelection.toNormalizedRange().get(), markGrammar && isGrammarCheckingEnabled(), grammarSelection.toNormalizedRange().get(), false);
+    TextCheckingOptions textCheckingOptions = MarkSpelling;
+    if (markGrammar && isGrammarCheckingEnabled())
+        textCheckingOptions |= MarkGrammar;
+    markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get());
 #else
     RefPtr<Range> firstMisspellingRange;
     markMisspellings(spellingSelection, firstMisspellingRange);
@@ -2730,6 +2780,45 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
 #endif
 }
 
+void Editor::correctionPanelTimerFired(Timer<Editor>*)
+{
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+    VisibleSelection selection(frame()->selection()->selection());
+    VisiblePosition start(selection.start(), selection.affinity());
+    VisiblePosition p = startOfWord(start, LeftWordIfOnBoundary);
+    VisibleSelection adjacentWords = VisibleSelection(p, start);
+    markAllMisspellingsAndBadGrammarInRanges(MarkSpelling | ShowCorrectionPanel, adjacentWords.toNormalizedRange().get(), 0);
+#endif
+}
+
+void Editor::handleRejectedCorrection()
+{
+    Range* replacedRange = m_rangeToBeReplacedByCorrection.get();
+    if (!replacedRange || m_frame->document() != replacedRange->ownerDocument())
+        return;
+
+    replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_stringToBeReplacedByCorrection);
+}
+
+void Editor::startCorrectionPanelTimer()
+{
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    static const double correctionPanelTimerInterval = 0.3;
+    if (client())
+        client()->dismissCorrectionPanel(true);
+    if (isAutomaticSpellingCorrectionEnabled())
+        m_correctionPanelTimer.startOneShot(correctionPanelTimerInterval);
+#endif
+}
+
+void Editor::handleCancelOperation()
+{
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    if (client())
+        client()->dismissCorrectionPanel(false);
+#endif
+}
+
 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
 {
     Document* document = m_frame->documentAtPoint(windowPoint);
diff --git a/WebCore/editing/Editor.h b/WebCore/editing/Editor.h
index 96513e1..78e89b4 100644
--- a/WebCore/editing/Editor.h
+++ b/WebCore/editing/Editor.h
@@ -224,7 +224,15 @@ public:
     void toggleAutomaticTextReplacement();
     bool isAutomaticSpellingCorrectionEnabled();
     void toggleAutomaticSpellingCorrection();
-    void markAllMisspellingsAndBadGrammarInRanges(bool markSpelling, Range* spellingRange, bool markGrammar, Range* grammarRange, bool performTextCheckingReplacements);
+    enum TextCheckingOptionFlags {
+        MarkSpelling = 1 << 0,
+        MarkGrammar = 1 << 1,
+        PerformReplacement = 1 << 2,
+        ShowCorrectionPanel = 1 << 3,
+    };
+    typedef unsigned TextCheckingOptions;
+
+    void markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions, Range* spellingRange, Range* grammarRange);
     void changeBackToReplacedString(const String& replacedString);
 #endif
     void advanceToNextMisspelling(bool startBeforeSelection = false);
@@ -294,9 +302,13 @@ public:
     bool insideVisibleArea(const IntPoint&) const;
     bool insideVisibleArea(Range*) const;
     PassRefPtr<Range> nextVisibleRange(Range*, const String&, bool forward, bool caseFlag, bool wrapFlag);
-    
+
     void addToKillRing(Range*, bool prepend);
 
+    void handleCancelOperation();
+    void startCorrectionPanelTimer();
+    void handleRejectedCorrection();
+
     void pasteAsFragment(PassRefPtr<DocumentFragment>, bool smartReplace, bool matchStyle);
     void pasteAsPlainText(const String&, bool smartReplace);
 
@@ -318,6 +330,9 @@ private:
     bool m_shouldStartNewKillRingSequence;
     bool m_shouldStyleWithCSS;
     OwnPtr<KillRing> m_killRing;
+    RefPtr<Range> m_rangeToBeReplacedByCorrection;
+    String m_stringToBeReplacedByCorrection;
+    Timer<Editor> m_correctionPanelTimer;
 
     bool canDeleteRange(Range*) const;
     bool canSmartReplaceWithPasteboard(Pasteboard*);
@@ -335,8 +350,9 @@ private:
 
     PassRefPtr<Range> firstVisibleRange(const String&, bool caseFlag);
     PassRefPtr<Range> lastVisibleRange(const String&, bool caseFlag);
-    
+
     void changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle);
+    void correctionPanelTimerFired(Timer<Editor>*);
     Node* findEventTargetFromSelection() const;
 };
 
diff --git a/WebCore/editing/EditorCommand.cpp b/WebCore/editing/EditorCommand.cpp
index 38a452a..4b8da0e 100644
--- a/WebCore/editing/EditorCommand.cpp
+++ b/WebCore/editing/EditorCommand.cpp
@@ -1069,6 +1069,14 @@ static bool executeYankAndSelect(Frame* frame, Event*, EditorCommandSource, cons
     return true;
 }
 
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+static bool executeCancelOperation(Frame* frame, Event*, EditorCommandSource, const String&)
+{
+    frame->editor()->handleCancelOperation();
+    return true;
+}
+#endif
+
 // Supported functions
 
 static bool supported(Frame*, EditorCommandSource)
@@ -1455,6 +1463,9 @@ static const CommandMap& createCommandMap()
         { "Unselect", { executeUnselect, supported, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "Yank", { executeYank, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "YankAndSelect", { executeYankAndSelect, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+        { "CancelOperation", { executeCancelOperation, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+#endif
     };
 
     // These unsupported commands are listed here since they appear in the Microsoft
diff --git a/WebCore/editing/TypingCommand.cpp b/WebCore/editing/TypingCommand.cpp
index ac865e5..81a6d5c 100644
--- a/WebCore/editing/TypingCommand.cpp
+++ b/WebCore/editing/TypingCommand.cpp
@@ -307,6 +307,10 @@ void TypingCommand::markMisspellingsAfterTyping()
         VisiblePosition p2 = startOfWord(start, LeftWordIfOnBoundary);
         if (p1 != p2)
             document()->frame()->editor()->markMisspellingsAfterTypingToPosition(p1);
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+        else
+            document()->frame()->editor()->startCorrectionPanelTimer();
+#endif
     }
 }
 
diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h
index 270752d..46b611b 100644
--- a/WebCore/loader/EmptyClients.h
+++ b/WebCore/loader/EmptyClients.h
@@ -460,6 +460,10 @@ public:
 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
     virtual void checkTextOfParagraph(const UChar*, int, uint64_t, Vector<TextCheckingResult>&) { };
 #endif
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    virtual void showCorrectionPanel(const FloatRect&, const String&, const String&, Editor*) { }
+    virtual void dismissCorrectionPanel(bool) { }
+#endif
     virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) { }
     virtual void updateSpellingUIWithMisspelledWord(const String&) { }
     virtual void showSpellingUI(bool) { }
diff --git a/WebCore/page/EditorClient.h b/WebCore/page/EditorClient.h
index 93e27ff..4a192d7 100644
--- a/WebCore/page/EditorClient.h
+++ b/WebCore/page/EditorClient.h
@@ -28,6 +28,7 @@
 #define EditorClient_h
 
 #include "EditorInsertAction.h"
+#include "FloatRect.h"
 #include "PlatformString.h"
 #include "TextAffinity.h"
 #include <wtf/Forward.h>
@@ -51,6 +52,7 @@ namespace WebCore {
 
 class CSSStyleDeclaration;
 class EditCommand;
+class Editor;
 class Element;
 class Frame;
 class HTMLElement;
@@ -177,6 +179,12 @@ public:
 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
     virtual void checkTextOfParagraph(const UChar* text, int length, uint64_t checkingTypes, Vector<TextCheckingResult>& results) = 0;
 #endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    virtual void showCorrectionPanel(const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacmentString, Editor*) = 0;
+    virtual void dismissCorrectionPanel(bool correctionAccepted) = 0;
+#endif
+
     virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail) = 0;
     virtual void updateSpellingUIWithMisspelledWord(const String&) = 0;
     virtual void showSpellingUI(bool show) = 0;
diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp
index 5b01220..e5d5bdb 100644
--- a/WebCore/page/Frame.cpp
+++ b/WebCore/page/Frame.cpp
@@ -1414,8 +1414,10 @@ void Frame::respondToChangedSelection(const VisibleSelection& oldSelection, bool
 
         // This only erases markers that are in the first unit (word or sentence) of the selection.
         // Perhaps peculiar, but it matches AppKit.
-        if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange())
+        if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange()) {
             document()->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
+            document()->markers()->removeMarkers(wordRange.get(), DocumentMarker::Replacement);
+        }
         if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange())
             document()->markers()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
     }
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index cb43f01..45ddee3 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -272,7 +272,12 @@ namespace WebCore {
         FloatRect roundToDevicePixels(const FloatRect&);
 
         void drawLineForText(const IntPoint&, int width, bool printing);
-        void drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar);
+        enum TextCheckingLineStyle {
+            TextCheckingSpellingLineStyle,
+            TextCheckingGrammarLineStyle,
+            TextCheckingReplacementLineStyle
+        };
+        void drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle);
 
         bool paintingDisabled() const;
         void setPaintingDisabled(bool);
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index cf91338..19cc518 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -774,7 +774,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
 #include "DrawErrorUnderline.h"
 #endif
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
 {
     if (paintingDisabled())
         return;
@@ -782,12 +782,17 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
     cairo_t* cr = m_data->cr;
     cairo_save(cr);
 
-    // Convention is green for grammar, red for spelling
-    // These need to become configurable
-    if (grammar)
-        cairo_set_source_rgb(cr, 0, 1, 0);
-    else
+    switch (style) {
+    case TextCheckingSpellingLineStyle:
         cairo_set_source_rgb(cr, 1, 0, 0);
+        break;
+    case TextCheckingGrammarLineStyle:
+        cairo_set_source_rgb(cr, 0, 1, 0);
+        break;
+    default:
+        cairo_restore(cr);
+        return;
+    }
 
 #if PLATFORM(GTK)
     // We ignore most of the provided constants in favour of the platform style
diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
index 6561c11..252abd7 100644
--- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
@@ -248,7 +248,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
     drawLine(origin, endPoint);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle)
 {
     if (paintingDisabled())
         return;
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index 5f111f6..f3301d8 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -119,7 +119,7 @@ static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool&
 }
 
 // WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline.
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width, TextCheckingLineStyle style)
 {
     if (paintingDisabled())
         return;
@@ -127,23 +127,41 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point,
     // These are the same for misspelling or bad grammar.
     int patternHeight = cMisspellingLineThickness;
     int patternWidth = cMisspellingLinePatternWidth;
- 
+
     bool usingDot;
     NSColor *patternColor;
-    if (grammar) {
-        // Constants for grammar pattern color.
-        static bool usingDotForGrammar = false;
-        DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar)));
-        
-        usingDot = usingDotForGrammar;
-        patternColor = grammarPatternColor.get();
-    } else {
-        // Constants for spelling pattern color.
-        static bool usingDotForSpelling = false;
-        DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling)));
-        
-        usingDot = usingDotForSpelling;
-        patternColor = spellingPatternColor.get();
+    switch (style) {
+        case TextCheckingSpellingLineStyle:
+        {
+            // Constants for spelling pattern color.
+            static bool usingDotForSpelling = false;
+            DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling)));
+            usingDot = usingDotForSpelling;
+            patternColor = spellingPatternColor.get();
+            break;
+        }
+        case TextCheckingGrammarLineStyle:
+        {
+            // Constants for grammar pattern color.
+            static bool usingDotForGrammar = false;
+            DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar)));
+            usingDot = usingDotForGrammar;
+            patternColor = grammarPatternColor.get();
+            break;
+        }
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+        case TextCheckingReplacementLineStyle:
+        {
+            // Constants for spelling pattern color.
+            static bool usingDotForSpelling = false;
+            DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"CorrectionDot", [NSColor blueColor], usingDotForSpelling)));
+            usingDot = usingDotForSpelling;
+            patternColor = spellingPatternColor.get();
+            break;
+        }
+#endif
+        default:
+            return;
     }
 
     // Make sure to draw only complete dots.
diff --git a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
index 0faf3ce..37fd8ad 100644
--- a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
+++ b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
@@ -273,7 +273,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
     UNUSED_PARAM(printing);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
 {
     if (paintingDisabled())
         return;
@@ -281,7 +281,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
     notImplemented();
     UNUSED_PARAM(origin);
     UNUSED_PARAM(width);
-    UNUSED_PARAM(grammar);
+    UNUSED_PARAM(style);
 }
 
 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 73dd997..c9c74dd 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -845,7 +845,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool)
     drawLine(origin, endPoint);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, bool)
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle)
 {
     if (paintingDisabled())
         return;
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index b4fddd5..1c80d49 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -615,9 +615,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
     platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt,
-                                                         int width,
-                                                         bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& pt, int width, TextCheckingLineStyle style)
 {
     if (paintingDisabled())
         return;
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 84c4ce0..7b65e96 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -176,11 +176,14 @@ static const Color& grammarPatternColor() {
     return grammarColor;
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width, TextCheckingLineStyle style)
 {
     if (paintingDisabled())
         return;
 
+    if (style != TextCheckingSpellingLineStyle && style != TextCheckingGrammarLineStyle)
+        return;
+
     // These are the same for misspelling or bad grammar
     const int patternHeight = 3; // 3 rows
     ASSERT(cMisspellingLineThickness == patternHeight);
@@ -201,7 +204,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point,
     CGContextRef context = platformContext();
     CGContextSaveGState(context);
 
-    const Color& patternColor = grammar ? grammarPatternColor() : spellingPatternColor();
+    const Color& patternColor = style == TextCheckingGrammarLineStyle ? grammarPatternColor() : spellingPatternColor();
     setCGStrokeColor(context, patternColor);
 
     wkSetPatternPhaseInUserSpace(context, point);
diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
index b1f48a4..990a31d 100644
--- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
+++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
@@ -1062,7 +1062,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
     setStrokeStyle(oldStyle);
 }
 
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle style)
 {
     notImplemented();
 }
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index 2428e7e..a39404a 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -357,14 +357,18 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
     m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
 }
 
-
-void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, TextCheckingLineStyle style)
 {
-    if (grammar)
-        m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
-    else
+    switch (style) {
+    case TextCheckingSpellingLineStyle:
         m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
-    
+        break;
+    case TextCheckingGrammarLineStyle:
+        m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
+        break;
+    default:
+        return;
+    }
     m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
 }
 
diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp
index e64ddde..c74fe1e 100644
--- a/WebCore/rendering/InlineTextBox.cpp
+++ b/WebCore/rendering/InlineTextBox.cpp
@@ -768,6 +768,21 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
         context->clearShadow();
 }
 
+static GraphicsContext::TextCheckingLineStyle textCheckingLineStyleForMarkerType(DocumentMarker::MarkerType markerType)
+{
+    switch (markerType) {
+    case DocumentMarker::Spelling:
+        return GraphicsContext::TextCheckingSpellingLineStyle;
+    case DocumentMarker::Grammar:
+        return GraphicsContext::TextCheckingGrammarLineStyle;
+    case DocumentMarker::Replacement:
+        return GraphicsContext::TextCheckingReplacementLineStyle;
+    default:
+        ASSERT_NOT_REACHED();
+        return GraphicsContext::TextCheckingSpellingLineStyle;
+    }
+}
+
 void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font, bool grammar)
 {
     // Never print spelling/grammar markers (5327887)
@@ -831,7 +846,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
         // In larger fonts, though, place the underline up near the baseline to prevent a big gap.
         underlineOffset = baseline + 2;
     }
-    pt->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar);
+    pt->drawLineForTextChecking(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, textCheckingLineStyleForMarkerType(marker.type));
 }
 
 void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, const DocumentMarker& marker, RenderStyle* style, const Font& font)
@@ -898,10 +913,10 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re
             case DocumentMarker::Grammar:
             case DocumentMarker::Spelling:
             case DocumentMarker::Replacement:
+            case DocumentMarker::RejectedCorrection:
                 if (background)
                     continue;
                 break;
-                
             case DocumentMarker::TextMatch:
                 if (!background)
                     continue;
@@ -933,6 +948,9 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re
                 break;
             case DocumentMarker::Replacement:
                 computeRectForReplacementMarker(tx, ty, marker, style, font);
+                paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, false);
+                break;
+            case DocumentMarker::RejectedCorrection:
                 break;
             default:
                 ASSERT_NOT_REACHED();
diff --git a/WebKit/mac/ChangeLog b/WebKit/mac/ChangeLog
index 3503a70..825e862 100644
--- a/WebKit/mac/ChangeLog
+++ b/WebKit/mac/ChangeLog
@@ -1,3 +1,24 @@
+2010-09-01  Jia Pu  <jpu at apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        Add support for autocorrection UI on Mac OS X.
+        https://bugs.webkit.org/show_bug.cgi?id=44958
+        <rdar://problem/7299621>
+
+        See detailed high level description in WebCore/ChangeLog.
+
+        * WebCoreSupport/WebEditorClient.h: Added new member methods declared in
+          EditorClient. Added m_correctionPanelTag to store the ID of current autocorrection UI object.
+
+        * WebCoreSupport/WebEditorClient.mm:
+        (WebEditorClient::WebEditorClient): Initialize m_correctionPanelTag.
+        (WebEditorClient::~WebEditorClient): Make sure the autocorrection UI is
+          dismissed before destroying the object.
+        (WebEditorClient::respondToChangedSelection): Dismiss autocorrection UI whenever the selection changes.
+        (WebEditorClient::showCorrectionPanel): Show autocorrection UI.
+        (WebEditorClient::dismissCorrectionPanel): Dismiss autocorrection UI.
+
 2010-09-01  Mark Rowe  <mrowe at apple.com>
 
         Reviewed by Adam Roben.
diff --git a/WebKit/mac/WebCoreSupport/WebEditorClient.h b/WebKit/mac/WebCoreSupport/WebEditorClient.h
index e6426aa..fe33e05 100644
--- a/WebKit/mac/WebCoreSupport/WebEditorClient.h
+++ b/WebKit/mac/WebCoreSupport/WebEditorClient.h
@@ -27,6 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#import <WebCore/Editor.h>
 #import <WebCore/EditorClient.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/Forward.h>
@@ -38,7 +39,7 @@
 class WebEditorClient : public WebCore::EditorClient {
 public:
     WebEditorClient(WebView *);
-    
+    virtual ~WebEditorClient();
     virtual void pageDestroyed();
 
     virtual bool isGrammarCheckingEnabled();
@@ -129,12 +130,19 @@ public:
     virtual void getGuessesForWord(const WTF::String&, WTF::Vector<WTF::String>& guesses);
     virtual void willSetInputMethodState();
     virtual void setInputMethodState(bool enabled);
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    virtual void showCorrectionPanel(const WebCore::FloatRect& boundingBoxOfReplacedString, const WTF::String& replacedString, const WTF::String& replacementString, WebCore::Editor*);
+    virtual void dismissCorrectionPanel(bool correctionAccepted);
+#endif
 private:
     void registerCommandForUndoOrRedo(PassRefPtr<WebCore::EditCommand>, bool isRedo);
     WebEditorClient();
-    
+
     WebView *m_webView;
     RetainPtr<WebEditorUndoTarget> m_undoTarget;
-    
     bool m_haveUndoRedoOperations;
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    NSInteger m_correctionPanelTag;
+#endif
 };
diff --git a/WebKit/mac/WebCoreSupport/WebEditorClient.mm b/WebKit/mac/WebCoreSupport/WebEditorClient.mm
index 2c89919..41cff68 100644
--- a/WebKit/mac/WebCoreSupport/WebEditorClient.mm
+++ b/WebKit/mac/WebCoreSupport/WebEditorClient.mm
@@ -64,6 +64,9 @@
 #import <runtime/InitializeThreading.h>
 #import <wtf/PassRefPtr.h>
 #import <wtf/Threading.h>
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#import <AppKit/NSTextChecker.h>
+#endif
 
 using namespace WebCore;
 using namespace WTF;
@@ -171,7 +174,17 @@ WebEditorClient::WebEditorClient(WebView *webView)
     : m_webView(webView)
     , m_undoTarget([[[WebEditorUndoTarget alloc] init] autorelease])
     , m_haveUndoRedoOperations(false)
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    , m_correctionPanelTag(-1)
+#endif
+{
+}
+
+WebEditorClient::~WebEditorClient()
 {
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    dismissCorrectionPanel(true);
+#endif
 }
 
 bool WebEditorClient::isContinuousSpellCheckingEnabled()
@@ -286,6 +299,10 @@ void WebEditorClient::respondToChangedSelection()
 {
     [m_webView _selectionChanged];
 
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    dismissCorrectionPanel(true);
+#endif
+
     // FIXME: This quirk is needed due to <rdar://problem/5009625> - We can phase it out once Aperture can adopt the new behavior on their end
     if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"])
         return;
@@ -790,6 +807,35 @@ void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammar
 #endif
 }
 
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+void WebEditorClient::showCorrectionPanel(const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, Editor* editor) {
+    dismissCorrectionPanel(true);
+
+    NSRect boundingBoxAsNSRect = boundingBoxOfReplacedString;
+    NSRect webViewFrame = m_webView.frame;
+    boundingBoxAsNSRect.origin.y = webViewFrame.size.height-NSMaxY(boundingBoxAsNSRect);
+
+    // Need to explicitly use these local NSString objects, because the C++ references may be invalidated by the time the block below is executed.
+    NSString *replacedStringAsNSString = replacedString;
+    NSString *replacementStringAsNSString = replacementString;
+
+    m_correctionPanelTag = [[NSSpellChecker sharedSpellChecker] showCorrection:replacementStringAsNSString forStringInRect:boundingBoxAsNSRect view:m_webView completionHandler:^(BOOL accepted) {
+        if (!accepted) {
+            [[NSSpellChecker sharedSpellChecker] recordResponse:NSCorrectionResponseRejected toCorrection:replacementStringAsNSString forWord:replacedStringAsNSString language:nil inSpellDocumentWithTag:[m_webView spellCheckerDocumentTag]];
+            editor->handleRejectedCorrection();
+        }
+    }];
+}
+
+void WebEditorClient::dismissCorrectionPanel(bool correctionAccepted)
+{
+    if (m_correctionPanelTag >= 0) {
+        [[NSSpellChecker sharedSpellChecker] dismissCorrection:m_correctionPanelTag acceptCorrection:correctionAccepted];
+        m_correctionPanelTag = -1;
+    }
+}
+#endif
+
 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
 {
     [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithMisspelledWord:misspelledWord];
diff --git a/WebKit2/ChangeLog b/WebKit2/ChangeLog
index b571768..b0f416e 100644
--- a/WebKit2/ChangeLog
+++ b/WebKit2/ChangeLog
@@ -1,3 +1,19 @@
+2010-09-01  Jia Pu  <jpu at apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        Add support for autocorrection UI on Mac OS X.
+        https://bugs.webkit.org/show_bug.cgi?id=44958
+        <rdar://problem/7299621>
+
+        See detailed high level description in WebCore/ChangeLog.
+
+        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+        (WebKit::WebEditorClient::showCorrectionPanel): Dummy implementation.
+        (WebKit::WebEditorClient::dismissCorrectionPanel): Ditto
+
+        * WebProcess/WebCoreSupport/WebEditorClient.h: Added new methods declared in base class.
+
 2010-09-01  Sam Weinig  <sam at webkit.org>
 
         Fix the build.
diff --git a/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp b/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp
index 5d16e3f..b96eff7 100644
--- a/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp
+++ b/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp
@@ -469,4 +469,16 @@ void WebEditorClient::setInputMethodState(bool)
     notImplemented();
 }
 
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+void WebEditorClient::showCorrectionPanel(const WebCore::FloatRect& boundingBoxOfReplacedString, const WTF::String& replacedString, const WTF::String& replacementString, WebCore::Editor*)
+{
+    notImplemented();
+}
+
+void WebEditorClient::dismissCorrectionPanel(bool correctionAccepted)
+{
+    notImplemented();
+}
+#endif
+
 } // namespace WebKit
diff --git a/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h b/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h
index 817caf9..c7521f7 100644
--- a/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h
+++ b/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h
@@ -39,12 +39,12 @@ public:
     {
     }
 
-private:    
+private:
     virtual void pageDestroyed();
-    
+
     virtual bool shouldDeleteRange(WebCore::Range*);
     virtual bool shouldShowDeleteInterface(WebCore::HTMLElement*);
-    virtual bool smartInsertDeleteEnabled(); 
+    virtual bool smartInsertDeleteEnabled();
     virtual bool isSelectTrailingWhitespaceEnabled();
     virtual bool isContinuousSpellCheckingEnabled();
     virtual void toggleContinuousSpellChecking();
@@ -131,7 +131,10 @@ private:
     virtual void getGuessesForWord(const WTF::String&, Vector<WTF::String>& guesses);
     virtual void willSetInputMethodState();
     virtual void setInputMethodState(bool enabled);
-
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    virtual void showCorrectionPanel(const WebCore::FloatRect& boundingBoxOfReplacedString, const WTF::String& replacedString, const WTF::String& replacementString, WebCore::Editor*);
+    virtual void dismissCorrectionPanel(bool correctionAccepted);
+#endif
     WebPage* m_page;
 };
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list