Home | History | Annotate | Download | only in WebCoreSupport
      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