ae83212139767066e01b29cf059d894f66e26ec7
[WebKit-https.git] / Source / WebCore / editing / SpellChecker.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 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 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 "SpellChecker.h"
28
29 #include "Document.h"
30 #include "DocumentMarkerController.h"
31 #include "Editor.h"
32 #include "Frame.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLTextAreaElement.h"
35 #include "Node.h"
36 #include "Page.h"
37 #include "PositionIterator.h"
38 #include "RenderObject.h"
39 #include "Settings.h"
40 #include "TextCheckerClient.h"
41 #include "TextCheckingHelper.h"
42 #include "htmlediting.h"
43
44 namespace WebCore {
45
46 SpellCheckRequest::SpellCheckRequest(PassRefPtr<Range> checkingRange, PassRefPtr<Range> paragraphRange, const String& text, TextCheckingTypeMask mask, TextCheckingProcessType processType)
47     : m_checker(0)
48     , m_checkingRange(checkingRange)
49     , m_paragraphRange(paragraphRange)
50     , m_rootEditableElement(m_checkingRange->startContainer()->rootEditableElement())
51     , m_requestData(unrequestedTextCheckingSequence, text, mask, processType)
52 {
53 }
54
55 SpellCheckRequest::~SpellCheckRequest()
56 {
57 }
58
59 // static
60 PassRefPtr<SpellCheckRequest> SpellCheckRequest::create(TextCheckingTypeMask textCheckingOptions, TextCheckingProcessType processType, PassRefPtr<Range> checkingRange, PassRefPtr<Range> paragraphRange)
61 {
62     ASSERT(checkingRange);
63     ASSERT(paragraphRange);
64
65     String text = checkingRange->text();
66     if (!text.length())
67         return PassRefPtr<SpellCheckRequest>();
68
69     return adoptRef(new SpellCheckRequest(checkingRange, paragraphRange, text, textCheckingOptions, processType));
70 }
71
72 const TextCheckingRequestData& SpellCheckRequest::data() const
73 {
74     return m_requestData;
75 }
76
77 void SpellCheckRequest::didSucceed(const Vector<TextCheckingResult>& results)
78 {
79     if (!m_checker)
80         return;
81     m_checker->didCheckSucceed(m_requestData.sequence(), results);
82     m_checker = 0;
83 }
84
85 void SpellCheckRequest::didCancel()
86 {
87     if (!m_checker)
88         return;
89     m_checker->didCheckCancel(m_requestData.sequence());
90     m_checker = 0;
91 }
92
93 void SpellCheckRequest::setCheckerAndSequence(SpellChecker* requester, int sequence)
94 {
95     ASSERT(!m_checker);
96     ASSERT(m_requestData.sequence() == unrequestedTextCheckingSequence);
97     m_checker = requester;
98     m_requestData.m_sequence = sequence;
99 }
100
101 void SpellCheckRequest::requesterDestroyed()
102 {
103     m_checker = 0;
104 }
105
106 SpellChecker::SpellChecker(Frame& frame)
107     : m_frame(frame)
108     , m_lastRequestSequence(0)
109     , m_lastProcessedSequence(0)
110     , m_timerToProcessQueuedRequest(this, &SpellChecker::timerFiredToProcessQueuedRequest)
111 {
112 }
113
114 SpellChecker::~SpellChecker()
115 {
116     if (m_processingRequest)
117         m_processingRequest->requesterDestroyed();
118     for (RequestQueue::iterator i = m_requestQueue.begin(); i != m_requestQueue.end(); ++i)
119         (*i)->requesterDestroyed();
120 }
121
122 TextCheckerClient* SpellChecker::client() const
123 {
124     Page* page = m_frame.page();
125     if (!page)
126         return 0;
127     return page->editorClient()->textChecker();
128 }
129
130 void SpellChecker::timerFiredToProcessQueuedRequest(Timer*)
131 {
132     ASSERT(!m_requestQueue.isEmpty());
133     if (m_requestQueue.isEmpty())
134         return;
135
136     invokeRequest(m_requestQueue.takeFirst());
137 }
138
139 bool SpellChecker::isAsynchronousEnabled() const
140 {
141     return m_frame.settings().asynchronousSpellCheckingEnabled();
142 }
143
144 bool SpellChecker::canCheckAsynchronously(Range* range) const
145 {
146     return client() && isCheckable(range) && isAsynchronousEnabled();
147 }
148
149 bool SpellChecker::isCheckable(Range* range) const
150 {
151     if (!range || !range->firstNode() || !range->firstNode()->renderer())
152         return false;
153     const Node* node = range->startContainer();
154     if (is<Element>(node) && !downcast<Element>(*node).isSpellCheckingEnabled())
155         return false;
156     return true;
157 }
158
159 void SpellChecker::requestCheckingFor(PassRefPtr<SpellCheckRequest> request)
160 {
161     if (!request || !canCheckAsynchronously(request->paragraphRange().get()))
162         return;
163
164     ASSERT(request->data().sequence() == unrequestedTextCheckingSequence);
165     int sequence = ++m_lastRequestSequence;
166     if (sequence == unrequestedTextCheckingSequence)
167         sequence = ++m_lastRequestSequence;
168
169     request->setCheckerAndSequence(this, sequence);
170
171     if (m_timerToProcessQueuedRequest.isActive() || m_processingRequest) {
172         enqueueRequest(request);
173         return;
174     }
175
176     invokeRequest(request);
177 }
178
179 void SpellChecker::invokeRequest(PassRefPtr<SpellCheckRequest> request)
180 {
181     ASSERT(!m_processingRequest);
182     if (!client())
183         return;
184     m_processingRequest = request;
185     client()->requestCheckingOfString(m_processingRequest);
186 }
187
188 void SpellChecker::enqueueRequest(PassRefPtr<SpellCheckRequest> request)
189 {
190     ASSERT(request);
191
192     for (RequestQueue::iterator it = m_requestQueue.begin(); it != m_requestQueue.end(); ++it) {
193         if (request->rootEditableElement() != (*it)->rootEditableElement())
194             continue;
195
196         *it = request;
197         return;
198     }
199
200     m_requestQueue.append(request);
201 }
202
203 void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& results)
204 {
205     ASSERT(m_processingRequest);
206     ASSERT(m_processingRequest->data().sequence() == sequence);
207     if (m_processingRequest->data().sequence() != sequence) {
208         m_requestQueue.clear();
209         return;
210     }
211
212     m_frame.editor().markAndReplaceFor(m_processingRequest, results);
213
214     if (m_lastProcessedSequence < sequence)
215         m_lastProcessedSequence = sequence;
216
217     m_processingRequest.clear();
218     if (!m_requestQueue.isEmpty())
219         m_timerToProcessQueuedRequest.startOneShot(0);
220 }
221
222 void SpellChecker::didCheckSucceed(int sequence, const Vector<TextCheckingResult>& results)
223 {
224     TextCheckingRequestData requestData = m_processingRequest->data();
225     if (requestData.sequence() == sequence) {
226         unsigned markers = 0;
227         if (requestData.mask() & TextCheckingTypeSpelling)
228             markers |= DocumentMarker::Spelling;
229         if (requestData.mask() & TextCheckingTypeGrammar)
230             markers |= DocumentMarker::Grammar;
231         if (markers)
232             m_frame.document()->markers().removeMarkers(m_processingRequest->checkingRange().get(), markers);
233     }
234     didCheck(sequence, results);
235 }
236
237 void SpellChecker::didCheckCancel(int sequence)
238 {
239     Vector<TextCheckingResult> results;
240     didCheck(sequence, results);
241 }
242
243 } // namespace WebCore