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