Changeset 148124 in webkit
- Timestamp:
- Apr 10, 2013 12:16:58 PM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r148123 r148124 1 2013-04-10 Ryosuke Niwa <rniwa@webkit.org> 2 3 Refactor Editor::markAndReplaceFor before fixing autocorrection bugs 4 https://bugs.webkit.org/show_bug.cgi?id=114344 5 6 Reviewed by Enrica Casucci. 7 8 This patch refactors Editor::markAndReplaceFor so that we can start fixing bugs in a sane state. 9 Extracted isAutomaticTextReplacementType and correctSpellcheckingPreservingTextCheckingParagraph, 10 and made convenience local variables const. 11 12 In particular, shouldMarkSpelling used to be assigned of false when shouldShowCorrectionPanel was true 13 in a middle of a function but this was removed in favor of explicitly checking this condition later 14 since shouldMarkSpelling was only referenced once after the assignment. 15 16 * editing/Editor.cpp: 17 (WebCore::isAutomaticTextReplacementType): Extracted. 18 19 (WebCore::correctSpellcheckingPreservingTextCheckingParagraph): Extracted. Used highestAncestor 20 and rangeFromLocationAndLength to match the rest of the up-to-date editing code. 21 22 (WebCore::Editor::markAndReplaceFor): See above. 23 1 24 2013-04-08 Anders Carlsson <andersca@apple.com> 2 25 -
trunk/Source/WebCore/editing/Editor.cpp
r146907 r148124 2134 2134 } 2135 2135 2136 static bool isAutomaticTextReplacementType(TextCheckingType type) 2137 { 2138 switch (type) { 2139 case TextCheckingTypeNone: 2140 case TextCheckingTypeSpelling: 2141 case TextCheckingTypeGrammar: 2142 return false; 2143 case TextCheckingTypeLink: 2144 case TextCheckingTypeQuote: 2145 case TextCheckingTypeDash: 2146 case TextCheckingTypeReplacement: 2147 case TextCheckingTypeCorrection: 2148 case TextCheckingTypeShowCorrectionPanel: 2149 return true; 2150 } 2151 ASSERT_NOT_REACHED(); 2152 return false; 2153 } 2154 2155 static void correctSpellcheckingPreservingTextCheckingParagraph(TextCheckingParagraph& paragraph, PassRefPtr<Range> rangeToReplace, const String& replacement, int resultLocation, int resultLength) 2156 { 2157 ContainerNode* scope = toContainerNode(highestAncestor(paragraph.paragraphRange()->startContainer())); 2158 2159 size_t paragraphLocation; 2160 size_t paragraphLength; 2161 TextIterator::getLocationAndLengthFromRange(scope, paragraph.paragraphRange().get(), paragraphLocation, paragraphLength); 2162 2163 applyCommand(SpellingCorrectionCommand::create(rangeToReplace, replacement)); 2164 2165 // TextCheckingParagraph may be orphaned after SpellingCorrectionCommand mutated DOM. 2166 // See <rdar://10305315>, http://webkit.org/b/89526. 2167 2168 RefPtr<Range> newParagraphRange = TextIterator::rangeFromLocationAndLength(scope, paragraphLocation, paragraphLength + replacement.length() - resultLength); 2169 2170 paragraph = TextCheckingParagraph(TextIterator::subrange(newParagraphRange.get(), resultLocation, replacement.length()), newParagraphRange); 2171 } 2172 2136 2173 void Editor::markAndReplaceFor(PassRefPtr<SpellCheckRequest> request, const Vector<TextCheckingResult>& results) 2137 2174 { … … 2141 2178 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraphRange()); 2142 2179 2143 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling;2144 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar;2145 bool shouldMarkLink = textCheckingOptions & TextCheckingTypeLink;2146 bool shouldPerformReplacement = textCheckingOptions & TextCheckingTypeReplacement;2147 bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel;2148 bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & TextCheckingTypeCorrection);2180 const bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; 2181 const bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; 2182 const bool shouldMarkLink = textCheckingOptions & TextCheckingTypeLink; 2183 const bool shouldPerformReplacement = textCheckingOptions & TextCheckingTypeReplacement; 2184 const bool shouldShowCorrectionPanel = textCheckingOptions & TextCheckingTypeShowCorrectionPanel; 2185 const bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & TextCheckingTypeCorrection); 2149 2186 2150 2187 // Expand the range to encompass entire paragraphs, since text checking needs that much context. … … 2168 2205 } 2169 2206 2170 // If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.2171 if (shouldShowCorrectionPanel)2172 shouldMarkSpelling = false;2173 2174 2207 int offsetDueToReplacement = 0; 2175 2208 2176 2209 for (unsigned i = 0; i < results.size(); i++) { 2177 int spellingRangeEndOffset = paragraph.checkingEnd() + offsetDueToReplacement; 2178 const TextCheckingResult* result = &results[i]; 2179 int resultLocation = result->location + offsetDueToReplacement; 2180 int resultLength = result->length; 2181 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset; 2210 const int spellingRangeEndOffset = paragraph.checkingEnd() + offsetDueToReplacement; 2211 const TextCheckingType resultType = results[i].type; 2212 const int resultLocation = results[i].location + offsetDueToReplacement; 2213 const int resultLength = results[i].length; 2214 const String& replacement = results[i].replacement; 2215 const bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset; 2182 2216 2183 2217 // Only mark misspelling if: … … 2186 2220 // 3. The word in question doesn't end at an ambiguous boundary. For instance, we would not mark 2187 2221 // "wouldn'" as misspelled right after apostrophe is typed. 2188 if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { 2222 if (shouldMarkSpelling && !shouldShowCorrectionPanel && resultType == TextCheckingTypeSpelling 2223 && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { 2189 2224 ASSERT(resultLength > 0 && resultLocation >= 0); 2190 2225 RefPtr<Range> misspellingRange = paragraph.subrange(resultLocation, resultLength); 2191 2226 if (!m_alternativeTextController->isSpellingMarkerAllowed(misspellingRange)) 2192 2227 continue; 2193 misspellingRange->startContainer()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling, re sult->replacement);2194 } else if (shouldMarkGrammar && result ->type == TextCheckingTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) {2228 misspellingRange->startContainer()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling, replacement); 2229 } else if (shouldMarkGrammar && resultType == TextCheckingTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { 2195 2230 ASSERT(resultLength > 0 && resultLocation >= 0); 2196 for (unsigned j = 0; j < result->details.size(); j++) { 2197 const GrammarDetail* detail = &result->details[j]; 2198 ASSERT(detail->length > 0 && detail->location >= 0); 2199 if (paragraph.checkingRangeCovers(resultLocation + detail->location, detail->length)) { 2200 RefPtr<Range> badGrammarRange = paragraph.subrange(resultLocation + detail->location, detail->length); 2201 badGrammarRange->startContainer()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription); 2231 const Vector<GrammarDetail>& details = results[i].details; 2232 for (unsigned j = 0; j < details.size(); j++) { 2233 const GrammarDetail& detail = details[j]; 2234 ASSERT(detail.length > 0 && detail.location >= 0); 2235 if (paragraph.checkingRangeCovers(resultLocation + detail.location, detail.length)) { 2236 RefPtr<Range> badGrammarRange = paragraph.subrange(resultLocation + detail.location, detail.length); 2237 badGrammarRange->startContainer()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail.userDescription); 2202 2238 } 2203 2239 } 2204 2240 } else if (resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= paragraph.checkingStart() 2205 && (result->type == TextCheckingTypeLink 2206 || result->type == TextCheckingTypeQuote 2207 || result->type == TextCheckingTypeDash 2208 || result->type == TextCheckingTypeReplacement 2209 || result->type == TextCheckingTypeCorrection)) { 2241 && isAutomaticTextReplacementType(resultType)) { 2210 2242 // In this case the result range just has to touch the spelling range, so we can handle replacing non-word text such as punctuation. 2211 2243 ASSERT(resultLength > 0 && resultLocation >= 0); 2212 2244 2213 if (shouldShowCorrectionPanel && (resultLocation + resultLength < spellingRangeEndOffset || result ->type != TextCheckingTypeCorrection))2245 if (shouldShowCorrectionPanel && (resultLocation + resultLength < spellingRangeEndOffset || resultType != TextCheckingTypeCorrection)) 2214 2246 continue; 2215 2216 int replacementLength = result->replacement.length();2217 2247 2218 2248 // Apply replacement if: … … 2220 2250 // 2. The result doesn't end at an ambiguous boundary. 2221 2251 // (FIXME: this is required until 6853027 is fixed and text checking can do this for us 2222 bool doReplacement = replacement Length> 0 && !resultEndsAtAmbiguousBoundary;2252 bool doReplacement = replacement.length() > 0 && !resultEndsAtAmbiguousBoundary; 2223 2253 RefPtr<Range> rangeToReplace = paragraph.subrange(resultLocation, resultLength); 2224 VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);2225 2254 2226 2255 // adding links should be done only immediately after they are typed 2227 2256 int resultEnd = resultLocation + resultLength; 2228 if (result ->type == TextCheckingTypeLink2257 if (resultType == TextCheckingTypeLink 2229 2258 && (selectionOffset > resultEnd + 1 || selectionOffset <= resultLocation)) 2230 2259 continue; … … 2234 2263 2235 2264 String replacedString = plainText(rangeToReplace.get()); 2236 bool existingMarkersPermitReplacement = m_alternativeTextController->processMarkersOnTextToBeReplacedByResult(result, rangeToReplace.get(), replacedString);2265 const bool existingMarkersPermitReplacement = m_alternativeTextController->processMarkersOnTextToBeReplacedByResult(&results[i], rangeToReplace.get(), replacedString); 2237 2266 if (!existingMarkersPermitReplacement) 2238 2267 continue; … … 2245 2274 if (resultLocation + resultLength == spellingRangeEndOffset) { 2246 2275 // We only show the correction panel on the last word. 2247 m_alternativeTextController->show(rangeToReplace, re sult->replacement);2276 m_alternativeTextController->show(rangeToReplace, replacement); 2248 2277 break; 2249 2278 } … … 2252 2281 } 2253 2282 2283 VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM); 2254 2284 if (selectionToReplace != m_frame->selection()->selection()) { 2255 2285 if (!m_frame->selection()->shouldChangeSelection(selectionToReplace)) … … 2257 2287 } 2258 2288 2259 if (result ->type == TextCheckingTypeLink) {2289 if (resultType == TextCheckingTypeLink) { 2260 2290 m_frame->selection()->setSelection(selectionToReplace); 2261 2291 selectionChanged = true; 2262 2292 restoreSelectionAfterChange = false; 2263 2293 if (canEditRichly()) 2264 applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement)); 2265 } else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) { 2266 Node* root = paragraph.paragraphRange()->startContainer(); 2267 while (ContainerNode* parent = root->parentNode()) 2268 root = parent; 2269 2270 int paragraphStartIndex = TextIterator::rangeLength(Range::create(m_frame->document(), root, 0, paragraph.paragraphRange()->startContainer(), paragraph.paragraphRange()->startOffset()).get()); 2271 int paragraphLength = TextIterator::rangeLength(paragraph.paragraphRange().get()); 2272 applyCommand(SpellingCorrectionCommand::create(rangeToReplace, result->replacement)); 2273 // Recalculate newParagraphRange, since SpellingCorrectionCommand modifies the DOM, such that the original paragraph range is no longer valid. Radar: 10305315 Bugzilla: 89526 2274 RefPtr<Range> newParagraphRange = TextIterator::rangeFromLocationAndLength(toContainerNode(root), paragraphStartIndex, paragraphLength + replacementLength - resultLength); 2275 paragraph = TextCheckingParagraph(TextIterator::subrange(newParagraphRange.get(), resultLocation, replacementLength), newParagraphRange); 2276 2294 applyCommand(CreateLinkCommand::create(m_frame->document(), replacement)); 2295 } else if (canEdit() && shouldInsertText(replacement, rangeToReplace.get(), EditorInsertActionTyped)) { 2296 correctSpellcheckingPreservingTextCheckingParagraph(paragraph, rangeToReplace, replacement, resultLocation, resultLength); 2297 2277 2298 if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache()) { 2278 2299 if (Element* root = m_frame->selection()->selection().rootEditableElement()) … … 2281 2302 2282 2303 selectionChanged = true; 2283 offsetDueToReplacement += replacement Length- resultLength;2304 offsetDueToReplacement += replacement.length() - resultLength; 2284 2305 if (resultLocation < selectionOffset) { 2285 selectionOffset += replacement Length- resultLength;2306 selectionOffset += replacement.length() - resultLength; 2286 2307 if (ambiguousBoundaryOffset >= 0) 2287 2308 ambiguousBoundaryOffset = selectionOffset - 1; … … 2289 2310 2290 2311 // Add a marker so that corrections can easily be undone and won't be re-corrected. 2291 if (result ->type == TextCheckingTypeCorrection)2292 m_alternativeTextController->markCorrection(paragraph.subrange(resultLocation, replacement Length), replacedString);2312 if (resultType == TextCheckingTypeCorrection) 2313 m_alternativeTextController->markCorrection(paragraph.subrange(resultLocation, replacement.length()), replacedString); 2293 2314 } 2294 2315 }
Note: See TracChangeset
for help on using the changeset viewer.