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