[Android] Force showing insertion handle when paste popup activated
[chromium-blink-merge.git] / content / browser / android / content_view_core_impl.cc
blob2ce8774f4bba13c89f37bd5f2c90b9df40eb71c6
1 // Copyright 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/android/content_view_core_impl.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h"
11 #include "base/command_line.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "cc/layers/layer.h"
18 #include "cc/layers/solid_color_layer.h"
19 #include "cc/output/begin_frame_args.h"
20 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
21 #include "content/browser/android/gesture_event_type.h"
22 #include "content/browser/android/interstitial_page_delegate_android.h"
23 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
24 #include "content/browser/android/load_url_params.h"
25 #include "content/browser/android/popup_touch_handle_drawable.h"
26 #include "content/browser/frame_host/interstitial_page_impl.h"
27 #include "content/browser/frame_host/navigation_controller_impl.h"
28 #include "content/browser/frame_host/navigation_entry_impl.h"
29 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
30 #include "content/browser/media/media_web_contents_observer.h"
31 #include "content/browser/renderer_host/compositor_impl_android.h"
32 #include "content/browser/renderer_host/input/motion_event_android.h"
33 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
34 #include "content/browser/renderer_host/input/web_input_event_util.h"
35 #include "content/browser/renderer_host/render_view_host_impl.h"
36 #include "content/browser/renderer_host/render_widget_host_impl.h"
37 #include "content/browser/renderer_host/render_widget_host_view_android.h"
38 #include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
39 #include "content/browser/ssl/ssl_host_state.h"
40 #include "content/browser/transition_request_manager.h"
41 #include "content/browser/web_contents/web_contents_view_android.h"
42 #include "content/common/frame_messages.h"
43 #include "content/common/input/web_input_event_traits.h"
44 #include "content/common/input_messages.h"
45 #include "content/common/view_messages.h"
46 #include "content/public/browser/browser_context.h"
47 #include "content/public/browser/browser_thread.h"
48 #include "content/public/browser/favicon_status.h"
49 #include "content/public/browser/render_frame_host.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/common/content_client.h"
52 #include "content/public/common/content_switches.h"
53 #include "content/public/common/menu_item.h"
54 #include "content/public/common/page_transition_types.h"
55 #include "content/public/common/user_agent.h"
56 #include "jni/ContentViewCore_jni.h"
57 #include "third_party/WebKit/public/web/WebInputEvent.h"
58 #include "ui/base/android/view_android.h"
59 #include "ui/base/android/window_android.h"
60 #include "ui/gfx/android/java_bitmap.h"
61 #include "ui/gfx/screen.h"
62 #include "ui/gfx/size_conversions.h"
63 #include "ui/gfx/size_f.h"
65 using base::android::AttachCurrentThread;
66 using base::android::ConvertJavaStringToUTF16;
67 using base::android::ConvertJavaStringToUTF8;
68 using base::android::ConvertUTF16ToJavaString;
69 using base::android::ConvertUTF8ToJavaString;
70 using base::android::ScopedJavaGlobalRef;
71 using base::android::ScopedJavaLocalRef;
72 using blink::WebGestureEvent;
73 using blink::WebInputEvent;
75 // Describes the type and enabled state of a select popup item.
76 namespace {
78 enum {
79 #define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value,
80 #include "content/browser/android/popup_item_type_list.h"
81 #undef DEFINE_POPUP_ITEM_TYPE
84 } //namespace
86 namespace content {
88 namespace {
90 const void* kContentViewUserDataKey = &kContentViewUserDataKey;
92 int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
93 DCHECK(host);
94 RenderProcessHost* render_process = host->GetProcess();
95 DCHECK(render_process);
96 if (render_process->HasConnection())
97 return render_process->GetHandle();
98 else
99 return 0;
102 ScopedJavaLocalRef<jobject> CreateJavaRect(
103 JNIEnv* env,
104 const gfx::Rect& rect) {
105 return ScopedJavaLocalRef<jobject>(
106 Java_ContentViewCore_createRect(env,
107 static_cast<int>(rect.x()),
108 static_cast<int>(rect.y()),
109 static_cast<int>(rect.right()),
110 static_cast<int>(rect.bottom())));
113 int ToGestureEventType(WebInputEvent::Type type) {
114 switch (type) {
115 case WebInputEvent::GestureScrollBegin:
116 return SCROLL_START;
117 case WebInputEvent::GestureScrollEnd:
118 return SCROLL_END;
119 case WebInputEvent::GestureScrollUpdate:
120 return SCROLL_BY;
121 case WebInputEvent::GestureFlingStart:
122 return FLING_START;
123 case WebInputEvent::GestureFlingCancel:
124 return FLING_CANCEL;
125 case WebInputEvent::GestureShowPress:
126 return SHOW_PRESS;
127 case WebInputEvent::GestureTap:
128 return SINGLE_TAP_CONFIRMED;
129 case WebInputEvent::GestureTapUnconfirmed:
130 return SINGLE_TAP_UNCONFIRMED;
131 case WebInputEvent::GestureTapDown:
132 return TAP_DOWN;
133 case WebInputEvent::GestureTapCancel:
134 return TAP_CANCEL;
135 case WebInputEvent::GestureDoubleTap:
136 return DOUBLE_TAP;
137 case WebInputEvent::GestureLongPress:
138 return LONG_PRESS;
139 case WebInputEvent::GestureLongTap:
140 return LONG_TAP;
141 case WebInputEvent::GesturePinchBegin:
142 return PINCH_BEGIN;
143 case WebInputEvent::GesturePinchEnd:
144 return PINCH_END;
145 case WebInputEvent::GesturePinchUpdate:
146 return PINCH_BY;
147 case WebInputEvent::GestureTwoFingerTap:
148 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
149 default:
150 NOTREACHED() << "Invalid source gesture type: "
151 << WebInputEventTraits::GetName(type);
152 return -1;
156 float GetPrimaryDisplayDeviceScaleFactor() {
157 const gfx::Display& display =
158 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
159 return display.device_scale_factor();
162 } // namespace
164 // Enables a callback when the underlying WebContents is destroyed, to enable
165 // nulling the back-pointer.
166 class ContentViewCoreImpl::ContentViewUserData
167 : public base::SupportsUserData::Data {
168 public:
169 explicit ContentViewUserData(ContentViewCoreImpl* content_view_core)
170 : content_view_core_(content_view_core) {
173 virtual ~ContentViewUserData() {
174 // TODO(joth): When chrome has finished removing the TabContents class (see
175 // crbug.com/107201) consider inverting relationship, so ContentViewCore
176 // would own WebContents. That effectively implies making the WebContents
177 // destructor private on Android.
178 delete content_view_core_;
181 ContentViewCoreImpl* get() const { return content_view_core_; }
183 private:
184 // Not using scoped_ptr as ContentViewCoreImpl destructor is private.
185 ContentViewCoreImpl* content_view_core_;
187 DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData);
190 // static
191 ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
192 content::WebContents* web_contents) {
193 ContentViewCoreImpl::ContentViewUserData* data =
194 reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>(
195 web_contents->GetUserData(kContentViewUserDataKey));
196 return data ? data->get() : NULL;
199 // static
200 ContentViewCore* ContentViewCore::FromWebContents(
201 content::WebContents* web_contents) {
202 return ContentViewCoreImpl::FromWebContents(web_contents);
205 // static
206 ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
207 jobject obj) {
208 return reinterpret_cast<ContentViewCore*>(
209 Java_ContentViewCore_getNativeContentViewCore(env, obj));
212 ContentViewCoreImpl::ContentViewCoreImpl(
213 JNIEnv* env,
214 jobject obj,
215 WebContents* web_contents,
216 ui::ViewAndroid* view_android,
217 ui::WindowAndroid* window_android,
218 jobject java_bridge_retained_object_set)
219 : WebContentsObserver(web_contents),
220 java_ref_(env, obj),
221 web_contents_(static_cast<WebContentsImpl*>(web_contents)),
222 root_layer_(cc::SolidColorLayer::Create()),
223 dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
224 view_android_(view_android),
225 window_android_(window_android),
226 device_orientation_(0),
227 accessibility_enabled_(false) {
228 CHECK(web_contents) <<
229 "A ContentViewCoreImpl should be created with a valid WebContents.";
230 DCHECK(view_android_);
231 DCHECK(window_android_);
233 root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj));
234 gfx::Size physical_size(
235 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
236 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
237 root_layer_->SetBounds(physical_size);
238 root_layer_->SetIsDrawable(true);
240 // Currently, the only use case we have for overriding a user agent involves
241 // spoofing a desktop Linux user agent for "Request desktop site".
242 // Automatically set it for all WebContents so that it is available when a
243 // NavigationEntry requires the user agent to be overridden.
244 const char kLinuxInfoStr[] = "X11; Linux x86_64";
245 std::string product = content::GetContentClient()->GetProduct();
246 std::string spoofed_ua =
247 BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
248 web_contents->SetUserAgentOverride(spoofed_ua);
250 java_bridge_dispatcher_host_.reset(
251 new GinJavaBridgeDispatcherHost(web_contents,
252 java_bridge_retained_object_set));
254 InitWebContents();
257 ContentViewCoreImpl::~ContentViewCoreImpl() {
258 JNIEnv* env = base::android::AttachCurrentThread();
259 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
260 java_ref_.reset();
261 if (!j_obj.is_null()) {
262 Java_ContentViewCore_onNativeContentViewCoreDestroyed(
263 env, j_obj.obj(), reinterpret_cast<intptr_t>(this));
267 base::android::ScopedJavaLocalRef<jobject>
268 ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env, jobject obj) {
269 return web_contents_->GetJavaWebContents();
272 void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env,
273 jobject obj) {
274 DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
275 java_ref_.reset();
276 // Java peer has gone, ContentViewCore is not functional and waits to
277 // be destroyed with WebContents.
278 // We need to reset WebContentsViewAndroid's reference, otherwise, there
279 // could have call in when swapping the WebContents,
280 // see http://crbug.com/383939 .
281 DCHECK(web_contents_);
282 static_cast<WebContentsViewAndroid*>(
283 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
284 SetContentViewCore(NULL);
287 void ContentViewCoreImpl::InitWebContents() {
288 DCHECK(web_contents_);
289 static_cast<WebContentsViewAndroid*>(
290 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
291 SetContentViewCore(this);
292 DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey));
293 web_contents_->SetUserData(kContentViewUserDataKey,
294 new ContentViewUserData(this));
297 void ContentViewCoreImpl::RenderViewReady() {
298 JNIEnv* env = AttachCurrentThread();
299 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
300 if (!obj.is_null())
301 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
303 if (device_orientation_ != 0)
304 SendOrientationChangeEventInternal();
307 void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host,
308 RenderViewHost* new_host) {
309 int old_pid = 0;
310 if (old_host) {
311 old_pid = GetRenderProcessIdFromRenderViewHost(old_host);
313 RenderWidgetHostViewAndroid* view =
314 static_cast<RenderWidgetHostViewAndroid*>(old_host->GetView());
315 if (view)
316 view->SetContentViewCore(NULL);
318 view = static_cast<RenderWidgetHostViewAndroid*>(new_host->GetView());
319 if (view)
320 view->SetContentViewCore(this);
322 int new_pid = GetRenderProcessIdFromRenderViewHost(
323 web_contents_->GetRenderViewHost());
324 if (new_pid != old_pid) {
325 // Notify the Java side that the renderer process changed.
326 JNIEnv* env = AttachCurrentThread();
327 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
328 if (!obj.is_null()) {
329 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
333 SetFocusInternal(HasFocus());
334 SetAccessibilityEnabledInternal(accessibility_enabled_);
337 RenderWidgetHostViewAndroid*
338 ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() {
339 RenderWidgetHostView* rwhv = NULL;
340 if (web_contents_) {
341 rwhv = web_contents_->GetRenderWidgetHostView();
342 if (web_contents_->ShowingInterstitialPage()) {
343 rwhv = static_cast<InterstitialPageImpl*>(
344 web_contents_->GetInterstitialPage())->
345 GetRenderViewHost()->GetView();
348 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
351 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() {
352 JNIEnv* env = AttachCurrentThread();
353 return java_ref_.get(env);
356 jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
357 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
358 if (!rwhva)
359 return SK_ColorWHITE;
360 return rwhva->GetCachedBackgroundColor();
363 void ContentViewCoreImpl::PauseVideo() {
364 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
365 web_contents_->GetRenderViewHost());
366 if (rvhi)
367 rvhi->media_web_contents_observer()->PauseVideo();
370 void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
371 web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause);
374 // All positions and sizes are in CSS pixels.
375 // Note that viewport_width/height is a best effort based.
376 // ContentViewCore has the actual information about the physical viewport size.
377 void ContentViewCoreImpl::UpdateFrameInfo(
378 const gfx::Vector2dF& scroll_offset,
379 float page_scale_factor,
380 const gfx::Vector2dF& page_scale_factor_limits,
381 const gfx::SizeF& content_size,
382 const gfx::SizeF& viewport_size,
383 const gfx::Vector2dF& controls_offset,
384 const gfx::Vector2dF& content_offset,
385 float overdraw_bottom_height) {
386 JNIEnv* env = AttachCurrentThread();
387 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
388 if (obj.is_null())
389 return;
391 window_android_->set_content_offset(
392 gfx::ScaleVector2d(content_offset, dpi_scale_));
394 Java_ContentViewCore_updateFrameInfo(
395 env, obj.obj(),
396 scroll_offset.x(),
397 scroll_offset.y(),
398 page_scale_factor,
399 page_scale_factor_limits.x(),
400 page_scale_factor_limits.y(),
401 content_size.width(),
402 content_size.height(),
403 viewport_size.width(),
404 viewport_size.height(),
405 controls_offset.y(),
406 content_offset.y(),
407 overdraw_bottom_height);
410 void ContentViewCoreImpl::SetTitle(const base::string16& title) {
411 JNIEnv* env = AttachCurrentThread();
412 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
413 if (obj.is_null())
414 return;
415 ScopedJavaLocalRef<jstring> jtitle =
416 ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title));
417 Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj());
420 void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
421 root_layer_->SetBackgroundColor(color);
423 JNIEnv* env = AttachCurrentThread();
424 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
425 if (obj.is_null())
426 return;
427 Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
430 void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds,
431 const std::vector<MenuItem>& items, int selected_item, bool multiple) {
432 JNIEnv* env = AttachCurrentThread();
433 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
434 if (j_obj.is_null())
435 return;
437 ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds));
439 // For multi-select list popups we find the list of previous selections by
440 // iterating through the items. But for single selection popups we take the
441 // given |selected_item| as is.
442 ScopedJavaLocalRef<jintArray> selected_array;
443 if (multiple) {
444 scoped_ptr<jint[]> native_selected_array(new jint[items.size()]);
445 size_t selected_count = 0;
446 for (size_t i = 0; i < items.size(); ++i) {
447 if (items[i].checked)
448 native_selected_array[selected_count++] = i;
451 selected_array = ScopedJavaLocalRef<jintArray>(
452 env, env->NewIntArray(selected_count));
453 env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
454 native_selected_array.get());
455 } else {
456 selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
457 jint value = selected_item;
458 env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
461 ScopedJavaLocalRef<jintArray> enabled_array(env,
462 env->NewIntArray(items.size()));
463 std::vector<base::string16> labels;
464 labels.reserve(items.size());
465 for (size_t i = 0; i < items.size(); ++i) {
466 labels.push_back(items[i].label);
467 jint enabled =
468 (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP :
469 (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED :
470 POPUP_ITEM_TYPE_DISABLED));
471 env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled);
473 ScopedJavaLocalRef<jobjectArray> items_array(
474 base::android::ToJavaArrayOfStrings(env, labels));
475 Java_ContentViewCore_showSelectPopup(env, j_obj.obj(),
476 bounds_rect.obj(),
477 items_array.obj(),
478 enabled_array.obj(),
479 multiple,
480 selected_array.obj());
483 void ContentViewCoreImpl::HideSelectPopupMenu() {
484 JNIEnv* env = AttachCurrentThread();
485 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
486 if (!j_obj.is_null())
487 Java_ContentViewCore_hideSelectPopup(env, j_obj.obj());
490 void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
491 InputEventAckState ack_result) {
492 JNIEnv* env = AttachCurrentThread();
493 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
494 if (j_obj.is_null())
495 return;
497 switch (event.type) {
498 case WebInputEvent::GestureFlingStart:
499 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
500 // The view expects the fling velocity in pixels/s.
501 Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(),
502 event.data.flingStart.velocityX * dpi_scale(),
503 event.data.flingStart.velocityY * dpi_scale());
504 } else {
505 // If a scroll ends with a fling, a SCROLL_END event is never sent.
506 // However, if that fling went unconsumed, we still need to let the
507 // listeners know that scrolling has ended.
508 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
511 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
512 // The view expects the fling velocity in pixels/s.
513 Java_ContentViewCore_onFlingStartEventHadNoConsumer(env, j_obj.obj(),
514 event.data.flingStart.velocityX * dpi_scale(),
515 event.data.flingStart.velocityY * dpi_scale());
517 break;
518 case WebInputEvent::GestureFlingCancel:
519 Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj());
520 break;
521 case WebInputEvent::GestureScrollBegin:
522 Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj());
523 break;
524 case WebInputEvent::GestureScrollUpdate:
525 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
526 Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj());
527 break;
528 case WebInputEvent::GestureScrollEnd:
529 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
530 break;
531 case WebInputEvent::GesturePinchBegin:
532 Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj());
533 break;
534 case WebInputEvent::GesturePinchEnd:
535 Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj());
536 break;
537 case WebInputEvent::GestureTap:
538 Java_ContentViewCore_onSingleTapEventAck(
539 env,
540 j_obj.obj(),
541 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED,
542 event.x * dpi_scale(),
543 event.y * dpi_scale());
544 break;
545 default:
546 break;
550 bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) {
551 if (event.type != WebInputEvent::GestureTap &&
552 event.type != WebInputEvent::GestureDoubleTap &&
553 event.type != WebInputEvent::GestureLongTap &&
554 event.type != WebInputEvent::GestureLongPress)
555 return false;
557 JNIEnv* env = AttachCurrentThread();
558 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
559 if (j_obj.is_null())
560 return false;
562 const blink::WebGestureEvent& gesture =
563 static_cast<const blink::WebGestureEvent&>(event);
564 int gesture_type = ToGestureEventType(event.type);
565 return Java_ContentViewCore_filterTapOrPressEvent(env,
566 j_obj.obj(),
567 gesture_type,
568 gesture.x * dpi_scale(),
569 gesture.y * dpi_scale());
571 // TODO(jdduke): Also report double-tap UMA, crbug/347568.
574 bool ContentViewCoreImpl::HasFocus() {
575 JNIEnv* env = AttachCurrentThread();
576 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
577 if (obj.is_null())
578 return false;
579 return Java_ContentViewCore_hasFocus(env, obj.obj());
582 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
583 JNIEnv* env = AttachCurrentThread();
584 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
585 if (obj.is_null())
586 return;
587 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text);
588 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
591 void ContentViewCoreImpl::OnSelectionEvent(SelectionEventType event,
592 const gfx::PointF& position) {
593 JNIEnv* env = AttachCurrentThread();
594 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
595 if (j_obj.is_null())
596 return;
597 Java_ContentViewCore_onSelectionEvent(
598 env, j_obj.obj(), event, position.x(), position.y());
601 scoped_ptr<TouchHandleDrawable>
602 ContentViewCoreImpl::CreatePopupTouchHandleDrawable() {
603 JNIEnv* env = AttachCurrentThread();
604 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
605 if (obj.is_null()) {
606 NOTREACHED();
607 return scoped_ptr<TouchHandleDrawable>();
609 return scoped_ptr<TouchHandleDrawable>(new PopupTouchHandleDrawable(
610 Java_ContentViewCore_createPopupTouchHandleDrawable(env, obj.obj()),
611 dpi_scale_));
614 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
615 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
616 if (!view)
617 return;
619 view->OnShowingPastePopup(gfx::PointF(x_dip, y_dip));
621 JNIEnv* env = AttachCurrentThread();
622 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
623 if (obj.is_null())
624 return;
625 Java_ContentViewCore_showPastePopup(env, obj.obj(),
626 static_cast<jint>(x_dip),
627 static_cast<jint>(y_dip));
630 void ContentViewCoreImpl::GetScaledContentBitmap(
631 float scale,
632 SkColorType color_type,
633 gfx::Rect src_subrect,
634 const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
635 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
636 if (!view) {
637 result_callback.Run(false, SkBitmap());
638 return;
641 view->GetScaledContentBitmap(scale, color_type, src_subrect,
642 result_callback);
645 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
646 JNIEnv* env = AttachCurrentThread();
647 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
648 if (j_obj.is_null())
649 return;
650 ScopedJavaLocalRef<jstring> jcontent_url =
651 ConvertUTF8ToJavaString(env, content_url.spec());
652 Java_ContentViewCore_startContentIntent(env,
653 j_obj.obj(),
654 jcontent_url.obj());
657 void ContentViewCoreImpl::ShowDisambiguationPopup(
658 const gfx::Rect& target_rect,
659 const SkBitmap& zoomed_bitmap) {
660 JNIEnv* env = AttachCurrentThread();
662 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
663 if (obj.is_null())
664 return;
666 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect));
668 ScopedJavaLocalRef<jobject> java_bitmap =
669 gfx::ConvertToJavaBitmap(&zoomed_bitmap);
670 DCHECK(!java_bitmap.is_null());
672 Java_ContentViewCore_showDisambiguationPopup(env,
673 obj.obj(),
674 rect_object.obj(),
675 java_bitmap.obj());
678 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
679 JNIEnv* env = AttachCurrentThread();
681 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
682 if (obj.is_null())
683 return ScopedJavaLocalRef<jobject>();
684 return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
687 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() {
688 JNIEnv* env = AttachCurrentThread();
690 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
691 if (obj.is_null())
692 return ScopedJavaLocalRef<jobject>();
694 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj());
697 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() {
698 JNIEnv* env = AttachCurrentThread();
700 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
701 if (obj.is_null())
702 return ScopedJavaLocalRef<jobject>();
704 return Java_ContentViewCore_getContext(env, obj.obj());
707 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
708 JNIEnv* env = AttachCurrentThread();
710 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
711 if (obj.is_null())
712 return true;
713 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
714 return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(),
715 j_url.obj());
718 void ContentViewCoreImpl::DidStopFlinging() {
719 JNIEnv* env = AttachCurrentThread();
721 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
722 if (!obj.is_null())
723 Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
726 gfx::Size ContentViewCoreImpl::GetViewSize() const {
727 gfx::Size size = GetViewportSizeDip();
728 gfx::Size offset = GetViewportSizeOffsetDip();
729 size.Enlarge(-offset.width(), -offset.height());
730 return size;
733 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
734 JNIEnv* env = AttachCurrentThread();
735 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
736 if (j_obj.is_null())
737 return gfx::Size();
738 return gfx::Size(
739 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()),
740 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj()));
743 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
744 JNIEnv* env = AttachCurrentThread();
745 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
746 if (j_obj.is_null())
747 return gfx::Size();
748 return gfx::Size(
749 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
750 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
753 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const {
754 JNIEnv* env = AttachCurrentThread();
755 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
756 if (j_obj.is_null())
757 return gfx::Size();
758 return gfx::Size(
759 Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()),
760 Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj()));
763 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
764 return gfx::ToCeiledSize(
765 gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
768 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const {
769 return gfx::ToCeiledSize(
770 gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / dpi_scale()));
773 float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const {
774 JNIEnv* env = AttachCurrentThread();
775 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
776 if (j_obj.is_null())
777 return 0.f;
778 return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj())
779 / dpi_scale();
782 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
783 root_layer_->InsertChild(layer, 0);
784 root_layer_->SetIsDrawable(false);
787 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
788 layer->RemoveFromParent();
790 if (!root_layer_->children().size())
791 root_layer_->SetIsDrawable(true);
794 void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& start,
795 const gfx::PointF& end) {
796 if (!web_contents_)
797 return;
799 gfx::Point start_point = gfx::Point(start.x(), start.y());
800 gfx::Point end_point = gfx::Point(end.x(), end.y());
801 if (start_point == end_point)
802 return;
804 web_contents_->SelectRange(start_point, end_point);
807 void ContentViewCoreImpl::LoadUrl(
808 NavigationController::LoadURLParams& params) {
809 GetWebContents()->GetController().LoadURLWithParams(params);
812 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
813 return view_android_;
816 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
817 return window_android_;
820 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
821 return root_layer_.get();
824 // ----------------------------------------------------------------------------
825 // Methods called from Java via JNI
826 // ----------------------------------------------------------------------------
828 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj,
829 jintArray indices) {
830 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
831 web_contents_->GetRenderViewHost());
832 DCHECK(rvhi);
833 if (indices == NULL) {
834 rvhi->DidCancelPopupMenu();
835 return;
838 int selected_count = env->GetArrayLength(indices);
839 std::vector<int> selected_indices;
840 jint* indices_ptr = env->GetIntArrayElements(indices, NULL);
841 for (int i = 0; i < selected_count; ++i)
842 selected_indices.push_back(indices_ptr[i]);
843 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
844 rvhi->DidSelectPopupMenuItems(selected_indices);
847 void ContentViewCoreImpl::LoadUrl(
848 JNIEnv* env, jobject obj,
849 jstring url,
850 jint load_url_type,
851 jint transition_type,
852 jstring j_referrer_url,
853 jint referrer_policy,
854 jint ua_override_option,
855 jstring extra_headers,
856 jbyteArray post_data,
857 jstring base_url_for_data_url,
858 jstring virtual_url_for_data_url,
859 jboolean can_load_local_resources,
860 jboolean is_renderer_initiated) {
861 DCHECK(url);
862 NavigationController::LoadURLParams params(
863 GURL(ConvertJavaStringToUTF8(env, url)));
865 params.load_type = static_cast<NavigationController::LoadURLType>(
866 load_url_type);
867 params.transition_type = PageTransitionFromInt(transition_type);
868 params.override_user_agent =
869 static_cast<NavigationController::UserAgentOverrideOption>(
870 ua_override_option);
872 if (extra_headers)
873 params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers);
875 if (post_data) {
876 std::vector<uint8> http_body_vector;
877 base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector);
878 params.browser_initiated_post_data =
879 base::RefCountedBytes::TakeVector(&http_body_vector);
882 if (base_url_for_data_url) {
883 params.base_url_for_data_url =
884 GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url));
887 if (virtual_url_for_data_url) {
888 params.virtual_url_for_data_url =
889 GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url));
892 params.can_load_local_resources = can_load_local_resources;
893 if (j_referrer_url) {
894 params.referrer = content::Referrer(
895 GURL(ConvertJavaStringToUTF8(env, j_referrer_url)),
896 static_cast<blink::WebReferrerPolicy>(referrer_policy));
899 params.is_renderer_initiated = is_renderer_initiated;
901 LoadUrl(params);
904 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL(
905 JNIEnv* env, jobject) const {
906 return ConvertUTF8ToJavaString(env, GetWebContents()->GetURL().spec());
909 jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) {
910 return GetWebContents()->GetBrowserContext()->IsOffTheRecord();
913 WebContents* ContentViewCoreImpl::GetWebContents() const {
914 return web_contents_;
917 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) {
918 SetFocusInternal(focused);
921 void ContentViewCoreImpl::SetFocusInternal(bool focused) {
922 if (!GetRenderWidgetHostViewAndroid())
923 return;
925 if (focused)
926 GetRenderWidgetHostViewAndroid()->Focus();
927 else
928 GetRenderWidgetHostViewAndroid()->Blur();
931 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env,
932 jobject obj,
933 jint orientation) {
934 if (device_orientation_ != orientation) {
935 device_orientation_ = orientation;
936 SendOrientationChangeEventInternal();
940 jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
941 jobject obj,
942 jobject motion_event,
943 jlong time_ms,
944 jint android_action,
945 jint pointer_count,
946 jint history_size,
947 jint action_index,
948 jfloat pos_x_0,
949 jfloat pos_y_0,
950 jfloat pos_x_1,
951 jfloat pos_y_1,
952 jint pointer_id_0,
953 jint pointer_id_1,
954 jfloat touch_major_0,
955 jfloat touch_major_1,
956 jfloat raw_pos_x,
957 jfloat raw_pos_y,
958 jint android_tool_type_0,
959 jint android_tool_type_1,
960 jint android_button_state,
961 jboolean is_touch_handle_event) {
962 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
963 // Avoid synthesizing a touch event if it cannot be forwarded.
964 if (!rwhv)
965 return false;
967 MotionEventAndroid event(1.f / dpi_scale(),
968 env,
969 motion_event,
970 time_ms,
971 android_action,
972 pointer_count,
973 history_size,
974 action_index,
975 pos_x_0,
976 pos_y_0,
977 pos_x_1,
978 pos_y_1,
979 pointer_id_0,
980 pointer_id_1,
981 touch_major_0,
982 touch_major_1,
983 raw_pos_x,
984 raw_pos_y,
985 android_tool_type_0,
986 android_tool_type_1,
987 android_button_state);
989 return is_touch_handle_event ? rwhv->OnTouchHandleEvent(event)
990 : rwhv->OnTouchEvent(event);
993 float ContentViewCoreImpl::GetDpiScale() const {
994 return dpi_scale_;
997 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env,
998 jobject obj,
999 jlong time_ms,
1000 jfloat x,
1001 jfloat y) {
1002 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1003 if (!rwhv)
1004 return false;
1006 blink::WebMouseEvent event = WebMouseEventBuilder::Build(
1007 WebInputEvent::MouseMove,
1008 blink::WebMouseEvent::ButtonNone,
1009 time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1);
1011 rwhv->SendMouseEvent(event);
1012 return true;
1015 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
1016 jobject obj,
1017 jlong time_ms,
1018 jfloat x,
1019 jfloat y,
1020 jfloat vertical_axis) {
1021 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1022 if (!rwhv)
1023 return false;
1025 WebMouseWheelEventBuilder::Direction direction;
1026 if (vertical_axis > 0) {
1027 direction = WebMouseWheelEventBuilder::DIRECTION_UP;
1028 } else if (vertical_axis < 0) {
1029 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN;
1030 } else {
1031 return false;
1033 blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build(
1034 direction, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1036 rwhv->SendMouseWheelEvent(event);
1037 return true;
1040 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent(
1041 WebInputEvent::Type type, int64 time_ms, float x, float y) const {
1042 return WebGestureEventBuilder::Build(
1043 type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1046 void ContentViewCoreImpl::SendGestureEvent(
1047 const blink::WebGestureEvent& event) {
1048 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1049 if (rwhv)
1050 rwhv->SendGestureEvent(event);
1053 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
1054 jobject obj,
1055 jlong time_ms,
1056 jfloat x,
1057 jfloat y,
1058 jfloat hintx,
1059 jfloat hinty) {
1060 WebGestureEvent event = MakeGestureEvent(
1061 WebInputEvent::GestureScrollBegin, time_ms, x, y);
1062 event.data.scrollBegin.deltaXHint = hintx / dpi_scale();
1063 event.data.scrollBegin.deltaYHint = hinty / dpi_scale();
1065 SendGestureEvent(event);
1068 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1069 WebGestureEvent event = MakeGestureEvent(
1070 WebInputEvent::GestureScrollEnd, time_ms, 0, 0);
1071 SendGestureEvent(event);
1074 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms,
1075 jfloat x, jfloat y, jfloat dx, jfloat dy) {
1076 WebGestureEvent event = MakeGestureEvent(
1077 WebInputEvent::GestureScrollUpdate, time_ms, x, y);
1078 event.data.scrollUpdate.deltaX = -dx / dpi_scale();
1079 event.data.scrollUpdate.deltaY = -dy / dpi_scale();
1081 SendGestureEvent(event);
1084 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms,
1085 jfloat x, jfloat y, jfloat vx, jfloat vy) {
1086 WebGestureEvent event = MakeGestureEvent(
1087 WebInputEvent::GestureFlingStart, time_ms, x, y);
1088 event.data.flingStart.velocityX = vx / dpi_scale();
1089 event.data.flingStart.velocityY = vy / dpi_scale();
1091 SendGestureEvent(event);
1094 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) {
1095 WebGestureEvent event = MakeGestureEvent(
1096 WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
1097 SendGestureEvent(event);
1100 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms,
1101 jfloat x, jfloat y) {
1102 WebGestureEvent event = MakeGestureEvent(
1103 WebInputEvent::GestureTap, time_ms, x, y);
1104 event.data.tap.tapCount = 1;
1106 SendGestureEvent(event);
1109 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
1110 jfloat x, jfloat y) {
1111 WebGestureEvent event = MakeGestureEvent(
1112 WebInputEvent::GestureDoubleTap, time_ms, x, y);
1113 // Set the tap count to 1 even for DoubleTap, in order to be consistent with
1114 // double tap behavior on a mobile viewport. See crbug.com/234986 for context.
1115 event.data.tap.tapCount = 1;
1117 SendGestureEvent(event);
1120 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms,
1121 jfloat x, jfloat y) {
1122 WebGestureEvent event = MakeGestureEvent(
1123 WebInputEvent::GestureLongPress, time_ms, x, y);
1125 SendGestureEvent(event);
1128 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms,
1129 jfloat x, jfloat y) {
1130 WebGestureEvent event = MakeGestureEvent(
1131 WebInputEvent::GesturePinchBegin, time_ms, x, y);
1132 SendGestureEvent(event);
1135 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1136 WebGestureEvent event = MakeGestureEvent(
1137 WebInputEvent::GesturePinchEnd, time_ms, 0, 0);
1138 SendGestureEvent(event);
1141 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms,
1142 jfloat anchor_x, jfloat anchor_y,
1143 jfloat delta) {
1144 WebGestureEvent event = MakeGestureEvent(
1145 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y);
1146 event.data.pinchUpdate.scale = delta;
1148 SendGestureEvent(event);
1151 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj,
1152 jfloat x1, jfloat y1,
1153 jfloat x2, jfloat y2) {
1154 SelectBetweenCoordinates(gfx::PointF(x1 / dpi_scale(), y1 / dpi_scale()),
1155 gfx::PointF(x2 / dpi_scale(), y2 / dpi_scale()));
1158 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj,
1159 jfloat x, jfloat y) {
1160 if (GetRenderWidgetHostViewAndroid()) {
1161 GetRenderWidgetHostViewAndroid()->MoveCaret(
1162 gfx::Point(x / dpi_scale_, y / dpi_scale_));
1166 void ContentViewCoreImpl::HideTextHandles(JNIEnv* env, jobject obj) {
1167 if (GetRenderWidgetHostViewAndroid())
1168 GetRenderWidgetHostViewAndroid()->HideTextHandles();
1171 void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) {
1172 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1173 if (rwhv)
1174 rwhv->ResetGestureDetection();
1177 void ContentViewCoreImpl::SetDoubleTapSupportEnabled(JNIEnv* env,
1178 jobject obj,
1179 jboolean enabled) {
1180 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1181 if (rwhv)
1182 rwhv->SetDoubleTapSupportEnabled(enabled);
1185 void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env,
1186 jobject obj,
1187 jboolean enabled) {
1188 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1189 if (rwhv)
1190 rwhv->SetMultiTouchZoomSupportEnabled(enabled);
1193 void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) {
1194 // TODO(creis): Do callers of this need to know if it fails?
1195 if (web_contents_->GetController().CanPruneAllButLastCommitted())
1196 web_contents_->GetController().PruneAllButLastCommitted();
1199 void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
1200 JNIEnv* env,
1201 jobject obj,
1202 jboolean allow) {
1203 java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow);
1206 void ContentViewCoreImpl::AddJavascriptInterface(
1207 JNIEnv* env,
1208 jobject /* obj */,
1209 jobject object,
1210 jstring name,
1211 jclass safe_annotation_clazz) {
1212 ScopedJavaLocalRef<jobject> scoped_object(env, object);
1213 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz);
1214 java_bridge_dispatcher_host_->AddNamedObject(
1215 ConvertJavaStringToUTF8(env, name), scoped_object, scoped_clazz);
1218 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
1219 jobject /* obj */,
1220 jstring name) {
1221 java_bridge_dispatcher_host_->RemoveNamedObject(
1222 ConvertJavaStringToUTF8(env, name));
1225 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
1226 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1227 gfx::Size physical_size(
1228 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
1229 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
1230 root_layer_->SetBounds(physical_size);
1232 if (view) {
1233 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
1234 view->GetRenderWidgetHost());
1235 host->SendScreenRects();
1236 view->WasResized();
1240 namespace {
1242 static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj,
1243 jobject history,
1244 NavigationEntry* entry,
1245 int index) {
1246 // Get the details of the current entry
1247 ScopedJavaLocalRef<jstring> j_url(
1248 ConvertUTF8ToJavaString(env, entry->GetURL().spec()));
1249 ScopedJavaLocalRef<jstring> j_virtual_url(
1250 ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec()));
1251 ScopedJavaLocalRef<jstring> j_original_url(
1252 ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
1253 ScopedJavaLocalRef<jstring> j_title(
1254 ConvertUTF16ToJavaString(env, entry->GetTitle()));
1255 ScopedJavaLocalRef<jobject> j_bitmap;
1256 const FaviconStatus& status = entry->GetFavicon();
1257 if (status.valid && status.image.ToSkBitmap()->getSize() > 0)
1258 j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
1260 // Add the item to the list
1261 Java_ContentViewCore_addToNavigationHistory(
1262 env, obj, history, index, j_url.obj(), j_virtual_url.obj(),
1263 j_original_url.obj(), j_title.obj(), j_bitmap.obj());
1266 } // namespace
1268 int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env,
1269 jobject obj,
1270 jobject history) {
1271 // Iterate through navigation entries to populate the list
1272 const NavigationController& controller = web_contents_->GetController();
1273 int count = controller.GetEntryCount();
1274 for (int i = 0; i < count; ++i) {
1275 AddNavigationEntryToHistory(
1276 env, obj, history, controller.GetEntryAtIndex(i), i);
1279 return controller.GetCurrentEntryIndex();
1282 void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env,
1283 jobject obj,
1284 jobject history,
1285 jboolean is_forward,
1286 jint max_entries) {
1287 // Iterate through navigation entries to populate the list
1288 const NavigationController& controller = web_contents_->GetController();
1289 int count = controller.GetEntryCount();
1290 int num_added = 0;
1291 int increment_value = is_forward ? 1 : -1;
1292 for (int i = controller.GetCurrentEntryIndex() + increment_value;
1293 i >= 0 && i < count;
1294 i += increment_value) {
1295 if (num_added >= max_entries)
1296 break;
1298 AddNavigationEntryToHistory(
1299 env, obj, history, controller.GetEntryAtIndex(i), i);
1300 num_added++;
1304 ScopedJavaLocalRef<jstring>
1305 ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env,
1306 jobject obj) {
1307 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1308 if (entry == NULL)
1309 return ScopedJavaLocalRef<jstring>(env, NULL);
1310 return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec());
1313 long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
1314 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
1315 if (!rwhva)
1316 return 0;
1317 return rwhva->GetNativeImeAdapter();
1320 namespace {
1321 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
1322 const base::Value* result) {
1323 JNIEnv* env = base::android::AttachCurrentThread();
1324 std::string json;
1325 base::JSONWriter::Write(result, &json);
1326 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
1327 Java_ContentViewCore_onEvaluateJavaScriptResult(env,
1328 j_json.obj(),
1329 callback.obj());
1331 } // namespace
1333 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
1334 jobject obj,
1335 jstring script,
1336 jobject callback,
1337 jboolean start_renderer) {
1338 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
1339 DCHECK(rvh);
1341 if (start_renderer && !rvh->IsRenderViewLive()) {
1342 if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) {
1343 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
1344 return;
1348 if (!callback) {
1349 // No callback requested.
1350 web_contents_->GetMainFrame()->ExecuteJavaScript(
1351 ConvertJavaStringToUTF16(env, script));
1352 return;
1355 // Secure the Java callback in a scoped object and give ownership of it to the
1356 // base::Callback.
1357 ScopedJavaGlobalRef<jobject> j_callback;
1358 j_callback.Reset(env, callback);
1359 content::RenderFrameHost::JavaScriptResultCallback c_callback =
1360 base::Bind(&JavaScriptResultCallback, j_callback);
1362 web_contents_->GetMainFrame()->ExecuteJavaScript(
1363 ConvertJavaStringToUTF16(env, script),
1364 c_callback);
1367 // TODO(sgurun) add support for posting a frame whose name is known (only
1368 // main frame is supported at this time, see crbug.com/389721)
1369 // TODO(sgurun) add support for passing message ports
1370 void ContentViewCoreImpl::PostMessageToFrame(JNIEnv* env, jobject obj,
1371 jstring frame_name, jstring message, jstring source_origin,
1372 jstring target_origin) {
1374 RenderViewHost* host = web_contents_->GetRenderViewHost();
1375 if (!host)
1376 return;
1377 ViewMsg_PostMessage_Params params;
1378 params.source_origin = ConvertJavaStringToUTF16(env, source_origin);
1379 params.target_origin = ConvertJavaStringToUTF16(env, target_origin);
1380 params.data = ConvertJavaStringToUTF16(env, message);
1381 params.is_data_raw_string = true;
1382 params.source_routing_id = MSG_ROUTING_NONE;
1383 host->Send(new ViewMsg_PostMessageEvent(host->GetRoutingID(), params));
1387 bool ContentViewCoreImpl::GetUseDesktopUserAgent(
1388 JNIEnv* env, jobject obj) {
1389 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1390 return entry && entry->GetIsOverridingUserAgent();
1393 void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
1394 int text_input_type,
1395 const std::string& text,
1396 int selection_start,
1397 int selection_end,
1398 int composition_start,
1399 int composition_end,
1400 bool show_ime_if_needed,
1401 bool is_non_ime_change) {
1402 JNIEnv* env = AttachCurrentThread();
1403 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1404 if (obj.is_null())
1405 return;
1407 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
1408 Java_ContentViewCore_updateImeAdapter(env, obj.obj(),
1409 native_ime_adapter, text_input_type,
1410 jstring_text.obj(),
1411 selection_start, selection_end,
1412 composition_start, composition_end,
1413 show_ime_if_needed, is_non_ime_change);
1416 void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) {
1417 SSLHostState* state = SSLHostState::GetFor(
1418 web_contents_->GetController().GetBrowserContext());
1419 state->Clear();
1422 void ContentViewCoreImpl::SetUseDesktopUserAgent(
1423 JNIEnv* env,
1424 jobject obj,
1425 jboolean enabled,
1426 jboolean reload_on_state_change) {
1427 if (GetUseDesktopUserAgent(env, obj) == enabled)
1428 return;
1430 // Make sure the navigation entry actually exists.
1431 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1432 if (!entry)
1433 return;
1435 // Set the flag in the NavigationEntry.
1436 entry->SetIsOverridingUserAgent(enabled);
1438 // Send the override to the renderer.
1439 if (reload_on_state_change) {
1440 // Reloading the page will send the override down as part of the
1441 // navigation IPC message.
1442 NavigationControllerImpl& controller =
1443 static_cast<NavigationControllerImpl&>(web_contents_->GetController());
1444 controller.ReloadOriginalRequestURL(false);
1448 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
1449 bool enabled) {
1450 SetAccessibilityEnabledInternal(enabled);
1453 bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
1454 JNIEnv* env = AttachCurrentThread();
1455 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1456 if (obj.is_null())
1457 return true;
1458 return Java_ContentViewCore_isFullscreenRequiredForOrientationLock(env,
1459 obj.obj());
1462 void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) {
1463 accessibility_enabled_ = enabled;
1464 BrowserAccessibilityStateImpl* accessibility_state =
1465 BrowserAccessibilityStateImpl::GetInstance();
1466 if (enabled) {
1467 // This enables accessibility globally unless it was explicitly disallowed
1468 // by a command-line flag.
1469 accessibility_state->OnScreenReaderDetected();
1470 // If it was actually enabled globally, enable it for this RenderWidget now.
1471 if (accessibility_state->IsAccessibleBrowser() && web_contents_)
1472 web_contents_->AddAccessibilityMode(AccessibilityModeComplete);
1473 } else {
1474 accessibility_state->ResetAccessibilityMode();
1475 if (web_contents_) {
1476 web_contents_->SetAccessibilityMode(
1477 accessibility_state->accessibility_mode());
1482 void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
1483 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1484 if (rwhv)
1485 rwhv->UpdateScreenInfo(GetViewAndroid());
1487 static_cast<WebContentsImpl*>(web_contents())->
1488 screen_orientation_dispatcher_host()->OnOrientationChange();
1491 void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
1492 jobject obj,
1493 jint x,
1494 jint y,
1495 jint width,
1496 jint height) {
1497 gfx::Rect rect(
1498 static_cast<int>(x / dpi_scale()),
1499 static_cast<int>(y / dpi_scale()),
1500 static_cast<int>((width > 0 && width < dpi_scale()) ?
1501 1 : (int)(width / dpi_scale())),
1502 static_cast<int>((height > 0 && height < dpi_scale()) ?
1503 1 : (int)(height / dpi_scale())));
1504 GetWebContents()->Send(new ViewMsg_ExtractSmartClipData(
1505 GetWebContents()->GetRoutingID(), rect));
1508 void ContentViewCoreImpl::ResumeResponseDeferredAtStart(JNIEnv* env,
1509 jobject obj) {
1510 static_cast<WebContentsImpl*>(GetWebContents())->
1511 ResumeResponseDeferredAtStart();
1514 void ContentViewCoreImpl::SetHasPendingNavigationTransitionForTesting(
1515 JNIEnv* env,
1516 jobject obj) {
1517 RenderFrameHost* frame = static_cast<WebContentsImpl*>(GetWebContents())->
1518 GetMainFrame();
1519 BrowserThread::PostTask(
1520 BrowserThread::IO,
1521 FROM_HERE,
1522 base::Bind(
1523 &TransitionRequestManager::SetHasPendingTransitionRequest,
1524 base::Unretained(TransitionRequestManager::GetInstance()),
1525 frame->GetProcess()->GetID(),
1526 frame->GetRoutingID(),
1527 true));
1530 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) {
1531 return GetRenderProcessIdFromRenderViewHost(
1532 web_contents_->GetRenderViewHost());
1535 void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj,
1536 jboolean opaque) {
1537 if (GetRenderWidgetHostViewAndroid())
1538 GetRenderWidgetHostViewAndroid()->SetBackgroundOpaque(opaque);
1541 void ContentViewCoreImpl::RequestTextSurroundingSelection(
1542 int max_length,
1543 const base::Callback<
1544 void(const base::string16& content, int start_offset, int end_offset)>&
1545 callback) {
1546 DCHECK(!callback.is_null());
1547 RenderFrameHost* focused_frame = web_contents_->GetFocusedFrame();
1548 if (!focused_frame)
1549 return;
1550 if (GetRenderWidgetHostViewAndroid()) {
1551 GetRenderWidgetHostViewAndroid()->SetTextSurroundingSelectionCallback(
1552 callback);
1553 focused_frame->Send(new FrameMsg_TextSurroundingSelectionRequest(
1554 focused_frame->GetRoutingID(), max_length));
1558 void ContentViewCoreImpl::DidDeferAfterResponseStarted(
1559 const scoped_refptr<net::HttpResponseHeaders>& headers,
1560 const GURL& url) {
1561 JNIEnv* env = AttachCurrentThread();
1562 ScopedJavaLocalRef<jobject> obj(java_ref_.get(env));
1563 if (obj.is_null())
1564 return;
1566 std::vector<GURL> entering_stylesheets;
1567 std::string transition_color;
1568 if (headers) {
1569 TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
1570 headers, entering_stylesheets, url);
1572 headers->EnumerateHeader(
1573 NULL, "X-Transition-Entering-Color", &transition_color);
1576 ScopedJavaLocalRef<jstring> jstring_transition_color(ConvertUTF8ToJavaString(
1577 env, transition_color));
1579 Java_ContentViewCore_didDeferAfterResponseStarted(
1580 env, obj.obj(), jstring_transition_color.obj());
1582 std::vector<GURL>::const_iterator iter = entering_stylesheets.begin();
1583 for (; iter != entering_stylesheets.end(); ++iter) {
1584 ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
1585 env, iter->spec()));
1586 Java_ContentViewCore_addEnteringStylesheetToTransition(
1587 env, obj.obj(), jstring_url.obj());
1591 bool ContentViewCoreImpl::WillHandleDeferAfterResponseStarted() {
1592 JNIEnv* env = AttachCurrentThread();
1593 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1594 if (obj.is_null())
1595 return false;
1597 return Java_ContentViewCore_willHandleDeferAfterResponseStarted(env,
1598 obj.obj());
1601 void ContentViewCoreImpl::DidStartNavigationTransitionForFrame(int64 frame_id) {
1602 JNIEnv* env = AttachCurrentThread();
1603 ScopedJavaLocalRef<jobject> obj(java_ref_.get(env));
1604 if (obj.is_null())
1605 return;
1606 Java_ContentViewCore_didStartNavigationTransitionForFrame(
1607 env, obj.obj(), frame_id);
1610 void ContentViewCoreImpl::OnSmartClipDataExtracted(
1611 const base::string16& text,
1612 const base::string16& html,
1613 const gfx::Rect& clip_rect) {
1614 JNIEnv* env = AttachCurrentThread();
1615 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1616 if (obj.is_null())
1617 return;
1618 ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
1619 ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html);
1620 ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect));
1621 Java_ContentViewCore_onSmartClipDataExtracted(
1622 env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj());
1625 void ContentViewCoreImpl::WebContentsDestroyed() {
1626 WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
1627 static_cast<WebContentsImpl*>(web_contents())->GetView());
1628 DCHECK(wcva);
1629 wcva->SetContentViewCore(NULL);
1632 // This is called for each ContentView.
1633 jlong Init(JNIEnv* env,
1634 jobject obj,
1635 jlong native_web_contents,
1636 jlong view_android,
1637 jlong window_android,
1638 jobject retained_objects_set) {
1639 ContentViewCoreImpl* view = new ContentViewCoreImpl(
1640 env, obj,
1641 reinterpret_cast<WebContents*>(native_web_contents),
1642 reinterpret_cast<ui::ViewAndroid*>(view_android),
1643 reinterpret_cast<ui::WindowAndroid*>(window_android),
1644 retained_objects_set);
1645 return reinterpret_cast<intptr_t>(view);
1648 bool RegisterContentViewCore(JNIEnv* env) {
1649 return RegisterNativesImpl(env);
1652 } // namespace content