aae1e000f8fac98e372294001c69c4c70ed53ff9
[WebKit-https.git] / Source / WebKitLegacy / win / WebCoreSupport / WebEditorClient.cpp
1 /*
2  * Copyright (C) 2006-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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "WebKitDLL.h"
27 #include "WebEditorClient.h"
28
29 #include "WebKit.h"
30 #include "WebNotification.h"
31 #include "WebNotificationCenter.h"
32 #include "WebView.h"
33 #include "DOMCoreClasses.h"
34 #include <comutil.h>
35 #include <WebCore/BString.h>
36 #include <WebCore/Document.h>
37 #include <WebCore/HTMLElement.h>
38 #include <WebCore/HTMLInputElement.h>
39 #include <WebCore/HTMLNames.h>
40 #include <WebCore/KeyboardEvent.h>
41 #include <WebCore/LocalizedStrings.h>
42 #include <WebCore/NotImplemented.h>
43 #include <WebCore/Page.h>
44 #include <WebCore/PlatformKeyboardEvent.h>
45 #include <WebCore/Range.h>
46 #include <WebCore/Settings.h>
47 #include <WebCore/UndoStep.h>
48 #include <WebCore/UserTypingGestureIndicator.h>
49 #include <WebCore/VisibleSelection.h>
50 #include <wtf/text/StringView.h>
51
52 using namespace WebCore;
53 using namespace HTMLNames;
54
55 // {09A11D2B-FAFB-4ca0-A6F7-791EE8932C88}
56 static const GUID IID_IWebUndoCommand = 
57 { 0x9a11d2b, 0xfafb, 0x4ca0, { 0xa6, 0xf7, 0x79, 0x1e, 0xe8, 0x93, 0x2c, 0x88 } };
58
59 class IWebUndoCommand : public IUnknown {
60 public:
61     virtual void execute() = 0;
62 };
63
64 // WebEditorUndoTarget -------------------------------------------------------------
65
66 class WebEditorUndoTarget final : public IWebUndoTarget
67 {
68 public:
69     WebEditorUndoTarget();
70
71     // IUnknown
72     virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject);
73     virtual ULONG STDMETHODCALLTYPE AddRef();
74     virtual ULONG STDMETHODCALLTYPE Release();
75
76     // IWebUndoTarget
77     virtual HRESULT STDMETHODCALLTYPE invoke( 
78         /* [in] */ BSTR actionName,
79         /* [in] */ IUnknown *obj);
80
81 private:
82     ULONG m_refCount;
83 };
84
85 WebEditorUndoTarget::WebEditorUndoTarget()
86 : m_refCount(1)
87 {
88 }
89
90 HRESULT WebEditorUndoTarget::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
91 {
92     if (!ppvObject)
93         return E_POINTER;
94     *ppvObject = nullptr;
95     if (IsEqualGUID(riid, IID_IUnknown))
96         *ppvObject = static_cast<IWebUndoTarget*>(this);
97     else if (IsEqualGUID(riid, IID_IWebUndoTarget))
98         *ppvObject = static_cast<IWebUndoTarget*>(this);
99     else
100         return E_NOINTERFACE;
101
102     AddRef();
103     return S_OK;
104 }
105
106 ULONG WebEditorUndoTarget::AddRef()
107 {
108     return ++m_refCount;
109 }
110
111 ULONG WebEditorUndoTarget::Release()
112 {
113     ULONG newRef = --m_refCount;
114     if (!newRef)
115         delete(this);
116
117     return newRef;
118 }
119
120 HRESULT WebEditorUndoTarget::invoke(/* [in] */ BSTR /*actionName*/, /* [in] */ IUnknown *obj)
121 {
122     IWebUndoCommand* undoCommand = 0;
123     if (SUCCEEDED(obj->QueryInterface(IID_IWebUndoCommand, (void**)&undoCommand))) {
124         undoCommand->execute();
125         undoCommand->Release();
126     }
127     return S_OK;
128 }
129
130 // WebEditorClient ------------------------------------------------------------------
131
132 WebEditorClient::WebEditorClient(WebView* webView)
133     : m_webView(webView)
134     , m_undoTarget(0)
135 {
136     m_undoTarget = new WebEditorUndoTarget();
137 }
138
139 WebEditorClient::~WebEditorClient()
140 {
141     if (m_undoTarget)
142         m_undoTarget->Release();
143 }
144
145 bool WebEditorClient::isContinuousSpellCheckingEnabled()
146 {
147     BOOL enabled;
148     if (FAILED(m_webView->isContinuousSpellCheckingEnabled(&enabled)))
149         return false;
150     return !!enabled;
151 }
152
153 void WebEditorClient::toggleContinuousSpellChecking()
154 {
155     m_webView->toggleContinuousSpellChecking(0);
156 }
157
158 bool WebEditorClient::isGrammarCheckingEnabled()
159 {
160     BOOL enabled;
161     if (FAILED(m_webView->isGrammarCheckingEnabled(&enabled)))
162         return false;
163     return !!enabled;
164 }
165
166 void WebEditorClient::toggleGrammarChecking()
167 {
168     m_webView->toggleGrammarChecking(0);
169 }
170
171 static void initViewSpecificSpelling(IWebViewEditing* viewEditing)
172 {
173     // we just use this as a flag to indicate that we've spell checked the document
174     // and need to close the spell checker out when the view closes.
175     int tag;
176     viewEditing->spellCheckerDocumentTag(&tag);
177 }
178
179 int WebEditorClient::spellCheckerDocumentTag()
180 {
181     // we don't use the concept of spelling tags
182     notImplemented();
183     ASSERT_NOT_REACHED();
184     return 0;
185 }
186
187 bool WebEditorClient::shouldBeginEditing(WebCore::Range* range)
188 {
189     COMPtr<IWebEditingDelegate> ed;
190     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
191         return true;
192
193     COMPtr<IDOMRange> currentRange(AdoptCOM, DOMRange::createInstance(range));
194
195     BOOL shouldBegin = FALSE;
196     if (FAILED(ed->shouldBeginEditingInDOMRange(m_webView, currentRange.get(), &shouldBegin)))
197         return true;
198
199     return shouldBegin;
200 }
201
202 bool WebEditorClient::shouldEndEditing(Range* range)
203 {
204     COMPtr<IWebEditingDelegate> ed;
205     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
206         return true;
207
208     COMPtr<IDOMRange> currentRange(AdoptCOM, DOMRange::createInstance(range));
209
210     BOOL shouldEnd = FALSE;
211     if (FAILED(ed->shouldEndEditingInDOMRange(m_webView, currentRange.get(), &shouldEnd)))
212         return true;
213
214     return shouldEnd;
215 }
216
217 void WebEditorClient::didBeginEditing()
218 {
219     static _bstr_t webViewDidBeginEditingNotificationName(WebViewDidBeginEditingNotification);
220     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
221     notifyCenter->postNotificationName(webViewDidBeginEditingNotificationName.GetBSTR(), static_cast<IWebView*>(m_webView), nullptr);
222 }
223
224 void WebEditorClient::respondToChangedContents()
225 {
226     static _bstr_t webViewDidChangeNotificationName(WebViewDidChangeNotification);
227     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
228     notifyCenter->postNotificationName(webViewDidChangeNotificationName.GetBSTR(), static_cast<IWebView*>(m_webView), 0);
229 }
230
231 void WebEditorClient::respondToChangedSelection(Frame*)
232 {
233     m_webView->selectionChanged();
234
235     static _bstr_t webViewDidChangeSelectionNotificationName(WebViewDidChangeSelectionNotification);
236     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
237     notifyCenter->postNotificationName(webViewDidChangeSelectionNotificationName.GetBSTR(), static_cast<IWebView*>(m_webView), 0);
238 }
239
240 void WebEditorClient::discardedComposition(Frame*)
241 {
242     notImplemented();
243 }
244
245 void WebEditorClient::canceledComposition()
246 {
247     notImplemented();
248 }
249
250 void WebEditorClient::didEndEditing()
251 {
252     static _bstr_t webViewDidEndEditingNotificationName(WebViewDidEndEditingNotification);
253     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
254     notifyCenter->postNotificationName(webViewDidEndEditingNotificationName.GetBSTR(), static_cast<IWebView*>(m_webView), nullptr);
255 }
256
257 void WebEditorClient::didWriteSelectionToPasteboard()
258 {
259     notImplemented();
260 }
261
262 void WebEditorClient::willWriteSelectionToPasteboard(WebCore::Range*)
263 {
264     notImplemented();
265 }
266
267 void WebEditorClient::getClientPasteboardDataForRange(WebCore::Range*, Vector<String>&, Vector<RefPtr<WebCore::SharedBuffer> >&)
268 {
269     notImplemented();
270 }
271
272 bool WebEditorClient::shouldDeleteRange(Range* range)
273 {
274     COMPtr<IWebEditingDelegate> ed;
275     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
276         return true;
277
278     COMPtr<IDOMRange> currentRange(AdoptCOM, DOMRange::createInstance(range));
279
280     BOOL shouldDelete = FALSE;
281     if (FAILED(ed->shouldDeleteDOMRange(m_webView, currentRange.get(), &shouldDelete)))
282         return true;
283
284     return shouldDelete;
285 }
286
287 static WebViewInsertAction kit(EditorInsertAction action)
288 {
289     switch (action) {
290     case EditorInsertAction::Typed:
291         return WebViewInsertActionTyped;
292     case EditorInsertAction::Pasted:
293         return WebViewInsertActionPasted;
294     case EditorInsertAction::Dropped:
295         return WebViewInsertActionDropped;
296     }
297
298     ASSERT_NOT_REACHED();
299     return WebViewInsertActionTyped;
300 }
301
302 bool WebEditorClient::shouldInsertNode(Node* node, Range* insertingRange, EditorInsertAction givenAction)
303
304     COMPtr<IWebEditingDelegate> editingDelegate;
305     if (FAILED(m_webView->editingDelegate(&editingDelegate)) || !editingDelegate.get())
306         return true;
307
308     COMPtr<IDOMRange> insertingDOMRange(AdoptCOM, DOMRange::createInstance(insertingRange));
309     if (!insertingDOMRange)
310         return true;
311
312     COMPtr<IDOMNode> insertDOMNode(AdoptCOM, DOMNode::createInstance(node));
313     if (!insertDOMNode)
314         return true;
315
316     BOOL shouldInsert = FALSE;
317     COMPtr<IWebEditingDelegate2> editingDelegate2(Query, editingDelegate);
318     if (editingDelegate2) {
319         if (FAILED(editingDelegate2->shouldInsertNode(m_webView, insertDOMNode.get(), insertingDOMRange.get(), kit(givenAction), &shouldInsert)))
320             return true;
321     }
322
323     return shouldInsert;
324 }
325
326 bool WebEditorClient::shouldInsertText(const String& str, Range* insertingRange, EditorInsertAction givenAction)
327 {
328     COMPtr<IWebEditingDelegate> editingDelegate;
329     if (FAILED(m_webView->editingDelegate(&editingDelegate)) || !editingDelegate.get())
330         return true;
331
332     COMPtr<IDOMRange> insertingDOMRange(AdoptCOM, DOMRange::createInstance(insertingRange));
333     if (!insertingDOMRange)
334         return true;
335
336     BString text(str);
337     BOOL shouldInsert = FALSE;
338     if (FAILED(editingDelegate->shouldInsertText(m_webView, text, insertingDOMRange.get(), kit(givenAction), &shouldInsert)))
339         return true;
340
341     return shouldInsert;
342 }
343
344 bool WebEditorClient::shouldChangeSelectedRange(WebCore::Range* currentRange, WebCore::Range* proposedRange, WebCore::EAffinity selectionAffinity, bool flag)
345 {
346     COMPtr<IWebEditingDelegate> ed;
347     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
348         return true;
349
350     COMPtr<IDOMRange> currentIDOMRange(AdoptCOM, DOMRange::createInstance(currentRange));
351     COMPtr<IDOMRange> proposedIDOMRange(AdoptCOM, DOMRange::createInstance(proposedRange));
352
353     BOOL shouldChange = FALSE;
354     if (FAILED(ed->shouldChangeSelectedDOMRange(m_webView, currentIDOMRange.get(), proposedIDOMRange.get(), static_cast<WebSelectionAffinity>(selectionAffinity), flag, &shouldChange)))
355         return true;
356
357     return shouldChange;
358 }
359
360 bool WebEditorClient::shouldApplyStyle(StyleProperties*, Range*)
361 {
362     notImplemented();
363     return true;
364 }
365
366 void WebEditorClient::didApplyStyle()
367 {
368     notImplemented();
369 }
370
371 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*)
372 {
373     notImplemented();
374     return true;
375 }
376
377 bool WebEditorClient::smartInsertDeleteEnabled(void)
378 {
379     Page* page = m_webView->page();
380     if (!page)
381         return false;
382     return page->settings().smartInsertDeleteEnabled();
383 }
384
385 bool WebEditorClient::isSelectTrailingWhitespaceEnabled(void) const
386 {
387     Page* page = m_webView->page();
388     if (!page)
389         return false;
390     return page->settings().selectTrailingWhitespaceEnabled();
391 }
392
393 void WebEditorClient::textFieldDidBeginEditing(Element* e)
394 {
395     IWebFormDelegate* formDelegate;
396     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
397         IDOMElement* domElement = DOMElement::createInstance(e);
398         if (domElement) {
399             IDOMHTMLInputElement* domInputElement;
400             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
401                 formDelegate->textFieldDidBeginEditing(domInputElement, kit(e->document().frame()));
402                 domInputElement->Release();
403             }
404             domElement->Release();
405         }
406         formDelegate->Release();
407     }
408 }
409
410 void WebEditorClient::textFieldDidEndEditing(Element* e)
411 {
412     IWebFormDelegate* formDelegate;
413     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
414         IDOMElement* domElement = DOMElement::createInstance(e);
415         if (domElement) {
416             IDOMHTMLInputElement* domInputElement;
417             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
418                 formDelegate->textFieldDidEndEditing(domInputElement, kit(e->document().frame()));
419                 domInputElement->Release();
420             }
421             domElement->Release();
422         }
423         formDelegate->Release();
424     }
425 }
426
427 void WebEditorClient::textDidChangeInTextField(Element* e)
428 {
429     if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != e)
430         return;
431
432     IWebFormDelegate* formDelegate;
433     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
434         IDOMElement* domElement = DOMElement::createInstance(e);
435         if (domElement) {
436             IDOMHTMLInputElement* domInputElement;
437             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
438                 formDelegate->textDidChangeInTextField(domInputElement, kit(e->document().frame()));
439                 domInputElement->Release();
440             }
441             domElement->Release();
442         }
443         formDelegate->Release();
444     }
445 }
446
447 bool WebEditorClient::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
448 {
449     BOOL result = FALSE;
450     IWebFormDelegate* formDelegate;
451     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
452         IDOMElement* domElement = DOMElement::createInstance(e);
453         if (domElement) {
454             IDOMHTMLInputElement* domInputElement;
455             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
456                 String command = m_webView->interpretKeyEvent(ke);
457                 // We allow empty commands here because the app code actually depends on this being called for all key presses.
458                 // We may want to revisit this later because it doesn't really make sense to send an empty command.
459                 formDelegate->doPlatformCommand(domInputElement, BString(command), kit(e->document().frame()), &result);
460                 domInputElement->Release();
461             }
462             domElement->Release();
463         }
464         formDelegate->Release();
465     }
466     return !!result;
467 }
468
469 void WebEditorClient::textWillBeDeletedInTextField(Element* e)
470 {
471     // We're using the deleteBackward command for all deletion operations since the autofill code treats all deletions the same way.
472     IWebFormDelegate* formDelegate;
473     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
474         IDOMElement* domElement = DOMElement::createInstance(e);
475         if (domElement) {
476             IDOMHTMLInputElement* domInputElement;
477             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
478                 BOOL result;
479                 formDelegate->doPlatformCommand(domInputElement, BString(L"DeleteBackward"), kit(e->document().frame()), &result);
480                 domInputElement->Release();
481             }
482             domElement->Release();
483         }
484         formDelegate->Release();
485     }
486 }
487
488 void WebEditorClient::textDidChangeInTextArea(Element* e)
489 {
490     IWebFormDelegate* formDelegate;
491     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
492         IDOMElement* domElement = DOMElement::createInstance(e);
493         if (domElement) {
494             IDOMHTMLTextAreaElement* domTextAreaElement;
495             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLTextAreaElement, (void**)&domTextAreaElement))) {
496                 formDelegate->textDidChangeInTextArea(domTextAreaElement, kit(e->document().frame()));
497                 domTextAreaElement->Release();
498             }
499             domElement->Release();
500         }
501         formDelegate->Release();
502     }
503 }
504
505 class WebEditorUndoCommand final : public IWebUndoCommand
506 {
507 public:
508     WebEditorUndoCommand(UndoStep&, bool isUndo);
509     void execute();
510
511     // IUnknown
512     virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject);
513     virtual ULONG STDMETHODCALLTYPE AddRef();
514     virtual ULONG STDMETHODCALLTYPE Release();
515
516 private:
517     ULONG m_refCount;
518     Ref<UndoStep> m_step;
519     bool m_isUndo;
520 };
521
522 WebEditorUndoCommand::WebEditorUndoCommand(UndoStep& step, bool isUndo)
523     : m_step(step)
524     , m_isUndo(isUndo) 
525     , m_refCount(1)
526
527 }
528
529 void WebEditorUndoCommand::execute()
530 {
531     if (m_isUndo)
532         m_step->unapply();
533     else
534         m_step->reapply();
535 }
536
537 HRESULT WebEditorUndoCommand::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
538 {
539     if (!ppvObject)
540         return E_POINTER;
541     *ppvObject = nullptr;
542     if (IsEqualGUID(riid, IID_IUnknown))
543         *ppvObject = static_cast<IWebUndoCommand*>(this);
544     else if (IsEqualGUID(riid, IID_IWebUndoCommand))
545         *ppvObject = static_cast<IWebUndoCommand*>(this);
546     else
547         return E_NOINTERFACE;
548
549     AddRef();
550     return S_OK;
551 }
552
553 ULONG WebEditorUndoCommand::AddRef()
554 {
555     return ++m_refCount;
556 }
557
558 ULONG WebEditorUndoCommand::Release()
559 {
560     ULONG newRef = --m_refCount;
561     if (!newRef)
562         delete(this);
563
564     return newRef;
565 }
566
567 static String undoNameForEditAction(EditAction editAction)
568 {
569     switch (editAction) {
570     case EditAction::Unspecified:
571     case EditAction::InsertReplacement:
572         return String();
573     case EditAction::SetColor: return WEB_UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name");
574     case EditAction::SetBackgroundColor: return WEB_UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name");
575     case EditAction::TurnOffKerning: return WEB_UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name");
576     case EditAction::TightenKerning: return WEB_UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name");
577     case EditAction::LoosenKerning: return WEB_UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name");
578     case EditAction::UseStandardKerning: return WEB_UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name");
579     case EditAction::TurnOffLigatures: return WEB_UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name");
580     case EditAction::UseStandardLigatures: return WEB_UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name");
581     case EditAction::UseAllLigatures: return WEB_UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name");
582     case EditAction::RaiseBaseline: return WEB_UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name");
583     case EditAction::LowerBaseline: return WEB_UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name");
584     case EditAction::SetTraditionalCharacterShape: return WEB_UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name");
585     case EditAction::SetFont: return WEB_UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name");
586     case EditAction::ChangeAttributes: return WEB_UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name");
587     case EditAction::AlignLeft: return WEB_UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name");
588     case EditAction::AlignRight: return WEB_UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name");
589     case EditAction::Center: return WEB_UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name");
590     case EditAction::Justify: return WEB_UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name");
591     case EditAction::SetInlineWritingDirection:
592     case EditAction::SetBlockWritingDirection:
593         return WEB_UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name");
594     case EditAction::Subscript: return WEB_UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name");
595     case EditAction::Superscript: return WEB_UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name");
596     case EditAction::Bold: return WEB_UI_STRING_KEY("Bold", "Bold (Undo action name)", "Undo action name");
597     case EditAction::Italics: return WEB_UI_STRING_KEY("Italics", "Italics (Undo action name)", "Undo action name");
598     case EditAction::Underline: return WEB_UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name");
599     case EditAction::Outline: return WEB_UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name");
600     case EditAction::Unscript: return WEB_UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name");
601     case EditAction::DeleteByDrag: return WEB_UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name");
602     case EditAction::Cut: return WEB_UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name");
603     case EditAction::Paste: return WEB_UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name");
604     case EditAction::PasteFont: return WEB_UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name");
605     case EditAction::PasteRuler: return WEB_UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name");
606     case EditAction::TypingDeleteSelection:
607     case EditAction::TypingDeleteBackward:
608     case EditAction::TypingDeleteForward:
609     case EditAction::TypingDeleteWordBackward:
610     case EditAction::TypingDeleteWordForward:
611     case EditAction::TypingDeleteLineBackward:
612     case EditAction::TypingDeleteLineForward:
613     case EditAction::TypingInsertText:
614     case EditAction::TypingInsertLineBreak:
615     case EditAction::TypingInsertParagraph:
616         return WEB_UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
617     case EditAction::CreateLink: return WEB_UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name");
618     case EditAction::Unlink: return WEB_UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name");
619     case EditAction::InsertUnorderedList:
620     case EditAction::InsertOrderedList:
621         return WEB_UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name");
622     case EditAction::FormatBlock: return WEB_UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name");
623     case EditAction::Indent: return WEB_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
624     case EditAction::Outdent: return WEB_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
625     }
626     return String();
627 }
628
629 void WebEditorClient::registerUndoStep(UndoStep& step)
630 {
631     IWebUIDelegate* uiDelegate = 0;
632     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
633         String actionName = undoNameForEditAction(step.editingAction());
634         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(step, true);
635         if (!undoCommand)
636             return;
637         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
638         undoCommand->Release(); // the undo manager owns the reference
639         if (!actionName.isEmpty())
640             uiDelegate->setActionTitle(BString(actionName));
641         uiDelegate->Release();
642     }
643 }
644
645 void WebEditorClient::registerRedoStep(UndoStep& step)
646 {
647     IWebUIDelegate* uiDelegate = 0;
648     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
649         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(step, false);
650         if (!undoCommand)
651             return;
652         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
653         undoCommand->Release(); // the undo manager owns the reference
654         uiDelegate->Release();
655     }
656 }
657
658 void WebEditorClient::clearUndoRedoOperations()
659 {
660     IWebUIDelegate* uiDelegate = 0;
661     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
662         uiDelegate->removeAllActionsWithTarget(m_undoTarget);
663         uiDelegate->Release();
664     }
665 }
666
667 bool WebEditorClient::canCopyCut(Frame*, bool defaultValue) const
668 {
669     return defaultValue;
670 }
671
672 bool WebEditorClient::canPaste(Frame*, bool defaultValue) const
673 {
674     return defaultValue;
675 }
676
677 bool WebEditorClient::canUndo() const
678 {
679     BOOL result = FALSE;
680     IWebUIDelegate* uiDelegate = 0;
681     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
682         uiDelegate->canUndo(&result);
683         uiDelegate->Release();
684     }
685     return !!result;
686 }
687
688 bool WebEditorClient::canRedo() const
689 {
690     BOOL result = FALSE;
691     IWebUIDelegate* uiDelegate = 0;
692     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
693         uiDelegate->canRedo(&result);
694         uiDelegate->Release();
695     }
696     return !!result;
697 }
698
699 void WebEditorClient::undo()
700 {
701     IWebUIDelegate* uiDelegate = 0;
702     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
703         uiDelegate->undo();
704         uiDelegate->Release();
705     }
706 }
707
708 void WebEditorClient::redo()
709 {
710     IWebUIDelegate* uiDelegate = 0;
711     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
712         uiDelegate->redo();
713         uiDelegate->Release();
714     }
715 }
716
717 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* evt)
718 {
719     if (m_webView->handleEditingKeyboardEvent(evt))
720         evt->setDefaultHandled();
721 }
722
723 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* )
724 {
725 }
726
727 bool WebEditorClient::shouldEraseMarkersAfterChangeSelection(TextCheckingType) const
728 {
729     return true;
730 }
731
732 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
733 {
734     COMPtr<IWebEditingDelegate> ed;
735     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
736         return;
737
738     initViewSpecificSpelling(m_webView);
739     ed->ignoreWordInSpellDocument(m_webView, BString(word));
740 }
741
742 void WebEditorClient::learnWord(const String& word)
743 {
744     COMPtr<IWebEditingDelegate> ed;
745     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
746         return;
747
748     ed->learnWord(BString(word));
749 }
750
751 void WebEditorClient::checkSpellingOfString(StringView text, int* misspellingLocation, int* misspellingLength)
752 {
753     *misspellingLocation = -1;
754     *misspellingLength = 0;
755
756     COMPtr<IWebEditingDelegate> ed;
757     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
758         return;
759
760     initViewSpecificSpelling(m_webView);
761     ed->checkSpellingOfString(m_webView, text.upconvertedCharacters(), text.length(), misspellingLocation, misspellingLength);
762 }
763
764 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord)
765 {
766     // This method can be implemented using customized algorithms for the particular browser.
767     // Currently, it computes an empty string.
768     return String();
769 }
770
771 void WebEditorClient::checkGrammarOfString(StringView text, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
772 {
773     details.clear();
774     *badGrammarLocation = -1;
775     *badGrammarLength = 0;
776
777     COMPtr<IWebEditingDelegate> ed;
778     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
779         return;
780
781     initViewSpecificSpelling(m_webView);
782     COMPtr<IEnumWebGrammarDetails> enumDetailsObj;
783     if (FAILED(ed->checkGrammarOfString(m_webView, text.upconvertedCharacters(), text.length(), &enumDetailsObj, badGrammarLocation, badGrammarLength)))
784         return;
785
786     while (true) {
787         ULONG fetched;
788         COMPtr<IWebGrammarDetail> detailObj;
789         if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK)
790             break;
791
792         GrammarDetail detail;
793         if (FAILED(detailObj->length(&detail.length)))
794             continue;
795         if (FAILED(detailObj->location(&detail.location)))
796             continue;
797         BString userDesc;
798         if (FAILED(detailObj->userDescription(&userDesc)))
799             continue;
800         detail.userDescription = String(userDesc, SysStringLen(userDesc));
801
802         COMPtr<IEnumSpellingGuesses> enumGuessesObj;
803         if (FAILED(detailObj->guesses(&enumGuessesObj)))
804             continue;
805         while (true) {
806             BString guess;
807             if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
808                 break;
809             detail.guesses.append(String(guess, SysStringLen(guess)));
810         }
811
812         details.append(detail);
813     }
814 }
815
816 void WebEditorClient::updateSpellingUIWithGrammarString(const String& string, const WebCore::GrammarDetail& detail)
817 {
818     COMPtr<IWebEditingDelegate> ed;
819     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
820         return;
821
822     Vector<BSTR> guessesBSTRs;
823     for (unsigned i = 0; i < detail.guesses.size(); i++) {
824         BString guess(detail.guesses[i]);
825         guessesBSTRs.append(guess.release());
826     }
827     BString userDescriptionBSTR(detail.userDescription);
828     ed->updateSpellingUIWithGrammarString(BString(string), detail.location, detail.length, userDescriptionBSTR, guessesBSTRs.data(), (int)guessesBSTRs.size());
829     for (unsigned i = 0; i < guessesBSTRs.size(); i++)
830         SysFreeString(guessesBSTRs[i]);
831 }
832
833 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& word)
834 {
835     COMPtr<IWebEditingDelegate> ed;
836     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
837         return;
838
839     ed->updateSpellingUIWithMisspelledWord(BString(word));
840 }
841
842 void WebEditorClient::showSpellingUI(bool show)
843 {
844     COMPtr<IWebEditingDelegate> ed;
845     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
846         return;
847     
848     ed->showSpellingUI(show);
849 }
850
851 bool WebEditorClient::spellingUIIsShowing()
852 {
853     COMPtr<IWebEditingDelegate> ed;
854     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
855         return false;
856
857     BOOL showing;
858     if (FAILED(ed->spellingUIIsShowing(&showing)))
859         return false;
860
861     return !!showing;
862 }
863
864 void WebEditorClient::getGuessesForWord(const String& word, const String& context, const VisibleSelection&, Vector<String>& guesses)
865 {
866     guesses.clear();
867
868     COMPtr<IWebEditingDelegate> ed;
869     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
870         return;
871
872     COMPtr<IEnumSpellingGuesses> enumGuessesObj;
873     if (FAILED(ed->guessesForWord(BString(word), &enumGuessesObj)))
874         return;
875
876     while (true) {
877         ULONG fetched;
878         BString guess;
879         if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
880             break;
881         guesses.append(String(guess, SysStringLen(guess)));
882     }
883 }
884
885 void WebEditorClient::willSetInputMethodState()
886 {
887 }
888
889 void WebEditorClient::setInputMethodState(bool enabled)
890 {
891     m_webView->setInputMethodState(enabled);
892 }