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