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