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