Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / editing / SpellCheckRequester.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "core/editing/SpellCheckRequester.h"
28
29 #include "core/dom/Document.h"
30 #include "core/dom/DocumentMarkerController.h"
31 #include "core/dom/Node.h"
32 #include "core/editing/SpellChecker.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/frame/Settings.h"
35 #include "platform/text/TextCheckerClient.h"
36
37 namespace blink {
38
39 SpellCheckRequest::SpellCheckRequest(
40     PassRefPtrWillBeRawPtr<Range> checkingRange,
41     PassRefPtrWillBeRawPtr<Range> paragraphRange,
42     const String& text,
43     TextCheckingTypeMask mask,
44     TextCheckingProcessType processType,
45     const Vector<uint32_t>& documentMarkersInRange,
46     const Vector<unsigned>& documentMarkerOffsets,
47     int requestNumber)
48     : m_requester(nullptr)
49     , m_checkingRange(checkingRange)
50     , m_paragraphRange(paragraphRange)
51     , m_rootEditableElement(m_checkingRange->startContainer()->rootEditableElement())
52     , m_requestData(unrequestedTextCheckingSequence, text, mask, processType, documentMarkersInRange, documentMarkerOffsets)
53     , m_requestNumber(requestNumber)
54 {
55 }
56
57 SpellCheckRequest::~SpellCheckRequest()
58 {
59 }
60
61 void SpellCheckRequest::trace(Visitor* visitor)
62 {
63     visitor->trace(m_requester);
64     visitor->trace(m_checkingRange);
65     visitor->trace(m_paragraphRange);
66     visitor->trace(m_rootEditableElement);
67     TextCheckingRequest::trace(visitor);
68 }
69
70 // static
71 PassRefPtrWillBeRawPtr<SpellCheckRequest> SpellCheckRequest::create(TextCheckingTypeMask textCheckingOptions, TextCheckingProcessType processType, PassRefPtrWillBeRawPtr<Range> checkingRange, PassRefPtrWillBeRawPtr<Range> paragraphRange, int requestNumber)
72 {
73     ASSERT(checkingRange);
74     ASSERT(paragraphRange);
75
76     String text = checkingRange->text();
77     if (!text.length())
78         return nullptr;
79
80     const DocumentMarkerVector& markers = checkingRange->ownerDocument().markers().markersInRange(checkingRange.get(), DocumentMarker::SpellCheckClientMarkers());
81     Vector<uint32_t> hashes(markers.size());
82     Vector<unsigned> offsets(markers.size());
83     for (size_t i = 0; i < markers.size(); i++) {
84         hashes[i] = markers[i]->hash();
85         offsets[i] = markers[i]->startOffset();
86     }
87
88     return adoptRefWillBeNoop(new SpellCheckRequest(checkingRange, paragraphRange, text, textCheckingOptions, processType, hashes, offsets, requestNumber));
89 }
90
91 const TextCheckingRequestData& SpellCheckRequest::data() const
92 {
93     return m_requestData;
94 }
95
96 void SpellCheckRequest::didSucceed(const Vector<TextCheckingResult>& results)
97 {
98     if (!m_requester)
99         return;
100     SpellCheckRequester* requester = m_requester;
101     m_requester = nullptr;
102     requester->didCheckSucceed(m_requestData.sequence(), results);
103 }
104
105 void SpellCheckRequest::didCancel()
106 {
107     if (!m_requester)
108         return;
109     SpellCheckRequester* requester = m_requester;
110     m_requester = nullptr;
111     requester->didCheckCancel(m_requestData.sequence());
112 }
113
114 void SpellCheckRequest::setCheckerAndSequence(SpellCheckRequester* requester, int sequence)
115 {
116     ASSERT(!m_requester);
117     ASSERT(m_requestData.sequence() == unrequestedTextCheckingSequence);
118     m_requester = requester;
119     m_requestData.m_sequence = sequence;
120 }
121
122 #if !ENABLE(OILPAN)
123 void SpellCheckRequest::requesterDestroyed()
124 {
125     m_requester = nullptr;
126 }
127 #endif
128
129 SpellCheckRequester::SpellCheckRequester(LocalFrame& frame)
130     : m_frame(&frame)
131     , m_lastRequestSequence(0)
132     , m_lastProcessedSequence(0)
133     , m_timerToProcessQueuedRequest(this, &SpellCheckRequester::timerFiredToProcessQueuedRequest)
134 {
135 }
136
137 SpellCheckRequester::~SpellCheckRequester()
138 {
139 #if !ENABLE(OILPAN)
140     if (m_processingRequest)
141         m_processingRequest->requesterDestroyed();
142     for (const auto& requestQueue : m_requestQueue)
143         requestQueue->requesterDestroyed();
144 #endif
145 }
146
147 TextCheckerClient& SpellCheckRequester::client() const
148 {
149     return frame().spellChecker().textChecker();
150 }
151
152 void SpellCheckRequester::timerFiredToProcessQueuedRequest(Timer<SpellCheckRequester>*)
153 {
154     ASSERT(!m_requestQueue.isEmpty());
155     if (m_requestQueue.isEmpty())
156         return;
157
158     invokeRequest(m_requestQueue.takeFirst());
159 }
160
161 bool SpellCheckRequester::isAsynchronousEnabled() const
162 {
163     return frame().settings() && frame().settings()->asynchronousSpellCheckingEnabled();
164 }
165
166 bool SpellCheckRequester::canCheckAsynchronously(Range* range) const
167 {
168     return isCheckable(range) && isAsynchronousEnabled();
169 }
170
171 bool SpellCheckRequester::isCheckable(Range* range) const
172 {
173     if (!range || !range->firstNode() || !range->firstNode()->renderer())
174         return false;
175     const Node* node = range->startContainer();
176     if (node && node->isElementNode() && !toElement(node)->isSpellCheckingEnabled())
177         return false;
178     return true;
179 }
180
181 void SpellCheckRequester::requestCheckingFor(PassRefPtrWillBeRawPtr<SpellCheckRequest> request)
182 {
183     if (!request || !canCheckAsynchronously(request->paragraphRange().get()))
184         return;
185
186     ASSERT(request->data().sequence() == unrequestedTextCheckingSequence);
187     int sequence = ++m_lastRequestSequence;
188     if (sequence == unrequestedTextCheckingSequence)
189         sequence = ++m_lastRequestSequence;
190
191     request->setCheckerAndSequence(this, sequence);
192
193     if (m_timerToProcessQueuedRequest.isActive() || m_processingRequest) {
194         enqueueRequest(request);
195         return;
196     }
197
198     invokeRequest(request);
199 }
200
201 void SpellCheckRequester::cancelCheck()
202 {
203     if (m_processingRequest)
204         m_processingRequest->didCancel();
205 }
206
207 void SpellCheckRequester::invokeRequest(PassRefPtrWillBeRawPtr<SpellCheckRequest> request)
208 {
209     ASSERT(!m_processingRequest);
210     m_processingRequest = request;
211     client().requestCheckingOfString(m_processingRequest);
212 }
213
214 void SpellCheckRequester::enqueueRequest(PassRefPtrWillBeRawPtr<SpellCheckRequest> request)
215 {
216     ASSERT(request);
217     bool continuation = false;
218     if (!m_requestQueue.isEmpty()) {
219         RefPtrWillBeRawPtr<SpellCheckRequest> lastRequest = m_requestQueue.last();
220         // It's a continuation if the number of the last request got incremented in the new one and
221         // both apply to the same editable.
222         continuation = request->rootEditableElement() == lastRequest->rootEditableElement()
223             && request->requestNumber() == lastRequest->requestNumber() + 1;
224     }
225
226     // Spellcheck requests for chunks of text in the same element should not overwrite each other.
227     if (!continuation) {
228         for (auto& requestQueue : m_requestQueue) {
229             if (request->rootEditableElement() != requestQueue->rootEditableElement())
230                 continue;
231
232             requestQueue = request;
233             return;
234         }
235     }
236
237     m_requestQueue.append(request);
238 }
239
240 void SpellCheckRequester::didCheck(int sequence, const Vector<TextCheckingResult>& results)
241 {
242     ASSERT(m_processingRequest);
243     ASSERT(m_processingRequest->data().sequence() == sequence);
244     if (m_processingRequest->data().sequence() != sequence) {
245         m_requestQueue.clear();
246         return;
247     }
248
249     frame().spellChecker().markAndReplaceFor(m_processingRequest, results);
250
251     if (m_lastProcessedSequence < sequence)
252         m_lastProcessedSequence = sequence;
253
254     m_processingRequest.clear();
255     if (!m_requestQueue.isEmpty())
256         m_timerToProcessQueuedRequest.startOneShot(0, FROM_HERE);
257 }
258
259 void SpellCheckRequester::didCheckSucceed(int sequence, const Vector<TextCheckingResult>& results)
260 {
261     TextCheckingRequestData requestData = m_processingRequest->data();
262     if (requestData.sequence() == sequence) {
263         DocumentMarker::MarkerTypes markers = DocumentMarker::SpellCheckClientMarkers();
264         if (!requestData.maskContains(TextCheckingTypeSpelling))
265             markers.remove(DocumentMarker::Spelling);
266         if (!requestData.maskContains(TextCheckingTypeGrammar))
267             markers.remove(DocumentMarker::Grammar);
268         frame().document()->markers().removeMarkers(m_processingRequest->checkingRange().get(), markers);
269     }
270     didCheck(sequence, results);
271 }
272
273 void SpellCheckRequester::didCheckCancel(int sequence)
274 {
275     Vector<TextCheckingResult> results;
276     didCheck(sequence, results);
277 }
278
279 void SpellCheckRequester::trace(Visitor* visitor)
280 {
281     visitor->trace(m_frame);
282     visitor->trace(m_processingRequest);
283     visitor->trace(m_requestQueue);
284 }
285
286 } // namespace blink