151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)/*
251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * Copyright (C) 2006, 2007 Apple, Inc.  All rights reserved.
351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * Copyright (C) 2012 Google, Inc.  All rights reserved.
451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) *
551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * modification, are permitted provided that the following conditions
751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * are met:
851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
1051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
1151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
1251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) *    documentation and/or other materials provided with the distribution.
1351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) *
1451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
1551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
1851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) */
2651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
2751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "config.h"
28f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "web/SpellCheckerClientImpl.h"
2951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
3051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "core/dom/DocumentMarkerController.h"
3151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "core/editing/Editor.h"
3251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "core/editing/SpellChecker.h"
33d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include "core/frame/LocalFrame.h"
3409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "core/frame/Settings.h"
35f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "core/page/Page.h"
36f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "public/web/WebSpellCheckClient.h"
37f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "public/web/WebTextCheckingResult.h"
38f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "web/WebTextCheckingCompletionImpl.h"
39f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "web/WebViewImpl.h"
4051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
4151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)namespace blink {
4251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
4351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)SpellCheckerClientImpl::SpellCheckerClientImpl(WebViewImpl* webview)
4451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    : m_webView(webview)
4551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    , m_spellCheckThisFieldStatus(SpellCheckAutomatic)
4651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
4751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
4851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
4951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)SpellCheckerClientImpl::~SpellCheckerClientImpl()
5051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
5151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
5251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
5351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool SpellCheckerClientImpl::shouldSpellcheckByDefault()
5451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
5551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // Spellcheck should be enabled for all editable areas (such as textareas,
5651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // contentEditable regions, designMode docs and inputs).
57e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    if (!m_webView->focusedCoreFrame()->isLocalFrame())
5807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch        return false;
59e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    const LocalFrame* frame = toLocalFrame(m_webView->focusedCoreFrame());
6051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!frame)
6151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return false;
6251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (frame->spellChecker().isSpellCheckingEnabledInFocusedNode())
6351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return true;
6451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    const Document* document = frame->document();
6551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!document)
6651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return false;
6751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    const Element* element = document->focusedElement();
6851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // If |element| is null, we default to allowing spellchecking. This is done
6951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // in order to mitigate the issue when the user clicks outside the textbox,
7051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // as a result of which |element| becomes null, resulting in all the spell
71d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // check markers being deleted. Also, the LocalFrame will decide not to do
7251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // spellchecking if the user can't edit - so returning true here will not
73d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // cause any problems to the LocalFrame's behavior.
7451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!element)
7551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return true;
7651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    const RenderObject* renderer = element->renderer();
7751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!renderer)
7851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return false;
7951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
8051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return true;
8151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
8251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
8351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool SpellCheckerClientImpl::isContinuousSpellCheckingEnabled()
8451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
8551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_spellCheckThisFieldStatus == SpellCheckForcedOff)
8651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return false;
8751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_spellCheckThisFieldStatus == SpellCheckForcedOn)
8851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return true;
8951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return shouldSpellcheckByDefault();
9051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
9151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
9251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void SpellCheckerClientImpl::toggleContinuousSpellChecking()
9351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
9451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (isContinuousSpellCheckingEnabled()) {
9551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_spellCheckThisFieldStatus = SpellCheckForcedOff;
9651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (Page* page = m_webView->page()) {
975d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)            for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
985d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)                if (!frame->isLocalFrame())
995d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)                    continue;
1005d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)                toLocalFrame(frame)->document()->markers().removeMarkers(DocumentMarker::MisspellingMarkers());
10151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            }
10251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        }
10351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    } else {
10451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_spellCheckThisFieldStatus = SpellCheckForcedOn;
105e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        if (m_webView->focusedCoreFrame()->isLocalFrame()) {
106e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)            if (LocalFrame* frame = toLocalFrame(m_webView->focusedCoreFrame())) {
10707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                VisibleSelection frameSelection = frame->selection().selection();
10807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                // If a selection is in an editable element spell check its content.
10907a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                if (Element* rootEditableElement = frameSelection.rootEditableElement()) {
11007a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                    frame->spellChecker().didBeginEditing(rootEditableElement);
11107a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch                }
11251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            }
11351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        }
11451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    }
11551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
11651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
11751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool SpellCheckerClientImpl::isGrammarCheckingEnabled()
11851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
119e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    const LocalFrame* frame = toLocalFrame(m_webView->focusedCoreFrame());
12051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return frame && frame->settings() && (frame->settings()->asynchronousSpellCheckingEnabled() || frame->settings()->unifiedTextCheckerEnabled());
12151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
12251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
12351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool SpellCheckerClientImpl::shouldEraseMarkersAfterChangeSelection(TextCheckingType type) const
12451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
125e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    const Frame* frame = m_webView->focusedCoreFrame();
12651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return !frame || !frame->settings() || (!frame->settings()->asynchronousSpellCheckingEnabled() && !frame->settings()->unifiedTextCheckerEnabled());
12751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
12851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
12951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void SpellCheckerClientImpl::checkSpellingOfString(const String& text, int* misspellingLocation, int* misspellingLength)
13051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
13151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // SpellCheckWord will write (0, 0) into the output vars, which is what our
13251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // caller expects if the word is spelled correctly.
13351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    int spellLocation = -1;
13451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    int spellLength = 0;
13551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
13651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // Check to see if the provided text is spelled correctly.
13751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient()) {
13851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_webView->spellCheckClient()->spellCheck(text, spellLocation, spellLength, 0);
13951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    } else {
14051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        spellLocation = 0;
14151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        spellLength = 0;
14251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    }
14351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
14451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // Note: the Mac code checks if the pointers are null before writing to them,
14551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // so we do too.
14651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (misspellingLocation)
14751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *misspellingLocation = spellLocation;
14851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (misspellingLength)
14951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *misspellingLength = spellLength;
15051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
15151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
1527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid SpellCheckerClientImpl::requestCheckingOfString(PassRefPtrWillBeRawPtr<TextCheckingRequest> request)
15351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
15451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient()) {
15551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        const String& text = request->data().text();
15651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        const Vector<uint32_t>& markers = request->data().markers();
15751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        const Vector<unsigned>& markerOffsets = request->data().offsets();
15851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_webView->spellCheckClient()->requestCheckingOfText(text, markers, markerOffsets, new WebTextCheckingCompletionImpl(request));
15951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    }
16051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
16151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
16251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)String SpellCheckerClientImpl::getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWord)
16351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
16451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!(isContinuousSpellCheckingEnabled() && m_webView->client()))
16551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return String();
16651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
16751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // Do not autocorrect words with capital letters in it except the
16851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // first letter. This will remove cases changing "IMB" to "IBM".
16951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    for (size_t i = 1; i < misspelledWord.length(); i++) {
17051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (u_isupper(static_cast<UChar32>(misspelledWord[i])))
17151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            return String();
17251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    }
17351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
17451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient())
17551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return m_webView->spellCheckClient()->autoCorrectWord(WebString(misspelledWord));
17651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return String();
17751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
17851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
17951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void SpellCheckerClientImpl::checkGrammarOfString(const String& text, WTF::Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
18051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
18151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (badGrammarLocation)
18251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *badGrammarLocation = -1;
18351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (badGrammarLength)
18451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *badGrammarLength = 0;
18551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
18651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!m_webView->spellCheckClient())
18751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return;
18851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    WebVector<WebTextCheckingResult> webResults;
18951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    m_webView->spellCheckClient()->checkTextOfParagraph(text, WebTextCheckingTypeGrammar, &webResults);
19051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!webResults.size())
19151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return;
19251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
19351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // Convert a list of WebTextCheckingResults to a list of GrammarDetails. If
19451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // the converted vector of GrammarDetails has grammar errors, we set
19551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // badGrammarLocation and badGrammarLength to tell WebKit that the input
19651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    // text has grammar errors.
19751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    for (size_t i = 0; i < webResults.size(); ++i) {
19851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        if (webResults[i].decoration == WebTextDecorationTypeGrammar) {
19951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            GrammarDetail detail;
20051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            detail.location = webResults[i].location;
20151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            detail.length = webResults[i].length;
20251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            detail.userDescription = webResults[i].replacement;
20351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            details.append(detail);
20451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        }
20551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    }
20651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (!details.size())
20751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return;
20851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (badGrammarLocation)
20951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *badGrammarLocation = 0;
21051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (badGrammarLength)
21151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        *badGrammarLength = text.length();
21251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
21351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
21451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void SpellCheckerClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
21551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
21651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient())
21751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_webView->spellCheckClient()->updateSpellingUIWithMisspelledWord(WebString(misspelledWord));
21851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
21951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
22051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void SpellCheckerClientImpl::showSpellingUI(bool show)
22151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
22251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient())
22351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        m_webView->spellCheckClient()->showSpellingUI(show);
22451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
22551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
22651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)bool SpellCheckerClientImpl::spellingUIIsShowing()
22751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){
22851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    if (m_webView->spellCheckClient())
22951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return m_webView->spellCheckClient()->isShowingSpellingUI();
23051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return false;
23151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)}
23251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
233e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)} // namespace blink
234