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