• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007 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 COMPUTER, 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 COMPUTER, 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 "config.h"
27 #include "WebKitDLL.h"
28 #include "WebEditorClient.h"
29 
30 #include "WebKit.h"
31 #include "WebLocalizableStrings.h"
32 #include "WebView.h"
33 #include "DOMCoreClasses.h"
34 #pragma warning(push, 0)
35 #include <WebCore/BString.h>
36 #include <WebCore/Document.h>
37 #include <WebCore/EditCommand.h>
38 #include <WebCore/HTMLElement.h>
39 #include <WebCore/HTMLInputElement.h>
40 #include <WebCore/HTMLNames.h>
41 #include <WebCore/KeyboardEvent.h>
42 #include <WebCore/PlatformKeyboardEvent.h>
43 #include <WebCore/NotImplemented.h>
44 #include <WebCore/Range.h>
45 #pragma warning(pop)
46 
47 using namespace WebCore;
48 using namespace HTMLNames;
49 
50 // {09A11D2B-FAFB-4ca0-A6F7-791EE8932C88}
51 static const GUID IID_IWebUndoCommand =
52 { 0x9a11d2b, 0xfafb, 0x4ca0, { 0xa6, 0xf7, 0x79, 0x1e, 0xe8, 0x93, 0x2c, 0x88 } };
53 
54 class IWebUndoCommand : public IUnknown {
55 public:
56     virtual void execute() = 0;
57 };
58 
59 // WebEditorUndoTarget -------------------------------------------------------------
60 
61 class WebEditorUndoTarget : public IWebUndoTarget
62 {
63 public:
64     WebEditorUndoTarget();
65 
66     // IUnknown
67     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
68     virtual ULONG STDMETHODCALLTYPE AddRef(void);
69     virtual ULONG STDMETHODCALLTYPE Release(void);
70 
71     // IWebUndoTarget
72     virtual HRESULT STDMETHODCALLTYPE invoke(
73         /* [in] */ BSTR actionName,
74         /* [in] */ IUnknown *obj);
75 
76 private:
77     ULONG m_refCount;
78 };
79 
WebEditorUndoTarget()80 WebEditorUndoTarget::WebEditorUndoTarget()
81 : m_refCount(1)
82 {
83 }
84 
QueryInterface(REFIID riid,void ** ppvObject)85 HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::QueryInterface(REFIID riid, void** ppvObject)
86 {
87     *ppvObject = 0;
88     if (IsEqualGUID(riid, IID_IUnknown))
89         *ppvObject = static_cast<IWebUndoTarget*>(this);
90     else if (IsEqualGUID(riid, IID_IWebUndoTarget))
91         *ppvObject = static_cast<IWebUndoTarget*>(this);
92     else
93         return E_NOINTERFACE;
94 
95     AddRef();
96     return S_OK;
97 }
98 
AddRef(void)99 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::AddRef(void)
100 {
101     return ++m_refCount;
102 }
103 
Release(void)104 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::Release(void)
105 {
106     ULONG newRef = --m_refCount;
107     if (!newRef)
108         delete(this);
109 
110     return newRef;
111 }
112 
invoke(BSTR,IUnknown * obj)113 HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::invoke(
114     /* [in] */ BSTR /*actionName*/,
115     /* [in] */ IUnknown *obj)
116 {
117     IWebUndoCommand* undoCommand = 0;
118     if (SUCCEEDED(obj->QueryInterface(IID_IWebUndoCommand, (void**)&undoCommand))) {
119         undoCommand->execute();
120         undoCommand->Release();
121     }
122     return S_OK;
123 }
124 
125 // WebEditorClient ------------------------------------------------------------------
126 
WebEditorClient(WebView * webView)127 WebEditorClient::WebEditorClient(WebView* webView)
128     : m_webView(webView)
129     , m_undoTarget(0)
130 {
131     m_undoTarget = new WebEditorUndoTarget();
132 }
133 
~WebEditorClient()134 WebEditorClient::~WebEditorClient()
135 {
136     if (m_undoTarget)
137         m_undoTarget->Release();
138 }
139 
pageDestroyed()140 void WebEditorClient::pageDestroyed()
141 {
142     delete this;
143 }
144 
isContinuousSpellCheckingEnabled()145 bool WebEditorClient::isContinuousSpellCheckingEnabled()
146 {
147     BOOL enabled;
148     if (FAILED(m_webView->isContinuousSpellCheckingEnabled(&enabled)))
149         return false;
150     return !!enabled;
151 }
152 
toggleContinuousSpellChecking()153 void WebEditorClient::toggleContinuousSpellChecking()
154 {
155     m_webView->toggleContinuousSpellChecking(0);
156 }
157 
isGrammarCheckingEnabled()158 bool WebEditorClient::isGrammarCheckingEnabled()
159 {
160     BOOL enabled;
161     if (FAILED(m_webView->isGrammarCheckingEnabled(&enabled)))
162         return false;
163     return !!enabled;
164 }
165 
toggleGrammarChecking()166 void WebEditorClient::toggleGrammarChecking()
167 {
168     m_webView->toggleGrammarChecking(0);
169 }
170 
initViewSpecificSpelling(IWebViewEditing * viewEditing)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 
spellCheckerDocumentTag()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 
shouldBeginEditing(Range *)187 bool WebEditorClient::shouldBeginEditing(Range*)
188 {
189     notImplemented();
190     return true;
191 }
192 
shouldEndEditing(Range *)193 bool WebEditorClient::shouldEndEditing(Range*)
194 {
195     notImplemented();
196     return true;
197 }
198 
didBeginEditing()199 void WebEditorClient::didBeginEditing()
200 {
201     notImplemented();
202 }
203 
respondToChangedContents()204 void WebEditorClient::respondToChangedContents()
205 {
206     notImplemented();
207 }
208 
respondToChangedSelection()209 void WebEditorClient::respondToChangedSelection()
210 {
211     m_webView->selectionChanged();
212 }
213 
didEndEditing()214 void WebEditorClient::didEndEditing()
215 {
216     notImplemented();
217 }
218 
didWriteSelectionToPasteboard()219 void WebEditorClient::didWriteSelectionToPasteboard()
220 {
221     notImplemented();
222 }
223 
didSetSelectionTypesForPasteboard()224 void WebEditorClient::didSetSelectionTypesForPasteboard()
225 {
226     notImplemented();
227 }
228 
shouldDeleteRange(Range *)229 bool WebEditorClient::shouldDeleteRange(Range* /*range*/)
230 {
231     notImplemented();
232     return true;
233 
234     // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented.
235     //BOOL result = false;
236     //IWebViewEditingDelegate* editingDelegate;
237     //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here
238     //IDOMRange* domRange(0);
239     //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) {
240     //    editingDelegate->shouldDeleteDOMRange(m_webView, domRange, &result);
241     //    editingDelegate->Release();
242     //}
243     //return !!result;
244 }
245 
shouldInsertNode(Node *,Range *,EditorInsertAction)246 bool WebEditorClient::shouldInsertNode(Node* /*node*/, Range* /*replacingRange*/, EditorInsertAction /*givenAction*/)
247 {
248     notImplemented();
249     return true;
250 }
251 
shouldInsertText(const String &,Range *,EditorInsertAction)252 bool WebEditorClient::shouldInsertText(const String& /*str*/, Range* /* replacingRange */, EditorInsertAction /*givenAction*/)
253 {
254     notImplemented();
255     return true;
256 
257     // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented.
258     //BOOL result = false;
259     //IWebViewEditingDelegate* editingDelegate;
260     //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here
261     //IDOMRange* domRange(0); // make a DOMRange from replacingRange
262     //BString text(str);
263     //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) {
264     //    editingDelegate->shouldInsertText(m_webView, text, domRange, (WebViewInsertAction) givenAction, &result);
265     //    editingDelegate->Release();
266     //}
267     //return !!result;
268 }
269 
270 //bool WebEditorClient::shouldChangeSelectedRange(Range *currentRange, Range *toProposedRange, SelectionAffinity selectionAffinity, bool stillSelecting)
271 //{ notImplemented(); return false; }
272 
shouldApplyStyle(CSSStyleDeclaration *,Range *)273 bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* /*style*/, Range* /*toElementsInDOMRange*/)
274 { notImplemented(); return true; }
275 
shouldMoveRangeAfterDelete(Range *,Range *)276 bool WebEditorClient::shouldMoveRangeAfterDelete(Range* /*range*/, Range* /*rangeToBeReplaced*/)
277 { notImplemented(); return true; }
278 
shouldChangeTypingStyle(CSSStyleDeclaration *,CSSStyleDeclaration *)279 bool WebEditorClient::shouldChangeTypingStyle(CSSStyleDeclaration* /*currentStyle*/, CSSStyleDeclaration* /*toProposedStyle*/)
280 { notImplemented(); return false; }
281 
webViewDidChangeTypingStyle(WebNotification *)282 void WebEditorClient::webViewDidChangeTypingStyle(WebNotification* /*notification*/)
283 {  notImplemented(); }
284 
webViewDidChangeSelection(WebNotification *)285 void WebEditorClient::webViewDidChangeSelection(WebNotification* /*notification*/)
286 {  notImplemented(); }
287 
shouldShowDeleteInterface(HTMLElement *)288 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* /*element*/)
289 { notImplemented(); return false; }
290 
smartInsertDeleteEnabled(void)291 bool WebEditorClient::smartInsertDeleteEnabled(void)
292 {
293     BOOL enabled = FALSE;
294     m_webView->smartInsertDeleteEnabled(&enabled);
295     return !!enabled;
296 }
297 
isSelectTrailingWhitespaceEnabled(void)298 bool WebEditorClient::isSelectTrailingWhitespaceEnabled(void)
299 {
300     BOOL enabled = FALSE;
301     m_webView->isSelectTrailingWhitespaceEnabled(&enabled);
302     return !!enabled;
303 }
304 
shouldChangeSelectedRange(WebCore::Range *,WebCore::Range *,WebCore::EAffinity,bool)305 bool WebEditorClient::shouldChangeSelectedRange(WebCore::Range*, WebCore::Range*, WebCore::EAffinity, bool)
306 { notImplemented(); return true; }
307 
textFieldDidBeginEditing(Element * e)308 void WebEditorClient::textFieldDidBeginEditing(Element* e)
309 {
310     IWebFormDelegate* formDelegate;
311     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
312         IDOMElement* domElement = DOMElement::createInstance(e);
313         if (domElement) {
314             IDOMHTMLInputElement* domInputElement;
315             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
316                 formDelegate->textFieldDidBeginEditing(domInputElement, kit(e->document()->frame()));
317                 domInputElement->Release();
318             }
319             domElement->Release();
320         }
321         formDelegate->Release();
322     }
323 }
324 
textFieldDidEndEditing(Element * e)325 void WebEditorClient::textFieldDidEndEditing(Element* e)
326 {
327     IWebFormDelegate* formDelegate;
328     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
329         IDOMElement* domElement = DOMElement::createInstance(e);
330         if (domElement) {
331             IDOMHTMLInputElement* domInputElement;
332             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
333                 formDelegate->textFieldDidEndEditing(domInputElement, kit(e->document()->frame()));
334                 domInputElement->Release();
335             }
336             domElement->Release();
337         }
338         formDelegate->Release();
339     }
340 }
341 
textDidChangeInTextField(Element * e)342 void WebEditorClient::textDidChangeInTextField(Element* e)
343 {
344     IWebFormDelegate* formDelegate;
345     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
346         IDOMElement* domElement = DOMElement::createInstance(e);
347         if (domElement) {
348             IDOMHTMLInputElement* domInputElement;
349             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
350                 formDelegate->textDidChangeInTextField(domInputElement, kit(e->document()->frame()));
351                 domInputElement->Release();
352             }
353             domElement->Release();
354         }
355         formDelegate->Release();
356     }
357 }
358 
doTextFieldCommandFromEvent(Element * e,KeyboardEvent * ke)359 bool WebEditorClient::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
360 {
361     BOOL result = FALSE;
362     IWebFormDelegate* formDelegate;
363     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
364         IDOMElement* domElement = DOMElement::createInstance(e);
365         if (domElement) {
366             IDOMHTMLInputElement* domInputElement;
367             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
368                 String command = m_webView->interpretKeyEvent(ke);
369                 // We allow empty commands here because the app code actually depends on this being called for all key presses.
370                 // We may want to revisit this later because it doesn't really make sense to send an empty command.
371                 formDelegate->doPlatformCommand(domInputElement, BString(command), kit(e->document()->frame()), &result);
372                 domInputElement->Release();
373             }
374             domElement->Release();
375         }
376         formDelegate->Release();
377     }
378     return !!result;
379 }
380 
textWillBeDeletedInTextField(Element * e)381 void WebEditorClient::textWillBeDeletedInTextField(Element* e)
382 {
383     // We're using the deleteBackward command for all deletion operations since the autofill code treats all deletions the same way.
384     IWebFormDelegate* formDelegate;
385     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
386         IDOMElement* domElement = DOMElement::createInstance(e);
387         if (domElement) {
388             IDOMHTMLInputElement* domInputElement;
389             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
390                 BOOL result;
391                 formDelegate->doPlatformCommand(domInputElement, BString(L"DeleteBackward"), kit(e->document()->frame()), &result);
392                 domInputElement->Release();
393             }
394             domElement->Release();
395         }
396         formDelegate->Release();
397     }
398 }
399 
textDidChangeInTextArea(Element * e)400 void WebEditorClient::textDidChangeInTextArea(Element* e)
401 {
402     IWebFormDelegate* formDelegate;
403     if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
404         IDOMElement* domElement = DOMElement::createInstance(e);
405         if (domElement) {
406             IDOMHTMLTextAreaElement* domTextAreaElement;
407             if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLTextAreaElement, (void**)&domTextAreaElement))) {
408                 formDelegate->textDidChangeInTextArea(domTextAreaElement, kit(e->document()->frame()));
409                 domTextAreaElement->Release();
410             }
411             domElement->Release();
412         }
413         formDelegate->Release();
414     }
415 }
416 
417 class WebEditorUndoCommand : public IWebUndoCommand
418 {
419 public:
420     WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo);
421     void execute();
422 
423     // IUnknown
424     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
425     virtual ULONG STDMETHODCALLTYPE AddRef(void);
426     virtual ULONG STDMETHODCALLTYPE Release(void);
427 
428 private:
429     ULONG m_refCount;
430     RefPtr<EditCommand> m_editCommand;
431     bool m_isUndo;
432 };
433 
WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand,bool isUndo)434 WebEditorUndoCommand::WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo)
435     : m_editCommand(editCommand)
436     , m_isUndo(isUndo)
437     , m_refCount(1)
438 {
439 }
440 
execute()441 void WebEditorUndoCommand::execute()
442 {
443     if (m_isUndo)
444         m_editCommand->unapply();
445     else
446         m_editCommand->reapply();
447 }
448 
QueryInterface(REFIID riid,void ** ppvObject)449 HRESULT STDMETHODCALLTYPE WebEditorUndoCommand::QueryInterface(REFIID riid, void** ppvObject)
450 {
451     *ppvObject = 0;
452     if (IsEqualGUID(riid, IID_IUnknown))
453         *ppvObject = static_cast<IWebUndoCommand*>(this);
454     else if (IsEqualGUID(riid, IID_IWebUndoCommand))
455         *ppvObject = static_cast<IWebUndoCommand*>(this);
456     else
457         return E_NOINTERFACE;
458 
459     AddRef();
460     return S_OK;
461 }
462 
AddRef(void)463 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::AddRef(void)
464 {
465     return ++m_refCount;
466 }
467 
Release(void)468 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::Release(void)
469 {
470     ULONG newRef = --m_refCount;
471     if (!newRef)
472         delete(this);
473 
474     return newRef;
475 }
476 
undoNameForEditAction(EditAction editAction)477 static LPCTSTR undoNameForEditAction(EditAction editAction)
478 {
479     switch (editAction) {
480         case EditActionUnspecified: return 0;
481         case EditActionSetColor: return LPCTSTR_UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name");
482         case EditActionSetBackgroundColor: return LPCTSTR_UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name");
483         case EditActionTurnOffKerning: return LPCTSTR_UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name");
484         case EditActionTightenKerning: return LPCTSTR_UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name");
485         case EditActionLoosenKerning: return LPCTSTR_UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name");
486         case EditActionUseStandardKerning: return LPCTSTR_UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name");
487         case EditActionTurnOffLigatures: return LPCTSTR_UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name");
488         case EditActionUseStandardLigatures: return LPCTSTR_UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name");
489         case EditActionUseAllLigatures: return LPCTSTR_UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name");
490         case EditActionRaiseBaseline: return LPCTSTR_UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name");
491         case EditActionLowerBaseline: return LPCTSTR_UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name");
492         case EditActionSetTraditionalCharacterShape: return LPCTSTR_UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name");
493         case EditActionSetFont: return LPCTSTR_UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name");
494         case EditActionChangeAttributes: return LPCTSTR_UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name");
495         case EditActionAlignLeft: return LPCTSTR_UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name");
496         case EditActionAlignRight: return LPCTSTR_UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name");
497         case EditActionCenter: return LPCTSTR_UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name");
498         case EditActionJustify: return LPCTSTR_UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name");
499         case EditActionSetWritingDirection: return LPCTSTR_UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name");
500         case EditActionSubscript: return LPCTSTR_UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name");
501         case EditActionSuperscript: return LPCTSTR_UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name");
502         case EditActionUnderline: return LPCTSTR_UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name");
503         case EditActionOutline: return LPCTSTR_UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name");
504         case EditActionUnscript: return LPCTSTR_UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name");
505         case EditActionDrag: return LPCTSTR_UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name");
506         case EditActionCut: return LPCTSTR_UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name");
507         case EditActionPaste: return LPCTSTR_UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name");
508         case EditActionPasteFont: return LPCTSTR_UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name");
509         case EditActionPasteRuler: return LPCTSTR_UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name");
510         case EditActionTyping: return LPCTSTR_UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
511         case EditActionCreateLink: return LPCTSTR_UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name");
512         case EditActionUnlink: return LPCTSTR_UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name");
513         case EditActionInsertList: return LPCTSTR_UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name");
514         case EditActionFormatBlock: return LPCTSTR_UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name");
515         case EditActionIndent: return LPCTSTR_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
516         case EditActionOutdent: return LPCTSTR_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
517     }
518     return 0;
519 }
520 
registerCommandForUndo(PassRefPtr<EditCommand> command)521 void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command)
522 {
523     IWebUIDelegate* uiDelegate = 0;
524     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
525         LPCTSTR actionName = undoNameForEditAction(command->editingAction());
526         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, true);
527         if (!undoCommand)
528             return;
529         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
530         undoCommand->Release(); // the undo manager owns the reference
531         BSTR actionNameBSTR = SysAllocString(actionName);
532         if (actionNameBSTR) {
533             uiDelegate->setActionTitle(actionNameBSTR);
534             SysFreeString(actionNameBSTR);
535         }
536         uiDelegate->Release();
537     }
538 }
539 
registerCommandForRedo(PassRefPtr<EditCommand> command)540 void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand> command)
541 {
542     IWebUIDelegate* uiDelegate = 0;
543     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
544         WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, false);
545         if (!undoCommand)
546             return;
547         uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
548         undoCommand->Release(); // the undo manager owns the reference
549         uiDelegate->Release();
550     }
551 }
552 
clearUndoRedoOperations()553 void WebEditorClient::clearUndoRedoOperations()
554 {
555     IWebUIDelegate* uiDelegate = 0;
556     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
557         uiDelegate->removeAllActionsWithTarget(m_undoTarget);
558         uiDelegate->Release();
559     }
560 }
561 
canUndo() const562 bool WebEditorClient::canUndo() const
563 {
564     BOOL result = FALSE;
565     IWebUIDelegate* uiDelegate = 0;
566     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
567         uiDelegate->canUndo(&result);
568         uiDelegate->Release();
569     }
570     return !!result;
571 }
572 
canRedo() const573 bool WebEditorClient::canRedo() const
574 {
575     BOOL result = FALSE;
576     IWebUIDelegate* uiDelegate = 0;
577     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
578         uiDelegate->canRedo(&result);
579         uiDelegate->Release();
580     }
581     return !!result;
582 }
583 
undo()584 void WebEditorClient::undo()
585 {
586     IWebUIDelegate* uiDelegate = 0;
587     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
588         uiDelegate->undo();
589         uiDelegate->Release();
590     }
591 }
592 
redo()593 void WebEditorClient::redo()
594 {
595     IWebUIDelegate* uiDelegate = 0;
596     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
597         uiDelegate->redo();
598         uiDelegate->Release();
599     }
600 }
601 
handleKeyboardEvent(KeyboardEvent * evt)602 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* evt)
603 {
604     if (m_webView->handleEditingKeyboardEvent(evt))
605         evt->setDefaultHandled();
606 }
607 
handleInputMethodKeydown(KeyboardEvent *)608 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* )
609 {
610 }
611 
isEditable()612 bool WebEditorClient::isEditable()
613 {
614     return false;
615 }
616 
ignoreWordInSpellDocument(const String & word)617 void WebEditorClient::ignoreWordInSpellDocument(const String& word)
618 {
619     COMPtr<IWebEditingDelegate> ed;
620     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
621         return;
622 
623     initViewSpecificSpelling(m_webView);
624     ed->ignoreWordInSpellDocument(m_webView, BString(word));
625 }
626 
learnWord(const String & word)627 void WebEditorClient::learnWord(const String& word)
628 {
629     COMPtr<IWebEditingDelegate> ed;
630     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
631         return;
632 
633     ed->learnWord(BString(word));
634 }
635 
checkSpellingOfString(const UChar * text,int length,int * misspellingLocation,int * misspellingLength)636 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
637 {
638     *misspellingLocation = -1;
639     *misspellingLength = 0;
640 
641     COMPtr<IWebEditingDelegate> ed;
642     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
643         return;
644 
645     initViewSpecificSpelling(m_webView);
646     ed->checkSpellingOfString(m_webView, text, length, misspellingLocation, misspellingLength);
647 }
648 
getAutoCorrectSuggestionForMisspelledWord(const String & inputWord)649 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord)
650 {
651     // This method can be implemented using customized algorithms for the particular browser.
652     // Currently, it computes an empty string.
653     return String();
654 }
655 
checkGrammarOfString(const UChar * text,int length,Vector<GrammarDetail> & details,int * badGrammarLocation,int * badGrammarLength)656 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
657 {
658     details.clear();
659     *badGrammarLocation = -1;
660     *badGrammarLength = 0;
661 
662     COMPtr<IWebEditingDelegate> ed;
663     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
664         return;
665 
666     initViewSpecificSpelling(m_webView);
667     COMPtr<IEnumWebGrammarDetails> enumDetailsObj;
668     if (FAILED(ed->checkGrammarOfString(m_webView, text, length, &enumDetailsObj, badGrammarLocation, badGrammarLength)))
669         return;
670 
671     while (true) {
672         ULONG fetched;
673         COMPtr<IWebGrammarDetail> detailObj;
674         if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK)
675             break;
676 
677         GrammarDetail detail;
678         if (FAILED(detailObj->length(&detail.length)))
679             continue;
680         if (FAILED(detailObj->location(&detail.location)))
681             continue;
682         BSTR userDesc;
683         if (FAILED(detailObj->userDescription(&userDesc)))
684             continue;
685         detail.userDescription = String(userDesc, SysStringLen(userDesc));
686         SysFreeString(userDesc);
687 
688         COMPtr<IEnumSpellingGuesses> enumGuessesObj;
689         if (FAILED(detailObj->guesses(&enumGuessesObj)))
690             continue;
691         while (true) {
692             BSTR guess;
693             if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
694                 break;
695             detail.guesses.append(String(guess, SysStringLen(guess)));
696             SysFreeString(guess);
697         }
698 
699         details.append(detail);
700     }
701 }
702 
updateSpellingUIWithGrammarString(const String & string,const WebCore::GrammarDetail & detail)703 void WebEditorClient::updateSpellingUIWithGrammarString(const String& string, const WebCore::GrammarDetail& detail)
704 {
705     COMPtr<IWebEditingDelegate> ed;
706     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
707         return;
708 
709     Vector<BSTR> guessesBSTRs;
710     for (unsigned i = 0; i < detail.guesses.size(); i++) {
711         BString guess(detail.guesses[i]);
712         guessesBSTRs.append(guess.release());
713     }
714     BString userDescriptionBSTR(detail.userDescription);
715     ed->updateSpellingUIWithGrammarString(BString(string), detail.location, detail.length, userDescriptionBSTR, guessesBSTRs.data(), (int)guessesBSTRs.size());
716     for (unsigned i = 0; i < guessesBSTRs.size(); i++)
717         SysFreeString(guessesBSTRs[i]);
718 }
719 
updateSpellingUIWithMisspelledWord(const String & word)720 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& word)
721 {
722     COMPtr<IWebEditingDelegate> ed;
723     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
724         return;
725 
726     ed->updateSpellingUIWithMisspelledWord(BString(word));
727 }
728 
showSpellingUI(bool show)729 void WebEditorClient::showSpellingUI(bool show)
730 {
731     COMPtr<IWebEditingDelegate> ed;
732     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
733         return;
734 
735     ed->showSpellingUI(show);
736 }
737 
spellingUIIsShowing()738 bool WebEditorClient::spellingUIIsShowing()
739 {
740     COMPtr<IWebEditingDelegate> ed;
741     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
742         return false;
743 
744     BOOL showing;
745     if (FAILED(ed->spellingUIIsShowing(&showing)))
746         return false;
747 
748     return !!showing;
749 }
750 
getGuessesForWord(const String & word,Vector<String> & guesses)751 void WebEditorClient::getGuessesForWord(const String& word, Vector<String>& guesses)
752 {
753     guesses.clear();
754 
755     COMPtr<IWebEditingDelegate> ed;
756     if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
757         return;
758 
759     COMPtr<IEnumSpellingGuesses> enumGuessesObj;
760     if (FAILED(ed->guessesForWord(BString(word), &enumGuessesObj)))
761         return;
762 
763     while (true) {
764         ULONG fetched;
765         BSTR guess;
766         if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
767             break;
768         guesses.append(String(guess, SysStringLen(guess)));
769         SysFreeString(guess);
770     }
771 }
772 
setInputMethodState(bool enabled)773 void WebEditorClient::setInputMethodState(bool enabled)
774 {
775     m_webView->setInputMethodState(enabled);
776 }
777