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