2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "WebEditorClient.h"
29 #include "EditorState.h"
30 #include "WebCoreArgumentCoders.h"
31 #include "WebFrameLoaderClient.h"
33 #include "WebPageProxy.h"
34 #include "WebPageProxyMessages.h"
35 #include "WebProcess.h"
36 #include <WebCore/ArchiveResource.h>
37 #include <WebCore/DocumentFragment.h>
38 #include <WebCore/FocusController.h>
39 #include <WebCore/Frame.h>
40 #include <WebCore/FrameView.h>
41 #include <WebCore/HTMLInputElement.h>
42 #include <WebCore/HTMLNames.h>
43 #include <WebCore/HTMLTextAreaElement.h>
44 #include <WebCore/KeyboardEvent.h>
45 #include <WebCore/NotImplemented.h>
46 #include <WebCore/Page.h>
47 #include <WebCore/TextIterator.h>
48 #include <WebCore/UndoStep.h>
49 #include <WebCore/UserTypingGestureIndicator.h>
51 using namespace WebCore;
52 using namespace HTMLNames;
56 void WebEditorClient::pageDestroyed()
61 bool WebEditorClient::shouldDeleteRange(Range* range)
63 bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(m_page, range);
68 #if OS(TIZEN) // https://bugs.webkit.org/show_bug.cgi?id=86615
69 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* element)
71 return element->getAttribute(HTMLNames::classAttr) == "needsDeletionUI";
74 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement*)
81 bool WebEditorClient::smartInsertDeleteEnabled()
83 // FIXME: Why isn't this Mac specific like toggleSmartInsertDeleteEnabled?
85 return m_page->isSmartInsertDeleteEnabled();
91 bool WebEditorClient::isSelectTrailingWhitespaceEnabled()
97 bool WebEditorClient::isContinuousSpellCheckingEnabled()
99 return WebProcess::shared().textCheckerState().isContinuousSpellCheckingEnabled;
102 void WebEditorClient::toggleContinuousSpellChecking()
107 bool WebEditorClient::isGrammarCheckingEnabled()
109 return WebProcess::shared().textCheckerState().isGrammarCheckingEnabled;
112 void WebEditorClient::toggleGrammarChecking()
117 int WebEditorClient::spellCheckerDocumentTag()
123 bool WebEditorClient::shouldBeginEditing(Range* range)
125 bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(m_page, range);
130 bool WebEditorClient::shouldEndEditing(Range* range)
132 bool result = m_page->injectedBundleEditorClient().shouldEndEditing(m_page, range);
137 bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action)
139 bool result = m_page->injectedBundleEditorClient().shouldInsertNode(m_page, node, rangeToReplace, action);
144 bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action)
146 bool result = m_page->injectedBundleEditorClient().shouldInsertText(m_page, text.impl(), rangeToReplace, action);
151 bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
153 bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(m_page, fromRange, toRange, affinity, stillSelecting);
158 bool WebEditorClient::shouldApplyStyle(StylePropertySet* style, Range* range)
160 bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(m_page, style->ensureCSSStyleDeclaration(), range);
165 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
171 void WebEditorClient::didBeginEditing()
173 // FIXME: What good is a notification name, if it's always the same?
174 DEFINE_STATIC_LOCAL(String, WebViewDidBeginEditingNotification, ("WebViewDidBeginEditingNotification"));
175 m_page->injectedBundleEditorClient().didBeginEditing(m_page, WebViewDidBeginEditingNotification.impl());
179 void WebEditorClient::respondToChangedContents()
181 DEFINE_STATIC_LOCAL(String, WebViewDidChangeNotification, ("WebViewDidChangeNotification"));
182 m_page->injectedBundleEditorClient().didChange(m_page, WebViewDidChangeNotification.impl());
186 void WebEditorClient::respondToChangedSelection(Frame* frame)
188 #if ENABLE(TIZEN_ISF_PORT)
189 if (m_lockCountOfRespondToChangedSelection)
193 DEFINE_STATIC_LOCAL(String, WebViewDidChangeSelectionNotification, ("WebViewDidChangeSelectionNotification"));
194 m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl());
198 EditorState state = m_page->editorState();
200 #if ENABLE(TIZEN_ISF_PORT) || ENABLE(TIZEN_WEBKIT2_TEXT_SELECTION)
201 const EditorState& currentState = m_page->currentEditorState();
202 if (currentState.hasComposition && currentState.inputMethodContextID != state.inputMethodContextID)
203 didCancelComposition(reinterpret_cast<Node*>(currentState.inputMethodContextID));
205 m_page->setEditorState(state);
208 m_page->send(Messages::WebPageProxy::EditorStateChanged(state));
211 // FIXME: This should also go into the selection state.
212 if (!frame->editor()->hasComposition() || frame->editor()->ignoreCompositionSelectionChange())
217 m_page->send(Messages::WebPageProxy::DidChangeCompositionSelection(frame->editor()->getCompositionSelection(start, end)));
219 setSelectionPrimaryClipboardIfNeeded(frame);
223 void WebEditorClient::didEndEditing()
225 DEFINE_STATIC_LOCAL(String, WebViewDidEndEditingNotification, ("WebViewDidEndEditingNotification"));
226 m_page->injectedBundleEditorClient().didEndEditing(m_page, WebViewDidEndEditingNotification.impl());
230 void WebEditorClient::didWriteSelectionToPasteboard()
235 void WebEditorClient::didSetSelectionTypesForPasteboard()
240 void WebEditorClient::registerUndoStep(PassRefPtr<UndoStep> step)
242 // FIXME: Add assertion that the command being reapplied is the same command that is
243 // being passed to us.
244 if (m_page->isInRedo())
247 RefPtr<WebUndoStep> webStep = WebUndoStep::create(step);
248 m_page->addWebUndoStep(webStep->stepID(), webStep.get());
249 uint32_t editAction = static_cast<uint32_t>(webStep->step()->editingAction());
251 m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webStep->stepID(), editAction));
254 void WebEditorClient::registerRedoStep(PassRefPtr<UndoStep>)
258 void WebEditorClient::clearUndoRedoOperations()
260 m_page->send(Messages::WebPageProxy::ClearAllEditCommands());
263 bool WebEditorClient::canCopyCut(Frame*, bool defaultValue) const
268 bool WebEditorClient::canPaste(Frame*, bool defaultValue) const
273 bool WebEditorClient::canUndo() const
276 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
280 bool WebEditorClient::canRedo() const
283 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
287 void WebEditorClient::undo()
290 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
293 void WebEditorClient::redo()
296 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
299 #if !PLATFORM(GTK) && !PLATFORM(MAC) && !PLATFORM(EFL)
300 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
302 if (m_page->handleEditingKeyboardEvent(event))
303 event->setDefaultHandled();
306 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
312 void WebEditorClient::textFieldDidBeginEditing(Element* element)
314 if (!element->hasTagName(inputTag))
317 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
318 m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
321 void WebEditorClient::textFieldDidEndEditing(Element* element)
323 if (!element->hasTagName(inputTag))
326 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
327 m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
330 void WebEditorClient::textDidChangeInTextField(Element* element)
332 if (!element->hasTagName(inputTag))
335 #if ENABLE(TIZEN_WEBKIT2_FORM_DATABASE)
336 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
337 if (inputElement->shouldAutocomplete() && !(inputElement->isPasswordField()))
338 m_page->send(Messages::WebPageProxy::TextChangeInTextField(inputElement->name(), inputElement->value()));
341 if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element)
344 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
345 m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, static_cast<HTMLInputElement*>(element), webFrame);
348 void WebEditorClient::textDidChangeInTextArea(Element* element)
350 if (!element->hasTagName(textareaTag))
353 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
354 m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, static_cast<HTMLTextAreaElement*>(element), webFrame);
357 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
359 String key = event->keyIdentifier();
361 type = WKInputFieldActionTypeMoveUp;
362 else if (key == "Down")
363 type = WKInputFieldActionTypeMoveDown;
364 else if (key == "U+001B")
365 type = WKInputFieldActionTypeCancel;
366 else if (key == "U+0009") {
367 if (event->shiftKey())
368 type = WKInputFieldActionTypeInsertBacktab;
370 type = WKInputFieldActionTypeInsertTab;
371 } else if (key == "Enter")
372 type = WKInputFieldActionTypeInsertNewline;
379 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
381 if (!element->hasTagName(inputTag))
384 WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0);
385 if (!getActionTypeForKeyEvent(event, actionType))
388 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
389 return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), actionType, webFrame);
392 void WebEditorClient::textWillBeDeletedInTextField(Element* element)
394 if (!element->hasTagName(inputTag))
397 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
398 m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame);
401 bool WebEditorClient::shouldEraseMarkersAfterChangeSelection(WebCore::TextCheckingType type) const
403 // This prevents erasing spelling markers on OS X Lion or later to match AppKit on these Mac OS X versions.
404 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
405 return type != TextCheckingTypeSpelling;
411 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
413 m_page->send(Messages::WebPageProxy::IgnoreWord(word));
416 void WebEditorClient::learnWord(const String& word)
418 m_page->send(Messages::WebPageProxy::LearnWord(word));
421 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
423 int32_t resultLocation = -1;
424 int32_t resultLength = 0;
425 // FIXME: It would be nice if we wouldn't have to copy the text here.
426 m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(String(text, length)),
427 Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength));
428 *misspellingLocation = resultLocation;
429 *misspellingLength = resultLength;
432 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&)
438 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength)
440 int32_t resultLocation = -1;
441 int32_t resultLength = 0;
442 // FIXME: It would be nice if we wouldn't have to copy the text here.
443 m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(String(text, length)),
444 Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength));
445 *badGrammarLocation = resultLocation;
446 *badGrammarLength = resultLength;
449 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
451 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail));
454 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
456 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord));
459 void WebEditorClient::showSpellingUI(bool)
464 bool WebEditorClient::spellingUIIsShowing()
466 bool isShowing = false;
467 m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing));
471 void WebEditorClient::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses)
473 m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses));
476 void WebEditorClient::willSetInputMethodState()
481 void WebEditorClient::setInputMethodState(bool active)
486 void WebEditorClient::requestCheckingOfString(WTF::PassRefPtr<WebCore::TextCheckingRequest>)
491 } // namespace WebKit