Roll src/third_party/WebKit c63b89c:29324ab (svn 202546:202547)
[chromium-blink-merge.git] / content / browser / renderer_host / ime_adapter_android.cc
blobdbad05cf8b619b442eb549a56f6a87af8dce683e
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/ime_adapter_android.h"
7 #include <algorithm>
8 #include <android/input.h>
9 #include <vector>
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/android/scoped_java_ref.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "content/browser/frame_host/frame_tree.h"
17 #include "content/browser/frame_host/frame_tree_node.h"
18 #include "content/browser/frame_host/render_frame_host_impl.h"
19 #include "content/browser/renderer_host/render_view_host_delegate.h"
20 #include "content/browser/renderer_host/render_view_host_impl.h"
21 #include "content/browser/renderer_host/render_widget_host_impl.h"
22 #include "content/browser/renderer_host/render_widget_host_view_android.h"
23 #include "content/common/frame_messages.h"
24 #include "content/common/input_messages.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/native_web_keyboard_event.h"
28 #include "content/public/browser/web_contents.h"
29 #include "jni/ImeAdapter_jni.h"
30 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
31 #include "third_party/WebKit/public/web/WebInputEvent.h"
32 #include "third_party/WebKit/public/web/WebTextInputType.h"
34 using base::android::AttachCurrentThread;
35 using base::android::ConvertJavaStringToUTF16;
37 namespace content {
38 namespace {
40 // Maps a java KeyEvent into a NativeWebKeyboardEvent.
41 // |java_key_event| is used to maintain a globalref for KeyEvent.
42 // |action| will help determine the WebInputEvent type.
43 // type, |modifiers|, |time_ms|, |key_code|, |unicode_char| is used to create
44 // WebKeyboardEvent. |key_code| is also needed ad need to treat the enter key
45 // as a key press of character \r.
46 NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
47 JNIEnv* env,
48 jobject java_key_event,
49 int action,
50 int modifiers,
51 long time_ms,
52 int key_code,
53 int scan_code,
54 bool is_system_key,
55 int unicode_char) {
56 blink::WebInputEvent::Type type = blink::WebInputEvent::Undefined;
57 if (action == AKEY_EVENT_ACTION_DOWN)
58 type = blink::WebInputEvent::RawKeyDown;
59 else if (action == AKEY_EVENT_ACTION_UP)
60 type = blink::WebInputEvent::KeyUp;
61 else
62 NOTREACHED() << "Invalid Android key event action: " << action;
63 return NativeWebKeyboardEvent(java_key_event, type, modifiers,
64 time_ms / 1000.0, key_code, scan_code, unicode_char, is_system_key);
67 } // anonymous namespace
69 bool RegisterImeAdapter(JNIEnv* env) {
70 return RegisterNativesImpl(env);
73 // Callback from Java to convert BackgroundColorSpan data to a
74 // blink::WebCompositionUnderline instance, and append it to |underlines_ptr|.
75 void AppendBackgroundColorSpan(JNIEnv*,
76 const JavaParamRef<jclass>&,
77 jlong underlines_ptr,
78 jint start,
79 jint end,
80 jint background_color) {
81 DCHECK_GE(start, 0);
82 DCHECK_GE(end, 0);
83 // Do not check |background_color|.
84 std::vector<blink::WebCompositionUnderline>* underlines =
85 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
86 underlines_ptr);
87 underlines->push_back(
88 blink::WebCompositionUnderline(static_cast<unsigned>(start),
89 static_cast<unsigned>(end),
90 SK_ColorTRANSPARENT,
91 false,
92 static_cast<unsigned>(background_color)));
95 // Callback from Java to convert UnderlineSpan data to a
96 // blink::WebCompositionUnderline instance, and append it to |underlines_ptr|.
97 void AppendUnderlineSpan(JNIEnv*,
98 const JavaParamRef<jclass>&,
99 jlong underlines_ptr,
100 jint start,
101 jint end) {
102 DCHECK_GE(start, 0);
103 DCHECK_GE(end, 0);
104 std::vector<blink::WebCompositionUnderline>* underlines =
105 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
106 underlines_ptr);
107 underlines->push_back(
108 blink::WebCompositionUnderline(static_cast<unsigned>(start),
109 static_cast<unsigned>(end),
110 SK_ColorBLACK,
111 false,
112 SK_ColorTRANSPARENT));
115 ImeAdapterAndroid::ImeAdapterAndroid(RenderWidgetHostViewAndroid* rwhva)
116 : rwhva_(rwhva) {
119 ImeAdapterAndroid::~ImeAdapterAndroid() {
120 JNIEnv* env = AttachCurrentThread();
121 base::android::ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
122 if (!obj.is_null())
123 Java_ImeAdapter_detach(env, obj.obj());
126 bool ImeAdapterAndroid::SendSyntheticKeyEvent(JNIEnv*,
127 jobject,
128 int type,
129 long time_ms,
130 int key_code,
131 int modifiers,
132 int text) {
133 NativeWebKeyboardEvent event(static_cast<blink::WebInputEvent::Type>(type),
134 modifiers, time_ms / 1000.0, key_code, 0,
135 text, false /* is_system_key */);
136 rwhva_->SendKeyEvent(event);
137 return true;
140 bool ImeAdapterAndroid::SendKeyEvent(JNIEnv* env, jobject,
141 jobject original_key_event,
142 int action, int modifiers,
143 long time_ms, int key_code,
144 int scan_code, bool is_system_key,
145 int unicode_char) {
146 NativeWebKeyboardEvent event = NativeWebKeyboardEventFromKeyEvent(
147 env, original_key_event, action, modifiers,
148 time_ms, key_code, scan_code, is_system_key, unicode_char);
149 bool key_down_text_insertion =
150 event.type == blink::WebInputEvent::RawKeyDown && event.text[0];
151 // If we are going to follow up with a synthetic Char event, then that's the
152 // one we expect to test if it's handled or unhandled, so skip handling the
153 // "real" event in the browser.
154 event.skip_in_browser = key_down_text_insertion;
155 rwhva_->SendKeyEvent(event);
156 if (key_down_text_insertion) {
157 // Send a Char event, but without an os_event since we don't want to
158 // roundtrip back to java such synthetic event.
159 NativeWebKeyboardEvent char_event(blink::WebInputEvent::Char, modifiers,
160 time_ms / 1000.0, key_code, scan_code,
161 unicode_char,
162 is_system_key);
163 char_event.skip_in_browser = key_down_text_insertion;
164 rwhva_->SendKeyEvent(char_event);
166 return true;
169 void ImeAdapterAndroid::SetComposingText(JNIEnv* env,
170 jobject obj,
171 jobject text,
172 jstring text_str,
173 int new_cursor_pos) {
174 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
175 if (!rwhi)
176 return;
178 base::string16 text16 = ConvertJavaStringToUTF16(env, text_str);
180 std::vector<blink::WebCompositionUnderline> underlines;
181 // Iterate over spans in |text|, dispatch those that we care about (e.g.,
182 // BackgroundColorSpan) to a matching callback (e.g.,
183 // AppendBackgroundColorSpan()), and populate |underlines|.
184 Java_ImeAdapter_populateUnderlinesFromSpans(
185 env, obj, text, reinterpret_cast<jlong>(&underlines));
187 // Default to plain underline if we didn't find any span that we care about.
188 if (underlines.empty()) {
189 underlines.push_back(blink::WebCompositionUnderline(
190 0, text16.length(), SK_ColorBLACK, false, SK_ColorTRANSPARENT));
192 // Sort spans by |.startOffset|.
193 std::sort(underlines.begin(), underlines.end());
195 // new_cursor_position is as described in the Android API for
196 // InputConnection#setComposingText, whereas the parameters for
197 // ImeSetComposition are relative to the start of the composition.
198 if (new_cursor_pos > 0)
199 new_cursor_pos = text16.length() + new_cursor_pos - 1;
201 rwhi->ImeSetComposition(text16, underlines, new_cursor_pos, new_cursor_pos);
204 void ImeAdapterAndroid::CommitText(JNIEnv* env, jobject, jstring text_str) {
205 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
206 if (!rwhi)
207 return;
209 base::string16 text16 = ConvertJavaStringToUTF16(env, text_str);
210 rwhi->ImeConfirmComposition(text16, gfx::Range::InvalidRange(), false);
213 void ImeAdapterAndroid::FinishComposingText(JNIEnv* env, jobject) {
214 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
215 if (!rwhi)
216 return;
218 rwhi->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(),
219 true);
222 void ImeAdapterAndroid::AttachImeAdapter(JNIEnv* env, jobject java_object) {
223 java_ime_adapter_ = JavaObjectWeakGlobalRef(env, java_object);
226 void ImeAdapterAndroid::CancelComposition() {
227 base::android::ScopedJavaLocalRef<jobject> obj =
228 java_ime_adapter_.get(AttachCurrentThread());
229 if (!obj.is_null())
230 Java_ImeAdapter_cancelComposition(AttachCurrentThread(), obj.obj());
233 void ImeAdapterAndroid::FocusedNodeChanged(bool is_editable_node) {
234 base::android::ScopedJavaLocalRef<jobject> obj =
235 java_ime_adapter_.get(AttachCurrentThread());
236 if (!obj.is_null()) {
237 Java_ImeAdapter_focusedNodeChanged(AttachCurrentThread(),
238 obj.obj(),
239 is_editable_node);
243 void ImeAdapterAndroid::SetEditableSelectionOffsets(JNIEnv*, jobject,
244 int start, int end) {
245 RenderFrameHost* rfh = GetFocusedFrame();
246 if (!rfh)
247 return;
249 rfh->Send(new FrameMsg_SetEditableSelectionOffsets(rfh->GetRoutingID(),
250 start, end));
253 void ImeAdapterAndroid::SetComposingRegion(JNIEnv*, jobject,
254 int start, int end) {
255 RenderFrameHost* rfh = GetFocusedFrame();
256 if (!rfh)
257 return;
259 std::vector<blink::WebCompositionUnderline> underlines;
260 underlines.push_back(blink::WebCompositionUnderline(
261 0, end - start, SK_ColorBLACK, false, SK_ColorTRANSPARENT));
263 rfh->Send(new InputMsg_SetCompositionFromExistingText(
264 rfh->GetRoutingID(), start, end, underlines));
267 void ImeAdapterAndroid::DeleteSurroundingText(JNIEnv*, jobject,
268 int before, int after) {
269 RenderFrameHostImpl* rfh =
270 static_cast<RenderFrameHostImpl*>(GetFocusedFrame());
271 if (rfh)
272 rfh->ExtendSelectionAndDelete(before, after);
275 void ImeAdapterAndroid::ResetImeAdapter(JNIEnv* env, jobject) {
276 java_ime_adapter_.reset();
279 RenderWidgetHostImpl* ImeAdapterAndroid::GetRenderWidgetHostImpl() {
280 DCHECK_CURRENTLY_ON(BrowserThread::UI);
281 DCHECK(rwhva_);
282 RenderWidgetHost* rwh = rwhva_->GetRenderWidgetHost();
283 if (!rwh)
284 return NULL;
286 return RenderWidgetHostImpl::From(rwh);
289 RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() {
290 RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
291 if (!rwh)
292 return NULL;
293 if (!rwh->IsRenderView())
294 return NULL;
295 RenderViewHost* rvh = RenderViewHost::From(rwh);
296 FrameTreeNode* focused_frame =
297 rvh->GetDelegate()->GetFrameTree()->GetFocusedFrame();
298 if (!focused_frame)
299 return NULL;
301 return focused_frame->current_frame_host();
304 WebContents* ImeAdapterAndroid::GetWebContents() {
305 RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
306 if (!rwh)
307 return NULL;
308 if (!rwh->IsRenderView())
309 return NULL;
310 return WebContents::FromRenderViewHost(RenderViewHost::From(rwh));
313 } // namespace content