Changeset 83060 in webkit
- Timestamp:
- Apr 6, 2011 9:09:28 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r83053 r83060 1 2011-04-06 Jia Pu <jpu@apple.com> 2 3 Reviewed by Darin Adler. 4 5 [Mac] WebCore need to notify AppKit spell checker after user has modified autocorrected text. 6 https://bugs.webkit.org/show_bug.cgi?id=57665 7 <rdar://problem/7350477> 8 9 We need to track how user modified an autocorrected word. If he changed it back to original 10 text, we want to record AutocorrectionReverted response. And if he changed it to something 11 else, we want to record AutocorrectionEdited response. 12 13 To achieve this, we need to distringuish between text replacement caused by autocorrection 14 from that due to other causes, such as reversion, text substitution, etc. So we added a new 15 marker type "Autocorrected". We also need to be able to check for correction, even when we 16 don't intend to actually carry out replacement. For this, we introduced a new TextCheckingOption 17 value, "CheckForCorrection". 18 19 We also added DocumentMarkerController::markersInRange() to retrieve a vector of markers in 20 specified range, and of specified type. 21 22 * dom/DocumentMarker.h: 23 * dom/DocumentMarkerController.cpp: 24 (WebCore::DocumentMarkerController::markersInRange): 25 (WebCore::DocumentMarkerController::hasMarkers): 26 * dom/DocumentMarkerController.h: 27 * editing/Editor.cpp: 28 (WebCore::markerTypesForAutocorrection): 29 (WebCore::markersHaveIdenticalDescription): 30 (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): 31 (WebCore::Editor::recordSpellcheckerResponseForModifiedCorrection): 32 (WebCore::Editor::changeBackToReplacedString): 33 (WebCore::Editor::markMisspellingsAndBadGrammar): 34 (WebCore::Editor::applyCorrectionPanelInfo): 35 (WebCore::Editor::unappliedSpellCorrection): 36 (WebCore::Editor::textCheckingTypeMaskFor): 37 * editing/Editor.h: 38 * editing/SpellingCorrectionCommand.cpp: 39 (WebCore::SpellingCorrectionCommand::doApply): 40 1 41 2011-04-06 Sheriff Bot <webkit.review.bot@gmail.com> 2 42 -
trunk/Source/WebCore/dom/DocumentMarker.h
r80023 r83060 38 38 Grammar = 1 << 1, 39 39 TextMatch = 1 << 2, 40 // Text has been modified by spell correction . On some platforms, this prevents the text41 // to be autocorrected again. On post Snow Leopard Mac OS X, if a Replacement marker contains42 // non-empty description, a reversion UI will be shown.40 // Text has been modified by spell correction, reversion of spell correction or other type of substitution. 41 // On some platforms, this prevents the text from being autocorrected again. On post Snow Leopard Mac OS X, 42 // if a Replacement marker contains non-empty description, a reversion UI will be shown. 43 43 Replacement = 1 << 3, 44 44 // Renderer needs to add underline indicating that the text has been modified by spell … … 50 50 // Correction suggestion has been offered, but got rejected by user. 51 51 RejectedCorrection = 1 << 5, 52 // On some platforms, this prevents the text to be spellchecked again. 53 SpellCheckingExemption = 1 << 6, 54 AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | SpellCheckingExemption 52 // Text has been modified by autocorrection. The description of this marker is the original text before autocorrection. 53 Autocorrected = 1 << 6, 54 // On some platforms, this prevents the text from being spellchecked again. 55 SpellCheckingExemption = 1 << 7, 56 AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | Autocorrected | SpellCheckingExemption 55 57 }; 56 58 MarkerType type; -
trunk/Source/WebCore/dom/DocumentMarkerController.cpp
r80075 r83060 318 318 } 319 319 320 Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType) 321 { 322 if (!possiblyHasMarkers(markerType)) 323 return Vector<DocumentMarker>(); 324 325 Vector<DocumentMarker> foundMarkers; 326 327 Node* startContainer = range->startContainer(); 328 ASSERT(startContainer); 329 Node* endContainer = range->endContainer(); 330 ASSERT(endContainer); 331 332 Node* pastLastNode = range->pastLastNode(); 333 for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { 334 Vector<DocumentMarker> markers = markersForNode(node); 335 Vector<DocumentMarker>::const_iterator end = markers.end(); 336 for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) { 337 if (!(markerType & it->type)) 338 continue; 339 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) 340 continue; 341 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) 342 continue; 343 foundMarkers.append(*it); 344 } 345 } 346 return foundMarkers; 347 } 348 320 349 Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) 321 350 { … … 603 632 if (!(markerTypes & it->type)) 604 633 continue; 605 if (node == startContainer && node == endContainer) { 606 // The range spans only one node. 607 if (it->endOffset > static_cast<unsigned>(range->startOffset()) && it->startOffset < static_cast<unsigned>(range->endOffset())) 608 return true; 609 } else { 610 if (node == startContainer) { 611 if (it->endOffset > static_cast<unsigned>(range->startOffset())) 612 return true; 613 } else if (node == endContainer) { 614 if (it->startOffset < static_cast<unsigned>(range->endOffset())) 615 return true; 616 } else 617 return true; 618 } 634 if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) 635 continue; 636 if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) 637 continue; 638 return true; 619 639 } 620 640 } -
trunk/Source/WebCore/dom/DocumentMarkerController.h
r80023 r83060 69 69 DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); 70 70 Vector<DocumentMarker> markersForNode(Node*); 71 Vector<DocumentMarker> markersInRange(Range*, DocumentMarker::MarkerType); 71 72 Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); 72 73 void clearDescriptionOnMarkersIntersectingRange(Range*, DocumentMarker::MarkerTypes); -
trunk/Source/WebCore/editing/Editor.cpp
r83049 r83060 109 109 markerTypesForAutoCorrection.append(DocumentMarker::CorrectionIndicator); 110 110 markerTypesForAutoCorrection.append(DocumentMarker::SpellCheckingExemption); 111 markerTypesForAutoCorrection.append(DocumentMarker::Autocorrected); 111 112 } 112 113 return markerTypesForAutoCorrection; … … 122 123 return markerTypesForReplacement; 123 124 } 125 126 #if SUPPORT_AUTOCORRECTION_PANEL 127 static bool markersHaveIdenticalDescription(const Vector<DocumentMarker>& markers) 128 { 129 if (markers.isEmpty()) 130 return true; 131 132 const String& description = markers[0].description; 133 for (size_t i = 1; i < markers.size(); ++i) { 134 if (description != markers[i].description) 135 return false; 136 } 137 return true; 138 } 139 #endif 124 140 125 141 // When an event handler has moved the selection outside of a text control … … 2213 2229 bool shouldPerformReplacement = textCheckingOptions & PerformReplacement; 2214 2230 bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel; 2231 bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection); 2215 2232 2216 2233 // This function is called with selections already expanded to word boundaries. … … 2240 2257 return; 2241 2258 2242 if (shouldPerformReplacement || shouldMarkSpelling ) {2259 if (shouldPerformReplacement || shouldMarkSpelling || shouldCheckForCorrection) { 2243 2260 if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) { 2244 2261 // Attempt to save the caret position so we can restore it later if needed … … 2303 2320 } 2304 2321 } 2305 } else if ( (shouldPerformReplacement || shouldShowCorrectionPanel) &&resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart()2322 } else if (resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart() 2306 2323 && (result->type == TextCheckingTypeLink 2307 2324 || result->type == TextCheckingTypeQuote … … 2329 2346 continue; 2330 2347 2348 String replacedString; 2349 2331 2350 // Don't correct spelling in an already-corrected word. 2332 2351 if (result->type == TextCheckingTypeCorrection) { 2333 Node* node = rangeToReplace->startContainer(); 2334 int startOffset = rangeToReplace->startOffset(); 2335 int endOffset = startOffset + replacementLength; 2336 Vector<DocumentMarker> markers = node->document()->markers()->markersForNode(node); 2337 size_t markerCount = markers.size(); 2338 for (size_t i = 0; i < markerCount; ++i) { 2339 const DocumentMarker& marker = markers[i]; 2340 if ((marker.type == DocumentMarker::Replacement || marker.type == DocumentMarker::RejectedCorrection) && static_cast<int>(marker.startOffset) < endOffset && static_cast<int>(marker.endOffset) > startOffset) { 2341 doReplacement = false; 2342 break; 2343 } 2344 if (static_cast<int>(marker.startOffset) >= endOffset) 2345 break; 2346 } 2352 replacedString = plainText(rangeToReplace.get()); 2353 DocumentMarkerController* markers = m_frame->document()->markers(); 2354 if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::Replacement)) { 2355 doReplacement = false; 2356 recordSpellcheckerResponseForModifiedCorrection(rangeToReplace.get(), replacedString, result->replacement); 2357 } else if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::RejectedCorrection)) 2358 doReplacement = false; 2347 2359 } 2348 2360 2349 if (! doReplacement)2361 if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement) 2350 2362 continue; 2351 2363 … … 2381 2393 applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement)); 2382 2394 } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) { 2383 String replacedString;2384 if (result->type == TextCheckingTypeCorrection)2385 replacedString = plainText(rangeToReplace.get());2386 2387 2395 bool useSpellingCorrectionCommand = false; 2388 2396 #if SUPPORT_AUTOCORRECTION_PANEL … … 2413 2421 // Add a marker so that corrections can easily be undone and won't be re-corrected. 2414 2422 RefPtr<Range> replacedRange = spellingParagraph.subrange(resultLocation, replacementLength); 2415 replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString); 2416 replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator); 2417 replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption); 2423 Vector<DocumentMarker::MarkerType> markerTypesToAdd = markerTypesForAutocorrection(); 2424 DocumentMarkerController* markers = replacedRange->startContainer()->document()->markers(); 2425 for (size_t i = 0; i < markerTypesToAdd.size(); ++i) { 2426 DocumentMarker::MarkerType markerType = markerTypesToAdd[i]; 2427 if (markerType == DocumentMarker::Replacement || markerType == DocumentMarker::Autocorrected) 2428 markers->addMarker(replacedRange.get(), markerType, replacedString); 2429 else 2430 markers->addMarker(replacedRange.get(), markerType); 2431 } 2418 2432 } 2419 2433 } … … 2443 2457 } 2444 2458 2459 void Editor::recordSpellcheckerResponseForModifiedCorrection(Range* rangeOfCorrection, const String& corrected, const String& correction) 2460 { 2461 #if SUPPORT_AUTOCORRECTION_PANEL 2462 if (!rangeOfCorrection) 2463 return; 2464 DocumentMarkerController* markers = rangeOfCorrection->startContainer()->document()->markers(); 2465 Vector<DocumentMarker> correctedOnceMarkers = markers->markersInRange(rangeOfCorrection, DocumentMarker::Autocorrected); 2466 if (correctedOnceMarkers.isEmpty()) 2467 return; 2468 2469 // Spelling corrected text has been edited. We need to determine whether user has reverted it to original text or 2470 // edited it to something else, and notify spellchecker accordingly. 2471 if (markersHaveIdenticalDescription(correctedOnceMarkers) && correctedOnceMarkers[0].description == corrected) 2472 client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, corrected, correction); 2473 else 2474 client()->recordAutocorrectionResponse(EditorClient::AutocorrectionEdited, corrected, correction); 2475 markers->removeMarkers(rangeOfCorrection, DocumentMarker::Autocorrected, DocumentMarkerController::RemovePartiallyOverlappingMarker); 2476 #else 2477 UNUSED_PARAM(rangeOfCorrection); 2478 UNUSED_PARAM(corrected); 2479 UNUSED_PARAM(correction); 2480 #endif 2481 } 2482 2445 2483 void Editor::changeBackToReplacedString(const String& replacedString) 2446 2484 { … … 2462 2500 changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String()); 2463 2501 #if SUPPORT_AUTOCORRECTION_PANEL 2502 changedRange->startContainer()->document()->markers()->removeMarkers(changedRange.get(), DocumentMarker::Autocorrected, DocumentMarkerController::RemovePartiallyOverlappingMarker); 2464 2503 changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::SpellCheckingExemption); 2465 2504 #endif … … 2476 2515 if (!isContinuousSpellCheckingEnabled()) 2477 2516 return; 2478 TextCheckingOptions textCheckingOptions = MarkSpelling ;2517 TextCheckingOptions textCheckingOptions = MarkSpelling | CheckForCorrection; 2479 2518 if (markGrammar && isGrammarCheckingEnabled()) 2480 2519 textCheckingOptions |= MarkGrammar; … … 2733 2772 size_t size = markerTypesToAdd.size(); 2734 2773 for (size_t i = 0; i < size; ++i) { 2735 if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion) 2736 markers->addMarker(replacementRange.get(), markerTypesToAdd[i]); 2737 else 2738 markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString); 2774 DocumentMarker::MarkerType markerType = markerTypesToAdd[i]; 2775 String description; 2776 if (m_correctionPanelInfo.panelType != CorrectionPanelInfo::PanelTypeReversion && (markerType == DocumentMarker::Replacement || markerType == DocumentMarker::Autocorrected)) 2777 description = m_correctionPanelInfo.replacedString; 2778 markers->addMarker(replacementRange.get(), markerType, description); 2739 2779 } 2740 2780 #else // SUPPORT_AUTOCORRECTION_PANEL … … 2773 2813 2774 2814 DocumentMarkerController* markers = m_frame->document()->markers(); 2775 markers->removeMarkers(range.get(), DocumentMarker::Spelling );2815 markers->removeMarkers(range.get(), DocumentMarker::Spelling | DocumentMarker::Autocorrected, DocumentMarkerController::RemovePartiallyOverlappingMarker); 2776 2816 markers->addMarker(range.get(), DocumentMarker::Replacement); 2777 2817 markers->addMarker(range.get(), DocumentMarker::SpellCheckingExemption); … … 3595 3635 bool shouldMarkGrammar = textCheckingOptions & MarkGrammar; 3596 3636 bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel; 3637 bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection); 3597 3638 3598 3639 TextCheckingTypeMask checkingTypes = 0; … … 3601 3642 if (shouldMarkGrammar) 3602 3643 checkingTypes |= TextCheckingTypeGrammar; 3603 if (should ShowCorrectionPanel)3644 if (shouldCheckForCorrection) 3604 3645 checkingTypes |= TextCheckingTypeCorrection; 3605 3646 -
trunk/Source/WebCore/editing/Editor.h
r82952 r83060 230 230 PerformReplacement = 1 << 2, 231 231 ShowCorrectionPanel = 1 << 3, 232 CheckForCorrection = 1 << 4, 232 233 }; 233 234 typedef unsigned TextCheckingOptions; … … 417 418 void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange); 418 419 TextCheckingTypeMask textCheckingTypeMaskFor(TextCheckingOptions); 420 void recordSpellcheckerResponseForModifiedCorrection(Range*, const String& corrected, const String& correction); 419 421 420 422 void selectComposition(); -
trunk/Source/WebCore/editing/SpellingCorrectionCommand.cpp
r80023 r83060 95 95 return; 96 96 97 applyCommandToComposite(SetSelectionCommand::create(m_selectionToBeCorrected, SelectionController:: CloseTyping | SelectionController::ClearTypingStyle));97 applyCommandToComposite(SetSelectionCommand::create(m_selectionToBeCorrected, SelectionController::SpellCorrectionTriggered | SelectionController::CloseTyping | SelectionController::ClearTypingStyle)); 98 98 #if SUPPORT_AUTOCORRECTION_PANEL 99 99 applyCommandToComposite(SpellingCorrectionRecordUndoCommand::create(document(), m_corrected, m_correction));
Note: See TracChangeset
for help on using the changeset viewer.