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