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