|
Lines 45-53
a/Source/WebCore/editing/SpellChecker.cpp_sec1
|
| 45 |
|
45 |
|
| 46 |
namespace WebCore { |
46 |
namespace WebCore { |
| 47 |
|
47 |
|
|
|
48 |
class SpellChecker::SpellCheckRequest : public RefCounted<SpellChecker::SpellCheckRequest> { |
| 49 |
public: |
| 50 |
SpellCheckRequest(int sequence, PassRefPtr<Range> range, const String& text, TextCheckingTypeMask mask) |
| 51 |
: m_sequence(sequence) |
| 52 |
, m_range(range) |
| 53 |
, m_text(text) |
| 54 |
, m_mask(mask) |
| 55 |
{ |
| 56 |
} |
| 57 |
|
| 58 |
int sequence() const { return m_sequence; } |
| 59 |
Range* range() const { return m_range.get(); } |
| 60 |
const String& text() const { return m_text; } |
| 61 |
TextCheckingTypeMask mask() const { return m_mask; } |
| 62 |
Element* rootEditableElement() const { return range()->startContainer()->rootEditableElement(); } |
| 63 |
|
| 64 |
private: |
| 65 |
int m_sequence; |
| 66 |
RefPtr<Range> m_range; |
| 67 |
String m_text; |
| 68 |
TextCheckingTypeMask m_mask; |
| 69 |
}; |
| 70 |
|
| 48 |
SpellChecker::SpellChecker(Frame* frame) |
71 |
SpellChecker::SpellChecker(Frame* frame) |
| 49 |
: m_frame(frame) |
72 |
: m_frame(frame) |
| 50 |
, m_requestSequence(0) |
73 |
, m_lastRequestedSequence(0) |
|
|
74 |
, m_timerToProcessQueuedRequest(this, &SpellChecker::timerFiredToProcessQueuedRequest) |
| 51 |
{ |
75 |
{ |
| 52 |
} |
76 |
} |
| 53 |
|
77 |
|
|
Lines 63-87
TextCheckerClient* SpellChecker::client() const
a/Source/WebCore/editing/SpellChecker.cpp_sec2
|
| 63 |
return page->editorClient()->textChecker(); |
87 |
return page->editorClient()->textChecker(); |
| 64 |
} |
88 |
} |
| 65 |
|
89 |
|
| 66 |
bool SpellChecker::initRequest(PassRefPtr<Range> range) |
90 |
PassRefPtr<SpellChecker::SpellCheckRequest> SpellChecker::createRequest(TextCheckingTypeMask mask, PassRefPtr<Range> range) |
| 67 |
{ |
91 |
{ |
| 68 |
ASSERT(canCheckAsynchronously(range.get())); |
92 |
ASSERT(canCheckAsynchronously(range.get())); |
| 69 |
|
93 |
|
| 70 |
String text = range->text(); |
94 |
String text = range->text(); |
| 71 |
if (!text.length()) |
95 |
if (!text.length()) |
| 72 |
return false; |
96 |
return PassRefPtr<SpellCheckRequest>(); |
| 73 |
|
97 |
|
| 74 |
m_requestRange = range; |
98 |
return adoptRef(new SpellCheckRequest(++m_lastRequestedSequence, range, text, mask)); |
| 75 |
m_requestText = text; |
|
|
| 76 |
m_requestSequence++; |
| 77 |
|
| 78 |
return true; |
| 79 |
} |
99 |
} |
| 80 |
|
100 |
|
| 81 |
void SpellChecker::clearRequest() |
101 |
void SpellChecker::timerFiredToProcessQueuedRequest(Timer<SpellChecker>*) |
| 82 |
{ |
102 |
{ |
| 83 |
m_requestRange.clear(); |
103 |
ASSERT(!m_requestQueue.isEmpty()); |
| 84 |
m_requestText = String(); |
104 |
if (m_requestQueue.isEmpty()) |
|
|
105 |
return; |
| 106 |
|
| 107 |
invokeRequest(m_requestQueue.takeFirst()); |
| 85 |
} |
108 |
} |
| 86 |
|
109 |
|
| 87 |
bool SpellChecker::isAsynchronousEnabled() const |
110 |
bool SpellChecker::isAsynchronousEnabled() const |
|
Lines 91-107
bool SpellChecker::isAsynchronousEnabled() const
a/Source/WebCore/editing/SpellChecker.cpp_sec3
|
| 91 |
|
114 |
|
| 92 |
bool SpellChecker::canCheckAsynchronously(Range* range) const |
115 |
bool SpellChecker::canCheckAsynchronously(Range* range) const |
| 93 |
{ |
116 |
{ |
| 94 |
return client() && isCheckable(range) && isAsynchronousEnabled() && !isBusy(); |
117 |
return client() && isCheckable(range) && isAsynchronousEnabled(); |
| 95 |
} |
|
|
| 96 |
|
| 97 |
bool SpellChecker::isBusy() const |
| 98 |
{ |
| 99 |
return m_requestRange.get(); |
| 100 |
} |
| 101 |
|
| 102 |
bool SpellChecker::isValid(int sequence) const |
| 103 |
{ |
| 104 |
return m_requestRange.get() && m_requestText.length() && m_requestSequence == sequence; |
| 105 |
} |
118 |
} |
| 106 |
|
119 |
|
| 107 |
bool SpellChecker::isCheckable(Range* range) const |
120 |
bool SpellChecker::isCheckable(Range* range) const |
|
Lines 121-129
void SpellChecker::doRequestCheckingFor(TextCheckingTypeMask mask, PassRefPtr<Ra
a/Source/WebCore/editing/SpellChecker.cpp_sec4
|
| 121 |
{ |
134 |
{ |
| 122 |
ASSERT(canCheckAsynchronously(range.get())); |
135 |
ASSERT(canCheckAsynchronously(range.get())); |
| 123 |
|
136 |
|
| 124 |
if (!initRequest(range)) |
137 |
RefPtr<SpellCheckRequest> request(createRequest(mask, range)); |
|
|
138 |
if (!request) |
| 139 |
return; |
| 140 |
|
| 141 |
if (m_timerToProcessQueuedRequest.isActive() || m_processingRequest) { |
| 142 |
enqueueRequest(request.release()); |
| 125 |
return; |
143 |
return; |
| 126 |
client()->requestCheckingOfString(this, m_requestSequence, mask, m_requestText); |
144 |
} |
|
|
145 |
|
| 146 |
invokeRequest(request.release()); |
| 147 |
} |
| 148 |
|
| 149 |
void SpellChecker::invokeRequest(PassRefPtr<SpellCheckRequest> request) |
| 150 |
{ |
| 151 |
ASSERT(!m_processingRequest); |
| 152 |
|
| 153 |
client()->requestCheckingOfString(this, request->sequence(), request->mask(), request->text()); |
| 154 |
m_processingRequest = request; |
| 155 |
} |
| 156 |
|
| 157 |
void SpellChecker::enqueueRequest(PassRefPtr<SpellCheckRequest> request) |
| 158 |
{ |
| 159 |
ASSERT(request); |
| 160 |
|
| 161 |
for (RequestQueue::iterator it = m_requestQueue.begin(); it != m_requestQueue.end(); ++it) { |
| 162 |
if (request->rootEditableElement() != (*it)->rootEditableElement()) |
| 163 |
continue; |
| 164 |
|
| 165 |
fprintf(stderr, "REMOVED!\n"); |
| 166 |
*it = request; |
| 167 |
return; |
| 168 |
} |
| 169 |
|
| 170 |
m_requestQueue.append(request); |
| 127 |
} |
171 |
} |
| 128 |
|
172 |
|
| 129 |
static bool forwardIterator(PositionIterator& iterator, int distance) |
173 |
static bool forwardIterator(PositionIterator& iterator, int distance) |
|
Lines 159-174
static DocumentMarker::MarkerType toMarkerType(TextCheckingType type)
a/Source/WebCore/editing/SpellChecker.cpp_sec5
|
| 159 |
// Currenntly ignoring TextCheckingResult::details but should be handled. See Bug 56368. |
203 |
// Currenntly ignoring TextCheckingResult::details but should be handled. See Bug 56368. |
| 160 |
void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& results) |
204 |
void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& results) |
| 161 |
{ |
205 |
{ |
| 162 |
if (!isValid(sequence)) |
206 |
ASSERT(m_processingRequest); |
| 163 |
return; |
|
|
| 164 |
|
207 |
|
| 165 |
if (!isCheckable(m_requestRange.get())) { |
208 |
ASSERT(m_processingRequest->sequence() == sequence); |
| 166 |
clearRequest(); |
209 |
if (m_processingRequest->sequence() != sequence) { |
|
|
210 |
m_requestQueue.clear(); |
| 167 |
return; |
211 |
return; |
| 168 |
} |
212 |
} |
| 169 |
|
213 |
|
| 170 |
int startOffset = 0; |
214 |
int startOffset = 0; |
| 171 |
PositionIterator start = m_requestRange->startPosition(); |
215 |
PositionIterator start = m_processingRequest->range()->startPosition(); |
| 172 |
for (size_t i = 0; i < results.size(); ++i) { |
216 |
for (size_t i = 0; i < results.size(); ++i) { |
| 173 |
if (results[i].type != TextCheckingTypeSpelling && results[i].type != TextCheckingTypeGrammar) |
217 |
if (results[i].type != TextCheckingTypeSpelling && results[i].type != TextCheckingTypeGrammar) |
| 174 |
continue; |
218 |
continue; |
|
Lines 186-202
void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& resu
a/Source/WebCore/editing/SpellChecker.cpp_sec6
|
| 186 |
// spellings in the background. To avoid adding markers to the words modified by users or |
230 |
// spellings in the background. To avoid adding markers to the words modified by users or |
| 187 |
// JavaScript applications, retrieve the words in the specified region and compare them with |
231 |
// JavaScript applications, retrieve the words in the specified region and compare them with |
| 188 |
// the original ones. |
232 |
// the original ones. |
| 189 |
RefPtr<Range> range = Range::create(m_requestRange->ownerDocument(), start, end); |
233 |
RefPtr<Range> range = Range::create(m_processingRequest->range()->ownerDocument(), start, end); |
| 190 |
// FIXME: Use textContent() compatible string conversion. |
234 |
// FIXME: Use textContent() compatible string conversion. |
| 191 |
String destination = range->text(); |
235 |
String destination = range->text(); |
| 192 |
String source = m_requestText.substring(results[i].location, results[i].length); |
236 |
String source = m_processingRequest->text().substring(results[i].location, results[i].length); |
| 193 |
if (destination == source) |
237 |
if (destination == source) |
| 194 |
m_requestRange->ownerDocument()->markers()->addMarker(range.get(), toMarkerType(results[i].type)); |
238 |
m_processingRequest->range()->ownerDocument()->markers()->addMarker(range.get(), toMarkerType(results[i].type)); |
| 195 |
|
239 |
|
| 196 |
startOffset = results[i].location; |
240 |
startOffset = results[i].location; |
| 197 |
} |
241 |
} |
| 198 |
|
242 |
|
| 199 |
clearRequest(); |
243 |
m_processingRequest.clear(); |
|
|
244 |
if (!m_requestQueue.isEmpty()) |
| 245 |
m_timerToProcessQueuedRequest.startOneShot(0); |
| 200 |
} |
246 |
} |
| 201 |
|
247 |
|
| 202 |
|
248 |
|