5393df20cd43bfe2f732c83646d80510023edf33
[WebKit-https.git] / Source / WebKit / WebProcess / WebCoreSupport / WebEditorClient.cpp
1 /*
2  * Copyright (C) 2010-2017 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 "WKBundlePageEditorClient.h"
31 #include "WebCoreArgumentCoders.h"
32 #include "WebFrame.h"
33 #include "WebPage.h"
34 #include "WebPageProxy.h"
35 #include "WebPageProxyMessages.h"
36 #include "WebProcess.h"
37 #include "WebUndoStep.h"
38 #include <WebCore/ArchiveResource.h>
39 #include <WebCore/DocumentFragment.h>
40 #include <WebCore/FocusController.h>
41 #include <WebCore/Frame.h>
42 #include <WebCore/FrameLoader.h>
43 #include <WebCore/FrameView.h>
44 #include <WebCore/HTMLInputElement.h>
45 #include <WebCore/HTMLNames.h>
46 #include <WebCore/HTMLTextAreaElement.h>
47 #include <WebCore/KeyboardEvent.h>
48 #include <WebCore/NotImplemented.h>
49 #include <WebCore/Page.h>
50 #include <WebCore/SpellChecker.h>
51 #include <WebCore/StyleProperties.h>
52 #include <WebCore/TextIterator.h>
53 #include <WebCore/UndoStep.h>
54 #include <WebCore/UserTypingGestureIndicator.h>
55 #include <WebCore/VisibleUnits.h>
56 #include <wtf/NeverDestroyed.h>
57 #include <wtf/text/StringView.h>
58
59 #if PLATFORM(GTK)
60 #include <WebCore/PlatformDisplay.h>
61 #endif
62
63 using namespace WebCore;
64 using namespace HTMLNames;
65
66 namespace WebKit {
67
68 static uint64_t generateTextCheckingRequestID()
69 {
70     static uint64_t uniqueTextCheckingRequestID = 1;
71     return uniqueTextCheckingRequestID++;
72 }
73
74 bool WebEditorClient::shouldDeleteRange(Range* range)
75 {
76     bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(*m_page, range);
77     notImplemented();
78     return result;
79 }
80
81 bool WebEditorClient::smartInsertDeleteEnabled()
82 {
83     return m_page->isSmartInsertDeleteEnabled();
84 }
85  
86 bool WebEditorClient::isSelectTrailingWhitespaceEnabled() const
87 {
88     return m_page->isSelectTrailingWhitespaceEnabled();
89 }
90
91 bool WebEditorClient::isContinuousSpellCheckingEnabled()
92 {
93     return WebProcess::singleton().textCheckerState().isContinuousSpellCheckingEnabled;
94 }
95
96 void WebEditorClient::toggleContinuousSpellChecking()
97 {
98     notImplemented();
99 }
100
101 bool WebEditorClient::isGrammarCheckingEnabled()
102 {
103     return WebProcess::singleton().textCheckerState().isGrammarCheckingEnabled;
104 }
105
106 void WebEditorClient::toggleGrammarChecking()
107 {
108     notImplemented();
109 }
110
111 int WebEditorClient::spellCheckerDocumentTag()
112 {
113     notImplemented();
114     return false;
115 }
116
117 bool WebEditorClient::shouldBeginEditing(Range* range)
118 {
119     bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(*m_page, range);
120     notImplemented();
121     return result;
122 }
123
124 bool WebEditorClient::shouldEndEditing(Range* range)
125 {
126     bool result = m_page->injectedBundleEditorClient().shouldEndEditing(*m_page, range);
127     notImplemented();
128     return result;
129 }
130
131 bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action)
132 {
133     bool result = m_page->injectedBundleEditorClient().shouldInsertNode(*m_page, node, rangeToReplace, action);
134     notImplemented();
135     return result;
136 }
137
138 bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action)
139 {
140     bool result = m_page->injectedBundleEditorClient().shouldInsertText(*m_page, text.impl(), rangeToReplace, action);
141     notImplemented();
142     return result;
143 }
144
145 bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
146 {
147     bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(*m_page, fromRange, toRange, affinity, stillSelecting);
148     notImplemented();
149     return result;
150 }
151     
152 bool WebEditorClient::shouldApplyStyle(StyleProperties* style, Range* range)
153 {
154     Ref<MutableStyleProperties> mutableStyle(style->isMutable() ? Ref<MutableStyleProperties>(static_cast<MutableStyleProperties&>(*style)) : style->mutableCopy());
155     bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(*m_page, &mutableStyle->ensureCSSStyleDeclaration(), range);
156     notImplemented();
157     return result;
158 }
159
160 #if ENABLE(ATTACHMENT_ELEMENT)
161
162 void WebEditorClient::didInsertAttachment(const String& identifier)
163 {
164     m_page->send(Messages::WebPageProxy::DidInsertAttachment(identifier));
165 }
166
167 void WebEditorClient::didRemoveAttachment(const String& identifier)
168 {
169     m_page->send(Messages::WebPageProxy::DidRemoveAttachment(identifier));
170 }
171
172 #endif
173
174 void WebEditorClient::didApplyStyle()
175 {
176     m_page->didApplyStyle();
177 }
178
179 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
180 {
181     notImplemented();
182     return true;
183 }
184
185 void WebEditorClient::didBeginEditing()
186 {
187     // FIXME: What good is a notification name, if it's always the same?
188     static NeverDestroyed<String> WebViewDidBeginEditingNotification(MAKE_STATIC_STRING_IMPL("WebViewDidBeginEditingNotification"));
189     m_page->injectedBundleEditorClient().didBeginEditing(*m_page, WebViewDidBeginEditingNotification.get().impl());
190     notImplemented();
191 }
192
193 void WebEditorClient::respondToChangedContents()
194 {
195     static NeverDestroyed<String> WebViewDidChangeNotification(MAKE_STATIC_STRING_IMPL("WebViewDidChangeNotification"));
196     m_page->injectedBundleEditorClient().didChange(*m_page, WebViewDidChangeNotification.get().impl());
197     m_page->didChangeContents();
198 }
199
200 void WebEditorClient::respondToChangedSelection(Frame* frame)
201 {
202     static NeverDestroyed<String> WebViewDidChangeSelectionNotification(MAKE_STATIC_STRING_IMPL("WebViewDidChangeSelectionNotification"));
203     m_page->injectedBundleEditorClient().didChangeSelection(*m_page, WebViewDidChangeSelectionNotification.get().impl());
204     if (!frame)
205         return;
206
207     m_page->didChangeSelection();
208
209 #if PLATFORM(GTK)
210     updateGlobalSelection(frame);
211 #endif
212 }
213
214 void WebEditorClient::didEndUserTriggeredSelectionChanges()
215 {
216     m_page->didEndUserTriggeredSelectionChanges();
217 }
218
219 void WebEditorClient::updateEditorStateAfterLayoutIfEditabilityChanged()
220 {
221     m_page->updateEditorStateAfterLayoutIfEditabilityChanged();
222 }
223
224 void WebEditorClient::didUpdateComposition()
225 {
226     m_page->didUpdateComposition();
227 }
228
229 void WebEditorClient::discardedComposition(Frame*)
230 {
231     m_page->discardedComposition();
232 }
233
234 void WebEditorClient::canceledComposition()
235 {
236     m_page->canceledComposition();
237 }
238
239 void WebEditorClient::didEndEditing()
240 {
241     static NeverDestroyed<String> WebViewDidEndEditingNotification(MAKE_STATIC_STRING_IMPL("WebViewDidEndEditingNotification"));
242     m_page->injectedBundleEditorClient().didEndEditing(*m_page, WebViewDidEndEditingNotification.get().impl());
243     notImplemented();
244 }
245
246 void WebEditorClient::didWriteSelectionToPasteboard()
247 {
248     m_page->injectedBundleEditorClient().didWriteToPasteboard(*m_page);
249 }
250
251 void WebEditorClient::willWriteSelectionToPasteboard(Range* range)
252 {
253     m_page->injectedBundleEditorClient().willWriteToPasteboard(*m_page, range);
254 }
255
256 void WebEditorClient::getClientPasteboardDataForRange(Range* range, Vector<String>& pasteboardTypes, Vector<RefPtr<SharedBuffer>>& pasteboardData)
257 {
258     m_page->injectedBundleEditorClient().getPasteboardDataForRange(*m_page, range, pasteboardTypes, pasteboardData);
259 }
260
261 bool WebEditorClient::performTwoStepDrop(DocumentFragment& fragment, Range& destination, bool isMove)
262 {
263     return m_page->injectedBundleEditorClient().performTwoStepDrop(*m_page, fragment, destination, isMove);
264 }
265
266 void WebEditorClient::registerUndoStep(UndoStep& step)
267 {
268     // FIXME: Add assertion that the command being reapplied is the same command that is
269     // being passed to us.
270     if (m_page->isInRedo())
271         return;
272
273     auto webStep = WebUndoStep::create(step);
274     auto editAction = static_cast<uint32_t>(webStep->step().editingAction());
275
276     m_page->addWebUndoStep(webStep->stepID(), webStep.ptr());
277     m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webStep->stepID(), editAction));
278 }
279
280 void WebEditorClient::registerRedoStep(UndoStep&)
281 {
282 }
283
284 void WebEditorClient::clearUndoRedoOperations()
285 {
286     m_page->send(Messages::WebPageProxy::ClearAllEditCommands());
287 }
288
289 bool WebEditorClient::canCopyCut(Frame*, bool defaultValue) const
290 {
291     return defaultValue;
292 }
293
294 bool WebEditorClient::canPaste(Frame*, bool defaultValue) const
295 {
296     return defaultValue;
297 }
298
299 bool WebEditorClient::canUndo() const
300 {
301     bool result = false;
302     m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
303     return result;
304 }
305
306 bool WebEditorClient::canRedo() const
307 {
308     bool result = false;
309     m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
310     return result;
311 }
312
313 void WebEditorClient::undo()
314 {
315     bool result = false;
316     m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
317 }
318
319 void WebEditorClient::redo()
320 {
321     bool result = false;
322     m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
323 }
324
325 #if !PLATFORM(GTK) && !PLATFORM(COCOA) && !PLATFORM(WPE)
326 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
327 {
328     if (m_page->handleEditingKeyboardEvent(event))
329         event->setDefaultHandled();
330 }
331
332 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
333 {
334     notImplemented();
335 }
336 #endif
337
338 void WebEditorClient::textFieldDidBeginEditing(Element* element)
339 {
340     if (!is<HTMLInputElement>(*element))
341         return;
342
343     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
344     ASSERT(webFrame);
345
346     m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, downcast<HTMLInputElement>(element), webFrame);
347 }
348
349 void WebEditorClient::textFieldDidEndEditing(Element* element)
350 {
351     if (!is<HTMLInputElement>(*element))
352         return;
353
354     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
355     ASSERT(webFrame);
356
357     m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, downcast<HTMLInputElement>(element), webFrame);
358 }
359
360 void WebEditorClient::textDidChangeInTextField(Element* element)
361 {
362     if (!is<HTMLInputElement>(*element))
363         return;
364
365     bool initiatedByUserTyping = UserTypingGestureIndicator::processingUserTypingGesture() && UserTypingGestureIndicator::focusedElementAtGestureStart() == element;
366
367     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
368     ASSERT(webFrame);
369
370     m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, downcast<HTMLInputElement>(element), webFrame, initiatedByUserTyping);
371 }
372
373 void WebEditorClient::textDidChangeInTextArea(Element* element)
374 {
375     if (!is<HTMLTextAreaElement>(*element))
376         return;
377
378     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
379     ASSERT(webFrame);
380
381     m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, downcast<HTMLTextAreaElement>(element), webFrame);
382 }
383
384 #if !PLATFORM(IOS)
385 void WebEditorClient::overflowScrollPositionChanged()
386 {
387     notImplemented();
388 }
389 #endif
390
391 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
392 {
393     String key = event->keyIdentifier();
394     if (key == "Up")
395         type = WKInputFieldActionTypeMoveUp;
396     else if (key == "Down")
397         type = WKInputFieldActionTypeMoveDown;
398     else if (key == "U+001B")
399         type = WKInputFieldActionTypeCancel;
400     else if (key == "U+0009") {
401         if (event->shiftKey())
402             type = WKInputFieldActionTypeInsertBacktab;
403         else
404             type = WKInputFieldActionTypeInsertTab;
405     } else if (key == "Enter")
406         type = WKInputFieldActionTypeInsertNewline;
407     else
408         return false;
409
410     return true;
411 }
412
413 static API::InjectedBundle::FormClient::InputFieldAction toInputFieldAction(WKInputFieldActionType action)
414 {
415     switch (action) {
416     case WKInputFieldActionTypeMoveUp:
417         return API::InjectedBundle::FormClient::InputFieldAction::MoveUp;
418     case WKInputFieldActionTypeMoveDown:
419         return API::InjectedBundle::FormClient::InputFieldAction::MoveDown;
420     case WKInputFieldActionTypeCancel:
421         return API::InjectedBundle::FormClient::InputFieldAction::Cancel;
422     case WKInputFieldActionTypeInsertTab:
423         return API::InjectedBundle::FormClient::InputFieldAction::InsertTab;
424     case WKInputFieldActionTypeInsertNewline:
425         return API::InjectedBundle::FormClient::InputFieldAction::InsertNewline;
426     case WKInputFieldActionTypeInsertDelete:
427         return API::InjectedBundle::FormClient::InputFieldAction::InsertDelete;
428     case WKInputFieldActionTypeInsertBacktab:
429         return API::InjectedBundle::FormClient::InputFieldAction::InsertBacktab;
430     }
431
432     ASSERT_NOT_REACHED();
433     return API::InjectedBundle::FormClient::InputFieldAction::Cancel;
434 }
435
436 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
437 {
438     if (!is<HTMLInputElement>(*element))
439         return false;
440
441     WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0);
442     if (!getActionTypeForKeyEvent(event, actionType))
443         return false;
444
445     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
446     ASSERT(webFrame);
447
448     return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, downcast<HTMLInputElement>(element), toInputFieldAction(actionType), webFrame);
449 }
450
451 void WebEditorClient::textWillBeDeletedInTextField(Element* element)
452 {
453     if (!is<HTMLInputElement>(*element))
454         return;
455
456     WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame());
457     ASSERT(webFrame);
458
459     m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, downcast<HTMLInputElement>(element), toInputFieldAction(WKInputFieldActionTypeInsertDelete), webFrame);
460 }
461
462 bool WebEditorClient::shouldEraseMarkersAfterChangeSelection(WebCore::TextCheckingType type) const
463 {
464     // This prevents erasing spelling markers on OS X Lion or later to match AppKit on these Mac OS X versions.
465 #if PLATFORM(COCOA)
466     return type != TextCheckingTypeSpelling;
467 #else
468     UNUSED_PARAM(type);
469     return true;
470 #endif
471 }
472
473 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
474 {
475     m_page->send(Messages::WebPageProxy::IgnoreWord(word));
476 }
477
478 void WebEditorClient::learnWord(const String& word)
479 {
480     m_page->send(Messages::WebPageProxy::LearnWord(word));
481 }
482
483 void WebEditorClient::checkSpellingOfString(StringView text, int* misspellingLocation, int* misspellingLength)
484 {
485     int32_t resultLocation = -1;
486     int32_t resultLength = 0;
487     m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(text.toStringWithoutCopying()),
488         Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength));
489     *misspellingLocation = resultLocation;
490     *misspellingLength = resultLength;
491 }
492
493 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&)
494 {
495     notImplemented();
496     return String();
497 }
498
499 void WebEditorClient::checkGrammarOfString(StringView text, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength)
500 {
501     int32_t resultLocation = -1;
502     int32_t resultLength = 0;
503     m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(text.toStringWithoutCopying()),
504         Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength));
505     *badGrammarLocation = resultLocation;
506     *badGrammarLength = resultLength;
507 }
508
509 static int32_t insertionPointFromCurrentSelection(const VisibleSelection& currentSelection)
510 {
511     VisiblePosition selectionStart = currentSelection.visibleStart();
512     VisiblePosition paragraphStart = startOfParagraph(selectionStart);
513     return TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
514 }
515
516 #if USE(UNIFIED_TEXT_CHECKING)
517 Vector<TextCheckingResult> WebEditorClient::checkTextOfParagraph(StringView stringView, WebCore::TextCheckingTypeMask checkingTypes, const VisibleSelection& currentSelection)
518 {
519     Vector<TextCheckingResult> results;
520
521     m_page->sendSync(Messages::WebPageProxy::CheckTextOfParagraph(stringView.toStringWithoutCopying(), checkingTypes, insertionPointFromCurrentSelection(currentSelection)), Messages::WebPageProxy::CheckTextOfParagraph::Reply(results));
522
523     return results;
524 }
525 #endif
526
527 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
528 {
529     m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail));
530 }
531
532 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
533 {
534     m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord));
535 }
536
537 void WebEditorClient::showSpellingUI(bool)
538 {
539     notImplemented();
540 }
541
542 bool WebEditorClient::spellingUIIsShowing()
543 {
544     bool isShowing = false;
545     m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing));
546     return isShowing;
547 }
548
549 void WebEditorClient::getGuessesForWord(const String& word, const String& context, const VisibleSelection& currentSelection, Vector<String>& guesses)
550 {
551     m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context, insertionPointFromCurrentSelection(currentSelection)), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses));
552 }
553
554 void WebEditorClient::requestCheckingOfString(TextCheckingRequest& request, const WebCore::VisibleSelection& currentSelection)
555 {
556     uint64_t requestID = generateTextCheckingRequestID();
557     m_page->addTextCheckingRequest(requestID, request);
558
559     m_page->send(Messages::WebPageProxy::RequestCheckingOfString(requestID, request.data(), insertionPointFromCurrentSelection(currentSelection)));
560 }
561
562 void WebEditorClient::willSetInputMethodState()
563 {
564 }
565
566 void WebEditorClient::setInputMethodState(bool enabled)
567 {
568 #if PLATFORM(GTK)
569     m_page->setInputMethodState(enabled);
570 #else
571     notImplemented();
572     UNUSED_PARAM(enabled);
573 #endif
574 }
575
576 bool WebEditorClient::supportsGlobalSelection()
577 {
578 #if PLATFORM(GTK)
579 #if PLATFORM(X11)
580     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11)
581         return true;
582 #endif
583 #if PLATFORM(WAYLAND)
584     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland)
585         return true;
586 #endif
587 #endif
588     return false;
589 }
590
591 } // namespace WebKit