blob: 197a0ab378c3bd2bccddab241397abf504f495c5 [file] [log] [blame]
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebEditorClient.h"
#include "EditorState.h"
#include "WebCoreArgumentCoders.h"
#include "WebFrameLoaderClient.h"
#include "WebPage.h"
#include "WebPageProxy.h"
#include "WebPageProxyMessages.h"
#include "WebProcess.h"
#include <WebCore/ArchiveResource.h>
#include <WebCore/DocumentFragment.h>
#include <WebCore/EditCommand.h>
#include <WebCore/FocusController.h>
#include <WebCore/Frame.h>
#include <WebCore/HTMLInputElement.h>
#include <WebCore/HTMLNames.h>
#include <WebCore/HTMLTextAreaElement.h>
#include <WebCore/KeyboardEvent.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/Page.h>
#include <WebCore/UserTypingGestureIndicator.h>
using namespace WebCore;
using namespace HTMLNames;
namespace WebKit {
void WebEditorClient::pageDestroyed()
{
delete this;
}
bool WebEditorClient::shouldDeleteRange(Range* range)
{
bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(m_page, range);
notImplemented();
return result;
}
bool WebEditorClient::shouldShowDeleteInterface(HTMLElement*)
{
notImplemented();
return false;
}
bool WebEditorClient::smartInsertDeleteEnabled()
{
// FIXME: Why isn't this Mac specific like toggleSmartInsertDeleteEnabled?
#if PLATFORM(MAC)
return m_page->isSmartInsertDeleteEnabled();
#else
return true;
#endif
}
bool WebEditorClient::isSelectTrailingWhitespaceEnabled()
{
notImplemented();
return false;
}
bool WebEditorClient::isContinuousSpellCheckingEnabled()
{
return WebProcess::shared().textCheckerState().isContinuousSpellCheckingEnabled;
}
void WebEditorClient::toggleContinuousSpellChecking()
{
notImplemented();
}
bool WebEditorClient::isGrammarCheckingEnabled()
{
return WebProcess::shared().textCheckerState().isGrammarCheckingEnabled;
}
void WebEditorClient::toggleGrammarChecking()
{
notImplemented();
}
int WebEditorClient::spellCheckerDocumentTag()
{
notImplemented();
return false;
}
bool WebEditorClient::isEditable()
{
notImplemented();
return false;
}
bool WebEditorClient::shouldBeginEditing(Range* range)
{
bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(m_page, range);
notImplemented();
return result;
}
bool WebEditorClient::shouldEndEditing(Range* range)
{
bool result = m_page->injectedBundleEditorClient().shouldEndEditing(m_page, range);
notImplemented();
return result;
}
bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action)
{
bool result = m_page->injectedBundleEditorClient().shouldInsertNode(m_page, node, rangeToReplace, action);
notImplemented();
return result;
}
bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action)
{
bool result = m_page->injectedBundleEditorClient().shouldInsertText(m_page, text.impl(), rangeToReplace, action);
notImplemented();
return result;
}
bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
{
bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(m_page, fromRange, toRange, affinity, stillSelecting);
notImplemented();
return result;
}
bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
{
bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(m_page, style, range);
notImplemented();
return result;
}
bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
{
notImplemented();
return true;
}
void WebEditorClient::didBeginEditing()
{
// FIXME: What good is a notification name, if it's always the same?
DEFINE_STATIC_LOCAL(String, WebViewDidBeginEditingNotification, ("WebViewDidBeginEditingNotification"));
m_page->injectedBundleEditorClient().didBeginEditing(m_page, WebViewDidBeginEditingNotification.impl());
notImplemented();
}
void WebEditorClient::respondToChangedContents()
{
DEFINE_STATIC_LOCAL(String, WebViewDidChangeNotification, ("WebViewDidChangeNotification"));
m_page->injectedBundleEditorClient().didChange(m_page, WebViewDidChangeNotification.impl());
notImplemented();
}
void WebEditorClient::respondToChangedSelection()
{
DEFINE_STATIC_LOCAL(String, WebViewDidChangeSelectionNotification, ("WebViewDidChangeSelectionNotification"));
m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl());
Frame* frame = m_page->corePage()->focusController()->focusedFrame();
if (!frame)
return;
m_page->send(Messages::WebPageProxy::EditorStateChanged(m_page->editorState()));
#if PLATFORM(WIN)
// FIXME: This should also go into the selection state.
if (!frame->editor()->hasComposition() || frame->editor()->ignoreCompositionSelectionChange())
return;
unsigned start;
unsigned end;
m_page->send(Messages::WebPageProxy::DidChangeCompositionSelection(frame->editor()->getCompositionSelection(start, end)));
#endif
}
void WebEditorClient::didEndEditing()
{
DEFINE_STATIC_LOCAL(String, WebViewDidEndEditingNotification, ("WebViewDidEndEditingNotification"));
m_page->injectedBundleEditorClient().didEndEditing(m_page, WebViewDidEndEditingNotification.impl());
notImplemented();
}
void WebEditorClient::didWriteSelectionToPasteboard()
{
notImplemented();
}
void WebEditorClient::didSetSelectionTypesForPasteboard()
{
notImplemented();
}
void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command)
{
// FIXME: Add assertion that the command being reapplied is the same command that is
// being passed to us.
if (m_page->isInRedo())
return;
RefPtr<WebEditCommand> webCommand = WebEditCommand::create(command);
m_page->addWebEditCommand(webCommand->commandID(), webCommand.get());
uint32_t editAction = static_cast<uint32_t>(webCommand->command()->editingAction());
m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webCommand->commandID(), editAction));
}
void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand>)
{
}
void WebEditorClient::clearUndoRedoOperations()
{
m_page->send(Messages::WebPageProxy::ClearAllEditCommands());
}
bool WebEditorClient::canCopyCut(bool defaultValue) const
{
return defaultValue;
}
bool WebEditorClient::canPaste(bool defaultValue) const
{
return defaultValue;
}
bool WebEditorClient::canUndo() const
{
bool result = false;
m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
return result;
}
bool WebEditorClient::canRedo() const
{
bool result = false;
m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
return result;
}
void WebEditorClient::undo()
{
bool result = false;
m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
}
void WebEditorClient::redo()
{
bool result = false;
m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
}
#if !PLATFORM(GTK) && !PLATFORM(MAC)
void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
{
if (m_page->handleEditingKeyboardEvent(event))
event->setDefaultHandled();
}
void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
{
notImplemented();
}
#endif
void WebEditorClient::textFieldDidBeginEditing(Element* element)
{
if (!element->hasTagName(inputTag))
return;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
}
void WebEditorClient::textFieldDidEndEditing(Element* element)
{
if (!element->hasTagName(inputTag))
return;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
}
void WebEditorClient::textDidChangeInTextField(Element* element)
{
if (!element->hasTagName(inputTag))
return;
if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element)
return;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, static_cast<HTMLInputElement*>(element), webFrame);
}
void WebEditorClient::textDidChangeInTextArea(Element* element)
{
if (!element->hasTagName(textareaTag))
return;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, static_cast<HTMLTextAreaElement*>(element), webFrame);
}
static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
{
String key = event->keyIdentifier();
if (key == "Up")
type = WKInputFieldActionTypeMoveUp;
else if (key == "Down")
type = WKInputFieldActionTypeMoveDown;
else if (key == "U+001B")
type = WKInputFieldActionTypeCancel;
else if (key == "U+0009") {
if (event->shiftKey())
type = WKInputFieldActionTypeInsertBacktab;
else
type = WKInputFieldActionTypeInsertTab;
} else if (key == "Enter")
type = WKInputFieldActionTypeInsertNewline;
else
return false;
return true;
}
bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
{
if (!element->hasTagName(inputTag))
return false;
WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0);
if (!getActionTypeForKeyEvent(event, actionType))
return false;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), actionType, webFrame);
}
void WebEditorClient::textWillBeDeletedInTextField(Element* element)
{
if (!element->hasTagName(inputTag))
return;
WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame);
}
void WebEditorClient::ignoreWordInSpellDocument(const String& word)
{
m_page->send(Messages::WebPageProxy::IgnoreWord(word));
}
void WebEditorClient::learnWord(const String& word)
{
m_page->send(Messages::WebPageProxy::LearnWord(word));
}
void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
{
int32_t resultLocation = -1;
int32_t resultLength = 0;
// FIXME: It would be nice if we wouldn't have to copy the text here.
m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(String(text, length)),
Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength));
*misspellingLocation = resultLocation;
*misspellingLength = resultLength;
}
String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&)
{
notImplemented();
return String();
}
void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength)
{
int32_t resultLocation = -1;
int32_t resultLength = 0;
// FIXME: It would be nice if we wouldn't have to copy the text here.
m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(String(text, length)),
Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength));
*badGrammarLocation = resultLocation;
*badGrammarLength = resultLength;
}
void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
{
m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail));
}
void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
{
m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord));
}
void WebEditorClient::showSpellingUI(bool)
{
notImplemented();
}
bool WebEditorClient::spellingUIIsShowing()
{
bool isShowing = false;
m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing));
return isShowing;
}
void WebEditorClient::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses)
{
m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses));
}
void WebEditorClient::willSetInputMethodState()
{
notImplemented();
}
void WebEditorClient::setInputMethodState(bool)
{
notImplemented();
}
void WebEditorClient::requestCheckingOfString(WebCore::SpellChecker*, int, WebCore::TextCheckingTypeMask, const WTF::String&)
{
notImplemented();
}
} // namespace WebKit