Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / android / content_view_core_impl.cc
blobdabf69c99ab3273679542dfdd3a8b6118b30c91a
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/android/gesture_event_type.h"
21 #include "content/browser/android/interstitial_page_delegate_android.h"
22 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
23 #include "content/browser/android/load_url_params.h"
24 #include "content/browser/frame_host/interstitial_page_impl.h"
25 #include "content/browser/frame_host/navigation_controller_impl.h"
26 #include "content/browser/frame_host/navigation_entry_impl.h"
27 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
28 #include "content/browser/media/media_web_contents_observer.h"
29 #include "content/browser/renderer_host/compositor_impl_android.h"
30 #include "content/browser/renderer_host/input/motion_event_android.h"
31 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
32 #include "content/browser/renderer_host/input/web_input_event_util.h"
33 #include "content/browser/renderer_host/render_view_host_impl.h"
34 #include "content/browser/renderer_host/render_widget_host_impl.h"
35 #include "content/browser/renderer_host/render_widget_host_view_android.h"
36 #include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
37 #include "content/browser/ssl/ssl_host_state.h"
38 #include "content/browser/transition_request_manager.h"
39 #include "content/browser/web_contents/web_contents_view_android.h"
40 #include "content/common/frame_messages.h"
41 #include "content/common/input/web_input_event_traits.h"
42 #include "content/common/input_messages.h"
43 #include "content/common/view_messages.h"
44 #include "content/public/browser/browser_accessibility_state.h"
45 #include "content/public/browser/browser_context.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/favicon_status.h"
48 #include "content/public/browser/render_frame_host.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/common/content_client.h"
51 #include "content/public/common/content_switches.h"
52 #include "content/public/common/menu_item.h"
53 #include "content/public/common/page_transition_types.h"
54 #include "content/public/common/user_agent.h"
55 #include "jni/ContentViewCore_jni.h"
56 #include "third_party/WebKit/public/web/WebInputEvent.h"
57 #include "ui/base/android/view_android.h"
58 #include "ui/base/android/window_android.h"
59 #include "ui/gfx/android/java_bitmap.h"
60 #include "ui/gfx/screen.h"
61 #include "ui/gfx/size_conversions.h"
62 #include "ui/gfx/size_f.h"
64 using base::android::AttachCurrentThread;
65 using base::android::ConvertJavaStringToUTF16;
66 using base::android::ConvertJavaStringToUTF8;
67 using base::android::ConvertUTF16ToJavaString;
68 using base::android::ConvertUTF8ToJavaString;
69 using base::android::ScopedJavaGlobalRef;
70 using base::android::ScopedJavaLocalRef;
71 using blink::WebGestureEvent;
72 using blink::WebInputEvent;
74 // Describes the type and enabled state of a select popup item.
75 namespace {
77 enum {
78 #define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value,
79 #include "content/browser/android/popup_item_type_list.h"
80 #undef DEFINE_POPUP_ITEM_TYPE
83 } //namespace
85 namespace content {
87 namespace {
89 const void* kContentViewUserDataKey = &kContentViewUserDataKey;
91 int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
92 DCHECK(host);
93 RenderProcessHost* render_process = host->GetProcess();
94 DCHECK(render_process);
95 if (render_process->HasConnection())
96 return render_process->GetHandle();
97 else
98 return 0;
101 ScopedJavaLocalRef<jobject> CreateJavaRect(
102 JNIEnv* env,
103 const gfx::Rect& rect) {
104 return ScopedJavaLocalRef<jobject>(
105 Java_ContentViewCore_createRect(env,
106 static_cast<int>(rect.x()),
107 static_cast<int>(rect.y()),
108 static_cast<int>(rect.right()),
109 static_cast<int>(rect.bottom())));
112 int ToGestureEventType(WebInputEvent::Type type) {
113 switch (type) {
114 case WebInputEvent::GestureScrollBegin:
115 return SCROLL_START;
116 case WebInputEvent::GestureScrollEnd:
117 return SCROLL_END;
118 case WebInputEvent::GestureScrollUpdate:
119 return SCROLL_BY;
120 case WebInputEvent::GestureFlingStart:
121 return FLING_START;
122 case WebInputEvent::GestureFlingCancel:
123 return FLING_CANCEL;
124 case WebInputEvent::GestureShowPress:
125 return SHOW_PRESS;
126 case WebInputEvent::GestureTap:
127 return SINGLE_TAP_CONFIRMED;
128 case WebInputEvent::GestureTapUnconfirmed:
129 return SINGLE_TAP_UNCONFIRMED;
130 case WebInputEvent::GestureTapDown:
131 return TAP_DOWN;
132 case WebInputEvent::GestureTapCancel:
133 return TAP_CANCEL;
134 case WebInputEvent::GestureDoubleTap:
135 return DOUBLE_TAP;
136 case WebInputEvent::GestureLongPress:
137 return LONG_PRESS;
138 case WebInputEvent::GestureLongTap:
139 return LONG_TAP;
140 case WebInputEvent::GesturePinchBegin:
141 return PINCH_BEGIN;
142 case WebInputEvent::GesturePinchEnd:
143 return PINCH_END;
144 case WebInputEvent::GesturePinchUpdate:
145 return PINCH_BY;
146 case WebInputEvent::GestureTwoFingerTap:
147 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
148 default:
149 NOTREACHED() << "Invalid source gesture type: "
150 << WebInputEventTraits::GetName(type);
151 return -1;
155 float GetPrimaryDisplayDeviceScaleFactor() {
156 const gfx::Display& display =
157 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
158 return display.device_scale_factor();
161 } // namespace
163 // Enables a callback when the underlying WebContents is destroyed, to enable
164 // nulling the back-pointer.
165 class ContentViewCoreImpl::ContentViewUserData
166 : public base::SupportsUserData::Data {
167 public:
168 explicit ContentViewUserData(ContentViewCoreImpl* content_view_core)
169 : content_view_core_(content_view_core) {
172 virtual ~ContentViewUserData() {
173 // TODO(joth): When chrome has finished removing the TabContents class (see
174 // crbug.com/107201) consider inverting relationship, so ContentViewCore
175 // would own WebContents. That effectively implies making the WebContents
176 // destructor private on Android.
177 delete content_view_core_;
180 ContentViewCoreImpl* get() const { return content_view_core_; }
182 private:
183 // Not using scoped_ptr as ContentViewCoreImpl destructor is private.
184 ContentViewCoreImpl* content_view_core_;
186 DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData);
189 // static
190 ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
191 content::WebContents* web_contents) {
192 ContentViewCoreImpl::ContentViewUserData* data =
193 reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>(
194 web_contents->GetUserData(kContentViewUserDataKey));
195 return data ? data->get() : NULL;
198 // static
199 ContentViewCore* ContentViewCore::FromWebContents(
200 content::WebContents* web_contents) {
201 return ContentViewCoreImpl::FromWebContents(web_contents);
204 // static
205 ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
206 jobject obj) {
207 return reinterpret_cast<ContentViewCore*>(
208 Java_ContentViewCore_getNativeContentViewCore(env, obj));
211 ContentViewCoreImpl::ContentViewCoreImpl(
212 JNIEnv* env,
213 jobject obj,
214 WebContents* web_contents,
215 ui::ViewAndroid* view_android,
216 ui::WindowAndroid* window_android,
217 jobject java_bridge_retained_object_set)
218 : WebContentsObserver(web_contents),
219 java_ref_(env, obj),
220 web_contents_(static_cast<WebContentsImpl*>(web_contents)),
221 root_layer_(cc::SolidColorLayer::Create()),
222 dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
223 view_android_(view_android),
224 window_android_(window_android),
225 device_orientation_(0),
226 accessibility_enabled_(false) {
227 CHECK(web_contents) <<
228 "A ContentViewCoreImpl should be created with a valid WebContents.";
229 DCHECK(view_android_);
230 DCHECK(window_android_);
232 root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj));
233 gfx::Size physical_size(
234 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
235 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
236 root_layer_->SetBounds(physical_size);
237 root_layer_->SetIsDrawable(true);
239 // Currently, the only use case we have for overriding a user agent involves
240 // spoofing a desktop Linux user agent for "Request desktop site".
241 // Automatically set it for all WebContents so that it is available when a
242 // NavigationEntry requires the user agent to be overridden.
243 const char kLinuxInfoStr[] = "X11; Linux x86_64";
244 std::string product = content::GetContentClient()->GetProduct();
245 std::string spoofed_ua =
246 BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
247 web_contents->SetUserAgentOverride(spoofed_ua);
249 java_bridge_dispatcher_host_.reset(
250 new GinJavaBridgeDispatcherHost(web_contents,
251 java_bridge_retained_object_set));
253 InitWebContents();
256 ContentViewCoreImpl::~ContentViewCoreImpl() {
257 JNIEnv* env = base::android::AttachCurrentThread();
258 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
259 java_ref_.reset();
260 if (!j_obj.is_null()) {
261 Java_ContentViewCore_onNativeContentViewCoreDestroyed(
262 env, j_obj.obj(), reinterpret_cast<intptr_t>(this));
266 base::android::ScopedJavaLocalRef<jobject>
267 ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env, jobject obj) {
268 return web_contents_->GetJavaWebContents();
271 void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env,
272 jobject obj) {
273 DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
274 java_ref_.reset();
275 // Java peer has gone, ContentViewCore is not functional and waits to
276 // be destroyed with WebContents.
277 // We need to reset WebContentsViewAndroid's reference, otherwise, there
278 // could have call in when swapping the WebContents,
279 // see http://crbug.com/383939 .
280 DCHECK(web_contents_);
281 static_cast<WebContentsViewAndroid*>(
282 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
283 SetContentViewCore(NULL);
286 void ContentViewCoreImpl::InitWebContents() {
287 DCHECK(web_contents_);
288 static_cast<WebContentsViewAndroid*>(
289 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
290 SetContentViewCore(this);
291 DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey));
292 web_contents_->SetUserData(kContentViewUserDataKey,
293 new ContentViewUserData(this));
296 void ContentViewCoreImpl::RenderViewReady() {
297 JNIEnv* env = AttachCurrentThread();
298 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
299 if (!obj.is_null())
300 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
302 if (device_orientation_ != 0)
303 SendOrientationChangeEventInternal();
306 void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host,
307 RenderViewHost* new_host) {
308 int old_pid = 0;
309 if (old_host) {
310 old_pid = GetRenderProcessIdFromRenderViewHost(old_host);
312 RenderWidgetHostViewAndroid* view =
313 static_cast<RenderWidgetHostViewAndroid*>(old_host->GetView());
314 if (view)
315 view->SetContentViewCore(NULL);
317 view = static_cast<RenderWidgetHostViewAndroid*>(new_host->GetView());
318 if (view)
319 view->SetContentViewCore(this);
321 int new_pid = GetRenderProcessIdFromRenderViewHost(
322 web_contents_->GetRenderViewHost());
323 if (new_pid != old_pid) {
324 // Notify the Java side that the renderer process changed.
325 JNIEnv* env = AttachCurrentThread();
326 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
327 if (!obj.is_null()) {
328 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
332 SetFocusInternal(HasFocus());
333 SetAccessibilityEnabledInternal(accessibility_enabled_);
336 RenderWidgetHostViewAndroid*
337 ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() {
338 RenderWidgetHostView* rwhv = NULL;
339 if (web_contents_) {
340 rwhv = web_contents_->GetRenderWidgetHostView();
341 if (web_contents_->ShowingInterstitialPage()) {
342 rwhv = static_cast<InterstitialPageImpl*>(
343 web_contents_->GetInterstitialPage())->
344 GetRenderViewHost()->GetView();
347 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
350 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() {
351 JNIEnv* env = AttachCurrentThread();
352 return java_ref_.get(env);
355 jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
356 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
357 if (!rwhva)
358 return SK_ColorWHITE;
359 return rwhva->GetCachedBackgroundColor();
362 void ContentViewCoreImpl::OnHide(JNIEnv* env, jobject obj) {
363 Hide();
366 void ContentViewCoreImpl::OnShow(JNIEnv* env, jobject obj) {
367 Show();
370 void ContentViewCoreImpl::Show() {
371 GetWebContents()->WasShown();
374 void ContentViewCoreImpl::Hide() {
375 GetWebContents()->WasHidden();
376 PauseVideo();
379 void ContentViewCoreImpl::PauseVideo() {
380 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
381 web_contents_->GetRenderViewHost());
382 if (rvhi)
383 rvhi->media_web_contents_observer()->PauseVideo();
386 void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
387 web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause);
390 // All positions and sizes are in CSS pixels.
391 // Note that viewport_width/height is a best effort based.
392 // ContentViewCore has the actual information about the physical viewport size.
393 void ContentViewCoreImpl::UpdateFrameInfo(
394 const gfx::Vector2dF& scroll_offset,
395 float page_scale_factor,
396 const gfx::Vector2dF& page_scale_factor_limits,
397 const gfx::SizeF& content_size,
398 const gfx::SizeF& viewport_size,
399 const gfx::Vector2dF& controls_offset,
400 const gfx::Vector2dF& content_offset,
401 float overdraw_bottom_height) {
402 JNIEnv* env = AttachCurrentThread();
403 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
404 if (obj.is_null())
405 return;
407 window_android_->set_content_offset(
408 gfx::ScaleVector2d(content_offset, dpi_scale_));
410 Java_ContentViewCore_updateFrameInfo(
411 env, obj.obj(),
412 scroll_offset.x(),
413 scroll_offset.y(),
414 page_scale_factor,
415 page_scale_factor_limits.x(),
416 page_scale_factor_limits.y(),
417 content_size.width(),
418 content_size.height(),
419 viewport_size.width(),
420 viewport_size.height(),
421 controls_offset.y(),
422 content_offset.y(),
423 overdraw_bottom_height);
426 void ContentViewCoreImpl::SetTitle(const base::string16& title) {
427 JNIEnv* env = AttachCurrentThread();
428 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
429 if (obj.is_null())
430 return;
431 ScopedJavaLocalRef<jstring> jtitle =
432 ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title));
433 Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj());
436 void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
437 root_layer_->SetBackgroundColor(color);
439 JNIEnv* env = AttachCurrentThread();
440 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
441 if (obj.is_null())
442 return;
443 Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
446 void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds,
447 const std::vector<MenuItem>& items, int selected_item, bool multiple) {
448 JNIEnv* env = AttachCurrentThread();
449 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
450 if (j_obj.is_null())
451 return;
453 ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds));
455 // For multi-select list popups we find the list of previous selections by
456 // iterating through the items. But for single selection popups we take the
457 // given |selected_item| as is.
458 ScopedJavaLocalRef<jintArray> selected_array;
459 if (multiple) {
460 scoped_ptr<jint[]> native_selected_array(new jint[items.size()]);
461 size_t selected_count = 0;
462 for (size_t i = 0; i < items.size(); ++i) {
463 if (items[i].checked)
464 native_selected_array[selected_count++] = i;
467 selected_array = ScopedJavaLocalRef<jintArray>(
468 env, env->NewIntArray(selected_count));
469 env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
470 native_selected_array.get());
471 } else {
472 selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
473 jint value = selected_item;
474 env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
477 ScopedJavaLocalRef<jintArray> enabled_array(env,
478 env->NewIntArray(items.size()));
479 std::vector<base::string16> labels;
480 labels.reserve(items.size());
481 for (size_t i = 0; i < items.size(); ++i) {
482 labels.push_back(items[i].label);
483 jint enabled =
484 (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP :
485 (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED :
486 POPUP_ITEM_TYPE_DISABLED));
487 env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled);
489 ScopedJavaLocalRef<jobjectArray> items_array(
490 base::android::ToJavaArrayOfStrings(env, labels));
491 Java_ContentViewCore_showSelectPopup(env, j_obj.obj(),
492 bounds_rect.obj(),
493 items_array.obj(),
494 enabled_array.obj(),
495 multiple,
496 selected_array.obj());
499 void ContentViewCoreImpl::HideSelectPopupMenu() {
500 JNIEnv* env = AttachCurrentThread();
501 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
502 if (!j_obj.is_null())
503 Java_ContentViewCore_hideSelectPopup(env, j_obj.obj());
506 void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
507 InputEventAckState ack_result) {
508 JNIEnv* env = AttachCurrentThread();
509 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
510 if (j_obj.is_null())
511 return;
513 switch (event.type) {
514 case WebInputEvent::GestureFlingStart:
515 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
516 // The view expects the fling velocity in pixels/s.
517 Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(),
518 event.data.flingStart.velocityX * dpi_scale(),
519 event.data.flingStart.velocityY * dpi_scale());
520 } else {
521 // If a scroll ends with a fling, a SCROLL_END event is never sent.
522 // However, if that fling went unconsumed, we still need to let the
523 // listeners know that scrolling has ended.
524 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
527 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
528 // The view expects the fling velocity in pixels/s.
529 Java_ContentViewCore_onFlingStartEventHadNoConsumer(env, j_obj.obj(),
530 event.data.flingStart.velocityX * dpi_scale(),
531 event.data.flingStart.velocityY * dpi_scale());
533 break;
534 case WebInputEvent::GestureFlingCancel:
535 Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj());
536 break;
537 case WebInputEvent::GestureScrollBegin:
538 Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj());
539 break;
540 case WebInputEvent::GestureScrollUpdate:
541 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
542 Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj());
543 break;
544 case WebInputEvent::GestureScrollEnd:
545 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
546 break;
547 case WebInputEvent::GesturePinchBegin:
548 Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj());
549 break;
550 case WebInputEvent::GesturePinchEnd:
551 Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj());
552 break;
553 case WebInputEvent::GestureTap:
554 Java_ContentViewCore_onSingleTapEventAck(
555 env,
556 j_obj.obj(),
557 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED,
558 event.x * dpi_scale(),
559 event.y * dpi_scale());
560 break;
561 case WebInputEvent::GestureDoubleTap:
562 Java_ContentViewCore_onDoubleTapEventAck(env, j_obj.obj());
563 break;
564 default:
565 break;
569 bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) {
570 if (event.type != WebInputEvent::GestureTap &&
571 event.type != WebInputEvent::GestureDoubleTap &&
572 event.type != WebInputEvent::GestureLongTap &&
573 event.type != WebInputEvent::GestureLongPress)
574 return false;
576 JNIEnv* env = AttachCurrentThread();
577 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
578 if (j_obj.is_null())
579 return false;
581 const blink::WebGestureEvent& gesture =
582 static_cast<const blink::WebGestureEvent&>(event);
583 int gesture_type = ToGestureEventType(event.type);
584 return Java_ContentViewCore_filterTapOrPressEvent(env,
585 j_obj.obj(),
586 gesture_type,
587 gesture.x * dpi_scale(),
588 gesture.y * dpi_scale());
590 // TODO(jdduke): Also report double-tap UMA, crbug/347568.
593 bool ContentViewCoreImpl::HasFocus() {
594 JNIEnv* env = AttachCurrentThread();
595 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
596 if (obj.is_null())
597 return false;
598 return Java_ContentViewCore_hasFocus(env, obj.obj());
601 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
602 JNIEnv* env = AttachCurrentThread();
603 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
604 if (obj.is_null())
605 return;
606 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text);
607 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
610 void ContentViewCoreImpl::OnSelectionBoundsChanged(
611 const ViewHostMsg_SelectionBounds_Params& params) {
612 JNIEnv* env = AttachCurrentThread();
613 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
614 if (obj.is_null())
615 return;
616 ScopedJavaLocalRef<jobject> anchor_rect_dip(
617 CreateJavaRect(env, params.anchor_rect));
618 ScopedJavaLocalRef<jobject> focus_rect_dip(
619 CreateJavaRect(env, params.focus_rect));
620 Java_ContentViewCore_onSelectionBoundsChanged(env, obj.obj(),
621 anchor_rect_dip.obj(),
622 params.anchor_dir,
623 focus_rect_dip.obj(),
624 params.focus_dir,
625 params.is_anchor_first);
628 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
629 JNIEnv* env = AttachCurrentThread();
630 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
631 if (obj.is_null())
632 return;
633 Java_ContentViewCore_showPastePopup(env, obj.obj(),
634 static_cast<jint>(x_dip),
635 static_cast<jint>(y_dip));
638 void ContentViewCoreImpl::GetScaledContentBitmap(
639 float scale,
640 jobject jbitmap_config,
641 gfx::Rect src_subrect,
642 const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
643 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
644 if (!view) {
645 result_callback.Run(false, SkBitmap());
646 return;
648 SkColorType color_type = gfx::ConvertToSkiaColorType(jbitmap_config);
649 view->GetScaledContentBitmap(scale, color_type, src_subrect,
650 result_callback);
653 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
654 JNIEnv* env = AttachCurrentThread();
655 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
656 if (j_obj.is_null())
657 return;
658 ScopedJavaLocalRef<jstring> jcontent_url =
659 ConvertUTF8ToJavaString(env, content_url.spec());
660 Java_ContentViewCore_startContentIntent(env,
661 j_obj.obj(),
662 jcontent_url.obj());
665 void ContentViewCoreImpl::ShowDisambiguationPopup(
666 const gfx::Rect& target_rect,
667 const SkBitmap& zoomed_bitmap) {
668 JNIEnv* env = AttachCurrentThread();
670 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
671 if (obj.is_null())
672 return;
674 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect));
676 ScopedJavaLocalRef<jobject> java_bitmap =
677 gfx::ConvertToJavaBitmap(&zoomed_bitmap);
678 DCHECK(!java_bitmap.is_null());
680 Java_ContentViewCore_showDisambiguationPopup(env,
681 obj.obj(),
682 rect_object.obj(),
683 java_bitmap.obj());
686 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
687 JNIEnv* env = AttachCurrentThread();
689 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
690 if (obj.is_null())
691 return ScopedJavaLocalRef<jobject>();
692 return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
695 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() {
696 JNIEnv* env = AttachCurrentThread();
698 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
699 if (obj.is_null())
700 return ScopedJavaLocalRef<jobject>();
702 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj());
705 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() {
706 JNIEnv* env = AttachCurrentThread();
708 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
709 if (obj.is_null())
710 return ScopedJavaLocalRef<jobject>();
712 return Java_ContentViewCore_getContext(env, obj.obj());
715 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
716 JNIEnv* env = AttachCurrentThread();
718 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
719 if (obj.is_null())
720 return true;
721 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
722 return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(),
723 j_url.obj());
726 void ContentViewCoreImpl::DidStopFlinging() {
727 JNIEnv* env = AttachCurrentThread();
729 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
730 if (!obj.is_null())
731 Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
734 gfx::Size ContentViewCoreImpl::GetViewSize() const {
735 gfx::Size size = GetViewportSizeDip();
736 gfx::Size offset = GetViewportSizeOffsetDip();
737 size.Enlarge(-offset.width(), -offset.height());
738 return size;
741 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
742 JNIEnv* env = AttachCurrentThread();
743 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
744 if (j_obj.is_null())
745 return gfx::Size();
746 return gfx::Size(
747 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()),
748 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj()));
751 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
752 JNIEnv* env = AttachCurrentThread();
753 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
754 if (j_obj.is_null())
755 return gfx::Size();
756 return gfx::Size(
757 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
758 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
761 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const {
762 JNIEnv* env = AttachCurrentThread();
763 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
764 if (j_obj.is_null())
765 return gfx::Size();
766 return gfx::Size(
767 Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()),
768 Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj()));
771 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
772 return gfx::ToCeiledSize(
773 gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
776 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const {
777 return gfx::ToCeiledSize(
778 gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / dpi_scale()));
781 float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const {
782 JNIEnv* env = AttachCurrentThread();
783 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
784 if (j_obj.is_null())
785 return 0.f;
786 return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj())
787 / dpi_scale();
790 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
791 root_layer_->AddChild(layer);
792 root_layer_->SetIsDrawable(false);
795 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
796 layer->RemoveFromParent();
798 if (!root_layer_->children().size())
799 root_layer_->SetIsDrawable(true);
802 void ContentViewCoreImpl::LoadUrl(
803 NavigationController::LoadURLParams& params) {
804 GetWebContents()->GetController().LoadURLWithParams(params);
807 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
808 return view_android_;
811 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
812 return window_android_;
815 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
816 return root_layer_.get();
819 // ----------------------------------------------------------------------------
820 // Methods called from Java via JNI
821 // ----------------------------------------------------------------------------
823 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj,
824 jintArray indices) {
825 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
826 web_contents_->GetRenderViewHost());
827 DCHECK(rvhi);
828 if (indices == NULL) {
829 rvhi->DidCancelPopupMenu();
830 return;
833 int selected_count = env->GetArrayLength(indices);
834 std::vector<int> selected_indices;
835 jint* indices_ptr = env->GetIntArrayElements(indices, NULL);
836 for (int i = 0; i < selected_count; ++i)
837 selected_indices.push_back(indices_ptr[i]);
838 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
839 rvhi->DidSelectPopupMenuItems(selected_indices);
842 void ContentViewCoreImpl::LoadUrl(
843 JNIEnv* env, jobject obj,
844 jstring url,
845 jint load_url_type,
846 jint transition_type,
847 jstring j_referrer_url,
848 jint referrer_policy,
849 jint ua_override_option,
850 jstring extra_headers,
851 jbyteArray post_data,
852 jstring base_url_for_data_url,
853 jstring virtual_url_for_data_url,
854 jboolean can_load_local_resources,
855 jboolean is_renderer_initiated) {
856 DCHECK(url);
857 NavigationController::LoadURLParams params(
858 GURL(ConvertJavaStringToUTF8(env, url)));
860 params.load_type = static_cast<NavigationController::LoadURLType>(
861 load_url_type);
862 params.transition_type = PageTransitionFromInt(transition_type);
863 params.override_user_agent =
864 static_cast<NavigationController::UserAgentOverrideOption>(
865 ua_override_option);
867 if (extra_headers)
868 params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers);
870 if (post_data) {
871 std::vector<uint8> http_body_vector;
872 base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector);
873 params.browser_initiated_post_data =
874 base::RefCountedBytes::TakeVector(&http_body_vector);
877 if (base_url_for_data_url) {
878 params.base_url_for_data_url =
879 GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url));
882 if (virtual_url_for_data_url) {
883 params.virtual_url_for_data_url =
884 GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url));
887 params.can_load_local_resources = can_load_local_resources;
888 if (j_referrer_url) {
889 params.referrer = content::Referrer(
890 GURL(ConvertJavaStringToUTF8(env, j_referrer_url)),
891 static_cast<blink::WebReferrerPolicy>(referrer_policy));
894 params.is_renderer_initiated = is_renderer_initiated;
896 LoadUrl(params);
899 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL(
900 JNIEnv* env, jobject) const {
901 return ConvertUTF8ToJavaString(env, GetWebContents()->GetURL().spec());
904 jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) {
905 return GetWebContents()->GetBrowserContext()->IsOffTheRecord();
908 WebContents* ContentViewCoreImpl::GetWebContents() const {
909 return web_contents_;
912 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) {
913 SetFocusInternal(focused);
916 void ContentViewCoreImpl::SetFocusInternal(bool focused) {
917 if (!GetRenderWidgetHostViewAndroid())
918 return;
920 if (focused)
921 GetRenderWidgetHostViewAndroid()->Focus();
922 else
923 GetRenderWidgetHostViewAndroid()->Blur();
926 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env,
927 jobject obj,
928 jint orientation) {
929 if (device_orientation_ != orientation) {
930 device_orientation_ = orientation;
931 SendOrientationChangeEventInternal();
935 jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
936 jobject obj,
937 jobject motion_event,
938 jlong time_ms,
939 jint android_action,
940 jint pointer_count,
941 jint history_size,
942 jint action_index,
943 jfloat pos_x_0,
944 jfloat pos_y_0,
945 jfloat pos_x_1,
946 jfloat pos_y_1,
947 jint pointer_id_0,
948 jint pointer_id_1,
949 jfloat touch_major_0,
950 jfloat touch_major_1,
951 jfloat raw_pos_x,
952 jfloat raw_pos_y,
953 jint android_tool_type_0,
954 jint android_tool_type_1,
955 jint android_button_state) {
956 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
957 // Avoid synthesizing a touch event if it cannot be forwarded.
958 if (!rwhv)
959 return false;
961 MotionEventAndroid event(1.f / dpi_scale(),
962 env,
963 motion_event,
964 time_ms,
965 android_action,
966 pointer_count,
967 history_size,
968 action_index,
969 pos_x_0,
970 pos_y_0,
971 pos_x_1,
972 pos_y_1,
973 pointer_id_0,
974 pointer_id_1,
975 touch_major_0,
976 touch_major_1,
977 raw_pos_x,
978 raw_pos_y,
979 android_tool_type_0,
980 android_tool_type_1,
981 android_button_state);
983 return rwhv->OnTouchEvent(event);
986 float ContentViewCoreImpl::GetDpiScale() const {
987 return dpi_scale_;
990 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env,
991 jobject obj,
992 jlong time_ms,
993 jfloat x,
994 jfloat y) {
995 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
996 if (!rwhv)
997 return false;
999 blink::WebMouseEvent event = WebMouseEventBuilder::Build(
1000 WebInputEvent::MouseMove,
1001 blink::WebMouseEvent::ButtonNone,
1002 time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1);
1004 rwhv->SendMouseEvent(event);
1005 return true;
1008 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
1009 jobject obj,
1010 jlong time_ms,
1011 jfloat x,
1012 jfloat y,
1013 jfloat vertical_axis) {
1014 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1015 if (!rwhv)
1016 return false;
1018 WebMouseWheelEventBuilder::Direction direction;
1019 if (vertical_axis > 0) {
1020 direction = WebMouseWheelEventBuilder::DIRECTION_UP;
1021 } else if (vertical_axis < 0) {
1022 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN;
1023 } else {
1024 return false;
1026 blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build(
1027 direction, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1029 rwhv->SendMouseWheelEvent(event);
1030 return true;
1033 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent(
1034 WebInputEvent::Type type, int64 time_ms, float x, float y) const {
1035 return WebGestureEventBuilder::Build(
1036 type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1039 void ContentViewCoreImpl::SendGestureEvent(
1040 const blink::WebGestureEvent& event) {
1041 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1042 if (rwhv)
1043 rwhv->SendGestureEvent(event);
1046 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
1047 jobject obj,
1048 jlong time_ms,
1049 jfloat x,
1050 jfloat y,
1051 jfloat hintx,
1052 jfloat hinty) {
1053 WebGestureEvent event = MakeGestureEvent(
1054 WebInputEvent::GestureScrollBegin, time_ms, x, y);
1055 event.data.scrollBegin.deltaXHint = hintx / dpi_scale();
1056 event.data.scrollBegin.deltaYHint = hinty / dpi_scale();
1058 SendGestureEvent(event);
1061 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1062 WebGestureEvent event = MakeGestureEvent(
1063 WebInputEvent::GestureScrollEnd, time_ms, 0, 0);
1064 SendGestureEvent(event);
1067 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms,
1068 jfloat x, jfloat y, jfloat dx, jfloat dy) {
1069 WebGestureEvent event = MakeGestureEvent(
1070 WebInputEvent::GestureScrollUpdate, time_ms, x, y);
1071 event.data.scrollUpdate.deltaX = -dx / dpi_scale();
1072 event.data.scrollUpdate.deltaY = -dy / dpi_scale();
1074 SendGestureEvent(event);
1077 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms,
1078 jfloat x, jfloat y, jfloat vx, jfloat vy) {
1079 WebGestureEvent event = MakeGestureEvent(
1080 WebInputEvent::GestureFlingStart, time_ms, x, y);
1081 event.data.flingStart.velocityX = vx / dpi_scale();
1082 event.data.flingStart.velocityY = vy / dpi_scale();
1084 SendGestureEvent(event);
1087 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) {
1088 WebGestureEvent event = MakeGestureEvent(
1089 WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
1090 SendGestureEvent(event);
1093 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms,
1094 jfloat x, jfloat y) {
1095 WebGestureEvent event = MakeGestureEvent(
1096 WebInputEvent::GestureTap, time_ms, x, y);
1097 event.data.tap.tapCount = 1;
1099 SendGestureEvent(event);
1102 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
1103 jfloat x, jfloat y) {
1104 WebGestureEvent event = MakeGestureEvent(
1105 WebInputEvent::GestureDoubleTap, time_ms, x, y);
1106 // Set the tap count to 1 even for DoubleTap, in order to be consistent with
1107 // double tap behavior on a mobile viewport. See crbug.com/234986 for context.
1108 event.data.tap.tapCount = 1;
1110 SendGestureEvent(event);
1113 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms,
1114 jfloat x, jfloat y) {
1115 WebGestureEvent event = MakeGestureEvent(
1116 WebInputEvent::GestureLongPress, time_ms, x, y);
1118 SendGestureEvent(event);
1121 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms,
1122 jfloat x, jfloat y) {
1123 WebGestureEvent event = MakeGestureEvent(
1124 WebInputEvent::GesturePinchBegin, time_ms, x, y);
1125 SendGestureEvent(event);
1128 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1129 WebGestureEvent event = MakeGestureEvent(
1130 WebInputEvent::GesturePinchEnd, time_ms, 0, 0);
1131 SendGestureEvent(event);
1134 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms,
1135 jfloat anchor_x, jfloat anchor_y,
1136 jfloat delta) {
1137 WebGestureEvent event = MakeGestureEvent(
1138 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y);
1139 event.data.pinchUpdate.scale = delta;
1141 SendGestureEvent(event);
1144 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj,
1145 jfloat x1, jfloat y1,
1146 jfloat x2, jfloat y2) {
1147 if (!web_contents_)
1148 return;
1150 web_contents_->SelectRange(
1151 gfx::Point(x1 / dpi_scale(), y1 / dpi_scale()),
1152 gfx::Point(x2 / dpi_scale(), y2 / dpi_scale()));
1155 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj,
1156 jfloat x, jfloat y) {
1157 if (GetRenderWidgetHostViewAndroid()) {
1158 GetRenderWidgetHostViewAndroid()->MoveCaret(
1159 gfx::Point(x / dpi_scale(), y / dpi_scale()));
1163 void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) {
1164 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1165 if (rwhv)
1166 rwhv->ResetGestureDetection();
1169 void ContentViewCoreImpl::SetDoubleTapSupportEnabled(JNIEnv* env,
1170 jobject obj,
1171 jboolean enabled) {
1172 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1173 if (rwhv)
1174 rwhv->SetDoubleTapSupportEnabled(enabled);
1177 void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env,
1178 jobject obj,
1179 jboolean enabled) {
1180 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1181 if (rwhv)
1182 rwhv->SetMultiTouchZoomSupportEnabled(enabled);
1185 void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) {
1186 // TODO(creis): Do callers of this need to know if it fails?
1187 if (web_contents_->GetController().CanPruneAllButLastCommitted())
1188 web_contents_->GetController().PruneAllButLastCommitted();
1191 void ContentViewCoreImpl::AddStyleSheetByURL(
1192 JNIEnv* env, jobject obj, jstring url) {
1193 if (!web_contents_)
1194 return;
1196 web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
1197 web_contents_->GetMainFrame()->GetRoutingID(),
1198 ConvertJavaStringToUTF8(env, url)));
1201 void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
1202 JNIEnv* env,
1203 jobject obj,
1204 jboolean allow) {
1205 java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow);
1208 void ContentViewCoreImpl::AddJavascriptInterface(
1209 JNIEnv* env,
1210 jobject /* obj */,
1211 jobject object,
1212 jstring name,
1213 jclass safe_annotation_clazz) {
1214 ScopedJavaLocalRef<jobject> scoped_object(env, object);
1215 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz);
1216 java_bridge_dispatcher_host_->AddNamedObject(
1217 ConvertJavaStringToUTF8(env, name), scoped_object, scoped_clazz);
1220 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
1221 jobject /* obj */,
1222 jstring name) {
1223 java_bridge_dispatcher_host_->RemoveNamedObject(
1224 ConvertJavaStringToUTF8(env, name));
1227 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
1228 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1229 gfx::Size physical_size(
1230 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
1231 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
1232 root_layer_->SetBounds(physical_size);
1234 if (view) {
1235 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
1236 view->GetRenderWidgetHost());
1237 host->SendScreenRects();
1238 view->WasResized();
1242 void ContentViewCoreImpl::ShowInterstitialPage(
1243 JNIEnv* env, jobject obj, jstring jurl, jlong delegate_ptr) {
1244 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
1245 InterstitialPageDelegateAndroid* delegate =
1246 reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
1247 InterstitialPage* interstitial = InterstitialPage::Create(
1248 web_contents_, false, url, delegate);
1249 delegate->set_interstitial_page(interstitial);
1250 interstitial->Show();
1253 jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env,
1254 jobject obj) {
1255 return web_contents_->ShowingInterstitialPage();
1258 jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env,
1259 jobject obj) {
1260 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1261 return view && view->HasValidFrame();
1264 void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) {
1265 RenderViewHost* host = web_contents_->GetRenderViewHost();
1266 if (!host)
1267 return;
1268 host->ExitFullscreen();
1271 void ContentViewCoreImpl::UpdateTopControlsState(JNIEnv* env,
1272 jobject obj,
1273 bool enable_hiding,
1274 bool enable_showing,
1275 bool animate) {
1276 RenderViewHost* host = web_contents_->GetRenderViewHost();
1277 if (!host)
1278 return;
1279 host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
1280 enable_hiding,
1281 enable_showing,
1282 animate));
1285 void ContentViewCoreImpl::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
1286 RenderViewHost* host = web_contents_->GetRenderViewHost();
1287 host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
1290 void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env,
1291 jobject obj) {
1292 RenderViewHost* host = web_contents_->GetRenderViewHost();
1293 host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
1294 host->GetRoutingID(), gfx::Rect()));
1297 void ContentViewCoreImpl::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
1298 RenderViewHost* host = web_contents_->GetRenderViewHost();
1299 if (!host)
1300 return;
1301 host->SelectWordAroundCaret();
1304 namespace {
1306 static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj,
1307 jobject history,
1308 NavigationEntry* entry,
1309 int index) {
1310 // Get the details of the current entry
1311 ScopedJavaLocalRef<jstring> j_url(
1312 ConvertUTF8ToJavaString(env, entry->GetURL().spec()));
1313 ScopedJavaLocalRef<jstring> j_virtual_url(
1314 ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec()));
1315 ScopedJavaLocalRef<jstring> j_original_url(
1316 ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
1317 ScopedJavaLocalRef<jstring> j_title(
1318 ConvertUTF16ToJavaString(env, entry->GetTitle()));
1319 ScopedJavaLocalRef<jobject> j_bitmap;
1320 const FaviconStatus& status = entry->GetFavicon();
1321 if (status.valid && status.image.ToSkBitmap()->getSize() > 0)
1322 j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
1324 // Add the item to the list
1325 Java_ContentViewCore_addToNavigationHistory(
1326 env, obj, history, index, j_url.obj(), j_virtual_url.obj(),
1327 j_original_url.obj(), j_title.obj(), j_bitmap.obj());
1330 } // namespace
1332 int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env,
1333 jobject obj,
1334 jobject history) {
1335 // Iterate through navigation entries to populate the list
1336 const NavigationController& controller = web_contents_->GetController();
1337 int count = controller.GetEntryCount();
1338 for (int i = 0; i < count; ++i) {
1339 AddNavigationEntryToHistory(
1340 env, obj, history, controller.GetEntryAtIndex(i), i);
1343 return controller.GetCurrentEntryIndex();
1346 void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env,
1347 jobject obj,
1348 jobject history,
1349 jboolean is_forward,
1350 jint max_entries) {
1351 // Iterate through navigation entries to populate the list
1352 const NavigationController& controller = web_contents_->GetController();
1353 int count = controller.GetEntryCount();
1354 int num_added = 0;
1355 int increment_value = is_forward ? 1 : -1;
1356 for (int i = controller.GetCurrentEntryIndex() + increment_value;
1357 i >= 0 && i < count;
1358 i += increment_value) {
1359 if (num_added >= max_entries)
1360 break;
1362 AddNavigationEntryToHistory(
1363 env, obj, history, controller.GetEntryAtIndex(i), i);
1364 num_added++;
1368 ScopedJavaLocalRef<jstring>
1369 ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env,
1370 jobject obj) {
1371 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1372 if (entry == NULL)
1373 return ScopedJavaLocalRef<jstring>(env, NULL);
1374 return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec());
1377 long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
1378 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
1379 if (!rwhva)
1380 return 0;
1381 return rwhva->GetNativeImeAdapter();
1384 namespace {
1385 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
1386 const base::Value* result) {
1387 JNIEnv* env = base::android::AttachCurrentThread();
1388 std::string json;
1389 base::JSONWriter::Write(result, &json);
1390 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
1391 Java_ContentViewCore_onEvaluateJavaScriptResult(env,
1392 j_json.obj(),
1393 callback.obj());
1395 } // namespace
1397 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
1398 jobject obj,
1399 jstring script,
1400 jobject callback,
1401 jboolean start_renderer) {
1402 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
1403 DCHECK(rvh);
1405 if (start_renderer && !rvh->IsRenderViewLive()) {
1406 if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) {
1407 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
1408 return;
1412 if (!callback) {
1413 // No callback requested.
1414 web_contents_->GetMainFrame()->ExecuteJavaScript(
1415 ConvertJavaStringToUTF16(env, script));
1416 return;
1419 // Secure the Java callback in a scoped object and give ownership of it to the
1420 // base::Callback.
1421 ScopedJavaGlobalRef<jobject> j_callback;
1422 j_callback.Reset(env, callback);
1423 content::RenderFrameHost::JavaScriptResultCallback c_callback =
1424 base::Bind(&JavaScriptResultCallback, j_callback);
1426 web_contents_->GetMainFrame()->ExecuteJavaScript(
1427 ConvertJavaStringToUTF16(env, script),
1428 c_callback);
1431 bool ContentViewCoreImpl::GetUseDesktopUserAgent(
1432 JNIEnv* env, jobject obj) {
1433 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1434 return entry && entry->GetIsOverridingUserAgent();
1437 void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
1438 int text_input_type,
1439 const std::string& text,
1440 int selection_start,
1441 int selection_end,
1442 int composition_start,
1443 int composition_end,
1444 bool show_ime_if_needed,
1445 bool is_non_ime_change) {
1446 JNIEnv* env = AttachCurrentThread();
1447 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1448 if (obj.is_null())
1449 return;
1451 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
1452 Java_ContentViewCore_updateImeAdapter(env, obj.obj(),
1453 native_ime_adapter, text_input_type,
1454 jstring_text.obj(),
1455 selection_start, selection_end,
1456 composition_start, composition_end,
1457 show_ime_if_needed, is_non_ime_change);
1460 void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) {
1461 SSLHostState* state = SSLHostState::GetFor(
1462 web_contents_->GetController().GetBrowserContext());
1463 state->Clear();
1466 void ContentViewCoreImpl::SetUseDesktopUserAgent(
1467 JNIEnv* env,
1468 jobject obj,
1469 jboolean enabled,
1470 jboolean reload_on_state_change) {
1471 if (GetUseDesktopUserAgent(env, obj) == enabled)
1472 return;
1474 // Make sure the navigation entry actually exists.
1475 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1476 if (!entry)
1477 return;
1479 // Set the flag in the NavigationEntry.
1480 entry->SetIsOverridingUserAgent(enabled);
1482 // Send the override to the renderer.
1483 if (reload_on_state_change) {
1484 // Reloading the page will send the override down as part of the
1485 // navigation IPC message.
1486 NavigationControllerImpl& controller =
1487 static_cast<NavigationControllerImpl&>(web_contents_->GetController());
1488 controller.ReloadOriginalRequestURL(false);
1492 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
1493 bool enabled) {
1494 SetAccessibilityEnabledInternal(enabled);
1497 void ContentViewCoreImpl::ShowSelectionHandlesAutomatically() const {
1498 JNIEnv* env = AttachCurrentThread();
1499 ScopedJavaLocalRef<jobject> obj(java_ref_.get(env));
1500 if (obj.is_null())
1501 return;
1502 Java_ContentViewCore_showSelectionHandlesAutomatically(env, obj.obj());
1505 bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
1506 JNIEnv* env = AttachCurrentThread();
1507 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1508 if (obj.is_null())
1509 return true;
1510 return Java_ContentViewCore_isFullscreenRequiredForOrientationLock(env,
1511 obj.obj());
1514 void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) {
1515 accessibility_enabled_ = enabled;
1516 RenderWidgetHostViewAndroid* host_view = GetRenderWidgetHostViewAndroid();
1517 if (!host_view)
1518 return;
1519 RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From(
1520 host_view->GetRenderWidgetHost());
1521 BrowserAccessibilityState* accessibility_state =
1522 BrowserAccessibilityState::GetInstance();
1523 if (enabled) {
1524 // This enables accessibility globally unless it was explicitly disallowed
1525 // by a command-line flag.
1526 accessibility_state->OnScreenReaderDetected();
1527 // If it was actually enabled globally, enable it for this RenderWidget now.
1528 if (accessibility_state->IsAccessibleBrowser() && host_impl)
1529 host_impl->AddAccessibilityMode(AccessibilityModeComplete);
1530 } else {
1531 accessibility_state->ResetAccessibilityMode();
1532 if (host_impl)
1533 host_impl->ResetAccessibilityMode();
1537 void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
1538 static_cast<WebContentsImpl*>(web_contents())->
1539 screen_orientation_dispatcher_host()->OnOrientationChange();
1541 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1542 if (rwhv)
1543 rwhv->UpdateScreenInfo(GetViewAndroid());
1546 void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
1547 jobject obj,
1548 jint x,
1549 jint y,
1550 jint width,
1551 jint height) {
1552 gfx::Rect rect(
1553 static_cast<int>(x / dpi_scale()),
1554 static_cast<int>(y / dpi_scale()),
1555 static_cast<int>((width > 0 && width < dpi_scale()) ?
1556 1 : (int)(width / dpi_scale())),
1557 static_cast<int>((height > 0 && height < dpi_scale()) ?
1558 1 : (int)(height / dpi_scale())));
1559 GetWebContents()->Send(new ViewMsg_ExtractSmartClipData(
1560 GetWebContents()->GetRoutingID(), rect));
1563 void ContentViewCoreImpl::ResumeResponseDeferredAtStart(JNIEnv* env,
1564 jobject obj) {
1565 static_cast<WebContentsImpl*>(GetWebContents())->
1566 ResumeResponseDeferredAtStart();
1569 void ContentViewCoreImpl::SetHasPendingNavigationTransitionForTesting(
1570 JNIEnv* env,
1571 jobject obj) {
1572 RenderFrameHost* frame = static_cast<WebContentsImpl*>(GetWebContents())->
1573 GetMainFrame();
1574 BrowserThread::PostTask(
1575 BrowserThread::IO,
1576 FROM_HERE,
1577 base::Bind(
1578 &TransitionRequestManager::SetHasPendingTransitionRequest,
1579 base::Unretained(TransitionRequestManager::GetInstance()),
1580 frame->GetProcess()->GetID(),
1581 frame->GetRoutingID(),
1582 true));
1585 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) {
1586 return GetRenderProcessIdFromRenderViewHost(
1587 web_contents_->GetRenderViewHost());
1590 void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj,
1591 jboolean opaque) {
1592 if (GetRenderWidgetHostViewAndroid())
1593 GetRenderWidgetHostViewAndroid()->SetBackgroundOpaque(opaque);
1596 void ContentViewCoreImpl::RequestTextSurroundingSelection(
1597 int max_length,
1598 const base::Callback<
1599 void(const base::string16& content, int start_offset, int end_offset)>&
1600 callback) {
1601 DCHECK(!callback.is_null());
1602 RenderFrameHost* focused_frame = web_contents_->GetFocusedFrame();
1603 if (!focused_frame)
1604 return;
1605 if (GetRenderWidgetHostViewAndroid()) {
1606 GetRenderWidgetHostViewAndroid()->SetTextSurroundingSelectionCallback(
1607 callback);
1608 focused_frame->Send(new FrameMsg_TextSurroundingSelectionRequest(
1609 focused_frame->GetRoutingID(), max_length));
1613 void ContentViewCoreImpl::DidDeferAfterResponseStarted() {
1614 JNIEnv* env = AttachCurrentThread();
1615 ScopedJavaLocalRef<jobject> obj(java_ref_.get(env));
1616 if (obj.is_null())
1617 return;
1618 Java_ContentViewCore_didDeferAfterResponseStarted(env, obj.obj());
1621 bool ContentViewCoreImpl::WillHandleDeferAfterResponseStarted() {
1622 JNIEnv* env = AttachCurrentThread();
1623 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1624 if (obj.is_null())
1625 return false;
1627 return Java_ContentViewCore_willHandleDeferAfterResponseStarted(env,
1628 obj.obj());
1631 void ContentViewCoreImpl::OnSmartClipDataExtracted(
1632 const base::string16& text,
1633 const base::string16& html,
1634 const gfx::Rect& clip_rect) {
1635 JNIEnv* env = AttachCurrentThread();
1636 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1637 if (obj.is_null())
1638 return;
1639 ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
1640 ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html);
1641 ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect));
1642 Java_ContentViewCore_onSmartClipDataExtracted(
1643 env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj());
1646 void ContentViewCoreImpl::WebContentsDestroyed() {
1647 WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
1648 static_cast<WebContentsImpl*>(web_contents())->GetView());
1649 DCHECK(wcva);
1650 wcva->SetContentViewCore(NULL);
1653 // This is called for each ContentView.
1654 jlong Init(JNIEnv* env,
1655 jobject obj,
1656 jlong native_web_contents,
1657 jlong view_android,
1658 jlong window_android,
1659 jobject retained_objects_set) {
1660 ContentViewCoreImpl* view = new ContentViewCoreImpl(
1661 env, obj,
1662 reinterpret_cast<WebContents*>(native_web_contents),
1663 reinterpret_cast<ui::ViewAndroid*>(view_android),
1664 reinterpret_cast<ui::WindowAndroid*>(window_android),
1665 retained_objects_set);
1666 return reinterpret_cast<intptr_t>(view);
1669 bool RegisterContentViewCore(JNIEnv* env) {
1670 return RegisterNativesImpl(env);
1673 } // namespace content