1/* 2 * Copyright 2007, The Android Open Source Project 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 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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#define LOG_TAG "WebCore" 27 28#include "config.h" 29#include "Editor.h" 30#include "EditorClientAndroid.h" 31#include "Event.h" 32#include "EventNames.h" 33#include "FocusController.h" 34#include "Frame.h" 35#include "HTMLNames.h" 36#include "KeyboardEvent.h" 37#include "NotImplemented.h" 38#include "PlatformKeyboardEvent.h" 39#include "PlatformString.h" 40#include "WebViewCore.h" 41#include "WindowsKeyboardCodes.h" 42 43using namespace WebCore::HTMLNames; 44 45namespace android { 46 47void EditorClientAndroid::pageDestroyed() { 48 delete this; 49} 50 51bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; } 52bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; } 53bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; } 54bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; } 55bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; } 56void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); } 57bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; } 58void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); } 59int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; } 60 61bool EditorClientAndroid::isEditable() { /* notImplemented(); */ return false; } 62 63// Following Qt's implementation. For shouldBeginEditing and shouldEndEditing. 64// Returning true for these fixes issue http://b/issue?id=735185 65bool EditorClientAndroid::shouldBeginEditing(Range*) 66{ 67 return true; 68} 69 70bool EditorClientAndroid::shouldEndEditing(Range*) 71{ 72 return true; 73} 74 75bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; } 76bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; } 77bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; } 78 79void EditorClientAndroid::didBeginEditing() { notImplemented(); } 80 81// This function is called so that the platform can handle changes to content. It is called 82// after the contents have been edited or unedited (ie undo) 83void EditorClientAndroid::respondToChangedContents() { notImplemented(); } 84 85void EditorClientAndroid::didEndEditing() { notImplemented(); } 86void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); } 87void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); } 88 89// Copied from the Window's port of WebKit. 90static const unsigned AltKey = 1 << 0; 91static const unsigned ShiftKey = 1 << 1; 92 93struct KeyDownEntry { 94 unsigned virtualKey; 95 unsigned modifiers; 96 const char* name; 97}; 98 99struct KeyPressEntry { 100 unsigned charCode; 101 unsigned modifiers; 102 const char* name; 103}; 104 105static const KeyDownEntry keyDownEntries[] = { 106 { VK_LEFT, 0, "MoveLeft" }, 107 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, 108 { VK_LEFT, AltKey, "MoveWordLeft" }, 109 { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" }, 110 { VK_RIGHT, 0, "MoveRight" }, 111 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, 112 { VK_RIGHT, AltKey, "MoveWordRight" }, 113 { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" }, 114 { VK_UP, 0, "MoveUp" }, 115 { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, 116 { VK_DOWN, 0, "MoveDown" }, 117 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, 118 119 { VK_BACK, 0, "BackwardDelete" }, 120 { VK_BACK, ShiftKey, "ForwardDelete" }, 121 { VK_BACK, AltKey, "DeleteWordBackward" }, 122 { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" }, 123 124 { VK_ESCAPE, 0, "Cancel" }, 125 { VK_TAB, 0, "InsertTab" }, 126 { VK_TAB, ShiftKey, "InsertBacktab" }, 127 { VK_RETURN, 0, "InsertNewline" }, 128 { VK_RETURN, AltKey, "InsertNewline" }, 129 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" } 130}; 131 132static const KeyPressEntry keyPressEntries[] = { 133 { '\t', 0, "InsertTab" }, 134 { '\t', ShiftKey, "InsertBackTab" }, 135 { '\r', 0, "InsertNewline" }, 136 { '\r', AltKey, "InsertNewline" }, 137 { '\r', AltKey | ShiftKey, "InsertNewline" } 138}; 139 140static const char* interpretKeyEvent(const KeyboardEvent* evt) 141{ 142 const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); 143 144 static HashMap<int, const char*>* keyDownCommandsMap = 0; 145 static HashMap<int, const char*>* keyPressCommandsMap = 0; 146 147 if (!keyDownCommandsMap) { 148 keyDownCommandsMap = new HashMap<int, const char*>; 149 keyPressCommandsMap = new HashMap<int, const char*>; 150 151 for (unsigned i = 0; i < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++) 152 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); 153 154 for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); i++) 155 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); 156 } 157 158 unsigned modifiers = 0; 159 if (keyEvent->shiftKey()) 160 modifiers |= ShiftKey; 161 if (keyEvent->altKey()) 162 modifiers |= AltKey; 163 164 if (evt->type() == eventNames().keydownEvent) { 165 int mapKey = modifiers << 16 | evt->keyCode(); 166 return mapKey ? keyDownCommandsMap->get(mapKey) : 0; 167 } 168 169 int mapKey = modifiers << 16 | evt->charCode(); 170 return mapKey ? keyPressCommandsMap->get(mapKey) : 0; 171} 172 173void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) { 174 ASSERT(m_page); 175 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 176 if (!frame) 177 return; 178 179 const PlatformKeyboardEvent* keyEvent = event->keyEvent(); 180 // TODO: If the event is not coming from Android Java, e.g. from JavaScript, 181 // PlatformKeyboardEvent is null. We should support this later. 182 if (!keyEvent) 183 return; 184 185 Editor::Command command = frame->editor()->command(interpretKeyEvent(event)); 186 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { 187 if (!command.isTextInsertion() && command.execute(event)) { 188 // This function mimics the Windows version. However, calling event->setDefaultHandled() 189 // prevents the javascript key events for the delete key from happening. 190 // Update: Safari doesn't send delete key events to javascript so 191 // we will mimic that behavior. 192 event->setDefaultHandled(); 193 } 194 return; 195 } 196 197 if (command.execute(event)) { 198 event->setDefaultHandled(); 199 return; 200 } 201 202 // Don't insert null or control characters as they can result in unexpected behaviour 203 if (event->charCode() < ' ') 204 return; 205 206 if (frame->editor()->insertText(keyEvent->text(), event)) 207 event->setDefaultHandled(); 208} 209 210//////////////////////////////////////////////////////////////////////////////////////////////// 211// we just don't support Undo/Redo at the moment 212 213void EditorClientAndroid::registerCommandForUndo(PassRefPtr<EditCommand>) {} 214void EditorClientAndroid::registerCommandForRedo(PassRefPtr<EditCommand>) {} 215void EditorClientAndroid::clearUndoRedoOperations() {} 216bool EditorClientAndroid::canUndo() const { return false; } 217bool EditorClientAndroid::canRedo() const { return false; } 218void EditorClientAndroid::undo() {} 219void EditorClientAndroid::redo() {} 220bool EditorClientAndroid::canCopyCut(bool defaultValue) const { return defaultValue; } 221bool EditorClientAndroid::canPaste(bool defaultValue) const { return defaultValue; } 222 223// functions new to Jun-07 tip of tree merge: 224void EditorClientAndroid::showSpellingUI(bool) {} 225void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector<String>&) {} 226bool EditorClientAndroid::spellingUIIsShowing() { return false; } 227void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector<GrammarDetail>&, int*, int*) {} 228void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {} 229String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); } 230void EditorClientAndroid::textFieldDidEndEditing(Element*) {} 231void EditorClientAndroid::textDidChangeInTextArea(Element* element) 232{ 233 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 234 if (!frame || !frame->view()) 235 return; 236 WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); 237 webViewCore->updateTextSizeAndScroll(element); 238} 239void EditorClientAndroid::textDidChangeInTextField(Element* element) 240{ 241 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 242 if (!frame || !frame->view()) 243 return; 244 WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); 245 webViewCore->updateTextSizeAndScroll(element); 246} 247void EditorClientAndroid::textFieldDidBeginEditing(Element*) {} 248void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {} 249 250// We need to pass the selection up to the WebTextView 251void EditorClientAndroid::respondToChangedSelection() { 252 if (m_uiGeneratedSelectionChange) 253 return; 254 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 255 if (!frame || !frame->view()) 256 return; 257 WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); 258 webViewCore->updateTextSelection(); 259} 260 261bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, 262 bool) { 263 return m_shouldChangeSelectedRange; 264} 265 266bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; } 267void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {} 268void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {} 269void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {} 270void EditorClientAndroid::learnWord(String const&) {} 271 272// functions new to the Nov-16-08 tip of tree merge: 273bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; } 274void EditorClientAndroid::setInputMethodState(bool) {} 275 276// functions new to Feb-19 tip of tree merge: 277void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {} 278 279void EditorClientAndroid::willSetInputMethodState() 280{ 281 notImplemented(); 282} 283 284void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, TextCheckingTypeMask, const String&) {} 285 286#if ENABLE(WEB_AUTOFILL) 287WebAutofill* EditorClientAndroid::getAutofill() 288{ 289 if (!m_autoFill) 290 m_autoFill.set(new WebAutofill()); 291 292 return m_autoFill.get(); 293} 294#endif 295 296} 297