/* * Copyright 2007, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "WebCore" #include "config.h" #include "Editor.h" #include "EditorClientAndroid.h" #include "Event.h" #include "EventNames.h" #include "FocusController.h" #include "Frame.h" #include "HTMLNames.h" #include "KeyboardEvent.h" #include "NotImplemented.h" #include "PlatformKeyboardEvent.h" #include "PlatformString.h" #include "WebViewCore.h" #include "WindowsKeyboardCodes.h" using namespace WebCore::HTMLNames; namespace android { void EditorClientAndroid::pageDestroyed() { delete this; } bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; } bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; } bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; } bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; } bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; } void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); } bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; } void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); } int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; } bool EditorClientAndroid::isEditable() { /* notImplemented(); */ return false; } // Following Qt's implementation. For shouldBeginEditing and shouldEndEditing. // Returning true for these fixes issue http://b/issue?id=735185 bool EditorClientAndroid::shouldBeginEditing(Range*) { return true; } bool EditorClientAndroid::shouldEndEditing(Range*) { return true; } bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; } bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; } bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; } void EditorClientAndroid::didBeginEditing() { notImplemented(); } // This function is called so that the platform can handle changes to content. It is called // after the contents have been edited or unedited (ie undo) void EditorClientAndroid::respondToChangedContents() { notImplemented(); } void EditorClientAndroid::didEndEditing() { notImplemented(); } void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); } void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); } // Copied from the Window's port of WebKit. static const unsigned AltKey = 1 << 0; static const unsigned ShiftKey = 1 << 1; struct KeyDownEntry { unsigned virtualKey; unsigned modifiers; const char* name; }; struct KeyPressEntry { unsigned charCode; unsigned modifiers; const char* name; }; static const KeyDownEntry keyDownEntries[] = { { VK_LEFT, 0, "MoveLeft" }, { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, { VK_LEFT, AltKey, "MoveWordLeft" }, { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" }, { VK_RIGHT, 0, "MoveRight" }, { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, { VK_RIGHT, AltKey, "MoveWordRight" }, { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" }, { VK_UP, 0, "MoveUp" }, { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, { VK_DOWN, 0, "MoveDown" }, { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, { VK_BACK, 0, "BackwardDelete" }, { VK_BACK, ShiftKey, "ForwardDelete" }, { VK_BACK, AltKey, "DeleteWordBackward" }, { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" }, { VK_ESCAPE, 0, "Cancel" }, { VK_TAB, 0, "InsertTab" }, { VK_TAB, ShiftKey, "InsertBacktab" }, { VK_RETURN, 0, "InsertNewline" }, { VK_RETURN, AltKey, "InsertNewline" }, { VK_RETURN, AltKey | ShiftKey, "InsertNewline" } }; static const KeyPressEntry keyPressEntries[] = { { '\t', 0, "InsertTab" }, { '\t', ShiftKey, "InsertBackTab" }, { '\r', 0, "InsertNewline" }, { '\r', AltKey, "InsertNewline" }, { '\r', AltKey | ShiftKey, "InsertNewline" } }; static const char* interpretKeyEvent(const KeyboardEvent* evt) { const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); static HashMap* keyDownCommandsMap = 0; static HashMap* keyPressCommandsMap = 0; if (!keyDownCommandsMap) { keyDownCommandsMap = new HashMap; keyPressCommandsMap = new HashMap; for (unsigned i = 0; i < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++) keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); i++) keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); } unsigned modifiers = 0; if (keyEvent->shiftKey()) modifiers |= ShiftKey; if (keyEvent->altKey()) modifiers |= AltKey; if (evt->type() == eventNames().keydownEvent) { int mapKey = modifiers << 16 | evt->keyCode(); return mapKey ? keyDownCommandsMap->get(mapKey) : 0; } int mapKey = modifiers << 16 | evt->charCode(); return mapKey ? keyPressCommandsMap->get(mapKey) : 0; } void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) { ASSERT(m_page); Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame) return; const PlatformKeyboardEvent* keyEvent = event->keyEvent(); // TODO: If the event is not coming from Android Java, e.g. from JavaScript, // PlatformKeyboardEvent is null. We should support this later. if (!keyEvent) return; Editor::Command command = frame->editor()->command(interpretKeyEvent(event)); if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { if (!command.isTextInsertion() && command.execute(event)) { // This function mimics the Windows version. However, calling event->setDefaultHandled() // prevents the javascript key events for the delete key from happening. // Update: Safari doesn't send delete key events to javascript so // we will mimic that behavior. event->setDefaultHandled(); } return; } if (command.execute(event)) { event->setDefaultHandled(); return; } // Don't insert null or control characters as they can result in unexpected behaviour if (event->charCode() < ' ') return; if (frame->editor()->insertText(keyEvent->text(), event)) event->setDefaultHandled(); } //////////////////////////////////////////////////////////////////////////////////////////////// // we just don't support Undo/Redo at the moment void EditorClientAndroid::registerCommandForUndo(PassRefPtr) {} void EditorClientAndroid::registerCommandForRedo(PassRefPtr) {} void EditorClientAndroid::clearUndoRedoOperations() {} bool EditorClientAndroid::canUndo() const { return false; } bool EditorClientAndroid::canRedo() const { return false; } void EditorClientAndroid::undo() {} void EditorClientAndroid::redo() {} bool EditorClientAndroid::canCopyCut(bool defaultValue) const { return defaultValue; } bool EditorClientAndroid::canPaste(bool defaultValue) const { return defaultValue; } // functions new to Jun-07 tip of tree merge: void EditorClientAndroid::showSpellingUI(bool) {} void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector&) {} bool EditorClientAndroid::spellingUIIsShowing() { return false; } void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector&, int*, int*) {} void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {} String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); } void EditorClientAndroid::textFieldDidEndEditing(Element*) {} void EditorClientAndroid::textDidChangeInTextArea(Element* element) { Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame || !frame->view()) return; WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); webViewCore->updateTextSizeAndScroll(element); } void EditorClientAndroid::textDidChangeInTextField(Element* element) { Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame || !frame->view()) return; WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); webViewCore->updateTextSizeAndScroll(element); } void EditorClientAndroid::textFieldDidBeginEditing(Element*) {} void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {} // We need to pass the selection up to the WebTextView void EditorClientAndroid::respondToChangedSelection() { if (m_uiGeneratedSelectionChange) return; Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame || !frame->view()) return; WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view()); webViewCore->updateTextSelection(); } bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) { return m_shouldChangeSelectedRange; } bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; } void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {} void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {} void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {} void EditorClientAndroid::learnWord(String const&) {} // functions new to the Nov-16-08 tip of tree merge: bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; } void EditorClientAndroid::setInputMethodState(bool) {} // functions new to Feb-19 tip of tree merge: void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {} void EditorClientAndroid::willSetInputMethodState() { notImplemented(); } void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, TextCheckingTypeMask, const String&) {} #if ENABLE(WEB_AUTOFILL) WebAutofill* EditorClientAndroid::getAutofill() { if (!m_autoFill) m_autoFill.set(new WebAutofill()); return m_autoFill.get(); } #endif }