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/EditCommand.h>
39 #include <WebCore/FocusController.h>
40 #include <WebCore/Frame.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/UserTypingGestureIndicator.h>
48
49 using namespace WebCore;
50 using namespace HTMLNames;
51
52 namespace WebKit {
53
pageDestroyed()54 void WebEditorClient::pageDestroyed()
55 {
56 delete this;
57 }
58
shouldDeleteRange(Range * range)59 bool WebEditorClient::shouldDeleteRange(Range* range)
60 {
61 bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(m_page, range);
62 notImplemented();
63 return result;
64 }
65
shouldShowDeleteInterface(HTMLElement *)66 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement*)
67 {
68 notImplemented();
69 return false;
70 }
71
smartInsertDeleteEnabled()72 bool WebEditorClient::smartInsertDeleteEnabled()
73 {
74 // FIXME: Why isn't this Mac specific like toggleSmartInsertDeleteEnabled?
75 #if PLATFORM(MAC)
76 return m_page->isSmartInsertDeleteEnabled();
77 #else
78 return true;
79 #endif
80 }
81
isSelectTrailingWhitespaceEnabled()82 bool WebEditorClient::isSelectTrailingWhitespaceEnabled()
83 {
84 notImplemented();
85 return false;
86 }
87
isContinuousSpellCheckingEnabled()88 bool WebEditorClient::isContinuousSpellCheckingEnabled()
89 {
90 return WebProcess::shared().textCheckerState().isContinuousSpellCheckingEnabled;
91 }
92
toggleContinuousSpellChecking()93 void WebEditorClient::toggleContinuousSpellChecking()
94 {
95 notImplemented();
96 }
97
isGrammarCheckingEnabled()98 bool WebEditorClient::isGrammarCheckingEnabled()
99 {
100 return WebProcess::shared().textCheckerState().isGrammarCheckingEnabled;
101 }
102
toggleGrammarChecking()103 void WebEditorClient::toggleGrammarChecking()
104 {
105 notImplemented();
106 }
107
spellCheckerDocumentTag()108 int WebEditorClient::spellCheckerDocumentTag()
109 {
110 notImplemented();
111 return false;
112 }
113
114
isEditable()115 bool WebEditorClient::isEditable()
116 {
117 notImplemented();
118 return false;
119 }
120
121
shouldBeginEditing(Range * range)122 bool WebEditorClient::shouldBeginEditing(Range* range)
123 {
124 bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(m_page, range);
125 notImplemented();
126 return result;
127 }
128
shouldEndEditing(Range * range)129 bool WebEditorClient::shouldEndEditing(Range* range)
130 {
131 bool result = m_page->injectedBundleEditorClient().shouldEndEditing(m_page, range);
132 notImplemented();
133 return result;
134 }
135
shouldInsertNode(Node * node,Range * rangeToReplace,EditorInsertAction action)136 bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action)
137 {
138 bool result = m_page->injectedBundleEditorClient().shouldInsertNode(m_page, node, rangeToReplace, action);
139 notImplemented();
140 return result;
141 }
142
shouldInsertText(const String & text,Range * rangeToReplace,EditorInsertAction action)143 bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action)
144 {
145 bool result = m_page->injectedBundleEditorClient().shouldInsertText(m_page, text.impl(), rangeToReplace, action);
146 notImplemented();
147 return result;
148 }
149
shouldChangeSelectedRange(Range * fromRange,Range * toRange,EAffinity affinity,bool stillSelecting)150 bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
151 {
152 bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(m_page, fromRange, toRange, affinity, stillSelecting);
153 notImplemented();
154 return result;
155 }
156
shouldApplyStyle(CSSStyleDeclaration * style,Range * range)157 bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
158 {
159 bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(m_page, style, range);
160 notImplemented();
161 return result;
162 }
163
shouldMoveRangeAfterDelete(Range *,Range *)164 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
165 {
166 notImplemented();
167 return true;
168 }
169
didBeginEditing()170 void WebEditorClient::didBeginEditing()
171 {
172 // FIXME: What good is a notification name, if it's always the same?
173 DEFINE_STATIC_LOCAL(String, WebViewDidBeginEditingNotification, ("WebViewDidBeginEditingNotification"));
174 m_page->injectedBundleEditorClient().didBeginEditing(m_page, WebViewDidBeginEditingNotification.impl());
175 notImplemented();
176 }
177
respondToChangedContents()178 void WebEditorClient::respondToChangedContents()
179 {
180 DEFINE_STATIC_LOCAL(String, WebViewDidChangeNotification, ("WebViewDidChangeNotification"));
181 m_page->injectedBundleEditorClient().didChange(m_page, WebViewDidChangeNotification.impl());
182 notImplemented();
183 }
184
respondToChangedSelection()185 void WebEditorClient::respondToChangedSelection()
186 {
187 DEFINE_STATIC_LOCAL(String, WebViewDidChangeSelectionNotification, ("WebViewDidChangeSelectionNotification"));
188 m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl());
189 Frame* frame = m_page->corePage()->focusController()->focusedFrame();
190 if (!frame)
191 return;
192
193 m_page->send(Messages::WebPageProxy::EditorStateChanged(m_page->editorState()));
194
195 #if PLATFORM(WIN)
196 // FIXME: This should also go into the selection state.
197 if (!frame->editor()->hasComposition() || frame->editor()->ignoreCompositionSelectionChange())
198 return;
199
200 unsigned start;
201 unsigned end;
202 m_page->send(Messages::WebPageProxy::DidChangeCompositionSelection(frame->editor()->getCompositionSelection(start, end)));
203 #endif
204 }
205
didEndEditing()206 void WebEditorClient::didEndEditing()
207 {
208 DEFINE_STATIC_LOCAL(String, WebViewDidEndEditingNotification, ("WebViewDidEndEditingNotification"));
209 m_page->injectedBundleEditorClient().didEndEditing(m_page, WebViewDidEndEditingNotification.impl());
210 notImplemented();
211 }
212
didWriteSelectionToPasteboard()213 void WebEditorClient::didWriteSelectionToPasteboard()
214 {
215 notImplemented();
216 }
217
didSetSelectionTypesForPasteboard()218 void WebEditorClient::didSetSelectionTypesForPasteboard()
219 {
220 notImplemented();
221 }
222
registerCommandForUndo(PassRefPtr<EditCommand> command)223 void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command)
224 {
225 // FIXME: Add assertion that the command being reapplied is the same command that is
226 // being passed to us.
227 if (m_page->isInRedo())
228 return;
229
230 RefPtr<WebEditCommand> webCommand = WebEditCommand::create(command);
231 m_page->addWebEditCommand(webCommand->commandID(), webCommand.get());
232 uint32_t editAction = static_cast<uint32_t>(webCommand->command()->editingAction());
233
234 m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webCommand->commandID(), editAction));
235 }
236
registerCommandForRedo(PassRefPtr<EditCommand>)237 void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand>)
238 {
239 }
240
clearUndoRedoOperations()241 void WebEditorClient::clearUndoRedoOperations()
242 {
243 m_page->send(Messages::WebPageProxy::ClearAllEditCommands());
244 }
245
canCopyCut(bool defaultValue) const246 bool WebEditorClient::canCopyCut(bool defaultValue) const
247 {
248 return defaultValue;
249 }
250
canPaste(bool defaultValue) const251 bool WebEditorClient::canPaste(bool defaultValue) const
252 {
253 return defaultValue;
254 }
255
canUndo() const256 bool WebEditorClient::canUndo() const
257 {
258 bool result = false;
259 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
260 return result;
261 }
262
canRedo() const263 bool WebEditorClient::canRedo() const
264 {
265 bool result = false;
266 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result));
267 return result;
268 }
269
undo()270 void WebEditorClient::undo()
271 {
272 bool result = false;
273 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
274 }
275
redo()276 void WebEditorClient::redo()
277 {
278 bool result = false;
279 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result));
280 }
281
282 #if !PLATFORM(GTK) && !PLATFORM(MAC)
handleKeyboardEvent(KeyboardEvent * event)283 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
284 {
285 if (m_page->handleEditingKeyboardEvent(event))
286 event->setDefaultHandled();
287 }
288
handleInputMethodKeydown(KeyboardEvent *)289 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
290 {
291 notImplemented();
292 }
293 #endif
294
textFieldDidBeginEditing(Element * element)295 void WebEditorClient::textFieldDidBeginEditing(Element* element)
296 {
297 if (!element->hasTagName(inputTag))
298 return;
299
300 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
301 m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
302 }
303
textFieldDidEndEditing(Element * element)304 void WebEditorClient::textFieldDidEndEditing(Element* element)
305 {
306 if (!element->hasTagName(inputTag))
307 return;
308
309 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
310 m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame);
311 }
312
textDidChangeInTextField(Element * element)313 void WebEditorClient::textDidChangeInTextField(Element* element)
314 {
315 if (!element->hasTagName(inputTag))
316 return;
317
318 if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element)
319 return;
320
321 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
322 m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, static_cast<HTMLInputElement*>(element), webFrame);
323 }
324
textDidChangeInTextArea(Element * element)325 void WebEditorClient::textDidChangeInTextArea(Element* element)
326 {
327 if (!element->hasTagName(textareaTag))
328 return;
329
330 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
331 m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, static_cast<HTMLTextAreaElement*>(element), webFrame);
332 }
333
getActionTypeForKeyEvent(KeyboardEvent * event,WKInputFieldActionType & type)334 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type)
335 {
336 String key = event->keyIdentifier();
337 if (key == "Up")
338 type = WKInputFieldActionTypeMoveUp;
339 else if (key == "Down")
340 type = WKInputFieldActionTypeMoveDown;
341 else if (key == "U+001B")
342 type = WKInputFieldActionTypeCancel;
343 else if (key == "U+0009") {
344 if (event->shiftKey())
345 type = WKInputFieldActionTypeInsertBacktab;
346 else
347 type = WKInputFieldActionTypeInsertTab;
348 } else if (key == "Enter")
349 type = WKInputFieldActionTypeInsertNewline;
350 else
351 return false;
352
353 return true;
354 }
355
doTextFieldCommandFromEvent(Element * element,KeyboardEvent * event)356 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event)
357 {
358 if (!element->hasTagName(inputTag))
359 return false;
360
361 WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0);
362 if (!getActionTypeForKeyEvent(event, actionType))
363 return false;
364
365 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
366 return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), actionType, webFrame);
367 }
368
textWillBeDeletedInTextField(Element * element)369 void WebEditorClient::textWillBeDeletedInTextField(Element* element)
370 {
371 if (!element->hasTagName(inputTag))
372 return;
373
374 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame();
375 m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame);
376 }
377
ignoreWordInSpellDocument(const String & word)378 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
379 {
380 m_page->send(Messages::WebPageProxy::IgnoreWord(word));
381 }
382
learnWord(const String & word)383 void WebEditorClient::learnWord(const String& word)
384 {
385 m_page->send(Messages::WebPageProxy::LearnWord(word));
386 }
387
checkSpellingOfString(const UChar * text,int length,int * misspellingLocation,int * misspellingLength)388 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
389 {
390 int32_t resultLocation = -1;
391 int32_t resultLength = 0;
392 // FIXME: It would be nice if we wouldn't have to copy the text here.
393 m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(String(text, length)),
394 Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength));
395 *misspellingLocation = resultLocation;
396 *misspellingLength = resultLength;
397 }
398
getAutoCorrectSuggestionForMisspelledWord(const String &)399 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&)
400 {
401 notImplemented();
402 return String();
403 }
404
checkGrammarOfString(const UChar * text,int length,Vector<WebCore::GrammarDetail> & grammarDetails,int * badGrammarLocation,int * badGrammarLength)405 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength)
406 {
407 int32_t resultLocation = -1;
408 int32_t resultLength = 0;
409 // FIXME: It would be nice if we wouldn't have to copy the text here.
410 m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(String(text, length)),
411 Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength));
412 *badGrammarLocation = resultLocation;
413 *badGrammarLength = resultLength;
414 }
415
updateSpellingUIWithGrammarString(const String & badGrammarPhrase,const GrammarDetail & grammarDetail)416 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
417 {
418 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail));
419 }
420
updateSpellingUIWithMisspelledWord(const String & misspelledWord)421 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
422 {
423 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord));
424 }
425
showSpellingUI(bool)426 void WebEditorClient::showSpellingUI(bool)
427 {
428 notImplemented();
429 }
430
spellingUIIsShowing()431 bool WebEditorClient::spellingUIIsShowing()
432 {
433 bool isShowing = false;
434 m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing));
435 return isShowing;
436 }
437
getGuessesForWord(const String & word,const String & context,Vector<String> & guesses)438 void WebEditorClient::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses)
439 {
440 m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses));
441 }
442
willSetInputMethodState()443 void WebEditorClient::willSetInputMethodState()
444 {
445 notImplemented();
446 }
447
setInputMethodState(bool)448 void WebEditorClient::setInputMethodState(bool)
449 {
450 notImplemented();
451 }
452
requestCheckingOfString(WebCore::SpellChecker *,int,WebCore::TextCheckingTypeMask,const WTF::String &)453 void WebEditorClient::requestCheckingOfString(WebCore::SpellChecker*, int, WebCore::TextCheckingTypeMask, const WTF::String&)
454 {
455 notImplemented();
456 }
457
458 } // namespace WebKit
459