summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp')
-rw-r--r--Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp260
1 files changed, 216 insertions, 44 deletions
diff --git a/Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp b/Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp
index 6bc419079..2513cbd69 100644
--- a/Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp
+++ b/Source/WebKit2/UIProcess/gtk/TextCheckerGtk.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved.
+ * Copyright (C) 2011-2013 Samsung Electronics
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,119 +29,290 @@
#include "TextChecker.h"
#include "TextCheckerState.h"
-#include "WebTextChecker.h"
+#include "WebProcessPool.h"
#include <WebCore/NotImplemented.h>
+#include <WebCore/TextCheckerEnchant.h>
+#include <unicode/ubrk.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/TextBreakIterator.h>
using namespace WebCore;
-
+
namespace WebKit {
-static TextCheckerState textCheckerState;
+#if ENABLE(SPELLCHECK)
+static WebCore::TextCheckerEnchant& enchantTextChecker()
+{
+ static NeverDestroyed<WebCore::TextCheckerEnchant> checker;
+ return checker;
+}
+#endif
-const TextCheckerState& TextChecker::state()
+TextCheckerState& checkerState()
{
- static bool didInitializeState = false;
- if (didInitializeState)
- return textCheckerState;
+ static TextCheckerState textCheckerState;
+ static std::once_flag onceFlag;
+ std::call_once(onceFlag, [] {
+ textCheckerState.isContinuousSpellCheckingEnabled = false;
+ textCheckerState.isGrammarCheckingEnabled = false;
+ });
+
+ return textCheckerState;
+}
- WebTextCheckerClient& client = WebTextChecker::shared()->client();
- textCheckerState.isContinuousSpellCheckingEnabled = client.continuousSpellCheckingEnabled();
- textCheckerState.isGrammarCheckingEnabled = client.grammarCheckingEnabled();
+const TextCheckerState& TextChecker::state()
+{
+ return checkerState();
+}
+
+static bool testingModeEnabled = false;
+
+void TextChecker::setTestingMode(bool enabled)
+{
+ testingModeEnabled = enabled;
+}
- didInitializeState = true;
+bool TextChecker::isTestingMode()
+{
+ return testingModeEnabled;
+}
- return textCheckerState;
+#if ENABLE(SPELLCHECK)
+static void updateStateForAllProcessPools()
+{
+ for (const auto& processPool : WebProcessPool::allProcessPools())
+ processPool->textCheckerStateChanged();
}
-
+#endif
+
bool TextChecker::isContinuousSpellCheckingAllowed()
{
- return WebTextChecker::shared()->client().continuousSpellCheckingAllowed();
+#if ENABLE(SPELLCHECK)
+ return true;
+#else
+ return false;
+#endif
}
void TextChecker::setContinuousSpellCheckingEnabled(bool isContinuousSpellCheckingEnabled)
{
- if (state().isContinuousSpellCheckingEnabled == isContinuousSpellCheckingEnabled)
+#if ENABLE(SPELLCHECK)
+ if (checkerState().isContinuousSpellCheckingEnabled == isContinuousSpellCheckingEnabled)
return;
- textCheckerState.isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled;
- WebTextChecker::shared()->client().setContinuousSpellCheckingEnabled(isContinuousSpellCheckingEnabled);
+ checkerState().isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled;
+ updateStateForAllProcessPools();
+#else
+ UNUSED_PARAM(isContinuousSpellCheckingEnabled);
+#endif
}
void TextChecker::setGrammarCheckingEnabled(bool isGrammarCheckingEnabled)
{
- if (state().isGrammarCheckingEnabled == isGrammarCheckingEnabled)
+#if ENABLE(SPELLCHECK)
+ if (checkerState().isGrammarCheckingEnabled == isGrammarCheckingEnabled)
return;
- textCheckerState.isGrammarCheckingEnabled = isGrammarCheckingEnabled;
- WebTextChecker::shared()->client().setGrammarCheckingEnabled(isGrammarCheckingEnabled);
+ checkerState().isGrammarCheckingEnabled = isGrammarCheckingEnabled;
+ updateStateForAllProcessPools();
+#else
+ UNUSED_PARAM(isGrammarCheckingEnabled);
+#endif
}
void TextChecker::continuousSpellCheckingEnabledStateChanged(bool enabled)
{
- textCheckerState.isContinuousSpellCheckingEnabled = enabled;
+#if ENABLE(SPELLCHECK)
+ checkerState().isContinuousSpellCheckingEnabled = enabled;
+#else
+ UNUSED_PARAM(enabled);
+#endif
}
void TextChecker::grammarCheckingEnabledStateChanged(bool enabled)
{
- textCheckerState.isGrammarCheckingEnabled = enabled;
+#if ENABLE(SPELLCHECK)
+ checkerState().isGrammarCheckingEnabled = enabled;
+#else
+ UNUSED_PARAM(enabled);
+#endif
}
-int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy* page)
+int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy*)
{
- return WebTextChecker::shared()->client().uniqueSpellDocumentTag(page);
+ return 0;
}
-void TextChecker::closeSpellDocumentWithTag(int64_t tag)
+void TextChecker::closeSpellDocumentWithTag(int64_t /* tag */)
{
- WebTextChecker::shared()->client().closeSpellDocumentWithTag(tag);
}
-void TextChecker::checkSpellingOfString(int64_t spellDocumentTag, const UChar* text, uint32_t length, int32_t& misspellingLocation, int32_t& misspellingLength)
+void TextChecker::checkSpellingOfString(int64_t /* spellDocumentTag */, StringView text, int32_t& misspellingLocation, int32_t& misspellingLength)
{
- WebTextChecker::shared()->client().checkSpellingOfString(spellDocumentTag, String(text, length), misspellingLocation, misspellingLength);
+#if ENABLE(SPELLCHECK)
+ misspellingLocation = -1;
+ misspellingLength = 0;
+ enchantTextChecker().checkSpellingOfString(text.toStringWithoutCopying(), misspellingLocation, misspellingLength);
+#else
+ UNUSED_PARAM(text);
+ UNUSED_PARAM(misspellingLocation);
+ UNUSED_PARAM(misspellingLength);
+#endif
}
-void TextChecker::checkGrammarOfString(int64_t spellDocumentTag, const UChar* text, uint32_t length, Vector<WebCore::GrammarDetail>& grammarDetails, int32_t& badGrammarLocation, int32_t& badGrammarLength)
+void TextChecker::checkGrammarOfString(int64_t /* spellDocumentTag */, StringView /* text */, Vector<WebCore::GrammarDetail>& /* grammarDetails */, int32_t& /* badGrammarLocation */, int32_t& /* badGrammarLength */)
{
- WebTextChecker::shared()->client().checkGrammarOfString(spellDocumentTag, String(text, length), grammarDetails, badGrammarLocation, badGrammarLength);
}
bool TextChecker::spellingUIIsShowing()
{
- return WebTextChecker::shared()->client().spellingUIIsShowing();
+ return false;
}
void TextChecker::toggleSpellingUIIsShowing()
{
- WebTextChecker::shared()->client().toggleSpellingUIIsShowing();
}
-void TextChecker::updateSpellingUIWithMisspelledWord(int64_t spellDocumentTag, const String& misspelledWord)
+void TextChecker::updateSpellingUIWithMisspelledWord(int64_t /* spellDocumentTag */, const String& /* misspelledWord */)
+{
+}
+
+void TextChecker::updateSpellingUIWithGrammarString(int64_t /* spellDocumentTag */, const String& /* badGrammarPhrase */, const GrammarDetail& /* grammarDetail */)
{
- WebTextChecker::shared()->client().updateSpellingUIWithMisspelledWord(spellDocumentTag, misspelledWord);
}
-void TextChecker::updateSpellingUIWithGrammarString(int64_t spellDocumentTag, const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
+void TextChecker::getGuessesForWord(int64_t /* spellDocumentTag */, const String& word, const String& /* context */, int32_t /* insertionPoint */, Vector<String>& guesses, bool)
{
- WebTextChecker::shared()->client().updateSpellingUIWithGrammarString(spellDocumentTag, badGrammarPhrase, grammarDetail);
+#if ENABLE(SPELLCHECK)
+ guesses = enchantTextChecker().getGuessesForWord(word);
+#else
+ UNUSED_PARAM(word);
+ UNUSED_PARAM(guesses);
+#endif
}
-void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word, const String& context, Vector<String>& guesses)
+void TextChecker::learnWord(int64_t /* spellDocumentTag */, const String& word)
{
- WebTextChecker::shared()->client().guessesForWord(spellDocumentTag, word, guesses);
+#if ENABLE(SPELLCHECK)
+ enchantTextChecker().learnWord(word);
+#else
+ UNUSED_PARAM(word);
+#endif
}
-void TextChecker::learnWord(int64_t spellDocumentTag, const String& word)
+void TextChecker::ignoreWord(int64_t /* spellDocumentTag */, const String& word)
{
- WebTextChecker::shared()->client().learnWord(spellDocumentTag, word);
+#if ENABLE(SPELLCHECK)
+ enchantTextChecker().ignoreWord(word);
+#else
+ UNUSED_PARAM(word);
+#endif
+}
+
+void TextChecker::requestCheckingOfString(PassRefPtr<TextCheckerCompletion> completion, int32_t insertionPoint)
+{
+#if ENABLE(SPELLCHECK)
+ if (!completion)
+ return;
+
+ TextCheckingRequestData request = completion->textCheckingRequestData();
+ ASSERT(request.sequence() != unrequestedTextCheckingSequence);
+ ASSERT(request.mask() != TextCheckingTypeNone);
+
+ completion->didFinishCheckingText(checkTextOfParagraph(completion->spellDocumentTag(), request.text(), insertionPoint, request.mask(), false));
+#else
+ UNUSED_PARAM(completion);
+#endif
+}
+
+#if USE(UNIFIED_TEXT_CHECKING) && ENABLE(SPELLCHECK)
+static unsigned nextWordOffset(StringView text, unsigned currentOffset)
+{
+ // FIXME: avoid creating textIterator object here, it could be passed as a parameter.
+ // ubrk_isBoundary() leaves the iterator pointing to the first boundary position at
+ // or after "offset" (ubrk_isBoundary side effect).
+ // For many word separators, the method doesn't properly determine the boundaries
+ // without resetting the iterator.
+ UBreakIterator* textIterator = wordBreakIterator(text);
+ if (!textIterator)
+ return currentOffset;
+
+ unsigned wordOffset = currentOffset;
+ while (wordOffset < text.length() && ubrk_isBoundary(textIterator, wordOffset))
+ ++wordOffset;
+
+ // Do not treat the word's boundary as a separator.
+ if (!currentOffset && wordOffset == 1)
+ return currentOffset;
+
+ // Omit multiple separators.
+ if ((wordOffset - currentOffset) > 1)
+ --wordOffset;
+
+ return wordOffset;
+}
+#endif
+
+#if USE(UNIFIED_TEXT_CHECKING)
+Vector<TextCheckingResult> TextChecker::checkTextOfParagraph(int64_t spellDocumentTag, StringView text, int32_t insertionPoint, uint64_t checkingTypes, bool)
+{
+ UNUSED_PARAM(insertionPoint);
+#if ENABLE(SPELLCHECK)
+ if (!(checkingTypes & TextCheckingTypeSpelling))
+ return Vector<TextCheckingResult>();
+
+ UBreakIterator* textIterator = wordBreakIterator(text);
+ if (!textIterator)
+ return Vector<TextCheckingResult>();
+
+ // Omit the word separators at the beginning/end of the text to don't unnecessarily
+ // involve the client to check spelling for them.
+ unsigned offset = nextWordOffset(text, 0);
+ unsigned lengthStrip = text.length();
+ while (lengthStrip > 0 && ubrk_isBoundary(textIterator, lengthStrip - 1))
+ --lengthStrip;
+
+ Vector<TextCheckingResult> paragraphCheckingResult;
+ while (offset < lengthStrip) {
+ int32_t misspellingLocation = -1;
+ int32_t misspellingLength = 0;
+ checkSpellingOfString(spellDocumentTag, text.substring(offset, lengthStrip - offset), misspellingLocation, misspellingLength);
+ if (!misspellingLength)
+ break;
+
+ TextCheckingResult misspellingResult;
+ misspellingResult.type = TextCheckingTypeSpelling;
+ misspellingResult.location = offset + misspellingLocation;
+ misspellingResult.length = misspellingLength;
+ paragraphCheckingResult.append(misspellingResult);
+ offset += misspellingLocation + misspellingLength;
+ // Generally, we end up checking at the word separator, move to the adjacent word.
+ offset = nextWordOffset(text.substring(0, lengthStrip), offset);
+ }
+ return paragraphCheckingResult;
+#else
+ UNUSED_PARAM(spellDocumentTag);
+ UNUSED_PARAM(text);
+ UNUSED_PARAM(checkingTypes);
+ return Vector<TextCheckingResult>();
+#endif // ENABLE(SPELLCHECK)
}
+#endif // USE(UNIFIED_TEXT_CHECKING)
-void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word)
+void TextChecker::setSpellCheckingLanguages(const Vector<String>& languages)
{
- WebTextChecker::shared()->client().ignoreWord(spellDocumentTag, word);
+#if ENABLE(SPELLCHECK)
+ enchantTextChecker().updateSpellCheckingLanguages(languages);
+#else
+ UNUSED_PARAM(languages);
+#endif
}
-void TextChecker::requestCheckingOfString(PassRefPtr<TextCheckerCompletion>)
+Vector<String> TextChecker::loadedSpellCheckingLanguages()
{
- notImplemented();
+#if ENABLE(SPELLCHECK)
+ return enchantTextChecker().loadedSpellCheckingLanguages();
+#else
+ return Vector<String>();
+#endif
}
} // namespace WebKit