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