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 82 WebEditorUndoTarget::WebEditorUndoTarget() 83 : m_refCount(1) 84 { 85 } 86 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 101 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::AddRef(void) 102 { 103 return ++m_refCount; 104 } 105 106 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::Release(void) 107 { 108 ULONG newRef = --m_refCount; 109 if (!newRef) 110 delete(this); 111 112 return newRef; 113 } 114 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 129 WebEditorClient::WebEditorClient(WebView* webView) 130 : m_webView(webView) 131 , m_undoTarget(0) 132 { 133 m_undoTarget = new WebEditorUndoTarget(); 134 } 135 136 WebEditorClient::~WebEditorClient() 137 { 138 if (m_undoTarget) 139 m_undoTarget->Release(); 140 } 141 142 void WebEditorClient::pageDestroyed() 143 { 144 delete this; 145 } 146 147 bool WebEditorClient::isContinuousSpellCheckingEnabled() 148 { 149 BOOL enabled; 150 if (FAILED(m_webView->isContinuousSpellCheckingEnabled(&enabled))) 151 return false; 152 return !!enabled; 153 } 154 155 void WebEditorClient::toggleContinuousSpellChecking() 156 { 157 m_webView->toggleContinuousSpellChecking(0); 158 } 159 160 bool WebEditorClient::isGrammarCheckingEnabled() 161 { 162 BOOL enabled; 163 if (FAILED(m_webView->isGrammarCheckingEnabled(&enabled))) 164 return false; 165 return !!enabled; 166 } 167 168 void WebEditorClient::toggleGrammarChecking() 169 { 170 m_webView->toggleGrammarChecking(0); 171 } 172 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 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 189 bool WebEditorClient::shouldBeginEditing(Range*) 190 { 191 notImplemented(); 192 return true; 193 } 194 195 bool WebEditorClient::shouldEndEditing(Range*) 196 { 197 notImplemented(); 198 return true; 199 } 200 201 void WebEditorClient::didBeginEditing() 202 { 203 notImplemented(); 204 } 205 206 void WebEditorClient::respondToChangedContents() 207 { 208 notImplemented(); 209 } 210 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 220 void WebEditorClient::didEndEditing() 221 { 222 notImplemented(); 223 } 224 225 void WebEditorClient::didWriteSelectionToPasteboard() 226 { 227 notImplemented(); 228 } 229 230 void WebEditorClient::didSetSelectionTypesForPasteboard() 231 { 232 notImplemented(); 233 } 234 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 252 bool WebEditorClient::shouldInsertNode(Node* /*node*/, Range* /*replacingRange*/, EditorInsertAction /*givenAction*/) 253 { 254 notImplemented(); 255 return true; 256 } 257 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 279 bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* /*style*/, Range* /*toElementsInDOMRange*/) 280 { notImplemented(); return true; } 281 282 bool WebEditorClient::shouldMoveRangeAfterDelete(Range* /*range*/, Range* /*rangeToBeReplaced*/) 283 { notImplemented(); return true; } 284 285 bool WebEditorClient::shouldChangeTypingStyle(CSSStyleDeclaration* /*currentStyle*/, CSSStyleDeclaration* /*toProposedStyle*/) 286 { notImplemented(); return false; } 287 288 void WebEditorClient::webViewDidChangeTypingStyle(WebNotification* /*notification*/) 289 { notImplemented(); } 290 291 void WebEditorClient::webViewDidChangeSelection(WebNotification* /*notification*/) 292 { notImplemented(); } 293 294 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* /*element*/) 295 { notImplemented(); return false; } 296 297 bool WebEditorClient::smartInsertDeleteEnabled(void) 298 { 299 BOOL enabled = FALSE; 300 m_webView->smartInsertDeleteEnabled(&enabled); 301 return !!enabled; 302 } 303 304 bool WebEditorClient::isSelectTrailingWhitespaceEnabled(void) 305 { 306 BOOL enabled = FALSE; 307 m_webView->isSelectTrailingWhitespaceEnabled(&enabled); 308 return !!enabled; 309 } 310 311 bool WebEditorClient::shouldChangeSelectedRange(WebCore::Range*, WebCore::Range*, WebCore::EAffinity, bool) 312 { notImplemented(); return true; } 313 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 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 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 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 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 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 440 WebEditorUndoCommand::WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo) 441 : m_editCommand(editCommand) 442 , m_isUndo(isUndo) 443 , m_refCount(1) 444 { 445 } 446 447 void WebEditorUndoCommand::execute() 448 { 449 if (m_isUndo) 450 m_editCommand->unapply(); 451 else 452 m_editCommand->reapply(); 453 } 454 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 469 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::AddRef(void) 470 { 471 return ++m_refCount; 472 } 473 474 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::Release(void) 475 { 476 ULONG newRef = --m_refCount; 477 if (!newRef) 478 delete(this); 479 480 return newRef; 481 } 482 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 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 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 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 568 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 579 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 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 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 608 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* evt) 609 { 610 if (m_webView->handleEditingKeyboardEvent(evt)) 611 evt->setDefaultHandled(); 612 } 613 614 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* ) 615 { 616 } 617 618 bool WebEditorClient::isEditable() 619 { 620 return false; 621 } 622 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 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 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 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 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 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 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 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 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 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 779 void WebEditorClient::setInputMethodState(bool enabled) 780 { 781 m_webView->setInputMethodState(enabled); 782 } 783