1 /* 2 * Copyright (C) 2010 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 INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebEditorClient.h" 28 29 #include "EditorState.h" 30 #include "WebCoreArgumentCoders.h" 31 #include "WebFrameLoaderClient.h" 32 #include "WebPage.h" 33 #include "WebPageProxy.h" 34 #include "WebPageProxyMessages.h" 35 #include "WebProcess.h" 36 #include <WebCore/ArchiveResource.h> 37 #include <WebCore/DocumentFragment.h> 38 #include <WebCore/EditCommand.h> 39 #include <WebCore/FocusController.h> 40 #include <WebCore/Frame.h> 41 #include <WebCore/HTMLInputElement.h> 42 #include <WebCore/HTMLNames.h> 43 #include <WebCore/HTMLTextAreaElement.h> 44 #include <WebCore/KeyboardEvent.h> 45 #include <WebCore/NotImplemented.h> 46 #include <WebCore/Page.h> 47 #include <WebCore/UserTypingGestureIndicator.h> 48 49 using namespace WebCore; 50 using namespace HTMLNames; 51 52 namespace WebKit { 53 54 void WebEditorClient::pageDestroyed() 55 { 56 delete this; 57 } 58 59 bool WebEditorClient::shouldDeleteRange(Range* range) 60 { 61 bool result = m_page->injectedBundleEditorClient().shouldDeleteRange(m_page, range); 62 notImplemented(); 63 return result; 64 } 65 66 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement*) 67 { 68 notImplemented(); 69 return false; 70 } 71 72 bool WebEditorClient::smartInsertDeleteEnabled() 73 { 74 // FIXME: Why isn't this Mac specific like toggleSmartInsertDeleteEnabled? 75 #if PLATFORM(MAC) 76 return m_page->isSmartInsertDeleteEnabled(); 77 #else 78 return true; 79 #endif 80 } 81 82 bool WebEditorClient::isSelectTrailingWhitespaceEnabled() 83 { 84 notImplemented(); 85 return false; 86 } 87 88 bool WebEditorClient::isContinuousSpellCheckingEnabled() 89 { 90 return WebProcess::shared().textCheckerState().isContinuousSpellCheckingEnabled; 91 } 92 93 void WebEditorClient::toggleContinuousSpellChecking() 94 { 95 notImplemented(); 96 } 97 98 bool WebEditorClient::isGrammarCheckingEnabled() 99 { 100 return WebProcess::shared().textCheckerState().isGrammarCheckingEnabled; 101 } 102 103 void WebEditorClient::toggleGrammarChecking() 104 { 105 notImplemented(); 106 } 107 108 int WebEditorClient::spellCheckerDocumentTag() 109 { 110 notImplemented(); 111 return false; 112 } 113 114 115 bool WebEditorClient::isEditable() 116 { 117 notImplemented(); 118 return false; 119 } 120 121 122 bool WebEditorClient::shouldBeginEditing(Range* range) 123 { 124 bool result = m_page->injectedBundleEditorClient().shouldBeginEditing(m_page, range); 125 notImplemented(); 126 return result; 127 } 128 129 bool WebEditorClient::shouldEndEditing(Range* range) 130 { 131 bool result = m_page->injectedBundleEditorClient().shouldEndEditing(m_page, range); 132 notImplemented(); 133 return result; 134 } 135 136 bool WebEditorClient::shouldInsertNode(Node* node, Range* rangeToReplace, EditorInsertAction action) 137 { 138 bool result = m_page->injectedBundleEditorClient().shouldInsertNode(m_page, node, rangeToReplace, action); 139 notImplemented(); 140 return result; 141 } 142 143 bool WebEditorClient::shouldInsertText(const String& text, Range* rangeToReplace, EditorInsertAction action) 144 { 145 bool result = m_page->injectedBundleEditorClient().shouldInsertText(m_page, text.impl(), rangeToReplace, action); 146 notImplemented(); 147 return result; 148 } 149 150 bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting) 151 { 152 bool result = m_page->injectedBundleEditorClient().shouldChangeSelectedRange(m_page, fromRange, toRange, affinity, stillSelecting); 153 notImplemented(); 154 return result; 155 } 156 157 bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* style, Range* range) 158 { 159 bool result = m_page->injectedBundleEditorClient().shouldApplyStyle(m_page, style, range); 160 notImplemented(); 161 return result; 162 } 163 164 bool WebEditorClient::shouldMoveRangeAfterDelete(Range*, Range*) 165 { 166 notImplemented(); 167 return true; 168 } 169 170 void WebEditorClient::didBeginEditing() 171 { 172 // FIXME: What good is a notification name, if it's always the same? 173 DEFINE_STATIC_LOCAL(String, WebViewDidBeginEditingNotification, ("WebViewDidBeginEditingNotification")); 174 m_page->injectedBundleEditorClient().didBeginEditing(m_page, WebViewDidBeginEditingNotification.impl()); 175 notImplemented(); 176 } 177 178 void WebEditorClient::respondToChangedContents() 179 { 180 DEFINE_STATIC_LOCAL(String, WebViewDidChangeNotification, ("WebViewDidChangeNotification")); 181 m_page->injectedBundleEditorClient().didChange(m_page, WebViewDidChangeNotification.impl()); 182 notImplemented(); 183 } 184 185 void WebEditorClient::respondToChangedSelection() 186 { 187 DEFINE_STATIC_LOCAL(String, WebViewDidChangeSelectionNotification, ("WebViewDidChangeSelectionNotification")); 188 m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl()); 189 Frame* frame = m_page->corePage()->focusController()->focusedFrame(); 190 if (!frame) 191 return; 192 193 m_page->send(Messages::WebPageProxy::EditorStateChanged(m_page->editorState())); 194 195 #if PLATFORM(WIN) 196 // FIXME: This should also go into the selection state. 197 if (!frame->editor()->hasComposition() || frame->editor()->ignoreCompositionSelectionChange()) 198 return; 199 200 unsigned start; 201 unsigned end; 202 m_page->send(Messages::WebPageProxy::DidChangeCompositionSelection(frame->editor()->getCompositionSelection(start, end))); 203 #endif 204 } 205 206 void WebEditorClient::didEndEditing() 207 { 208 DEFINE_STATIC_LOCAL(String, WebViewDidEndEditingNotification, ("WebViewDidEndEditingNotification")); 209 m_page->injectedBundleEditorClient().didEndEditing(m_page, WebViewDidEndEditingNotification.impl()); 210 notImplemented(); 211 } 212 213 void WebEditorClient::didWriteSelectionToPasteboard() 214 { 215 notImplemented(); 216 } 217 218 void WebEditorClient::didSetSelectionTypesForPasteboard() 219 { 220 notImplemented(); 221 } 222 223 void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command) 224 { 225 // FIXME: Add assertion that the command being reapplied is the same command that is 226 // being passed to us. 227 if (m_page->isInRedo()) 228 return; 229 230 RefPtr<WebEditCommand> webCommand = WebEditCommand::create(command); 231 m_page->addWebEditCommand(webCommand->commandID(), webCommand.get()); 232 uint32_t editAction = static_cast<uint32_t>(webCommand->command()->editingAction()); 233 234 m_page->send(Messages::WebPageProxy::RegisterEditCommandForUndo(webCommand->commandID(), editAction)); 235 } 236 237 void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand>) 238 { 239 } 240 241 void WebEditorClient::clearUndoRedoOperations() 242 { 243 m_page->send(Messages::WebPageProxy::ClearAllEditCommands()); 244 } 245 246 bool WebEditorClient::canCopyCut(bool defaultValue) const 247 { 248 return defaultValue; 249 } 250 251 bool WebEditorClient::canPaste(bool defaultValue) const 252 { 253 return defaultValue; 254 } 255 256 bool WebEditorClient::canUndo() const 257 { 258 bool result = false; 259 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::CanUndoRedo::Reply(result)); 260 return result; 261 } 262 263 bool WebEditorClient::canRedo() const 264 { 265 bool result = false; 266 m_page->sendSync(Messages::WebPageProxy::CanUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::CanUndoRedo::Reply(result)); 267 return result; 268 } 269 270 void WebEditorClient::undo() 271 { 272 bool result = false; 273 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Undo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result)); 274 } 275 276 void WebEditorClient::redo() 277 { 278 bool result = false; 279 m_page->sendSync(Messages::WebPageProxy::ExecuteUndoRedo(static_cast<uint32_t>(WebPageProxy::Redo)), Messages::WebPageProxy::ExecuteUndoRedo::Reply(result)); 280 } 281 282 #if !PLATFORM(GTK) && !PLATFORM(MAC) 283 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event) 284 { 285 if (m_page->handleEditingKeyboardEvent(event)) 286 event->setDefaultHandled(); 287 } 288 289 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*) 290 { 291 notImplemented(); 292 } 293 #endif 294 295 void WebEditorClient::textFieldDidBeginEditing(Element* element) 296 { 297 if (!element->hasTagName(inputTag)) 298 return; 299 300 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 301 m_page->injectedBundleFormClient().textFieldDidBeginEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame); 302 } 303 304 void WebEditorClient::textFieldDidEndEditing(Element* element) 305 { 306 if (!element->hasTagName(inputTag)) 307 return; 308 309 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 310 m_page->injectedBundleFormClient().textFieldDidEndEditing(m_page, static_cast<HTMLInputElement*>(element), webFrame); 311 } 312 313 void WebEditorClient::textDidChangeInTextField(Element* element) 314 { 315 if (!element->hasTagName(inputTag)) 316 return; 317 318 if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element) 319 return; 320 321 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 322 m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, static_cast<HTMLInputElement*>(element), webFrame); 323 } 324 325 void WebEditorClient::textDidChangeInTextArea(Element* element) 326 { 327 if (!element->hasTagName(textareaTag)) 328 return; 329 330 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 331 m_page->injectedBundleFormClient().textDidChangeInTextArea(m_page, static_cast<HTMLTextAreaElement*>(element), webFrame); 332 } 333 334 static bool getActionTypeForKeyEvent(KeyboardEvent* event, WKInputFieldActionType& type) 335 { 336 String key = event->keyIdentifier(); 337 if (key == "Up") 338 type = WKInputFieldActionTypeMoveUp; 339 else if (key == "Down") 340 type = WKInputFieldActionTypeMoveDown; 341 else if (key == "U+001B") 342 type = WKInputFieldActionTypeCancel; 343 else if (key == "U+0009") { 344 if (event->shiftKey()) 345 type = WKInputFieldActionTypeInsertBacktab; 346 else 347 type = WKInputFieldActionTypeInsertTab; 348 } else if (key == "Enter") 349 type = WKInputFieldActionTypeInsertNewline; 350 else 351 return false; 352 353 return true; 354 } 355 356 bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event) 357 { 358 if (!element->hasTagName(inputTag)) 359 return false; 360 361 WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0); 362 if (!getActionTypeForKeyEvent(event, actionType)) 363 return false; 364 365 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 366 return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), actionType, webFrame); 367 } 368 369 void WebEditorClient::textWillBeDeletedInTextField(Element* element) 370 { 371 if (!element->hasTagName(inputTag)) 372 return; 373 374 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(element->document()->frame()->loader()->client())->webFrame(); 375 m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame); 376 } 377 378 void WebEditorClient::ignoreWordInSpellDocument(const String& word) 379 { 380 m_page->send(Messages::WebPageProxy::IgnoreWord(word)); 381 } 382 383 void WebEditorClient::learnWord(const String& word) 384 { 385 m_page->send(Messages::WebPageProxy::LearnWord(word)); 386 } 387 388 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength) 389 { 390 int32_t resultLocation = -1; 391 int32_t resultLength = 0; 392 // FIXME: It would be nice if we wouldn't have to copy the text here. 393 m_page->sendSync(Messages::WebPageProxy::CheckSpellingOfString(String(text, length)), 394 Messages::WebPageProxy::CheckSpellingOfString::Reply(resultLocation, resultLength)); 395 *misspellingLocation = resultLocation; 396 *misspellingLength = resultLength; 397 } 398 399 String WebEditorClient::getAutoCorrectSuggestionForMisspelledWord(const String&) 400 { 401 notImplemented(); 402 return String(); 403 } 404 405 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<WebCore::GrammarDetail>& grammarDetails, int* badGrammarLocation, int* badGrammarLength) 406 { 407 int32_t resultLocation = -1; 408 int32_t resultLength = 0; 409 // FIXME: It would be nice if we wouldn't have to copy the text here. 410 m_page->sendSync(Messages::WebPageProxy::CheckGrammarOfString(String(text, length)), 411 Messages::WebPageProxy::CheckGrammarOfString::Reply(grammarDetails, resultLocation, resultLength)); 412 *badGrammarLocation = resultLocation; 413 *badGrammarLength = resultLength; 414 } 415 416 void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail) 417 { 418 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail)); 419 } 420 421 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord) 422 { 423 m_page->send(Messages::WebPageProxy::UpdateSpellingUIWithMisspelledWord(misspelledWord)); 424 } 425 426 void WebEditorClient::showSpellingUI(bool) 427 { 428 notImplemented(); 429 } 430 431 bool WebEditorClient::spellingUIIsShowing() 432 { 433 bool isShowing = false; 434 m_page->sendSync(Messages::WebPageProxy::SpellingUIIsShowing(), Messages::WebPageProxy::SpellingUIIsShowing::Reply(isShowing)); 435 return isShowing; 436 } 437 438 void WebEditorClient::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses) 439 { 440 m_page->sendSync(Messages::WebPageProxy::GetGuessesForWord(word, context), Messages::WebPageProxy::GetGuessesForWord::Reply(guesses)); 441 } 442 443 void WebEditorClient::willSetInputMethodState() 444 { 445 notImplemented(); 446 } 447 448 void WebEditorClient::setInputMethodState(bool) 449 { 450 notImplemented(); 451 } 452 453 void WebEditorClient::requestCheckingOfString(WebCore::SpellChecker*, int, WebCore::TextCheckingTypeMask, const WTF::String&) 454 { 455 notImplemented(); 456 } 457 458 } // namespace WebKit 459