Add smartInsertDeleteEnabled setting to WebCore::Page
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebCoreSupport / WebEditorClient.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "WebEditorClient.h"
28
29 #include "EditorState.h"
30 #include "WebCoreArgumentCoders.h"
31 #include "WebFrameLoaderClient.h"
32 #include "WebPage.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/StylePropertySet.h>
48 #include <WebCore/TextIterator.h>
49 #include <WebCore/UndoStep.h>
50 #include <WebCore/UserTypingGestureIndicator.h>
51
52 #if PLATFORM(QT)
53 #include <QClipboard>
54 #include <QGuiApplication>
55 #include <WebCore/Pasteboard.h>
56 #endif
57
58 using namespace WebCore;
59 using namespace HTMLNames;
60
61 namespace WebKit {
62
63 void WebEditorClient::pageDestroyed()
64 {
65     delete this;
66 }
67
68 bool WebEditorClient::shouldDeleteRange(Range* range)
69 {
70     bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(m_page, range);
71     notImplemented();
72     return result;
73 }
74
75 #if ENABLE(DELETION_UI)
76 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement*)
77 {
78     notImplemented();
79     return false;
80 }
81 #endif
82
83 bool WebEditorClient::smartInsertDeleteEnabled()
84 {
85     return m_page->isSmartInsertDeleteEnabled();
86 }
87  
88 bool WebEditorClient::isSelectTrailingWhitespaceEnabled()
89 {
90     notImplemented();
91     return false;
92 }
93
94 bool WebEditorClient::isContinuousSpellCheckingEnabled()
95 {
96     return WebProcess::shared().textCheckerState().isContinuousSpellCheckingEnabled;
97 }
98
99 void WebEditorClient::toggleContinuousSpellChecking()
100 {
101     notImplemented();
102 }
103
104 bool WebEditorClient::isGrammarCheckingEnabled()
105 {
106     return WebProcess::shared().textCheckerState().isGrammarCheckingEnabled;
107 }
108
109 void WebEditorClient::toggleGrammarChecking()
110 {
111     notImplemented();
112 }
113
114 int WebEditorClient::spellCheckerDocumentTag()
115 {
116     notImplemented();
117     return false;
118 }
119
120 bool WebEditorClient::shouldBeginEditing(Range* range)
121 {
122     bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(m_page, range);
123     notImplemented();
124     return result;
125 }
126
127 bool WebEditorClient::shouldEndEditing(Range* range)
128 {
129     bool result = m_page->injectedBundleEditorClient().shouldEndEditing(m_page, range);
130     notImplemented();
131     return result;
132 }
133
134 bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action)
135 {
136     bool result = m_page->injectedBundleEditorClient().shouldInsertNode(m_page, node, rangeToReplace, action);
137     notImplemented();
138     return result;
139 }
140
141 bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action)
142 {
143     bool result = m_page->injectedBundleEditorClient().shouldInsertText(m_page, text.impl(), rangeToReplace, action);
144     notImplemented();
145     return result;
146 }
147
148 bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
149 {
150     bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(m_page, fromRange, toRange, affinity, stillSelecting);
151     notImplemented();
152     return result;
153 }
154     
155 bool WebEditorClient::shouldApplyStyle(StylePropertySet* style, Range* range)
156 {
157     bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(m_page, style->ensureCSSStyleDeclaration(), range);
158     notImplemented();
159     return result;
160 }
161
162 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
163 {
164     notImplemented();
165     return true;
166 }
167
168 void WebEditorClient::didBeginEditing()
169 {
170     // FIXME: What good is a notification name, if it's always the same?
171     DEFINE_STATIC_LOCAL(String, WebViewDidBeginEditingNotification, (ASCIILiteral("WebViewDidBeginEditingNotification")));
172     m_page->injectedBundleEditorClient().didBeginEditing(m_page, WebViewDidBeginEditingNotification.impl());
173     notImplemented();
174 }
175
176 void WebEditorClient::respondToChangedContents()
177 {
178     DEFINE_STATIC_LOCAL(String, WebViewDidChangeNotification, (ASCIILiteral("WebViewDidChangeNotification")));
179     m_page->injectedBundleEditorClient().didChange(m_page, WebViewDidChangeNotification.impl());
180     notImplemented();
181 }
182
183 void WebEditorClient::respondToChangedSelection(Frame* frame)
184 {
185     DEFINE_STATIC_LOCAL(String, WebViewDidChangeSelectionNotification, (ASCIILiteral("WebViewDidChangeSelectionNotification")));
186     m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl());
187     if (!frame)
188         return;
189
190     EditorState state = m_page->editorState();
191
192     m_page->send(Messages::WebPageProxy::EditorStateChanged(state));
193
194 #if PLATFORM(GTK) || PLATFORM(QT)
195     updateGlobalSelection(frame);
196 #endif
197 }
198
199 #if PLATFORM(QT)
200 // FIXME: Use this function for other X11-based platforms that need to manually update the global selection.
201 void WebEditorClient::updateGlobalSelection(Frame* frame)
202 {
203     if (supportsGlobalSelection() && frame->selection()->isRange()) {
204         bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
205         Pasteboard::generalPasteboard()->setSelectionMode(true);
206         Pasteboard::generalPasteboard()->writeSelection(frame->selection()->toNormalizedRange().get(), frame->editor()->canSmartCopyOrDelete(), frame);
207         Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
208     }
209 }
210 #endif
211
212 void WebEditorClient::didEndEditing()
213 {
214     DEFINE_STATIC_LOCAL(String, WebViewDidEndEditingNotification, (ASCIILiteral("WebViewDidEndEditingNotification")));
215     m_page->injectedBundleEditorClient().didEndEditing(m_page, WebViewDidEndEditingNotification.impl());
216     notImplemented();
217 }
218
219 void WebEditorClient::didWriteSelectionToPasteboard()
220 {
221     m_page->injectedBundleEditorClient().didWriteToPasteboard(m_page);
222 }
223
224 void WebEditorClient::willWriteSelectionToPasteboard(Range* range)
225 {
226     m_page->injectedBundleEditorClient().willWriteToPasteboard(m_page, range);
227 }
228
229 void WebEditorClient::getClientPasteboardDataForRange(Range* range, Vector<String>& pasteboardTypes, Vector<RefPtr<SharedBuffer> >& pasteboardData)
230 {
231     m_page->injectedBundleEditorClient().getPasteboardDataForRange(m_page, range, pasteboardTypes, pasteboardData);
232 }
233
234 void WebEditorClient::didSetSelectionTypesForPasteboard()
235 {
236     notImplemented();
237 }
238
239 void WebEditorClient::registerUndoStep(PassRefPtr<UndoStep> step)
240 {
241     // FIXME: Add assertion that the command being reapplied is the same command that is
242     // being passed to us.
243     if (m_page->isInRedo())
244         return;
245
246     RefPtr<WebUndoStep> webStep = WebUndoStep::create(step);
247     m_page->addWebUndoStep(webStep->stepID(), webStep.get());
248     uint32_t editAction = static_cast<uint32_t>(webStep->step()->editingAction());
249
250     m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webStep->stepID(), editAction));
251 }
252
253 void WebEditorClient::registerRedoStep(PassRefPtr<UndoStep>)
254 {
255 }
256
257 void WebEditorClient::clearUndoRedoOperations()
258 {
259     m_page->send(Messages::WebPageProxy::ClearAllEditCommands());
260 }
261
262 bool WebEditorClient::canCopyCut(Frame*, bool defaultValue) const
263 {
264     return defaultValue;
265 }
266
267 bool WebEditorClient::canPaste(Frame*, bool defaultValue) const
268 {
269     return defaultValue;
270 }
271
272 bool WebEditorClient::canUndo() const
273 {
274     bool result = false;
275     m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
276     return result;
277 }
278
279 bool WebEditorClient::canRedo() const
280 {
281     bool result = false;
282     m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
283     return result;
284 }
285
286 void WebEditorClient::undo()
287 {
288     bool result = false;
289     m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
290 }
291
292 void WebEditorClient::redo()
293 {
294     bool result = false;
295     m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
296 }
297
298 #if !PLATFORM(GTK) && !PLATFORM(MAC) && !PLATFORM(EFL)
299 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
300 {
301     if (m_page->handleEditingKeyboardEvent(event))
302         event->setDefaultHandled();
303 }
304
305 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
306 {
307     notImplemented();
308 }
309 #endif
310
311 void WebEditorClient::textFieldDidBeginEditing(Element* element)
312 {
313     if (!element->hasTagName(inputTag))
314         return;
315
316     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
317     m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
318 }
319
320 void WebEditorClient::textFieldDidEndEditing(Element* element)
321 {
322     if (!element->hasTagName(inputTag))
323         return;
324
325     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
326     m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
327 }
328
329 void WebEditorClient::textDidChangeInTextField(Element* element)
330 {
331     if (!element->hasTagName(inputTag))
332         return;
333
334     if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element)
335         return;
336
337     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
338     m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, static_cast<HTMLInputElement*>(element), webFrame);
339 }
340
341 void WebEditorClient::textDidChangeInTextArea(Element* element)
342 {
343     if (!element->hasTagName(textareaTag))
344         return;
345
346     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
347     m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, static_cast<HTMLTextAreaElement*>(element), webFrame);
348 }
349
350 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
351 {
352     String key = event->keyIdentifier();
353     if (key == "Up")
354         type = WKInputFieldActionTypeMoveUp;
355     else if (key == "Down")
356         type = WKInputFieldActionTypeMoveDown;
357     else if (key == "U+001B")
358         type = WKInputFieldActionTypeCancel;
359     else if (key == "U+0009") {
360         if (event->shiftKey())
361             type = WKInputFieldActionTypeInsertBacktab;
362         else
363             type = WKInputFieldActionTypeInsertTab;
364     } else if (key == "Enter")
365         type = WKInputFieldActionTypeInsertNewline;
366     else
367         return false;
368
369     return true;
370 }
371
372 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
373 {
374     if (!element->hasTagName(inputTag))
375         return false;
376
377     WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0);
378     if (!getActionTypeForKeyEvent(event, actionType))
379         return false;
380
381     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
382     return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), actionType, webFrame);
383 }
384
385 void WebEditorClient::textWillBeDeletedInTextField(Element* element)
386 {
387     if (!element->hasTagName(inputTag))
388         return;
389
390     WebFrame* webFrame =  static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
391     m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame);
392 }
393
394 bool WebEditorClient::shouldEraseMarkersAfterChangeSelection(WebCore::TextCheckingType type) const
395 {
396     // This prevents erasing spelling markers on OS X Lion or later to match AppKit on these Mac OS X versions.
397 #if PLATFORM(MAC)
398     return type != TextCheckingTypeSpelling;
399 #else
400     UNUSED_PARAM(type);
401     return true;
402 #endif
403 }
404
405 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
406 {
407     m_page->send(Messages::WebPageProxy::IgnoreWord(word));
408 }
409
410 void WebEditorClient::learnWord(const String& word)
411 {
412     m_page->send(Messages::WebPageProxy::LearnWord(word));
413 }
414
415 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
416 {
417     int32_t resultLocation = -1;
418     int32_t resultLength = 0;
419     // FIXME: It would be nice if we wouldn't have to copy the text here.
420     m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(String(text, length)),
421         Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength));
422     *misspellingLocation = resultLocation;
423     *misspellingLength = resultLength;
424 }
425
426 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&)
427 {
428     notImplemented();
429     return String();
430 }
431
432 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength)
433 {
434     int32_t resultLocation = -1;
435     int32_t resultLength = 0;
436     // FIXME: It would be nice if we wouldn't have to copy the text here.
437     m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(String(text, length)),
438         Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength));
439     *badGrammarLocation = resultLocation;
440     *badGrammarLength = resultLength;
441 }
442
443 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
444 {
445     m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail));
446 }
447
448 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
449 {
450     m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord));
451 }
452
453 void WebEditorClient::showSpellingUI(bool)
454 {
455     notImplemented();
456 }
457
458 bool WebEditorClient::spellingUIIsShowing()
459 {
460     bool isShowing = false;
461     m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing));
462     return isShowing;
463 }
464
465 void WebEditorClient::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses)
466 {
467     m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses));
468 }
469
470 void WebEditorClient::willSetInputMethodState()
471 {
472 #if PLATFORM(QT)
473     m_page->send(Messages::WebPageProxy::WillSetInputMethodState());
474 #else
475     notImplemented();
476 #endif
477 }
478
479 void WebEditorClient::setInputMethodState(bool)
480 {
481     notImplemented();
482 }
483
484 void WebEditorClient::requestCheckingOfString(WTF::PassRefPtr<WebCore::TextCheckingRequest>)
485 {
486     notImplemented();
487 }
488
489 bool WebEditorClient::supportsGlobalSelection()
490 {
491 #if PLATFORM(QT) && !defined(QT_NO_CLIPBOARD)
492     return qApp->clipboard()->supportsSelection();
493 #elif PLATFORM(GTK) && PLATFORM(X11)
494     return true;
495 #else
496     // FIXME: Return true on other X11 platforms when they support global selection.
497     return false;
498 #endif
499 }
500
501 } // namespace WebKit