blob: 460000b8c373a1e07b3d490605442e22dc803050 [file] [log] [blame]
/*
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
* Copyright (C) 2008 Nuanti Ltd.
* Copyright (C) 2009 Diego Escalante Urrelo <diegoe@gnome.org>
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2009, 2010 Igalia S.L.
* Copyright (C) 2010, Martin Robinson <mrobinson@webkit.org>
*
* 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 <enchant.h>
#include <glib.h>
#include <wtf/text/CString.h>
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<EnchantDict*>(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<EnchantDict*>(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<gchar> utf8Text(g_utf16_to_utf8(const_cast<gunichar2*>(text), length, 0, 0, 0));
int utf8Length = g_utf8_strlen(utf8Text.get(), -1);
PangoLanguage* language(pango_language_get_default());
GOwnPtr<PangoLogAttr> 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<gint>(g_utf8_offset_to_pointer(utf8Text.get(), end) - cstart);
GOwnPtr<gchar> word(g_new0(gchar, bytes + 1));
g_utf8_strncpy(word.get(), cstart, wordLength);
for (; dicts; dicts = dicts->next) {
EnchantDict* dict = static_cast<EnchantDict*>(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<GrammarDetail>&, int*, int*)
{
notImplemented();
}
void TextCheckerClientEnchant::getGuessesForWord(const String& word, const String& context, WTF::Vector<String>& guesses)
{
GSList* dicts = m_enchantDicts;
guesses.clear();
for (; dicts; dicts = dicts->next) {
size_t numberOfSuggestions;
size_t i;
EnchantDict* dict = static_cast<EnchantDict*>(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<CString>* dicts = static_cast<Vector<CString>*>(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<CString> 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<EnchantDict*>(data);
enchant_broker_free_dict(broker, dict);
}
}