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