181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch/*
281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2007 Alp Toker <alp@atoker.com>
381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2008 Nuanti Ltd.
481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2009 Diego Escalante Urrelo <diegoe@gnome.org>
581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2009, 2010 Igalia S.L.
781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Copyright (C) 2010, Martin Robinson <mrobinson@webkit.org>
881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *
981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  This library is free software; you can redistribute it and/or
1081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  modify it under the terms of the GNU Lesser General Public
1181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  License as published by the Free Software Foundation; either
1281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  version 2 of the License, or (at your option) any later version.
1381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *
1481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  This library is distributed in the hope that it will be useful,
1581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Lesser General Public License for more details.
1881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *
1981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  You should have received a copy of the GNU Lesser General Public
2081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  License along with this library; if not, write to the Free Software
2181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
2281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch */
2381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
2481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "config.h"
2581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "TextCheckerClientEnchant.h"
2681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
2781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "NotImplemented.h"
2881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "webkitwebsettingsprivate.h"
2981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "webkitwebviewprivate.h"
3081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include <enchant.h>
3181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include <glib.h>
3281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include <wtf/text/CString.h>
3381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochusing namespace WebCore;
3581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochnamespace WebKit {
3781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochEnchantBroker* TextCheckerClientEnchant::broker = 0;
3981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
4081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochTextCheckerClientEnchant::TextCheckerClientEnchant(WebKitWebView* webView)
4181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    : m_webView(webView)
4281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    , m_enchantDicts(0)
4381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
4481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
4581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
4681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochTextCheckerClientEnchant::~TextCheckerClientEnchant()
4781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
4881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    g_slist_foreach(m_enchantDicts, freeSpellCheckingLanguage, 0);
4981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    g_slist_free(m_enchantDicts);
5081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
5181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::ignoreWordInSpellDocument(const String& text)
5381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
5481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    GSList* dicts = m_enchantDicts;
5581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    for (; dicts; dicts = dicts->next) {
5781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        EnchantDict* dict = static_cast<EnchantDict*>(dicts->data);
5881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        enchant_dict_add_to_session(dict, text.utf8().data(), -1);
6081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    }
6181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
6281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
6381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::learnWord(const String& text)
6481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
6581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    GSList* dicts = m_enchantDicts;
6681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
6781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    for (; dicts; dicts = dicts->next) {
6881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        EnchantDict* dict = static_cast<EnchantDict*>(dicts->data);
6981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
7081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        enchant_dict_add_to_personal(dict, text.utf8().data(), -1);
7181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    }
7281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
7381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
7481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
7581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
7681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    GSList* dicts = m_enchantDicts;
7781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!dicts)
7881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return;
7981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
802bde8e466a4451c7319e3a072d118917957d6554Steve Block    GOwnPtr<gchar> utf8Text(g_utf16_to_utf8(const_cast<gunichar2*>(text), length, 0, 0, 0));
812bde8e466a4451c7319e3a072d118917957d6554Steve Block    int utf8Length = g_utf8_strlen(utf8Text.get(), -1);
8281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
8381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    PangoLanguage* language(pango_language_get_default());
842bde8e466a4451c7319e3a072d118917957d6554Steve Block    GOwnPtr<PangoLogAttr> attrs(g_new(PangoLogAttr, utf8Length + 1));
8581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
8681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // pango_get_log_attrs uses an aditional position at the end of the text.
872bde8e466a4451c7319e3a072d118917957d6554Steve Block    pango_get_log_attrs(utf8Text.get(), -1, -1, language, attrs.get(), utf8Length + 1);
8881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
892bde8e466a4451c7319e3a072d118917957d6554Steve Block    for (int i = 0; i < length + 1; i++) {
9081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        // We go through each character until we find an is_word_start,
9181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        // then we get into an inner loop to find the is_word_end corresponding
9281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        // to it.
9381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (attrs.get()[i].is_word_start) {
9481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            int start = i;
9581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            int end = i;
9681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            int wordLength;
9781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
9881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            while (attrs.get()[end].is_word_end < 1)
9981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                end++;
10081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
10181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            wordLength = end - start;
10281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // Set the iterator to be at the current word end, so we don't
10381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // check characters twice.
10481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            i = end;
10581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1062bde8e466a4451c7319e3a072d118917957d6554Steve Block            gchar* cstart = g_utf8_offset_to_pointer(utf8Text.get(), start);
1072bde8e466a4451c7319e3a072d118917957d6554Steve Block            gint bytes = static_cast<gint>(g_utf8_offset_to_pointer(utf8Text.get(), end) - cstart);
1082bde8e466a4451c7319e3a072d118917957d6554Steve Block            GOwnPtr<gchar> word(g_new0(gchar, bytes + 1));
10981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1102bde8e466a4451c7319e3a072d118917957d6554Steve Block            g_utf8_strncpy(word.get(), cstart, wordLength);
11181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1122bde8e466a4451c7319e3a072d118917957d6554Steve Block            for (; dicts; dicts = dicts->next) {
1132bde8e466a4451c7319e3a072d118917957d6554Steve Block                EnchantDict* dict = static_cast<EnchantDict*>(dicts->data);
1142bde8e466a4451c7319e3a072d118917957d6554Steve Block                if (enchant_dict_check(dict, word.get(), wordLength)) {
11581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    *misspellingLocation = start;
11681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    *misspellingLength = wordLength;
11781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                } else {
11881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    // Stop checking, this word is ok in at least one dict.
11981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    *misspellingLocation = -1;
12081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    *misspellingLength = 0;
12181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    break;
12281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                }
12381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            }
12481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
12581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    }
12681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
12781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
12881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString TextCheckerClientEnchant::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord)
12981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
13081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // This method can be implemented using customized algorithms for the particular browser.
13181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Currently, it computes an empty string.
13281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return String();
13381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
13481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
13581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::checkGrammarOfString(const UChar*, int, Vector<GrammarDetail>&, int*, int*)
13681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
13781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    notImplemented();
13881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
13981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
14081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::getGuessesForWord(const String& word, const String& context, WTF::Vector<String>& guesses)
14181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
14281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    GSList* dicts = m_enchantDicts;
14381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    guesses.clear();
14481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
14581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    for (; dicts; dicts = dicts->next) {
14681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        size_t numberOfSuggestions;
14781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        size_t i;
14881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
14981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        EnchantDict* dict = static_cast<EnchantDict*>(dicts->data);
15081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        gchar** suggestions = enchant_dict_suggest(dict, word.utf8().data(), -1, &numberOfSuggestions);
15181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
15281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        for (i = 0; i < numberOfSuggestions && i < 10; i++)
15381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            guesses.append(String::fromUTF8(suggestions[i]));
15481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
15581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (numberOfSuggestions > 0)
15681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            enchant_dict_free_suggestions(dict, suggestions);
15781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    }
15881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
15981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
16081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic void getAvailableDictionariesCallback(const char* const languageTag, const char* const, const char* const, const char* const, void* data)
16181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
16281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    Vector<CString>* dicts = static_cast<Vector<CString>*>(data);
16381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
16481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    dicts->append(languageTag);
16581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
16681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
16781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::updateSpellCheckingLanguage(const char* spellCheckingLanguages)
16881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
16981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    EnchantDict* dict;
17081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    GSList* spellDictionaries = 0;
17181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
17281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!broker)
17381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        broker = enchant_broker_init();
17481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
17581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (spellCheckingLanguages) {
17681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        char** langs = g_strsplit(spellCheckingLanguages, ",", -1);
17781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        for (int i = 0; langs[i]; i++) {
17881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (enchant_broker_dict_exists(broker, langs[i])) {
17981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                dict = enchant_broker_request_dict(broker, langs[i]);
18081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                spellDictionaries = g_slist_append(spellDictionaries, dict);
18181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            }
18281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
18381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        g_strfreev(langs);
18481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    } else {
18581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        const char* language = pango_language_to_string(gtk_get_default_language());
18681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (enchant_broker_dict_exists(broker, language)) {
18781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            dict = enchant_broker_request_dict(broker, language);
18881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            spellDictionaries = g_slist_append(spellDictionaries, dict);
18981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        } else {
19081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            // No dictionaries selected, we get one from the list
19181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            Vector<CString> allDictionaries;
19281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            enchant_broker_list_dicts(broker, getAvailableDictionariesCallback, &allDictionaries);
19381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            if (!allDictionaries.isEmpty()) {
19481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                dict = enchant_broker_request_dict(broker, allDictionaries[0].data());
19581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                spellDictionaries = g_slist_append(spellDictionaries, dict);
19681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            }
19781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
19881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    }
19981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    g_slist_foreach(m_enchantDicts, freeSpellCheckingLanguage, 0);
20081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    g_slist_free(m_enchantDicts);
20181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    m_enchantDicts = spellDictionaries;
20281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
20381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
20481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid TextCheckerClientEnchant::freeSpellCheckingLanguage(gpointer data, gpointer)
20581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
20681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!broker)
20781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        broker = enchant_broker_init();
20881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
20981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    EnchantDict* dict = static_cast<EnchantDict*>(data);
21081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    enchant_broker_free_dict(broker, dict);
21181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
21281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
21381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
214