Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp

Issue 2247003005: Eliminate class TextCheckingHelper (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@CleanupUnifiedTextChecker
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "core/editing/spellcheck/TextCheckingHelper.h"
28
29 #include "core/dom/Document.h"
30 #include "core/dom/Range.h"
31 #include "core/editing/VisiblePosition.h"
32 #include "core/editing/VisibleUnits.h"
33 #include "core/editing/iterators/CharacterIterator.h"
34 #include "core/editing/iterators/WordAwareIterator.h"
35 #include "core/editing/markers/DocumentMarkerController.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/Settings.h"
38 #include "core/page/SpellCheckerClient.h"
39 #include "platform/text/TextBreakIterator.h"
40 #include "platform/text/TextCheckerClient.h"
41
42 namespace blink {
43
44 static void findMisspellings(TextCheckerClient& client, const String& text, Vect or<TextCheckingResult>& results)
45 {
46 Vector<UChar> characters;
47 text.appendTo(characters);
48 unsigned length = text.length();
49
50 TextBreakIterator* iterator = wordBreakIterator(characters.data(), length);
51 if (!iterator)
52 return;
53
54 int wordStart = iterator->current();
55 while (0 <= wordStart) {
56 int wordEnd = iterator->next();
57 if (wordEnd < 0)
58 break;
59 int wordLength = wordEnd - wordStart;
60 int misspellingLocation = -1;
61 int misspellingLength = 0;
62 client.checkSpellingOfString(String(characters.data() + wordStart, wordL ength), &misspellingLocation, &misspellingLength);
63 if (0 < misspellingLength) {
64 DCHECK_LE(0, misspellingLocation);
65 DCHECK_LE(misspellingLocation, wordLength);
66 DCHECK_LT(0, misspellingLength);
67 DCHECK_LE(misspellingLocation + misspellingLength, wordLength);
68 TextCheckingResult misspelling;
69 misspelling.decoration = TextDecorationTypeSpelling;
70 misspelling.location = wordStart + misspellingLocation;
71 misspelling.length = misspellingLength;
72 results.append(misspelling);
73 }
74
75 wordStart = wordEnd;
76 }
77 }
78
79 static EphemeralRange expandToParagraphBoundary(const EphemeralRange& range)
80 {
81 const VisiblePosition& start = createVisiblePosition(range.startPosition());
82 DCHECK(start.isNotNull()) << range.startPosition();
83 const VisiblePosition& paragraphStart = startOfParagraph(start);
84 DCHECK(paragraphStart.isNotNull()) << range.startPosition();
85
86 const VisiblePosition& end = createVisiblePosition(range.endPosition());
87 DCHECK(end.isNotNull()) << range.endPosition();
88 const VisiblePosition& paragraphEnd = endOfParagraph(end);
89 DCHECK(paragraphEnd.isNotNull()) << range.endPosition();
90
91 return EphemeralRange(paragraphStart.deepEquivalent(), paragraphEnd.deepEqui valent());
92 }
93
94 TextCheckingParagraph::TextCheckingParagraph(const EphemeralRange& checkingRange )
95 : m_checkingRange(checkingRange)
96 , m_checkingStart(-1)
97 , m_checkingEnd(-1)
98 , m_checkingLength(-1)
99 {
100 }
101
102 TextCheckingParagraph::TextCheckingParagraph(const EphemeralRange& checkingRange , const EphemeralRange& paragraphRange)
103 : m_checkingRange(checkingRange)
104 , m_paragraphRange(paragraphRange)
105 , m_checkingStart(-1)
106 , m_checkingEnd(-1)
107 , m_checkingLength(-1)
108 {
109 }
110
111 TextCheckingParagraph::TextCheckingParagraph(Range* checkingRange, Range* paragr aphRange)
112 : m_checkingRange(checkingRange)
113 , m_paragraphRange(paragraphRange)
114 , m_checkingStart(-1)
115 , m_checkingEnd(-1)
116 , m_checkingLength(-1)
117 {
118 }
119
120 TextCheckingParagraph::~TextCheckingParagraph()
121 {
122 }
123
124 void TextCheckingParagraph::expandRangeToNextEnd()
125 {
126 DCHECK(m_checkingRange.isNotNull());
127 setParagraphRange(EphemeralRange(paragraphRange().startPosition(), endOfPara graph(startOfNextParagraph(createVisiblePosition(paragraphRange().startPosition( )))).deepEquivalent()));
128 invalidateParagraphRangeValues();
129 }
130
131 void TextCheckingParagraph::invalidateParagraphRangeValues()
132 {
133 m_checkingStart = m_checkingEnd = -1;
134 m_offsetAsRange = EphemeralRange();
135 m_text = String();
136 }
137
138 int TextCheckingParagraph::rangeLength() const
139 {
140 DCHECK(m_checkingRange.isNotNull());
141 return TextIterator::rangeLength(paragraphRange().startPosition(), paragraph Range().endPosition());
142 }
143
144 EphemeralRange TextCheckingParagraph::paragraphRange() const
145 {
146 DCHECK(m_checkingRange.isNotNull());
147 if (m_paragraphRange.isNull())
148 m_paragraphRange = expandToParagraphBoundary(checkingRange());
149 return m_paragraphRange;
150 }
151
152 void TextCheckingParagraph::setParagraphRange(const EphemeralRange& range)
153 {
154 m_paragraphRange = range;
155 }
156
157 EphemeralRange TextCheckingParagraph::subrange(int characterOffset, int characte rCount) const
158 {
159 DCHECK(m_checkingRange.isNotNull());
160 return calculateCharacterSubrange(paragraphRange(), characterOffset, charact erCount);
161 }
162
163 int TextCheckingParagraph::offsetTo(const Position& position) const
164 {
165 DCHECK(m_checkingRange.isNotNull());
166 return TextIterator::rangeLength(offsetAsRange().startPosition(), position);
167 }
168
169 bool TextCheckingParagraph::isEmpty() const
170 {
171 // Both predicates should have same result, but we check both just to be sur e.
172 // We need to investigate to remove this redundancy.
173 return isRangeEmpty() || isTextEmpty();
174 }
175
176 EphemeralRange TextCheckingParagraph::offsetAsRange() const
177 {
178 DCHECK(m_checkingRange.isNotNull());
179 if (m_offsetAsRange.isNotNull())
180 return m_offsetAsRange;
181 const Position& paragraphStart = paragraphRange().startPosition();
182 const Position& checkingStart = checkingRange().startPosition();
183 if (paragraphStart <= checkingStart) {
184 m_offsetAsRange = EphemeralRange(paragraphStart, checkingStart);
185 return m_offsetAsRange;
186 }
187 // editing/pasteboard/paste-table-001.html and more reach here.
188 m_offsetAsRange = EphemeralRange(checkingStart, paragraphStart);
189 return m_offsetAsRange;
190 }
191
192 const String& TextCheckingParagraph::text() const
193 {
194 DCHECK(m_checkingRange.isNotNull());
195 if (m_text.isEmpty())
196 m_text = plainText(paragraphRange());
197 return m_text;
198 }
199
200 int TextCheckingParagraph::checkingStart() const
201 {
202 DCHECK(m_checkingRange.isNotNull());
203 if (m_checkingStart == -1)
204 m_checkingStart = TextIterator::rangeLength(offsetAsRange().startPositio n(), offsetAsRange().endPosition());
205 return m_checkingStart;
206 }
207
208 int TextCheckingParagraph::checkingEnd() const
209 {
210 DCHECK(m_checkingRange.isNotNull());
211 if (m_checkingEnd == -1)
212 m_checkingEnd = checkingStart() + TextIterator::rangeLength(checkingRang e().startPosition(), checkingRange().endPosition());
213 return m_checkingEnd;
214 }
215
216 int TextCheckingParagraph::checkingLength() const
217 {
218 DCHECK(m_checkingRange.isNotNull());
219 if (-1 == m_checkingLength)
220 m_checkingLength = TextIterator::rangeLength(checkingRange().startPositi on(), checkingRange().endPosition());
221 return m_checkingLength;
222 }
223
224 TextCheckingHelper::TextCheckingHelper(SpellCheckerClient& client, const Positio n& start, const Position& end)
225 : m_client(&client)
226 , m_start(start)
227 , m_end(end)
228 {
229 }
230
231 TextCheckingHelper::~TextCheckingHelper()
232 {
233 }
234
235 String TextCheckingHelper::findFirstMisspellingOrBadGrammar(int& outFirstFoundOf fset)
236 {
237 String firstFoundItem;
238 String misspelledWord;
239
240 // Initialize out parameter; it will be updated if we find something to retu rn.
241 outFirstFoundOffset = 0;
242
243 // Expand the search range to encompass entire paragraphs, since text checki ng needs that much context.
244 // Determine the character offset from the start of the paragraph to the sta rt of the original search range,
245 // since we will want to ignore results in this area.
246 Position paragraphStart = startOfParagraph(createVisiblePosition(m_start)).t oParentAnchoredPosition();
247 Position paragraphEnd = m_end;
248 int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEn d);
249 paragraphEnd = endOfParagraph(createVisiblePosition(m_start)).toParentAnchor edPosition();
250
251 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, m_start);
252 int totalLengthProcessed = 0;
253
254 bool firstIteration = true;
255 bool lastIteration = false;
256 while (totalLengthProcessed < totalRangeLength) {
257 // Iterate through the search range by paragraphs, checking each one for spelling.
258 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphE nd);
259 int currentStartOffset = firstIteration ? rangeStartOffset : 0;
260 int currentEndOffset = currentLength;
261 if (inSameParagraph(createVisiblePosition(paragraphStart), createVisible Position(m_end))) {
262 // Determine the character offset from the end of the original searc h range to the end of the paragraph,
263 // since we will want to ignore results in this area.
264 currentEndOffset = TextIterator::rangeLength(paragraphStart, m_end);
265 lastIteration = true;
266 }
267 if (currentStartOffset < currentEndOffset) {
268 String paragraphString = plainText(EphemeralRange(paragraphStart, pa ragraphEnd));
269 if (paragraphString.length() > 0) {
270 int spellingLocation = 0;
271
272 Vector<TextCheckingResult> results;
273 findMisspellings(m_client->textChecker(), paragraphString, resul ts);
274
275 for (unsigned i = 0; i < results.size(); i++) {
276 const TextCheckingResult* result = &results[i];
277 if (result->decoration == TextDecorationTypeSpelling && resu lt->location >= currentStartOffset && result->location + result->length <= curre ntEndOffset) {
278 DCHECK_GT(result->length, 0);
279 DCHECK_GE(result->location, 0);
280 spellingLocation = result->location;
281 misspelledWord = paragraphString.substring(result->locat ion, result->length);
282 DCHECK(misspelledWord.length());
283 break;
284 }
285 }
286
287 if (!misspelledWord.isEmpty()) {
288 int spellingOffset = spellingLocation - currentStartOffset;
289 if (!firstIteration)
290 spellingOffset += TextIterator::rangeLength(m_start, par agraphStart);
291 outFirstFoundOffset = spellingOffset;
292 firstFoundItem = misspelledWord;
293 break;
294 }
295 }
296 }
297 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL ength)
298 break;
299 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd));
300 paragraphStart = newParagraphStart.toParentAnchoredPosition();
301 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n();
302 firstIteration = false;
303 totalLengthProcessed += currentLength;
304 }
305 return firstFoundItem;
306 }
307
308 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698