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
43 using namespace WebCore::HTMLNames;
44
45 namespace android {
46
pageDestroyed()47 void EditorClientAndroid::pageDestroyed() {
48 delete this;
49 }
50
shouldDeleteRange(Range *)51 bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; }
shouldShowDeleteInterface(HTMLElement *)52 bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; }
smartInsertDeleteEnabled()53 bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; }
isSelectTrailingWhitespaceEnabled()54 bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; }
isContinuousSpellCheckingEnabled()55 bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; }
toggleContinuousSpellChecking()56 void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); }
isGrammarCheckingEnabled()57 bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; }
toggleGrammarChecking()58 void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); }
spellCheckerDocumentTag()59 int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; }
60
isEditable()61 bool 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
shouldBeginEditing(Range *)65 bool EditorClientAndroid::shouldBeginEditing(Range*)
66 {
67 return true;
68 }
69
shouldEndEditing(Range *)70 bool EditorClientAndroid::shouldEndEditing(Range*)
71 {
72 return true;
73 }
74
shouldInsertNode(Node *,Range *,EditorInsertAction)75 bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; }
shouldInsertText(const String &,Range *,EditorInsertAction)76 bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; }
shouldApplyStyle(CSSStyleDeclaration *,Range *)77 bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; }
78
didBeginEditing()79 void 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)
respondToChangedContents()83 void EditorClientAndroid::respondToChangedContents() { notImplemented(); }
84
didEndEditing()85 void EditorClientAndroid::didEndEditing() { notImplemented(); }
didWriteSelectionToPasteboard()86 void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); }
didSetSelectionTypesForPasteboard()87 void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); }
88
89 // Copied from the Window's port of WebKit.
90 static const unsigned AltKey = 1 << 0;
91 static const unsigned ShiftKey = 1 << 1;
92
93 struct KeyDownEntry {
94 unsigned virtualKey;
95 unsigned modifiers;
96 const char* name;
97 };
98
99 struct KeyPressEntry {
100 unsigned charCode;
101 unsigned modifiers;
102 const char* name;
103 };
104
105 static 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
132 static 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
interpretKeyEvent(const KeyboardEvent * evt)140 static 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
handleKeyboardEvent(KeyboardEvent * event)173 void 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
registerCommandForUndo(PassRefPtr<EditCommand>)213 void EditorClientAndroid::registerCommandForUndo(PassRefPtr<EditCommand>) {}
registerCommandForRedo(PassRefPtr<EditCommand>)214 void EditorClientAndroid::registerCommandForRedo(PassRefPtr<EditCommand>) {}
clearUndoRedoOperations()215 void EditorClientAndroid::clearUndoRedoOperations() {}
canUndo() const216 bool EditorClientAndroid::canUndo() const { return false; }
canRedo() const217 bool EditorClientAndroid::canRedo() const { return false; }
undo()218 void EditorClientAndroid::undo() {}
redo()219 void EditorClientAndroid::redo() {}
canCopyCut(bool defaultValue) const220 bool EditorClientAndroid::canCopyCut(bool defaultValue) const { return defaultValue; }
canPaste(bool defaultValue) const221 bool EditorClientAndroid::canPaste(bool defaultValue) const { return defaultValue; }
222
223 // functions new to Jun-07 tip of tree merge:
showSpellingUI(bool)224 void EditorClientAndroid::showSpellingUI(bool) {}
getGuessesForWord(String const &,const String &,WTF::Vector<String> &)225 void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector<String>&) {}
spellingUIIsShowing()226 bool EditorClientAndroid::spellingUIIsShowing() { return false; }
checkGrammarOfString(unsigned short const *,int,WTF::Vector<GrammarDetail> &,int *,int *)227 void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector<GrammarDetail>&, int*, int*) {}
checkSpellingOfString(unsigned short const *,int,int *,int *)228 void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {}
getAutoCorrectSuggestionForMisspelledWord(const String &)229 String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); }
textFieldDidEndEditing(Element *)230 void EditorClientAndroid::textFieldDidEndEditing(Element*) {}
textDidChangeInTextArea(Element * element)231 void 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 }
textDidChangeInTextField(Element * element)239 void 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 }
textFieldDidBeginEditing(Element *)247 void EditorClientAndroid::textFieldDidBeginEditing(Element*) {}
ignoreWordInSpellDocument(String const &)248 void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {}
249
250 // We need to pass the selection up to the WebTextView
respondToChangedSelection()251 void 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
shouldChangeSelectedRange(Range *,Range *,EAffinity,bool)261 bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity,
262 bool) {
263 return m_shouldChangeSelectedRange;
264 }
265
doTextFieldCommandFromEvent(Element *,KeyboardEvent *)266 bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; }
textWillBeDeletedInTextField(Element *)267 void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {}
updateSpellingUIWithGrammarString(String const &,GrammarDetail const &)268 void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {}
updateSpellingUIWithMisspelledWord(String const &)269 void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {}
learnWord(String const &)270 void EditorClientAndroid::learnWord(String const&) {}
271
272 // functions new to the Nov-16-08 tip of tree merge:
shouldMoveRangeAfterDelete(Range *,Range *)273 bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; }
setInputMethodState(bool)274 void EditorClientAndroid::setInputMethodState(bool) {}
275
276 // functions new to Feb-19 tip of tree merge:
handleInputMethodKeydown(KeyboardEvent *)277 void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {}
278
willSetInputMethodState()279 void EditorClientAndroid::willSetInputMethodState()
280 {
281 notImplemented();
282 }
283
requestCheckingOfString(SpellChecker *,int,TextCheckingTypeMask,const String &)284 void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, TextCheckingTypeMask, const String&) {}
285
286 #if ENABLE(WEB_AUTOFILL)
getAutofill()287 WebAutofill* 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