Make WebCore::EditorInsertAction an enum class
[WebKit-https.git] / Source / WebKit / win / WebCoreSupport / WebEditorClient.cpp
1 /*
2  * Copyright (C) 2006-2007, 2011, 2014-2015 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 : 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::shouldChangeTypingStyle(StyleProperties*, StyleProperties*)
378 {
379     notImplemented();
380     return false;
381 }
382
383 void WebEditorClient::webViewDidChangeTypingStyle(WebNotification* /*notification*/)
384 {
385     notImplemented();
386 }
387
388 void WebEditorClient::webViewDidChangeSelection(WebNotification* /*notification*/)
389 {
390     notImplemented();
391 }
392
393 bool WebEditorClient::smartInsertDeleteEnabled(void)
394 {
395     Page* page = m_webView->page();
396     if (!page)
397         return false;
398     return page->settings().smartInsertDeleteEnabled();
399 }
400
401 bool WebEditorClient::isSelectTrailingWhitespaceEnabled(void)
402 {
403     Page* page = m_webView->page();
404     if (!page)
405         return false;
406     return page->settings().selectTrailingWhitespaceEnabled();
407 }
408
409 void WebEditorClient::textFieldDidBeginEditing(Element* e)
410 {
411     IWebFormDelegate* formDelegate;
412     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
413         IDOMElement* domElement = DOMElement::createInstance(e);
414         if (domElement) {
415             IDOMHTMLInputElement* domInputElement;
416             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
417                 formDelegate->textFieldDidBeginEditing(domInputElement, kit(e->document().frame()));
418                 domInputElement->Release();
419             }
420             domElement->Release();
421         }
422         formDelegate->Release();
423     }
424 }
425
426 void WebEditorClient::textFieldDidEndEditing(Element* e)
427 {
428     IWebFormDelegate* formDelegate;
429     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
430         IDOMElement* domElement = DOMElement::createInstance(e);
431         if (domElement) {
432             IDOMHTMLInputElement* domInputElement;
433             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
434                 formDelegate->textFieldDidEndEditing(domInputElement, kit(e->document().frame()));
435                 domInputElement->Release();
436             }
437             domElement->Release();
438         }
439         formDelegate->Release();
440     }
441 }
442
443 void WebEditorClient::textDidChangeInTextField(Element* e)
444 {
445     if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != e)
446         return;
447
448     IWebFormDelegate* formDelegate;
449     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
450         IDOMElement* domElement = DOMElement::createInstance(e);
451         if (domElement) {
452             IDOMHTMLInputElement* domInputElement;
453             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
454                 formDelegate->textDidChangeInTextField(domInputElement, kit(e->document().frame()));
455                 domInputElement->Release();
456             }
457             domElement->Release();
458         }
459         formDelegate->Release();
460     }
461 }
462
463 bool WebEditorClient::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
464 {
465     BOOL result = FALSE;
466     IWebFormDelegate* formDelegate;
467     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
468         IDOMElement* domElement = DOMElement::createInstance(e);
469         if (domElement) {
470             IDOMHTMLInputElement* domInputElement;
471             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
472                 String command = m_webView->interpretKeyEvent(ke);
473                 // We allow empty commands here because the app code actually depends on this being called for all key presses.
474                 // We may want to revisit this later because it doesn't really make sense to send an empty command.
475                 formDelegate->doPlatformCommand(domInputElement, BString(command), kit(e->document().frame()), &result);
476                 domInputElement->Release();
477             }
478             domElement->Release();
479         }
480         formDelegate->Release();
481     }
482     return !!result;
483 }
484
485 void WebEditorClient::textWillBeDeletedInTextField(Element* e)
486 {
487     // We're using the deleteBackward command for all deletion operations since the autofill code treats all deletions the same way.
488     IWebFormDelegate* formDelegate;
489     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
490         IDOMElement* domElement = DOMElement::createInstance(e);
491         if (domElement) {
492             IDOMHTMLInputElement* domInputElement;
493             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
494                 BOOL result;
495                 formDelegate->doPlatformCommand(domInputElement, BString(L"DeleteBackward"), kit(e->document().frame()), &result);
496                 domInputElement->Release();
497             }
498             domElement->Release();
499         }
500         formDelegate->Release();
501     }
502 }
503
504 void WebEditorClient::textDidChangeInTextArea(Element* e)
505 {
506     IWebFormDelegate* formDelegate;
507     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
508         IDOMElement* domElement = DOMElement::createInstance(e);
509         if (domElement) {
510             IDOMHTMLTextAreaElement* domTextAreaElement;
511             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLTextAreaElement, (void**)&domTextAreaElement))) {
512                 formDelegate->textDidChangeInTextArea(domTextAreaElement, kit(e->document().frame()));
513                 domTextAreaElement->Release();
514             }
515             domElement->Release();
516         }
517         formDelegate->Release();
518     }
519 }
520
521 class WebEditorUndoCommand : public IWebUndoCommand
522 {
523 public:
524     WebEditorUndoCommand(PassRefPtr<UndoStep>, bool isUndo);
525     void execute();
526
527     // IUnknown
528     virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject);
529     virtual ULONG STDMETHODCALLTYPE AddRef();
530     virtual ULONG STDMETHODCALLTYPE Release();
531
532 private:
533     ULONG m_refCount;
534     RefPtr<UndoStep> m_step;
535     bool m_isUndo;
536 };
537
538 WebEditorUndoCommand::WebEditorUndoCommand(PassRefPtr<UndoStep> step, bool isUndo)
539     : m_step(step)
540     , m_isUndo(isUndo) 
541     , m_refCount(1)
542
543 }
544
545 void WebEditorUndoCommand::execute()
546 {
547     if (m_isUndo)
548         m_step->unapply();
549     else
550         m_step->reapply();
551 }
552
553 HRESULT WebEditorUndoCommand::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
554 {
555     if (!ppvObject)
556         return E_POINTER;
557     *ppvObject = nullptr;
558     if (IsEqualGUID(riid, IID_IUnknown))
559         *ppvObject = static_cast<IWebUndoCommand*>(this);
560     else if (IsEqualGUID(riid, IID_IWebUndoCommand))
561         *ppvObject = static_cast<IWebUndoCommand*>(this);
562     else
563         return E_NOINTERFACE;
564
565     AddRef();
566     return S_OK;
567 }
568
569 ULONG WebEditorUndoCommand::AddRef()
570 {
571     return ++m_refCount;
572 }
573
574 ULONG WebEditorUndoCommand::Release()
575 {
576     ULONG newRef = --m_refCount;
577     if (!newRef)
578         delete(this);
579
580     return newRef;
581 }
582
583 static String undoNameForEditAction(EditAction editAction)
584 {
585     switch (editAction) {
586     case EditActionUnspecified:
587     case EditActionInsertReplacement:
588         return String();
589     case EditActionSetColor: return WEB_UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name");
590     case EditActionSetBackgroundColor: return WEB_UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name");
591     case EditActionTurnOffKerning: return WEB_UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name");
592     case EditActionTightenKerning: return WEB_UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name");
593     case EditActionLoosenKerning: return WEB_UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name");
594     case EditActionUseStandardKerning: return WEB_UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name");
595     case EditActionTurnOffLigatures: return WEB_UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name");
596     case EditActionUseStandardLigatures: return WEB_UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name");
597     case EditActionUseAllLigatures: return WEB_UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name");
598     case EditActionRaiseBaseline: return WEB_UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name");
599     case EditActionLowerBaseline: return WEB_UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name");
600     case EditActionSetTraditionalCharacterShape: return WEB_UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name");
601     case EditActionSetFont: return WEB_UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name");
602     case EditActionChangeAttributes: return WEB_UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name");
603     case EditActionAlignLeft: return WEB_UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name");
604     case EditActionAlignRight: return WEB_UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name");
605     case EditActionCenter: return WEB_UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name");
606     case EditActionJustify: return WEB_UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name");
607     case EditActionSetWritingDirection: return WEB_UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name");
608     case EditActionSubscript: return WEB_UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name");
609     case EditActionSuperscript: return WEB_UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name");
610     case EditActionBold: return WEB_UI_STRING_KEY("Bold", "Bold (Undo action name)", "Undo action name");
611     case EditActionItalics: return WEB_UI_STRING_KEY("Italics", "Italics (Undo action name)", "Undo action name");
612     case EditActionUnderline: return WEB_UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name");
613     case EditActionOutline: return WEB_UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name");
614     case EditActionUnscript: return WEB_UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name");
615     case EditActionDeleteByDrag: return WEB_UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name");
616     case EditActionCut: return WEB_UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name");
617     case EditActionPaste: return WEB_UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name");
618     case EditActionPasteFont: return WEB_UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name");
619     case EditActionPasteRuler: return WEB_UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name");
620     case EditActionTypingDeleteSelection:
621     case EditActionTypingDeleteBackward:
622     case EditActionTypingDeleteForward:
623     case EditActionTypingDeleteWordBackward:
624     case EditActionTypingDeleteWordForward:
625     case EditActionTypingDeleteLineBackward:
626     case EditActionTypingDeleteLineForward:
627     case EditActionTypingInsertText:
628     case EditActionTypingInsertLineBreak:
629     case EditActionTypingInsertParagraph:
630         return WEB_UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
631     case EditActionCreateLink: return WEB_UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name");
632     case EditActionUnlink: return WEB_UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name");
633     case EditActionInsertUnorderedList:
634     case EditActionInsertOrderedList:
635         return WEB_UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name");
636     case EditActionFormatBlock: return WEB_UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name");
637     case EditActionIndent: return WEB_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
638     case EditActionOutdent: return WEB_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
639     }
640     return String();
641 }
642
643 void WebEditorClient::registerUndoStep(PassRefPtr<UndoStep> step)
644 {
645     IWebUIDelegate* uiDelegate = 0;
646     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
647         String actionName = undoNameForEditAction(step->editingAction());
648         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(step, true);
649         if (!undoCommand)
650             return;
651         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
652         undoCommand->Release(); // the undo manager owns the reference
653         if (!actionName.isEmpty())
654             uiDelegate->setActionTitle(BString(actionName));
655         uiDelegate->Release();
656     }
657 }
658
659 void WebEditorClient::registerRedoStep(PassRefPtr<UndoStep> step)
660 {
661     IWebUIDelegate* uiDelegate = 0;
662     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
663         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(step, false);
664         if (!undoCommand)
665             return;
666         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
667         undoCommand->Release(); // the undo manager owns the reference
668         uiDelegate->Release();
669     }
670 }
671
672 void WebEditorClient::clearUndoRedoOperations()
673 {
674     IWebUIDelegate* uiDelegate = 0;
675     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
676         uiDelegate->removeAllActionsWithTarget(m_undoTarget);
677         uiDelegate->Release();
678     }
679 }
680
681 bool WebEditorClient::canCopyCut(Frame*, bool defaultValue) const
682 {
683     return defaultValue;
684 }
685
686 bool WebEditorClient::canPaste(Frame*, bool defaultValue) const
687 {
688     return defaultValue;
689 }
690
691 bool WebEditorClient::canUndo() const
692 {
693     BOOL result = FALSE;
694     IWebUIDelegate* uiDelegate = 0;
695     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
696         uiDelegate->canUndo(&result);
697         uiDelegate->Release();
698     }
699     return !!result;
700 }
701
702 bool WebEditorClient::canRedo() const
703 {
704     BOOL result = FALSE;
705     IWebUIDelegate* uiDelegate = 0;
706     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
707         uiDelegate->canRedo(&result);
708         uiDelegate->Release();
709     }
710     return !!result;
711 }
712
713 void WebEditorClient::undo()
714 {
715     IWebUIDelegate* uiDelegate = 0;
716     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
717         uiDelegate->undo();
718         uiDelegate->Release();
719     }
720 }
721
722 void WebEditorClient::redo()
723 {
724     IWebUIDelegate* uiDelegate = 0;
725     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
726         uiDelegate->redo();
727         uiDelegate->Release();
728     }
729 }
730
731 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* evt)
732 {
733     if (m_webView->handleEditingKeyboardEvent(evt))
734         evt->setDefaultHandled();
735 }
736
737 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* )
738 {
739 }
740
741 bool WebEditorClient::shouldEraseMarkersAfterChangeSelection(TextCheckingType) const
742 {
743     return true;
744 }
745
746 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
747 {
748     COMPtr<IWebEditingDelegate> ed;
749     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
750         return;
751
752     initViewSpecificSpelling(m_webView);
753     ed->ignoreWordInSpellDocument(m_webView, BString(word));
754 }
755
756 void WebEditorClient::learnWord(const String& word)
757 {
758     COMPtr<IWebEditingDelegate> ed;
759     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
760         return;
761
762     ed->learnWord(BString(word));
763 }
764
765 void WebEditorClient::checkSpellingOfString(StringView text, int* misspellingLocation, int* misspellingLength)
766 {
767     *misspellingLocation = -1;
768     *misspellingLength = 0;
769
770     COMPtr<IWebEditingDelegate> ed;
771     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
772         return;
773
774     initViewSpecificSpelling(m_webView);
775     ed->checkSpellingOfString(m_webView, text.upconvertedCharacters(), text.length(), misspellingLocation, misspellingLength);
776 }
777
778 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord)
779 {
780     // This method can be implemented using customized algorithms for the particular browser.
781     // Currently, it computes an empty string.
782     return String();
783 }
784
785 void WebEditorClient::checkGrammarOfString(StringView text, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
786 {
787     details.clear();
788     *badGrammarLocation = -1;
789     *badGrammarLength = 0;
790
791     COMPtr<IWebEditingDelegate> ed;
792     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
793         return;
794
795     initViewSpecificSpelling(m_webView);
796     COMPtr<IEnumWebGrammarDetails> enumDetailsObj;
797     if (FAILED(ed->checkGrammarOfString(m_webView, text.upconvertedCharacters(), text.length(), &enumDetailsObj, badGrammarLocation, badGrammarLength)))
798         return;
799
800     while (true) {
801         ULONG fetched;
802         COMPtr<IWebGrammarDetail> detailObj;
803         if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK)
804             break;
805
806         GrammarDetail detail;
807         if (FAILED(detailObj->length(&detail.length)))
808             continue;
809         if (FAILED(detailObj->location(&detail.location)))
810             continue;
811         BString userDesc;
812         if (FAILED(detailObj->userDescription(&userDesc)))
813             continue;
814         detail.userDescription = String(userDesc, SysStringLen(userDesc));
815
816         COMPtr<IEnumSpellingGuesses> enumGuessesObj;
817         if (FAILED(detailObj->guesses(&enumGuessesObj)))
818             continue;
819         while (true) {
820             BString guess;
821             if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
822                 break;
823             detail.guesses.append(String(guess, SysStringLen(guess)));
824         }
825
826         details.append(detail);
827     }
828 }
829
830 void WebEditorClient::updateSpellingUIWithGrammarString(const String& string, const WebCore::GrammarDetail& detail)
831 {
832     COMPtr<IWebEditingDelegate> ed;
833     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
834         return;
835
836     Vector<BSTR> guessesBSTRs;
837     for (unsigned i = 0; i < detail.guesses.size(); i++) {
838         BString guess(detail.guesses[i]);
839         guessesBSTRs.append(guess.release());
840     }
841     BString userDescriptionBSTR(detail.userDescription);
842     ed->updateSpellingUIWithGrammarString(BString(string), detail.location, detail.length, userDescriptionBSTR, guessesBSTRs.data(), (int)guessesBSTRs.size());
843     for (unsigned i = 0; i < guessesBSTRs.size(); i++)
844         SysFreeString(guessesBSTRs[i]);
845 }
846
847 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& word)
848 {
849     COMPtr<IWebEditingDelegate> ed;
850     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
851         return;
852
853     ed->updateSpellingUIWithMisspelledWord(BString(word));
854 }
855
856 void WebEditorClient::showSpellingUI(bool show)
857 {
858     COMPtr<IWebEditingDelegate> ed;
859     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
860         return;
861     
862     ed->showSpellingUI(show);
863 }
864
865 bool WebEditorClient::spellingUIIsShowing()
866 {
867     COMPtr<IWebEditingDelegate> ed;
868     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
869         return false;
870
871     BOOL showing;
872     if (FAILED(ed->spellingUIIsShowing(&showing)))
873         return false;
874
875     return !!showing;
876 }
877
878 void WebEditorClient::getGuessesForWord(const String& word, const String& context, const VisibleSelection&, Vector<String>& guesses)
879 {
880     guesses.clear();
881
882     COMPtr<IWebEditingDelegate> ed;
883     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
884         return;
885
886     COMPtr<IEnumSpellingGuesses> enumGuessesObj;
887     if (FAILED(ed->guessesForWord(BString(word), &enumGuessesObj)))
888         return;
889
890     while (true) {
891         ULONG fetched;
892         BString guess;
893         if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
894             break;
895         guesses.append(String(guess, SysStringLen(guess)));
896     }
897 }
898
899 void WebEditorClient::willSetInputMethodState()
900 {
901 }
902
903 void WebEditorClient::setInputMethodState(bool enabled)
904 {
905     m_webView->setInputMethodState(enabled);
906 }