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/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "cc/layers/layer.h"
17 #include "cc/layers/solid_color_layer.h"
18 #include "cc/output/begin_frame_args.h"
19 #include "content/browser/accessibility/browser_accessibility_state_impl.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/android/popup_touch_handle_drawable.h"
25 #include "content/browser/frame_host/interstitial_page_impl.h"
26 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
27 #include "content/browser/media/media_web_contents_observer.h"
28 #include "content/browser/renderer_host/compositor_impl_android.h"
29 #include "content/browser/renderer_host/input/motion_event_android.h"
30 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
31 #include "content/browser/renderer_host/input/web_input_event_util.h"
32 #include "content/browser/renderer_host/render_view_host_impl.h"
33 #include "content/browser/renderer_host/render_widget_host_impl.h"
34 #include "content/browser/renderer_host/render_widget_host_view_android.h"
35 #include "content/browser/transition_request_manager.h"
36 #include "content/browser/web_contents/web_contents_view_android.h"
37 #include "content/common/frame_messages.h"
38 #include "content/common/input/web_input_event_traits.h"
39 #include "content/common/input_messages.h"
40 #include "content/common/view_messages.h"
41 #include "content/public/browser/browser_context.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/favicon_status.h"
44 #include "content/public/browser/render_frame_host.h"
45 #include "content/public/browser/screen_orientation_dispatcher_host.h"
46 #include "content/public/browser/ssl_host_state_delegate.h"
47 #include "content/public/browser/web_contents.h"
48 #include "content/public/common/content_client.h"
49 #include "content/public/common/content_switches.h"
50 #include "content/public/common/menu_item.h"
51 #include "content/public/common/user_agent.h"
52 #include "jni/ContentViewCore_jni.h"
53 #include "third_party/WebKit/public/web/WebInputEvent.h"
54 #include "ui/base/android/view_android.h"
55 #include "ui/base/android/window_android.h"
56 #include "ui/gfx/android/java_bitmap.h"
57 #include "ui/gfx/screen.h"
58 #include "ui/gfx/size_conversions.h"
59 #include "ui/gfx/size_f.h"
61 using base::android::AttachCurrentThread;
62 using base::android::ConvertJavaStringToUTF16;
63 using base::android::ConvertJavaStringToUTF8;
64 using base::android::ConvertUTF16ToJavaString;
65 using base::android::ConvertUTF8ToJavaString;
66 using base::android::ScopedJavaLocalRef;
67 using blink::WebGestureEvent;
68 using blink::WebInputEvent;
70 // Describes the type and enabled state of a select popup item.
74 #define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value,
75 #include "content/browser/android/popup_item_type_list.h"
76 #undef DEFINE_POPUP_ITEM_TYPE
85 const void* kContentViewUserDataKey = &kContentViewUserDataKey;
87 int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
89 RenderProcessHost* render_process = host->GetProcess();
90 DCHECK(render_process);
91 if (render_process->HasConnection())
92 return render_process->GetHandle();
97 ScopedJavaLocalRef<jobject> CreateJavaRect(
99 const gfx::Rect& rect) {
100 return ScopedJavaLocalRef<jobject>(
101 Java_ContentViewCore_createRect(env,
102 static_cast<int>(rect.x()),
103 static_cast<int>(rect.y()),
104 static_cast<int>(rect.right()),
105 static_cast<int>(rect.bottom())));
108 int ToGestureEventType(WebInputEvent::Type type) {
110 case WebInputEvent::GestureScrollBegin:
112 case WebInputEvent::GestureScrollEnd:
114 case WebInputEvent::GestureScrollUpdate:
116 case WebInputEvent::GestureFlingStart:
118 case WebInputEvent::GestureFlingCancel:
120 case WebInputEvent::GestureShowPress:
122 case WebInputEvent::GestureTap:
123 return SINGLE_TAP_CONFIRMED;
124 case WebInputEvent::GestureTapUnconfirmed:
125 return SINGLE_TAP_UNCONFIRMED;
126 case WebInputEvent::GestureTapDown:
128 case WebInputEvent::GestureTapCancel:
130 case WebInputEvent::GestureDoubleTap:
132 case WebInputEvent::GestureLongPress:
134 case WebInputEvent::GestureLongTap:
136 case WebInputEvent::GesturePinchBegin:
138 case WebInputEvent::GesturePinchEnd:
140 case WebInputEvent::GesturePinchUpdate:
142 case WebInputEvent::GestureTwoFingerTap:
143 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
145 NOTREACHED() << "Invalid source gesture type: "
146 << WebInputEventTraits::GetName(type);
151 float GetPrimaryDisplayDeviceScaleFactor() {
152 const gfx::Display& display =
153 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
154 return display.device_scale_factor();
159 // Enables a callback when the underlying WebContents is destroyed, to enable
160 // nulling the back-pointer.
161 class ContentViewCoreImpl::ContentViewUserData
162 : public base::SupportsUserData::Data {
164 explicit ContentViewUserData(ContentViewCoreImpl* content_view_core)
165 : content_view_core_(content_view_core) {
168 virtual ~ContentViewUserData() {
169 // TODO(joth): When chrome has finished removing the TabContents class (see
170 // crbug.com/107201) consider inverting relationship, so ContentViewCore
171 // would own WebContents. That effectively implies making the WebContents
172 // destructor private on Android.
173 delete content_view_core_;
176 ContentViewCoreImpl* get() const { return content_view_core_; }
179 // Not using scoped_ptr as ContentViewCoreImpl destructor is private.
180 ContentViewCoreImpl* content_view_core_;
182 DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData);
186 ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
187 content::WebContents* web_contents) {
188 ContentViewCoreImpl::ContentViewUserData* data =
189 reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>(
190 web_contents->GetUserData(kContentViewUserDataKey));
191 return data ? data->get() : NULL;
195 ContentViewCore* ContentViewCore::FromWebContents(
196 content::WebContents* web_contents) {
197 return ContentViewCoreImpl::FromWebContents(web_contents);
201 ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
203 return reinterpret_cast<ContentViewCore*>(
204 Java_ContentViewCore_getNativeContentViewCore(env, obj));
207 ContentViewCoreImpl::ContentViewCoreImpl(
210 WebContents* web_contents,
211 ui::ViewAndroid* view_android,
212 ui::WindowAndroid* window_android,
213 jobject java_bridge_retained_object_set)
214 : WebContentsObserver(web_contents),
216 web_contents_(static_cast<WebContentsImpl*>(web_contents)),
217 root_layer_(cc::SolidColorLayer::Create()),
218 dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
219 view_android_(view_android),
220 window_android_(window_android),
221 device_orientation_(0),
222 accessibility_enabled_(false) {
223 CHECK(web_contents) <<
224 "A ContentViewCoreImpl should be created with a valid WebContents.";
225 DCHECK(view_android_);
226 DCHECK(window_android_);
228 root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj));
229 gfx::Size physical_size(
230 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
231 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
232 root_layer_->SetBounds(physical_size);
233 root_layer_->SetIsDrawable(true);
235 // Currently, the only use case we have for overriding a user agent involves
236 // spoofing a desktop Linux user agent for "Request desktop site".
237 // Automatically set it for all WebContents so that it is available when a
238 // NavigationEntry requires the user agent to be overridden.
239 const char kLinuxInfoStr[] = "X11; Linux x86_64";
240 std::string product = content::GetContentClient()->GetProduct();
241 std::string spoofed_ua =
242 BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
243 web_contents->SetUserAgentOverride(spoofed_ua);
245 java_bridge_dispatcher_host_.reset(
246 new GinJavaBridgeDispatcherHost(web_contents,
247 java_bridge_retained_object_set));
252 ContentViewCoreImpl::~ContentViewCoreImpl() {
253 JNIEnv* env = base::android::AttachCurrentThread();
254 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
256 if (!j_obj.is_null()) {
257 Java_ContentViewCore_onNativeContentViewCoreDestroyed(
258 env, j_obj.obj(), reinterpret_cast<intptr_t>(this));
262 base::android::ScopedJavaLocalRef<jobject>
263 ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env, jobject obj) {
264 return web_contents_->GetJavaWebContents();
267 void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env,
269 DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
271 // Java peer has gone, ContentViewCore is not functional and waits to
272 // be destroyed with WebContents.
273 // We need to reset WebContentsViewAndroid's reference, otherwise, there
274 // could have call in when swapping the WebContents,
275 // see http://crbug.com/383939 .
276 DCHECK(web_contents_);
277 static_cast<WebContentsViewAndroid*>(
278 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
279 SetContentViewCore(NULL);
282 void ContentViewCoreImpl::InitWebContents() {
283 DCHECK(web_contents_);
284 static_cast<WebContentsViewAndroid*>(
285 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
286 SetContentViewCore(this);
287 DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey));
288 web_contents_->SetUserData(kContentViewUserDataKey,
289 new ContentViewUserData(this));
292 void ContentViewCoreImpl::RenderViewReady() {
293 JNIEnv* env = AttachCurrentThread();
294 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
296 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
298 if (device_orientation_ != 0)
299 SendOrientationChangeEventInternal();
302 void ContentViewCoreImpl::RenderViewHostChanged(RenderViewHost* old_host,
303 RenderViewHost* new_host) {
306 old_pid = GetRenderProcessIdFromRenderViewHost(old_host);
308 RenderWidgetHostViewAndroid* view =
309 static_cast<RenderWidgetHostViewAndroid*>(old_host->GetView());
311 view->SetContentViewCore(NULL);
313 view = static_cast<RenderWidgetHostViewAndroid*>(new_host->GetView());
315 view->SetContentViewCore(this);
317 int new_pid = GetRenderProcessIdFromRenderViewHost(
318 web_contents_->GetRenderViewHost());
319 if (new_pid != old_pid) {
320 // Notify the Java side that the renderer process changed.
321 JNIEnv* env = AttachCurrentThread();
322 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
323 if (!obj.is_null()) {
324 Java_ContentViewCore_onRenderProcessChange(env, obj.obj());
328 SetFocusInternal(HasFocus());
329 SetAccessibilityEnabledInternal(accessibility_enabled_);
332 RenderWidgetHostViewAndroid*
333 ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() {
334 RenderWidgetHostView* rwhv = NULL;
336 rwhv = web_contents_->GetRenderWidgetHostView();
337 if (web_contents_->ShowingInterstitialPage()) {
338 rwhv = static_cast<InterstitialPageImpl*>(
339 web_contents_->GetInterstitialPage())->
340 GetRenderViewHost()->GetView();
343 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
346 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() {
347 JNIEnv* env = AttachCurrentThread();
348 return java_ref_.get(env);
351 jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
352 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
354 return SK_ColorWHITE;
355 return rwhva->GetCachedBackgroundColor();
358 void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
359 web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause);
362 // All positions and sizes are in CSS pixels.
363 // Note that viewport_width/height is a best effort based.
364 // ContentViewCore has the actual information about the physical viewport size.
365 void ContentViewCoreImpl::UpdateFrameInfo(
366 const gfx::Vector2dF& scroll_offset,
367 float page_scale_factor,
368 const gfx::Vector2dF& page_scale_factor_limits,
369 const gfx::SizeF& content_size,
370 const gfx::SizeF& viewport_size,
371 const gfx::Vector2dF& controls_offset,
372 const gfx::Vector2dF& content_offset) {
373 JNIEnv* env = AttachCurrentThread();
374 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
378 window_android_->set_content_offset(
379 gfx::ScaleVector2d(content_offset, dpi_scale_));
381 Java_ContentViewCore_updateFrameInfo(
386 page_scale_factor_limits.x(),
387 page_scale_factor_limits.y(),
388 content_size.width(),
389 content_size.height(),
390 viewport_size.width(),
391 viewport_size.height(),
396 void ContentViewCoreImpl::SetTitle(const base::string16& title) {
397 JNIEnv* env = AttachCurrentThread();
398 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
401 ScopedJavaLocalRef<jstring> jtitle =
402 ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title));
403 Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj());
406 void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
407 root_layer_->SetBackgroundColor(color);
409 JNIEnv* env = AttachCurrentThread();
410 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
413 Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
416 void ContentViewCoreImpl::ShowSelectPopupMenu(
417 RenderFrameHost* frame,
418 const gfx::Rect& bounds,
419 const std::vector<MenuItem>& items,
422 JNIEnv* env = AttachCurrentThread();
423 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
427 ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds));
429 // For multi-select list popups we find the list of previous selections by
430 // iterating through the items. But for single selection popups we take the
431 // given |selected_item| as is.
432 ScopedJavaLocalRef<jintArray> selected_array;
434 scoped_ptr<jint[]> native_selected_array(new jint[items.size()]);
435 size_t selected_count = 0;
436 for (size_t i = 0; i < items.size(); ++i) {
437 if (items[i].checked)
438 native_selected_array[selected_count++] = i;
441 selected_array = ScopedJavaLocalRef<jintArray>(
442 env, env->NewIntArray(selected_count));
443 env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
444 native_selected_array.get());
446 selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
447 jint value = selected_item;
448 env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
451 ScopedJavaLocalRef<jintArray> enabled_array(env,
452 env->NewIntArray(items.size()));
453 std::vector<base::string16> labels;
454 labels.reserve(items.size());
455 for (size_t i = 0; i < items.size(); ++i) {
456 labels.push_back(items[i].label);
458 (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP :
459 (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED :
460 POPUP_ITEM_TYPE_DISABLED));
461 env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled);
463 ScopedJavaLocalRef<jobjectArray> items_array(
464 base::android::ToJavaArrayOfStrings(env, labels));
465 Java_ContentViewCore_showSelectPopup(env,
467 reinterpret_cast<intptr_t>(frame),
472 selected_array.obj());
475 void ContentViewCoreImpl::HideSelectPopupMenu() {
476 JNIEnv* env = AttachCurrentThread();
477 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
478 if (!j_obj.is_null())
479 Java_ContentViewCore_hideSelectPopup(env, j_obj.obj());
482 void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
483 InputEventAckState ack_result) {
484 JNIEnv* env = AttachCurrentThread();
485 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
489 switch (event.type) {
490 case WebInputEvent::GestureFlingStart:
491 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
492 // The view expects the fling velocity in pixels/s.
493 Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(),
494 event.data.flingStart.velocityX * dpi_scale(),
495 event.data.flingStart.velocityY * dpi_scale());
497 // If a scroll ends with a fling, a SCROLL_END event is never sent.
498 // However, if that fling went unconsumed, we still need to let the
499 // listeners know that scrolling has ended.
500 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
503 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
504 // The view expects the fling velocity in pixels/s.
505 Java_ContentViewCore_onFlingStartEventHadNoConsumer(env, j_obj.obj(),
506 event.data.flingStart.velocityX * dpi_scale(),
507 event.data.flingStart.velocityY * dpi_scale());
510 case WebInputEvent::GestureFlingCancel:
511 Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj());
513 case WebInputEvent::GestureScrollBegin:
514 Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj());
516 case WebInputEvent::GestureScrollUpdate:
517 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
518 Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj());
520 case WebInputEvent::GestureScrollEnd:
521 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
523 case WebInputEvent::GesturePinchBegin:
524 Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj());
526 case WebInputEvent::GesturePinchEnd:
527 Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj());
529 case WebInputEvent::GestureTap:
530 Java_ContentViewCore_onSingleTapEventAck(
533 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED,
534 event.x * dpi_scale(),
535 event.y * dpi_scale());
542 bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) {
543 if (event.type != WebInputEvent::GestureTap &&
544 event.type != WebInputEvent::GestureDoubleTap &&
545 event.type != WebInputEvent::GestureLongTap &&
546 event.type != WebInputEvent::GestureLongPress)
549 JNIEnv* env = AttachCurrentThread();
550 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
554 const blink::WebGestureEvent& gesture =
555 static_cast<const blink::WebGestureEvent&>(event);
556 int gesture_type = ToGestureEventType(event.type);
557 return Java_ContentViewCore_filterTapOrPressEvent(env,
560 gesture.x * dpi_scale(),
561 gesture.y * dpi_scale());
563 // TODO(jdduke): Also report double-tap UMA, crbug/347568.
566 bool ContentViewCoreImpl::HasFocus() {
567 JNIEnv* env = AttachCurrentThread();
568 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
571 return Java_ContentViewCore_hasFocus(env, obj.obj());
574 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
575 JNIEnv* env = AttachCurrentThread();
576 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
579 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text);
580 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
583 void ContentViewCoreImpl::OnSelectionEvent(SelectionEventType event,
584 const gfx::PointF& position) {
585 JNIEnv* env = AttachCurrentThread();
586 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
589 Java_ContentViewCore_onSelectionEvent(
590 env, j_obj.obj(), event, position.x(), position.y());
593 scoped_ptr<TouchHandleDrawable>
594 ContentViewCoreImpl::CreatePopupTouchHandleDrawable() {
595 JNIEnv* env = AttachCurrentThread();
596 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
599 return scoped_ptr<TouchHandleDrawable>();
601 return scoped_ptr<TouchHandleDrawable>(new PopupTouchHandleDrawable(
602 Java_ContentViewCore_createPopupTouchHandleDrawable(env, obj.obj()),
606 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
607 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
611 view->OnShowingPastePopup(gfx::PointF(x_dip, y_dip));
613 JNIEnv* env = AttachCurrentThread();
614 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
617 Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
618 static_cast<jint>(x_dip),
619 static_cast<jint>(y_dip));
622 void ContentViewCoreImpl::GetScaledContentBitmap(
624 SkColorType color_type,
625 gfx::Rect src_subrect,
626 const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
627 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
629 result_callback.Run(false, SkBitmap());
633 view->GetScaledContentBitmap(scale, color_type, src_subrect,
637 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
638 JNIEnv* env = AttachCurrentThread();
639 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
642 ScopedJavaLocalRef<jstring> jcontent_url =
643 ConvertUTF8ToJavaString(env, content_url.spec());
644 Java_ContentViewCore_startContentIntent(env,
649 void ContentViewCoreImpl::ShowDisambiguationPopup(
650 const gfx::Rect& rect_pixels,
651 const SkBitmap& zoomed_bitmap) {
652 JNIEnv* env = AttachCurrentThread();
654 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
658 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, rect_pixels));
660 ScopedJavaLocalRef<jobject> java_bitmap =
661 gfx::ConvertToJavaBitmap(&zoomed_bitmap);
662 DCHECK(!java_bitmap.is_null());
664 Java_ContentViewCore_showDisambiguationPopup(env,
670 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
671 JNIEnv* env = AttachCurrentThread();
673 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
675 return ScopedJavaLocalRef<jobject>();
676 return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
679 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() {
680 JNIEnv* env = AttachCurrentThread();
682 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
684 return ScopedJavaLocalRef<jobject>();
686 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj());
689 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() {
690 JNIEnv* env = AttachCurrentThread();
692 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
694 return ScopedJavaLocalRef<jobject>();
696 return Java_ContentViewCore_getContext(env, obj.obj());
699 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
700 JNIEnv* env = AttachCurrentThread();
702 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
705 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
706 return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(),
710 void ContentViewCoreImpl::DidStopFlinging() {
711 JNIEnv* env = AttachCurrentThread();
713 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
715 Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
718 gfx::Size ContentViewCoreImpl::GetViewSize() const {
719 gfx::Size size = GetViewportSizeDip();
720 size.Enlarge(0, -GetTopControlsLayoutHeightDip());
724 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
725 JNIEnv* env = AttachCurrentThread();
726 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
730 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()),
731 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj()));
734 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
735 JNIEnv* env = AttachCurrentThread();
736 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
740 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
741 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
744 int ContentViewCoreImpl::GetTopControlsLayoutHeightPix() const {
745 JNIEnv* env = AttachCurrentThread();
746 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
749 return Java_ContentViewCore_getTopControlsLayoutHeightPix(env, j_obj.obj());
752 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
753 return gfx::ToCeiledSize(
754 gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
757 float ContentViewCoreImpl::GetTopControlsLayoutHeightDip() const {
758 return GetTopControlsLayoutHeightPix() / dpi_scale();
761 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
762 root_layer_->InsertChild(layer, 0);
763 root_layer_->SetIsDrawable(false);
766 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
767 layer->RemoveFromParent();
769 if (!root_layer_->children().size())
770 root_layer_->SetIsDrawable(true);
773 void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& start,
774 const gfx::PointF& end) {
778 gfx::Point start_point = gfx::Point(start.x(), start.y());
779 gfx::Point end_point = gfx::Point(end.x(), end.y());
780 if (start_point == end_point)
783 web_contents_->SelectRange(start_point, end_point);
786 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
787 return view_android_;
790 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
791 return window_android_;
794 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
795 return root_layer_.get();
798 // ----------------------------------------------------------------------------
799 // Methods called from Java via JNI
800 // ----------------------------------------------------------------------------
802 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env,
804 jlong selectPopupSourceFrame,
806 RenderFrameHostImpl* rfhi =
807 reinterpret_cast<RenderFrameHostImpl*>(selectPopupSourceFrame);
809 if (indices == NULL) {
810 rfhi->DidCancelPopupMenu();
814 int selected_count = env->GetArrayLength(indices);
815 std::vector<int> selected_indices;
816 jint* indices_ptr = env->GetIntArrayElements(indices, NULL);
817 for (int i = 0; i < selected_count; ++i)
818 selected_indices.push_back(indices_ptr[i]);
819 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
820 rfhi->DidSelectPopupMenuItems(selected_indices);
823 WebContents* ContentViewCoreImpl::GetWebContents() const {
824 return web_contents_;
827 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) {
828 SetFocusInternal(focused);
831 void ContentViewCoreImpl::SetFocusInternal(bool focused) {
832 if (!GetRenderWidgetHostViewAndroid())
836 GetRenderWidgetHostViewAndroid()->Focus();
838 GetRenderWidgetHostViewAndroid()->Blur();
841 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env,
844 if (device_orientation_ != orientation) {
845 device_orientation_ = orientation;
846 SendOrientationChangeEventInternal();
850 jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
852 jobject motion_event,
864 jfloat touch_major_0,
865 jfloat touch_major_1,
866 jfloat touch_minor_0,
867 jfloat touch_minor_1,
868 jfloat orientation_0,
869 jfloat orientation_1,
872 jint android_tool_type_0,
873 jint android_tool_type_1,
874 jint android_button_state,
875 jint android_meta_state,
876 jboolean is_touch_handle_event) {
877 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
878 // Avoid synthesizing a touch event if it cannot be forwarded.
882 MotionEventAndroid event(1.f / dpi_scale(),
906 android_button_state,
909 return is_touch_handle_event ? rwhv->OnTouchHandleEvent(event)
910 : rwhv->OnTouchEvent(event);
913 float ContentViewCoreImpl::GetDpiScale() const {
917 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env,
922 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
926 blink::WebMouseEvent event = WebMouseEventBuilder::Build(
927 WebInputEvent::MouseMove,
928 blink::WebMouseEvent::ButtonNone,
929 time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1);
931 rwhv->SendMouseEvent(event);
935 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
940 jfloat vertical_axis) {
941 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
945 WebMouseWheelEventBuilder::Direction direction;
946 if (vertical_axis > 0) {
947 direction = WebMouseWheelEventBuilder::DIRECTION_UP;
948 } else if (vertical_axis < 0) {
949 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN;
953 blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build(
954 direction, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
956 rwhv->SendMouseWheelEvent(event);
960 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent(
961 WebInputEvent::Type type, int64 time_ms, float x, float y) const {
962 return WebGestureEventBuilder::Build(
963 type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
966 void ContentViewCoreImpl::SendGestureEvent(
967 const blink::WebGestureEvent& event) {
968 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
970 rwhv->SendGestureEvent(event);
973 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
980 WebGestureEvent event = MakeGestureEvent(
981 WebInputEvent::GestureScrollBegin, time_ms, x, y);
982 event.data.scrollBegin.deltaXHint = hintx / dpi_scale();
983 event.data.scrollBegin.deltaYHint = hinty / dpi_scale();
985 SendGestureEvent(event);
988 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) {
989 WebGestureEvent event = MakeGestureEvent(
990 WebInputEvent::GestureScrollEnd, time_ms, 0, 0);
991 SendGestureEvent(event);
994 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms,
995 jfloat x, jfloat y, jfloat dx, jfloat dy) {
996 WebGestureEvent event = MakeGestureEvent(
997 WebInputEvent::GestureScrollUpdate, time_ms, x, y);
998 event.data.scrollUpdate.deltaX = -dx / dpi_scale();
999 event.data.scrollUpdate.deltaY = -dy / dpi_scale();
1001 SendGestureEvent(event);
1004 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms,
1005 jfloat x, jfloat y, jfloat vx, jfloat vy) {
1006 WebGestureEvent event = MakeGestureEvent(
1007 WebInputEvent::GestureFlingStart, time_ms, x, y);
1008 event.data.flingStart.velocityX = vx / dpi_scale();
1009 event.data.flingStart.velocityY = vy / dpi_scale();
1011 SendGestureEvent(event);
1014 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) {
1015 WebGestureEvent event = MakeGestureEvent(
1016 WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
1017 SendGestureEvent(event);
1020 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms,
1021 jfloat x, jfloat y) {
1022 WebGestureEvent event = MakeGestureEvent(
1023 WebInputEvent::GestureTap, time_ms, x, y);
1024 event.data.tap.tapCount = 1;
1026 SendGestureEvent(event);
1029 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
1030 jfloat x, jfloat y) {
1031 WebGestureEvent event = MakeGestureEvent(
1032 WebInputEvent::GestureDoubleTap, time_ms, x, y);
1033 // Set the tap count to 1 even for DoubleTap, in order to be consistent with
1034 // double tap behavior on a mobile viewport. See crbug.com/234986 for context.
1035 event.data.tap.tapCount = 1;
1037 SendGestureEvent(event);
1040 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms,
1041 jfloat x, jfloat y) {
1042 WebGestureEvent event = MakeGestureEvent(
1043 WebInputEvent::GestureLongPress, time_ms, x, y);
1045 SendGestureEvent(event);
1048 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms,
1049 jfloat x, jfloat y) {
1050 WebGestureEvent event = MakeGestureEvent(
1051 WebInputEvent::GesturePinchBegin, time_ms, x, y);
1052 SendGestureEvent(event);
1055 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1056 WebGestureEvent event = MakeGestureEvent(
1057 WebInputEvent::GesturePinchEnd, time_ms, 0, 0);
1058 SendGestureEvent(event);
1061 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms,
1062 jfloat anchor_x, jfloat anchor_y,
1064 WebGestureEvent event = MakeGestureEvent(
1065 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y);
1066 event.data.pinchUpdate.scale = delta;
1068 SendGestureEvent(event);
1071 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj,
1072 jfloat x1, jfloat y1,
1073 jfloat x2, jfloat y2) {
1074 SelectBetweenCoordinates(gfx::PointF(x1 / dpi_scale(), y1 / dpi_scale()),
1075 gfx::PointF(x2 / dpi_scale(), y2 / dpi_scale()));
1078 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj,
1079 jfloat x, jfloat y) {
1080 if (GetRenderWidgetHostViewAndroid()) {
1081 GetRenderWidgetHostViewAndroid()->MoveCaret(
1082 gfx::Point(x / dpi_scale_, y / dpi_scale_));
1086 void ContentViewCoreImpl::HideTextHandles(JNIEnv* env, jobject obj) {
1087 if (GetRenderWidgetHostViewAndroid())
1088 GetRenderWidgetHostViewAndroid()->HideTextHandles();
1091 void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) {
1092 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1094 rwhv->ResetGestureDetection();
1097 void ContentViewCoreImpl::SetDoubleTapSupportEnabled(JNIEnv* env,
1100 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1102 rwhv->SetDoubleTapSupportEnabled(enabled);
1105 void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env,
1108 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1110 rwhv->SetMultiTouchZoomSupportEnabled(enabled);
1113 void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
1117 java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow);
1120 void ContentViewCoreImpl::AddJavascriptInterface(
1125 jclass safe_annotation_clazz) {
1126 ScopedJavaLocalRef<jobject> scoped_object(env, object);
1127 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz);
1128 java_bridge_dispatcher_host_->AddNamedObject(
1129 ConvertJavaStringToUTF8(env, name), scoped_object, scoped_clazz);
1132 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
1135 java_bridge_dispatcher_host_->RemoveNamedObject(
1136 ConvertJavaStringToUTF8(env, name));
1139 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
1140 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1141 gfx::Size physical_size(
1142 Java_ContentViewCore_getPhysicalBackingWidthPix(env, obj),
1143 Java_ContentViewCore_getPhysicalBackingHeightPix(env, obj));
1144 root_layer_->SetBounds(physical_size);
1147 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
1148 view->GetRenderWidgetHost());
1149 host->SendScreenRects();
1154 long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
1155 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
1158 return rwhva->GetNativeImeAdapter();
1161 // TODO(sgurun) add support for posting a frame whose name is known (only
1162 // main frame is supported at this time, see crbug.com/389721)
1163 // TODO(sgurun) add support for passing message ports
1164 void ContentViewCoreImpl::PostMessageToFrame(JNIEnv* env, jobject obj,
1165 jstring frame_name, jstring message, jstring source_origin,
1166 jstring target_origin) {
1168 RenderViewHost* host = web_contents_->GetRenderViewHost();
1171 ViewMsg_PostMessage_Params params;
1172 params.source_origin = ConvertJavaStringToUTF16(env, source_origin);
1173 params.target_origin = ConvertJavaStringToUTF16(env, target_origin);
1174 params.data = ConvertJavaStringToUTF16(env, message);
1175 params.is_data_raw_string = true;
1176 params.source_routing_id = MSG_ROUTING_NONE;
1177 host->Send(new ViewMsg_PostMessageEvent(host->GetRoutingID(), params));
1180 void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
1181 int text_input_type,
1182 int text_input_flags,
1183 const std::string& text,
1184 int selection_start,
1186 int composition_start,
1187 int composition_end,
1188 bool show_ime_if_needed,
1189 bool is_non_ime_change) {
1190 JNIEnv* env = AttachCurrentThread();
1191 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1195 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
1196 Java_ContentViewCore_updateImeAdapter(env,
1210 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
1212 SetAccessibilityEnabledInternal(enabled);
1215 bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
1216 JNIEnv* env = AttachCurrentThread();
1217 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1220 return Java_ContentViewCore_isFullscreenRequiredForOrientationLock(env,
1224 void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) {
1225 accessibility_enabled_ = enabled;
1226 BrowserAccessibilityStateImpl* accessibility_state =
1227 BrowserAccessibilityStateImpl::GetInstance();
1229 // This enables accessibility globally unless it was explicitly disallowed
1230 // by a command-line flag.
1231 accessibility_state->OnScreenReaderDetected();
1232 // If it was actually enabled globally, enable it for this RenderWidget now.
1233 if (accessibility_state->IsAccessibleBrowser() && web_contents_)
1234 web_contents_->AddAccessibilityMode(AccessibilityModeComplete);
1236 accessibility_state->ResetAccessibilityMode();
1237 if (web_contents_) {
1238 web_contents_->SetAccessibilityMode(
1239 accessibility_state->accessibility_mode());
1244 void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
1245 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1247 rwhv->UpdateScreenInfo(GetViewAndroid());
1249 static_cast<WebContentsImpl*>(web_contents())->
1250 screen_orientation_dispatcher_host()->OnOrientationChange();
1253 void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
1260 static_cast<int>(x / dpi_scale()),
1261 static_cast<int>(y / dpi_scale()),
1262 static_cast<int>((width > 0 && width < dpi_scale()) ?
1263 1 : (int)(width / dpi_scale())),
1264 static_cast<int>((height > 0 && height < dpi_scale()) ?
1265 1 : (int)(height / dpi_scale())));
1266 GetWebContents()->Send(new ViewMsg_ExtractSmartClipData(
1267 GetWebContents()->GetRoutingID(), rect));
1270 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) {
1271 return GetRenderProcessIdFromRenderViewHost(
1272 web_contents_->GetRenderViewHost());
1275 void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj,
1277 if (GetRenderWidgetHostViewAndroid())
1278 GetRenderWidgetHostViewAndroid()->SetBackgroundOpaque(opaque);
1281 void ContentViewCoreImpl::RequestTextSurroundingSelection(
1283 const base::Callback<
1284 void(const base::string16& content, int start_offset, int end_offset)>&
1286 DCHECK(!callback.is_null());
1287 RenderFrameHost* focused_frame = web_contents_->GetFocusedFrame();
1290 if (GetRenderWidgetHostViewAndroid()) {
1291 GetRenderWidgetHostViewAndroid()->SetTextSurroundingSelectionCallback(
1293 focused_frame->Send(new FrameMsg_TextSurroundingSelectionRequest(
1294 focused_frame->GetRoutingID(), max_length));
1298 void ContentViewCoreImpl::OnSmartClipDataExtracted(
1299 const base::string16& text,
1300 const base::string16& html,
1301 const gfx::Rect& clip_rect) {
1302 JNIEnv* env = AttachCurrentThread();
1303 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1306 ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
1307 ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html);
1308 ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect));
1309 Java_ContentViewCore_onSmartClipDataExtracted(
1310 env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj());
1313 void ContentViewCoreImpl::WebContentsDestroyed() {
1314 WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
1315 static_cast<WebContentsImpl*>(web_contents())->GetView());
1317 wcva->SetContentViewCore(NULL);
1320 // This is called for each ContentView.
1321 jlong Init(JNIEnv* env,
1323 jlong native_web_contents,
1325 jlong window_android,
1326 jobject retained_objects_set) {
1327 ContentViewCoreImpl* view = new ContentViewCoreImpl(
1329 reinterpret_cast<WebContents*>(native_web_contents),
1330 reinterpret_cast<ui::ViewAndroid*>(view_android),
1331 reinterpret_cast<ui::WindowAndroid*>(window_android),
1332 retained_objects_set);
1333 return reinterpret_cast<intptr_t>(view);
1336 bool RegisterContentViewCore(JNIEnv* env) {
1337 return RegisterNativesImpl(env);
1340 } // namespace content