Changeset 86295 in webkit


Ignore:
Timestamp:
May 11, 2011 5:54:08 PM (13 years ago)
Author:
jpu@apple.com
Message:

2011-05-11 Jia Pu <jpu@apple.com>

Reviewed by Darin Adler.

Autocorrection persists after deleting and retyping the same word at same location.
https://bugs.webkit.org/show_bug.cgi?id=60555
<rdar://problem/9373915>

See WebCore/ChangeLog for detail.

  • platform/mac-leopard/Skipped:
  • platform/mac-snowleopard/Skipped:
  • platform/mac/editing/spelling/delete-autocorrected-word-2-expected.png: Added.
  • platform/mac/editing/spelling/delete-autocorrected-word-2-expected.txt: Added.
  • platform/mac/editing/spelling/delete-autocorrected-word-2.html: Added.

2011-05-11 Jia Pu <jpu@apple.com>

Reviewed by Darin Adler.

Autocorrection persists after deleting and retyping the same word at same location.
https://bugs.webkit.org/show_bug.cgi?id=60555
<rdar://problem/9373915>

This patch intends to alleviate the issue of repetitively applying the same autocorrection
when user delete and retype the same word at the same location. This scenario is especially
common when autocorrection modifies the first letter of the word.

This patch consists following major changes:

  1. Added a new marker type, DeletedAutocorrection. This marker is added to the whitespace that precedes a deleted autocorrection. If the user later types the same original word at after this whitespace, the autocorrection will not be applied again.
  2. In DeleteSelectionCommand, added code to notify SpellingCorrectionController about the autocorrection that has just been deleted.
  3. In Editor and SpellingCorrectionController, added code to apply the marker and to suppress autocorrection when necessary.
  4. The change in CompositeEditCommand::replaceTextInNode is necessary for preserving markers. Otherwise, we will loose the DeletedAutocorrection on the whitespace, when inserting text after the whitespace.

Test: platform/mac/editing/spelling/delete-autocorrected-word-2.html

  • dom/DocumentMarker.h: Added new marker type DeletedAutocorrection. (WebCore::DocumentMarker::AllMarkers::AllMarkers):
  • dom/DocumentMarkerController.cpp: (WebCore::DocumentMarkerController::markersInRange): Support querying multiple marker types.
  • dom/DocumentMarkerController.h:
  • editing/CompositeEditCommand.cpp: (WebCore::CompositeEditCommand::replaceTextInNodeAndPreserveMarkers): (WebCore::CompositeEditCommand::rebalanceWhitespaceOnTextSubstring): (WebCore::CompositeEditCommand::prepareWhitespaceAtPositionForSplit):
  • editing/CompositeEditCommand.h:
  • editing/DeleteSelectionCommand.cpp: (WebCore::DeleteSelectionCommand::DeleteSelectionCommand): (WebCore::DeleteSelectionCommand::fixupWhitespace): (WebCore::DeleteSelectionCommand::originalStringForAutocorrectionAtBeginningOfSelection): Extracting

the original string if we are deleting an autocorrection.

(WebCore::DeleteSelectionCommand::doApply): Notify editor about the deleted autocorrection and its position.

  • editing/DeleteSelectionCommand.h:
  • editing/Editor.cpp: (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Moved all logic of determining

when to suppress an autocorrection into SpellingCorrectionController.

(WebCore::Editor::deletedAutocorrectionAtPosition):

  • editing/Editor.h:
  • editing/InsertParagraphSeparatorCommand.cpp: (WebCore::InsertParagraphSeparatorCommand::doApply):
  • editing/SpellingCorrectionController.cpp: (WebCore::SpellingCorrectionController::respondToAppliedEditing): (WebCore::SpellingCorrectionController::deletedAutocorrectionAtPosition): (WebCore::SpellingCorrectionController::markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand): (WebCore::SpellingCorrectionController::processMarkersOnTextToBeReplacedByResult):
  • editing/SpellingCorrectionController.h: (WebCore::SpellingCorrectionController::UNLESS_ENABLED):
  • editing/visible_units.cpp: (WebCore::isStartOfWord):
  • editing/visible_units.h:
  • manual-tests/autocorrection/spell-checking-after-reversion.html:
Location:
trunk
Files:
3 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r86292 r86295  
     12011-05-11  Jia Pu  <jpu@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        Autocorrection persists after deleting and retyping the same word at same location.
     6        https://bugs.webkit.org/show_bug.cgi?id=60555
     7        <rdar://problem/9373915>
     8
     9        See WebCore/ChangeLog for detail.
     10
     11        * platform/mac-leopard/Skipped:
     12        * platform/mac-snowleopard/Skipped:
     13        * platform/mac/editing/spelling/delete-autocorrected-word-2-expected.png: Added.
     14        * platform/mac/editing/spelling/delete-autocorrected-word-2-expected.txt: Added.
     15        * platform/mac/editing/spelling/delete-autocorrected-word-2.html: Added.
     16
    1172011-05-11  Kent Tamura  <tkent@chromium.org>
    218
  • trunk/LayoutTests/platform/mac-leopard/Skipped

    r85306 r86295  
    119119platform/mac/editing/spelling/click-autocorrected-word.html
    120120platform/mac/editing/spelling/delete-autocorrected-word-1.html
     121platform/mac/editing/spelling/delete-autocorrected-word-2.html
    121122platform/mac/editing/spelling/delete-into-autocorrected-word.html
    122123platform/mac/editing/spelling/delete-into-misspelled-word.html
  • trunk/LayoutTests/platform/mac-snowleopard/Skipped

    r84959 r86295  
    141141platform/mac/editing/spelling/click-autocorrected-word.html
    142142platform/mac/editing/spelling/delete-autocorrected-word-1.html
     143platform/mac/editing/spelling/delete-autocorrected-word-2.html
    143144platform/mac/editing/spelling/delete-into-autocorrected-word.html
    144145platform/mac/editing/spelling/delete-into-misspelled-word.html
  • trunk/Source/WebCore/ChangeLog

    r86293 r86295  
     12011-05-11  Jia Pu  <jpu@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        Autocorrection persists after deleting and retyping the same word at same location.
     6        https://bugs.webkit.org/show_bug.cgi?id=60555
     7        <rdar://problem/9373915>
     8
     9        This patch intends to alleviate the issue of repetitively applying the same autocorrection
     10        when user delete and retype the same word at the same location. This scenario is especially
     11        common when autocorrection modifies the first letter of the word.
     12
     13        This patch consists following major changes:
     14        1. Added a new marker type, DeletedAutocorrection. This marker is added to the whitespace that
     15           precedes a deleted autocorrection. If the user later types the same original word at after
     16           this whitespace, the autocorrection will not be applied again.
     17        2. In DeleteSelectionCommand, added code to notify SpellingCorrectionController about the
     18           autocorrection that has just been deleted.
     19        3. In Editor and SpellingCorrectionController, added code to apply the marker and to suppress
     20           autocorrection when necessary.
     21        4. The change in CompositeEditCommand::replaceTextInNode is necessary for preserving markers.
     22           Otherwise, we will loose the DeletedAutocorrection on the whitespace, when inserting text
     23           after the whitespace.
     24
     25        Test: platform/mac/editing/spelling/delete-autocorrected-word-2.html
     26
     27        * dom/DocumentMarker.h: Added new marker type DeletedAutocorrection.
     28        (WebCore::DocumentMarker::AllMarkers::AllMarkers):
     29        * dom/DocumentMarkerController.cpp:
     30        (WebCore::DocumentMarkerController::markersInRange): Support querying multiple marker types.
     31        * dom/DocumentMarkerController.h:
     32        * editing/CompositeEditCommand.cpp:
     33        (WebCore::CompositeEditCommand::replaceTextInNodeAndPreserveMarkers):
     34        (WebCore::CompositeEditCommand::rebalanceWhitespaceOnTextSubstring):
     35        (WebCore::CompositeEditCommand::prepareWhitespaceAtPositionForSplit):
     36        * editing/CompositeEditCommand.h:
     37        * editing/DeleteSelectionCommand.cpp:
     38        (WebCore::DeleteSelectionCommand::DeleteSelectionCommand):
     39        (WebCore::DeleteSelectionCommand::fixupWhitespace):
     40        (WebCore::DeleteSelectionCommand::originalStringForAutocorrectionAtBeginningOfSelection): Extracting
     41           the original string if we are deleting an autocorrection.
     42        (WebCore::DeleteSelectionCommand::doApply): Notify editor about the deleted autocorrection and its position.
     43        * editing/DeleteSelectionCommand.h:
     44        * editing/Editor.cpp:
     45        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Moved all logic of determining
     46           when to suppress an autocorrection into SpellingCorrectionController.
     47        (WebCore::Editor::deletedAutocorrectionAtPosition):
     48        * editing/Editor.h:
     49        * editing/InsertParagraphSeparatorCommand.cpp:
     50        (WebCore::InsertParagraphSeparatorCommand::doApply):
     51        * editing/SpellingCorrectionController.cpp:
     52        (WebCore::SpellingCorrectionController::respondToAppliedEditing):
     53        (WebCore::SpellingCorrectionController::deletedAutocorrectionAtPosition):
     54        (WebCore::SpellingCorrectionController::markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand):
     55        (WebCore::SpellingCorrectionController::processMarkersOnTextToBeReplacedByResult):
     56        * editing/SpellingCorrectionController.h:
     57        (WebCore::SpellingCorrectionController::UNLESS_ENABLED):
     58        * editing/visible_units.cpp:
     59        (WebCore::isStartOfWord):
     60        * editing/visible_units.h:
     61        * manual-tests/autocorrection/spell-checking-after-reversion.html:
     62
    1632011-05-11  Dan Bernstein  <mitz@apple.com>
    264
  • trunk/Source/WebCore/dom/DocumentMarker.h

    r85118 r86295  
    5555        // On some platforms, this prevents the text from being spellchecked again.
    5656        SpellCheckingExemption = 1 << 7,
     57        // This marker indicates user has deleted an autocorrection starting at the end of the
     58        // range that bears this marker. In some platforms, if the user later inserts the same original
     59        // word again at this position, it will not be autocorrected again. The description of this
     60        // marker is the original word before autocorrection was applied.
     61        DeletedAutocorrection = 1 << 8
    5762    };
    5863
     
    7681    public:
    7782        AllMarkers()
    78             : MarkerTypes(Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | Autocorrected | SpellCheckingExemption)
     83            : MarkerTypes(Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | Autocorrected | SpellCheckingExemption | DeletedAutocorrection)
    7984        {
    8085        }
  • trunk/Source/WebCore/dom/DocumentMarkerController.cpp

    r85118 r86295  
    294294}
    295295
    296 Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType)
    297 {
    298     if (!possiblyHasMarkers(markerType))
     296Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerTypes markerTypes)
     297{
     298    if (!possiblyHasMarkers(markerTypes))
    299299        return Vector<DocumentMarker>();
    300300
     
    311311        Vector<DocumentMarker>::const_iterator end = markers.end();
    312312        for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) {
    313             if (markerType != it->type)
     313            if (!markerTypes.contains(it->type))
    314314                continue;
    315315            if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset()))
  • trunk/Source/WebCore/dom/DocumentMarkerController.h

    r85118 r86295  
    7171    DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType);
    7272    Vector<DocumentMarker> markersForNode(Node*);
    73     Vector<DocumentMarker> markersInRange(Range*, DocumentMarker::MarkerType);
     73    Vector<DocumentMarker> markersInRange(Range*, DocumentMarker::MarkerTypes);
    7474    Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType);
    7575    void clearDescriptionOnMarkersIntersectingRange(Range*, DocumentMarker::MarkerTypes);
  • trunk/Source/WebCore/editing/CompositeEditCommand.cpp

    r83322 r86295  
    3333#include "Document.h"
    3434#include "DocumentFragment.h"
     35#include "DocumentMarkerController.h"
    3536#include "EditorInsertAction.h"
    3637#include "Frame.h"
     
    341342}
    342343
     344void CompositeEditCommand::replaceTextInNodePreservingMarkers(PassRefPtr<Text> prpNode, unsigned offset, unsigned count, const String& replacementText)
     345{
     346    RefPtr<Text> node(prpNode);
     347    DocumentMarkerController* markerController = document()->markers();
     348    Vector<DocumentMarker> markers = markerController->markersInRange(Range::create(document(), node, offset, node, offset + count).get(), DocumentMarker::AllMarkers());
     349    replaceTextInNode(node, offset, count, replacementText);
     350    RefPtr<Range> newRange = Range::create(document(), node, offset, node, offset + replacementText.length());
     351    for (size_t i = 0; i < markers.size(); ++i)
     352        markerController->addMarker(newRange.get(), markers[i].type, markers[i].description);
     353}
     354
    343355Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
    344356{
     
    476488   
    477489    if (string != rebalancedString)
    478         replaceTextInNode(textNode, upstream, length, rebalancedString);
     490        replaceTextInNodePreservingMarkers(textNode, upstream, length, rebalancedString);
    479491}
    480492
     
    502514   
    503515    if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.deprecatedNode()->isTextNode() && !previous.deprecatedNode()->hasTagName(brTag))
    504         replaceTextInNode(static_cast<Text*>(previous.deprecatedNode()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
     516        replaceTextInNodePreservingMarkers(static_cast<Text*>(previous.deprecatedNode()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    505517    if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.deprecatedNode()->isTextNode() && !position.deprecatedNode()->hasTagName(brTag))
    506         replaceTextInNode(static_cast<Text*>(position.deprecatedNode()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
     518        replaceTextInNodePreservingMarkers(static_cast<Text*>(position.deprecatedNode()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    507519}
    508520
  • trunk/Source/WebCore/editing/CompositeEditCommand.h

    r81185 r86295  
    8484    void prune(PassRefPtr<Node>);
    8585    void replaceTextInNode(PassRefPtr<Text>, unsigned offset, unsigned count, const String& replacementText);
     86    void replaceTextInNodePreservingMarkers(PassRefPtr<Text>, unsigned offset, unsigned count, const String& replacementText);
    8687    Position positionOutsideTabSpan(const Position&);
    8788    void setNodeAttribute(PassRefPtr<Element>, const QualifiedName& attribute, const AtomicString& value);
  • trunk/Source/WebCore/editing/DeleteSelectionCommand.cpp

    r83247 r86295  
    2929#include "Document.h"
    3030#include "DocumentFragment.h"
     31#include "DocumentMarkerController.h"
    3132#include "EditingBoundary.h"
    3233#include "Editor.h"
     
    6970
    7071DeleteSelectionCommand::DeleteSelectionCommand(Document *document, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
    71     : CompositeEditCommand(document),
    72       m_hasSelectionToDelete(false),
    73       m_smartDelete(smartDelete),
    74       m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
    75       m_needPlaceholder(false),
    76       m_replace(replace),
    77       m_expandForSpecialElements(expandForSpecialElements),
    78       m_pruneStartBlockIfNecessary(false),
    79       m_startsAtEmptyLine(false),
    80       m_startBlock(0),
    81       m_endBlock(0),
    82       m_typingStyle(0),
    83       m_deleteIntoBlockquoteStyle(0)
     72    : CompositeEditCommand(document)
     73    , m_hasSelectionToDelete(false)
     74    , m_smartDelete(smartDelete)
     75    , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete)
     76    , m_needPlaceholder(false)
     77    , m_replace(replace)
     78    , m_expandForSpecialElements(expandForSpecialElements)
     79    , m_pruneStartBlockIfNecessary(false)
     80    , m_startsAtEmptyLine(false)
     81    , m_startBlock(0)
     82    , m_endBlock(0)
     83    , m_typingStyle(0)
     84    , m_deleteIntoBlockquoteStyle(0)
    8485{
    8586}
    8687
    8788DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
    88     : CompositeEditCommand(selection.start().anchorNode()->document()),
    89       m_hasSelectionToDelete(true),
    90       m_smartDelete(smartDelete),
    91       m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
    92       m_needPlaceholder(false),
    93       m_replace(replace),
    94       m_expandForSpecialElements(expandForSpecialElements),
    95       m_pruneStartBlockIfNecessary(false),
    96       m_startsAtEmptyLine(false),
    97       m_selectionToDelete(selection),
    98       m_startBlock(0),
    99       m_endBlock(0),
    100       m_typingStyle(0),
    101       m_deleteIntoBlockquoteStyle(0)
     89    : CompositeEditCommand(selection.start().anchorNode()->document())
     90    , m_hasSelectionToDelete(true)
     91    , m_smartDelete(smartDelete)
     92    , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete)
     93    , m_needPlaceholder(false)
     94    , m_replace(replace)
     95    , m_expandForSpecialElements(expandForSpecialElements)
     96    , m_pruneStartBlockIfNecessary(false)
     97    , m_startsAtEmptyLine(false)
     98    , m_selectionToDelete(selection)
     99    , m_startBlock(0)
     100    , m_endBlock(0)
     101    , m_typingStyle(0)
     102    , m_deleteIntoBlockquoteStyle(0)
    102103{
    103104}
     
    556557        Text* textNode = static_cast<Text*>(m_leadingWhitespace.deprecatedNode());
    557558        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
    558         replaceTextInNode(textNode, m_leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
     559        replaceTextInNodePreservingMarkers(textNode, m_leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    559560    }
    560561    if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter() && m_trailingWhitespace.deprecatedNode()->isTextNode()) {
    561562        Text* textNode = static_cast<Text*>(m_trailingWhitespace.deprecatedNode());
    562563        ASSERT(!textNode->renderer() ||textNode->renderer()->style()->collapseWhiteSpace());
    563         replaceTextInNode(textNode, m_trailingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
     564        replaceTextInNodePreservingMarkers(textNode, m_trailingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    564565    }
    565566}
     
    744745    m_trailingWhitespace.clear();
    745746}
     747   
     748String DeleteSelectionCommand::originalStringForAutocorrectionAtBeginningOfSelection()
     749{
     750    if (!m_selectionToDelete.isRange())
     751        return String();
     752
     753    VisiblePosition startOfSelection = m_selectionToDelete.start();
     754    if (!isStartOfWord(startOfSelection))
     755        return String();
     756
     757    RefPtr<Range> rangeOfFirstCharacter = Range::create(document(), startOfSelection.deepEquivalent(), startOfSelection.next().deepEquivalent());
     758    Vector<DocumentMarker> markers = document()->markers()->markersInRange(rangeOfFirstCharacter.get(), DocumentMarker::Autocorrected);
     759    for (size_t i = 0; i < markers.size(); ++i) {
     760        const DocumentMarker& marker = markers[i];
     761        int startOffset = marker.startOffset;
     762        if (startOffset == startOfSelection.deepEquivalent().offsetInContainerNode())
     763            return marker.description;
     764    }
     765    return String();
     766}
    746767
    747768void DeleteSelectionCommand::doApply()
     
    754775    if (!m_selectionToDelete.isNonOrphanedRange())
    755776        return;
     777
     778    String originalString = originalStringForAutocorrectionAtBeginningOfSelection();
    756779
    757780    // If the deletion is occurring in a text field, and we're not deleting to replace the selection, then let the frame call across the bridge to notify the form delegate.
     
    816839
    817840    calculateTypingStyleAfterDelete();
    818    
     841
     842    if (!originalString.isEmpty()) {
     843        if (Frame* frame = document()->frame())
     844            frame->editor()->deletedAutocorrectionAtPosition(m_endingPosition, originalString);
     845    }
     846
    819847    setEndingSelection(VisibleSelection(m_endingPosition, affinity));
    820848    clearTransientState();
  • trunk/Source/WebCore/editing/DeleteSelectionCommand.h

    r71469 r86295  
    6969    virtual void deleteTextFromNode(PassRefPtr<Text>, unsigned, unsigned);
    7070
     71    // This function provides access to original string after the correction has been deleted.
     72    String originalStringForAutocorrectionAtBeginningOfSelection();
     73
    7174    bool m_hasSelectionToDelete;
    7275    bool m_smartDelete;
  • trunk/Source/WebCore/editing/Editor.cpp

    r86132 r86295  
    22302230                continue;
    22312231
     2232            if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement)
     2233                continue;
     2234
    22322235            String replacedString = plainText(rangeToReplace.get());
    2233 
    2234             // Don't correct spelling in an already-corrected word.
    2235             DocumentMarkerController* markers = m_frame->document()->markers();
    2236             if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::Replacement)) {
    2237                 doReplacement = false;
    2238                 if (result->type == TextCheckingTypeCorrection)
    2239                     m_spellingCorrector->recordSpellcheckerResponseForModifiedCorrection(rangeToReplace.get(), replacedString, result->replacement);
    2240             } else if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::RejectedCorrection))
    2241                 doReplacement = false;
    2242 
    2243             if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement)
     2236            bool existingMarkersPermitReplacement = m_spellingCorrector->processMarkersOnTextToBeReplacedByResult(result, rangeToReplace.get(), replacedString);
     2237            if (!existingMarkersPermitReplacement)
    22442238                continue;
    22452239
     
    24252419    document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption, DocumentMarkerController::RemovePartiallyOverlappingMarker);
    24262420    document->markers()->clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
     2421}
     2422
     2423void Editor::deletedAutocorrectionAtPosition(const Position& position, const String& originalString)
     2424{
     2425    m_spellingCorrector->deletedAutocorrectionAtPosition(position, originalString);
    24272426}
    24282427
  • trunk/Source/WebCore/editing/Editor.h

    r86135 r86295  
    385385    bool selectionStartHasMarkerFor(DocumentMarker::MarkerType, int from, int length) const;
    386386    void updateMarkersForWordsAffectedByEditing(bool onlyHandleWordsContainingSelection);
     387    void deletedAutocorrectionAtPosition(const Position&, const String& originalString);
    387388
    388389private:
  • trunk/Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp

    r83247 r86295  
    313313        Text* textNode = static_cast<Text*>(leadingWhitespace.deprecatedNode());
    314314        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
    315         replaceTextInNode(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
     315        replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    316316    }
    317317   
  • trunk/Source/WebCore/editing/SpellingCorrectionController.cpp

    r85864 r86295  
    430430    if (command->isTopLevelCommand() && !command->shouldRetainAutocorrectionIndicator())
    431431        m_frame->document()->markers()->removeMarkers(DocumentMarker::CorrectionIndicator);
     432
     433    markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand(command);
     434    m_originalStringForLastDeletedAutocorrection = String();
    432435}
    433436
     
    503506}
    504507
     508void SpellingCorrectionController::deletedAutocorrectionAtPosition(const Position& position, const String& originalString)
     509{
     510    m_originalStringForLastDeletedAutocorrection = originalString;
     511    m_positionForLastDeletedAutocorrection = position;
     512}
     513
     514void SpellingCorrectionController::markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand(EditCommand* command)
     515{
     516    Position endOfSelection = command->endingSelection().end();
     517    if (endOfSelection != m_positionForLastDeletedAutocorrection)
     518        return;
     519
     520    Position precedingCharacterPosition = endOfSelection.previous();
     521    if (endOfSelection == precedingCharacterPosition)
     522        return;
     523
     524    RefPtr<Range> precedingCharacterRange = Range::create(m_frame->document(), precedingCharacterPosition, endOfSelection);
     525    String string = plainText(precedingCharacterRange.get());
     526    if (string.isEmpty() || !isWhitespace(string[string.length() - 1]))
     527        return;
     528
     529    // Mark this whitespace to indicate we have deleted an autocorrection following this
     530    // whitespace. So if the user types the same original word again at this position, we
     531    // won't autocorrect it again.
     532    m_frame->document()->markers()->addMarker(precedingCharacterRange.get(), DocumentMarker::DeletedAutocorrection, m_originalStringForLastDeletedAutocorrection);
     533}
     534
     535bool SpellingCorrectionController::processMarkersOnTextToBeReplacedByResult(const TextCheckingResult* result, Range* rangeToBeReplaced, const String& stringToBeReplaced)
     536{
     537    DocumentMarkerController* markerController = m_frame->document()->markers();
     538    if (markerController->hasMarkers(rangeToBeReplaced, DocumentMarker::Replacement)) {
     539        if (result->type == TextCheckingTypeCorrection)
     540            recordSpellcheckerResponseForModifiedCorrection(rangeToBeReplaced, stringToBeReplaced, result->replacement);
     541        return false;
     542    }
     543
     544    if (markerController->hasMarkers(rangeToBeReplaced, DocumentMarker::RejectedCorrection))
     545        return false;
     546
     547    Position beginningOfRange = rangeToBeReplaced->startPosition();
     548    Position precedingCharacterPosition = beginningOfRange.previous();
     549    RefPtr<Range> precedingCharacterRange = Range::create(m_frame->document(), precedingCharacterPosition, beginningOfRange);
     550
     551    Vector<DocumentMarker> markers = markerController->markersInRange(precedingCharacterRange.get(), DocumentMarker::DeletedAutocorrection);
     552
     553    for (size_t i = 0; i < markers.size(); ++i) {
     554        if (markers[i].description == stringToBeReplaced)
     555            return false;
     556    }
     557
     558    return true;
     559}
     560   
    505561#endif
    506562
  • trunk/Source/WebCore/editing/SpellingCorrectionController.h

    r85036 r86295  
    6767};
    6868
     69struct TextCheckingResult;
     70
    6971enum ReasonForDismissingCorrectionPanel {
    7072    ReasonForDismissingCorrectionPanelCancelled = 0,
     
    118120    void recordSpellcheckerResponseForModifiedCorrection(Range* rangeOfCorrection, const String& corrected, const String& correction) UNLESS_ENABLED({ UNUSED_PARAM(rangeOfCorrection); UNUSED_PARAM(corrected); UNUSED_PARAM(correction); })
    119121
     122    // This function returns false if the replacement should not be carried out.
     123    bool processMarkersOnTextToBeReplacedByResult(const TextCheckingResult*, Range* rangeToBeReplaced, const String& stringToBeReplaced) UNLESS_ENABLED({ UNUSED_PARAM(rangeToBeReplaced); UNUSED_PARAM(stringToBeReplaced); return true; });
     124    void deletedAutocorrectionAtPosition(const Position&, const String& originalString) UNLESS_ENABLED({ UNUSED_PARAM(originalString); })
     125
    120126#if SUPPORT_AUTOCORRECTION_PANEL
    121127private:
     
    131137    TextCheckerClient* textChecker();
    132138    FloatRect windowRectForRange(const Range*) const;
     139    void markPrecedingWhitespaceForDeletedAutocorrectionAfterCommand(EditCommand*);
    133140
    134141    EditorClient* m_client;
     
    138145    CorrectionPanelInfo m_correctionPanelInfo;
    139146    bool m_correctionPanelIsDismissedByEditor;
     147
     148    String m_originalStringForLastDeletedAutocorrection;
     149    Position m_positionForLastDeletedAutocorrection;
    140150#endif
    141151};
  • trunk/Source/WebCore/editing/visible_units.cpp

    r84710 r86295  
    314314}
    315315
     316bool isStartOfWord(const VisiblePosition& p)
     317{
     318    return p.isNotNull() && p == startOfWord(p, RightWordIfOnBoundary);
     319}
     320
    316321// ---------
    317322
  • trunk/Source/WebCore/editing/visible_units.h

    r82588 r86295  
    4545VisiblePosition rightWordPosition(const VisiblePosition&);
    4646VisiblePosition leftWordPosition(const VisiblePosition&);
     47bool isStartOfWord(const VisiblePosition&);
    4748
    4849// sentences
  • trunk/Source/WebCore/manual-tests/autocorrection/spell-checking-after-reversion.html

    r77577 r86295  
    3535<li>After seeing the correction panel, press space to accept the correction.</li>
    3636<li>Press delete key to bring up reversion bubble.</li>
    37 <li>Press ESC key to accept the reversion suggestion.</li>
     37<li>Press down arrow followed by return key to accept the reversion suggestion.</li>
    3838<li>Press space key again, and verify that the word "cylindr" IS NOT marked as misspelled.</li>
    3939<li>Press delete key twice.</li>
Note: See TracChangeset for help on using the changeset viewer.