/* * Copyright (C) 2007 Alp Toker * Copyright (C) 2008 Nuanti Ltd. * Copyright (C) 2009 Diego Escalante Urrelo * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2009, 2010 Igalia S.L. * Copyright (C) 2010, Martin Robinson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "TextCheckerClientEnchant.h" #include "NotImplemented.h" #include "webkitwebsettingsprivate.h" #include "webkitwebviewprivate.h" #include #include #include using namespace WebCore; namespace WebKit { EnchantBroker* TextCheckerClientEnchant::broker = 0; TextCheckerClientEnchant::TextCheckerClientEnchant(WebKitWebView* webView) : m_webView(webView) , m_enchantDicts(0) { } TextCheckerClientEnchant::~TextCheckerClientEnchant() { g_slist_foreach(m_enchantDicts, freeSpellCheckingLanguage, 0); g_slist_free(m_enchantDicts); } void TextCheckerClientEnchant::ignoreWordInSpellDocument(const String& text) { GSList* dicts = m_enchantDicts; for (; dicts; dicts = dicts->next) { EnchantDict* dict = static_cast(dicts->data); enchant_dict_add_to_session(dict, text.utf8().data(), -1); } } void TextCheckerClientEnchant::learnWord(const String& text) { GSList* dicts = m_enchantDicts; for (; dicts; dicts = dicts->next) { EnchantDict* dict = static_cast(dicts->data); enchant_dict_add_to_personal(dict, text.utf8().data(), -1); } } void TextCheckerClientEnchant::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength) { GSList* dicts = m_enchantDicts; if (!dicts) return; GOwnPtr utf8Text(g_utf16_to_utf8(const_cast(text), length, 0, 0, 0)); int utf8Length = g_utf8_strlen(utf8Text.get(), -1); PangoLanguage* language(pango_language_get_default()); GOwnPtr attrs(g_new(PangoLogAttr, utf8Length + 1)); // pango_get_log_attrs uses an aditional position at the end of the text. pango_get_log_attrs(utf8Text.get(), -1, -1, language, attrs.get(), utf8Length + 1); for (int i = 0; i < length + 1; i++) { // We go through each character until we find an is_word_start, // then we get into an inner loop to find the is_word_end corresponding // to it. if (attrs.get()[i].is_word_start) { int start = i; int end = i; int wordLength; while (attrs.get()[end].is_word_end < 1) end++; wordLength = end - start; // Set the iterator to be at the current word end, so we don't // check characters twice. i = end; gchar* cstart = g_utf8_offset_to_pointer(utf8Text.get(), start); gint bytes = static_cast(g_utf8_offset_to_pointer(utf8Text.get(), end) - cstart); GOwnPtr word(g_new0(gchar, bytes + 1)); g_utf8_strncpy(word.get(), cstart, wordLength); for (; dicts; dicts = dicts->next) { EnchantDict* dict = static_cast(dicts->data); if (enchant_dict_check(dict, word.get(), wordLength)) { *misspellingLocation = start; *misspellingLength = wordLength; } else { // Stop checking, this word is ok in at least one dict. *misspellingLocation = -1; *misspellingLength = 0; break; } } } } } String TextCheckerClientEnchant::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord) { // This method can be implemented using customized algorithms for the particular browser. // Currently, it computes an empty string. return String(); } void TextCheckerClientEnchant::checkGrammarOfString(const UChar*, int, Vector&, int*, int*) { notImplemented(); } void TextCheckerClientEnchant::getGuessesForWord(const String& word, const String& context, WTF::Vector& guesses) { GSList* dicts = m_enchantDicts; guesses.clear(); for (; dicts; dicts = dicts->next) { size_t numberOfSuggestions; size_t i; EnchantDict* dict = static_cast(dicts->data); gchar** suggestions = enchant_dict_suggest(dict, word.utf8().data(), -1, &numberOfSuggestions); for (i = 0; i < numberOfSuggestions && i < 10; i++) guesses.append(String::fromUTF8(suggestions[i])); if (numberOfSuggestions > 0) enchant_dict_free_suggestions(dict, suggestions); } } static void getAvailableDictionariesCallback(const char* const languageTag, const char* const, const char* const, const char* const, void* data) { Vector* dicts = static_cast*>(data); dicts->append(languageTag); } void TextCheckerClientEnchant::updateSpellCheckingLanguage(const char* spellCheckingLanguages) { EnchantDict* dict; GSList* spellDictionaries = 0; if (!broker) broker = enchant_broker_init(); if (spellCheckingLanguages) { char** langs = g_strsplit(spellCheckingLanguages, ",", -1); for (int i = 0; langs[i]; i++) { if (enchant_broker_dict_exists(broker, langs[i])) { dict = enchant_broker_request_dict(broker, langs[i]); spellDictionaries = g_slist_append(spellDictionaries, dict); } } g_strfreev(langs); } else { const char* language = pango_language_to_string(gtk_get_default_language()); if (enchant_broker_dict_exists(broker, language)) { dict = enchant_broker_request_dict(broker, language); spellDictionaries = g_slist_append(spellDictionaries, dict); } else { // No dictionaries selected, we get one from the list Vector allDictionaries; enchant_broker_list_dicts(broker, getAvailableDictionariesCallback, &allDictionaries); if (!allDictionaries.isEmpty()) { dict = enchant_broker_request_dict(broker, allDictionaries[0].data()); spellDictionaries = g_slist_append(spellDictionaries, dict); } } } g_slist_foreach(m_enchantDicts, freeSpellCheckingLanguage, 0); g_slist_free(m_enchantDicts); m_enchantDicts = spellDictionaries; } void TextCheckerClientEnchant::freeSpellCheckingLanguage(gpointer data, gpointer) { if (!broker) broker = enchant_broker_init(); EnchantDict* dict = static_cast(data); enchant_broker_free_dict(broker, dict); } }