Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / content / browser / android / content_view_core_impl.cc
blobbca737d5cc773a61cbea3645b92e9857b97ed3a1
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/output/begin_frame_args.h"
19 #include "content/browser/android/gesture_event_type.h"
20 #include "content/browser/android/interstitial_page_delegate_android.h"
21 #include "content/browser/android/load_url_params.h"
22 #include "content/browser/frame_host/interstitial_page_impl.h"
23 #include "content/browser/frame_host/navigation_controller_impl.h"
24 #include "content/browser/frame_host/navigation_entry_impl.h"
25 #include "content/browser/media/android/browser_media_player_manager.h"
26 #include "content/browser/renderer_host/compositor_impl_android.h"
27 #include "content/browser/renderer_host/input/motion_event_android.h"
28 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
29 #include "content/browser/renderer_host/input/web_input_event_util.h"
30 #include "content/browser/renderer_host/java/java_bound_object.h"
31 #include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.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/screen_orientation/screen_orientation_dispatcher_host.h"
36 #include "content/browser/ssl/ssl_host_state.h"
37 #include "content/browser/web_contents/web_contents_view_android.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_accessibility_state.h"
42 #include "content/public/browser/browser_context.h"
43 #include "content/public/browser/favicon_status.h"
44 #include "content/public/browser/notification_details.h"
45 #include "content/public/browser/notification_service.h"
46 #include "content/public/browser/notification_source.h"
47 #include "content/public/browser/notification_types.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/WebBindings.h"
57 #include "third_party/WebKit/public/web/WebInputEvent.h"
58 #include "ui/base/android/view_android.h"
59 #include "ui/base/android/window_android.h"
60 #include "ui/gfx/android/java_bitmap.h"
61 #include "ui/gfx/screen.h"
62 #include "ui/gfx/size_conversions.h"
63 #include "ui/gfx/size_f.h"
65 using base::android::AttachCurrentThread;
66 using base::android::ConvertJavaStringToUTF16;
67 using base::android::ConvertJavaStringToUTF8;
68 using base::android::ConvertUTF16ToJavaString;
69 using base::android::ConvertUTF8ToJavaString;
70 using base::android::ScopedJavaGlobalRef;
71 using base::android::ScopedJavaLocalRef;
72 using blink::WebGestureEvent;
73 using blink::WebInputEvent;
75 // Describes the type and enabled state of a select popup item.
76 namespace {
78 enum {
79 #define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value,
80 #include "content/browser/android/popup_item_type_list.h"
81 #undef DEFINE_POPUP_ITEM_TYPE
84 } //namespace
86 namespace content {
88 namespace {
90 const void* kContentViewUserDataKey = &kContentViewUserDataKey;
92 int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
93 DCHECK(host);
94 RenderProcessHost* render_process = host->GetProcess();
95 DCHECK(render_process);
96 if (render_process->HasConnection())
97 return render_process->GetHandle();
98 else
99 return 0;
102 ScopedJavaLocalRef<jobject> CreateJavaRect(
103 JNIEnv* env,
104 const gfx::Rect& rect) {
105 return ScopedJavaLocalRef<jobject>(
106 Java_ContentViewCore_createRect(env,
107 static_cast<int>(rect.x()),
108 static_cast<int>(rect.y()),
109 static_cast<int>(rect.right()),
110 static_cast<int>(rect.bottom())));
113 int ToGestureEventType(WebInputEvent::Type type) {
114 switch (type) {
115 case WebInputEvent::GestureScrollBegin:
116 return SCROLL_START;
117 case WebInputEvent::GestureScrollEnd:
118 return SCROLL_END;
119 case WebInputEvent::GestureScrollUpdate:
120 return SCROLL_BY;
121 case WebInputEvent::GestureFlingStart:
122 return FLING_START;
123 case WebInputEvent::GestureFlingCancel:
124 return FLING_CANCEL;
125 case WebInputEvent::GestureShowPress:
126 return SHOW_PRESS;
127 case WebInputEvent::GestureTap:
128 return SINGLE_TAP_CONFIRMED;
129 case WebInputEvent::GestureTapUnconfirmed:
130 return SINGLE_TAP_UNCONFIRMED;
131 case WebInputEvent::GestureTapDown:
132 return TAP_DOWN;
133 case WebInputEvent::GestureTapCancel:
134 return TAP_CANCEL;
135 case WebInputEvent::GestureDoubleTap:
136 return DOUBLE_TAP;
137 case WebInputEvent::GestureLongPress:
138 return LONG_PRESS;
139 case WebInputEvent::GestureLongTap:
140 return LONG_TAP;
141 case WebInputEvent::GesturePinchBegin:
142 return PINCH_BEGIN;
143 case WebInputEvent::GesturePinchEnd:
144 return PINCH_END;
145 case WebInputEvent::GesturePinchUpdate:
146 return PINCH_BY;
147 case WebInputEvent::GestureTwoFingerTap:
148 case WebInputEvent::GestureScrollUpdateWithoutPropagation:
149 default:
150 NOTREACHED() << "Invalid source gesture type: "
151 << WebInputEventTraits::GetName(type);
152 return -1;
156 float GetPrimaryDisplayDeviceScaleFactor() {
157 const gfx::Display& display =
158 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
159 return display.device_scale_factor();
162 } // namespace
164 // Enables a callback when the underlying WebContents is destroyed, to enable
165 // nulling the back-pointer.
166 class ContentViewCoreImpl::ContentViewUserData
167 : public base::SupportsUserData::Data {
168 public:
169 explicit ContentViewUserData(ContentViewCoreImpl* content_view_core)
170 : content_view_core_(content_view_core) {
173 virtual ~ContentViewUserData() {
174 // TODO(joth): When chrome has finished removing the TabContents class (see
175 // crbug.com/107201) consider inverting relationship, so ContentViewCore
176 // would own WebContents. That effectively implies making the WebContents
177 // destructor private on Android.
178 delete content_view_core_;
181 ContentViewCoreImpl* get() const { return content_view_core_; }
183 private:
184 // Not using scoped_ptr as ContentViewCoreImpl destructor is private.
185 ContentViewCoreImpl* content_view_core_;
187 DISALLOW_IMPLICIT_CONSTRUCTORS(ContentViewUserData);
190 // static
191 ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
192 content::WebContents* web_contents) {
193 ContentViewCoreImpl::ContentViewUserData* data =
194 reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>(
195 web_contents->GetUserData(kContentViewUserDataKey));
196 return data ? data->get() : NULL;
199 // static
200 ContentViewCore* ContentViewCore::FromWebContents(
201 content::WebContents* web_contents) {
202 return ContentViewCoreImpl::FromWebContents(web_contents);
205 // static
206 ContentViewCore* ContentViewCore::GetNativeContentViewCore(JNIEnv* env,
207 jobject obj) {
208 return reinterpret_cast<ContentViewCore*>(
209 Java_ContentViewCore_getNativeContentViewCore(env, obj));
212 ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env,
213 jobject obj,
214 WebContents* web_contents,
215 ui::ViewAndroid* view_android,
216 ui::WindowAndroid* window_android)
217 : WebContentsObserver(web_contents),
218 java_ref_(env, obj),
219 web_contents_(static_cast<WebContentsImpl*>(web_contents)),
220 root_layer_(cc::Layer::Create()),
221 dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
222 view_android_(view_android),
223 window_android_(window_android),
224 device_orientation_(0),
225 geolocation_needs_pause_(false) {
226 CHECK(web_contents) <<
227 "A ContentViewCoreImpl should be created with a valid WebContents.";
229 // Currently, the only use case we have for overriding a user agent involves
230 // spoofing a desktop Linux user agent for "Request desktop site".
231 // Automatically set it for all WebContents so that it is available when a
232 // NavigationEntry requires the user agent to be overridden.
233 const char kLinuxInfoStr[] = "X11; Linux x86_64";
234 std::string product = content::GetContentClient()->GetProduct();
235 std::string spoofed_ua =
236 BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
237 web_contents->SetUserAgentOverride(spoofed_ua);
239 InitWebContents();
242 ContentViewCoreImpl::~ContentViewCoreImpl() {
243 JNIEnv* env = base::android::AttachCurrentThread();
244 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
245 java_ref_.reset();
246 if (!j_obj.is_null()) {
247 Java_ContentViewCore_onNativeContentViewCoreDestroyed(
248 env, j_obj.obj(), reinterpret_cast<intptr_t>(this));
250 // Make sure nobody calls back into this object while we are tearing things
251 // down.
252 notification_registrar_.RemoveAll();
255 base::android::ScopedJavaLocalRef<jobject>
256 ContentViewCoreImpl::GetWebContentsAndroid(JNIEnv* env, jobject obj) {
257 return web_contents_->GetJavaWebContents();
260 void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env,
261 jobject obj) {
262 DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
263 java_ref_.reset();
266 void ContentViewCoreImpl::InitWebContents() {
267 DCHECK(web_contents_);
268 notification_registrar_.Add(
269 this, NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
270 Source<WebContents>(web_contents_));
271 notification_registrar_.Add(
272 this, NOTIFICATION_RENDERER_PROCESS_CREATED,
273 content::NotificationService::AllBrowserContextsAndSources());
274 notification_registrar_.Add(
275 this, NOTIFICATION_WEB_CONTENTS_CONNECTED,
276 Source<WebContents>(web_contents_));
278 static_cast<WebContentsViewAndroid*>(
279 static_cast<WebContentsImpl*>(web_contents_)->GetView())->
280 SetContentViewCore(this);
281 DCHECK(!web_contents_->GetUserData(kContentViewUserDataKey));
282 web_contents_->SetUserData(kContentViewUserDataKey,
283 new ContentViewUserData(this));
286 void ContentViewCoreImpl::Observe(int type,
287 const NotificationSource& source,
288 const NotificationDetails& details) {
289 switch (type) {
290 case NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
291 std::pair<RenderViewHost*, RenderViewHost*>* switched_details =
292 Details<std::pair<RenderViewHost*, RenderViewHost*> >(details).ptr();
293 int old_pid = 0;
294 if (switched_details->first) {
295 old_pid = GetRenderProcessIdFromRenderViewHost(
296 switched_details->first);
298 RenderWidgetHostViewAndroid* view =
299 static_cast<RenderWidgetHostViewAndroid*>(
300 switched_details->first->GetView());
301 if (view)
302 view->SetContentViewCore(NULL);
304 view = static_cast<RenderWidgetHostViewAndroid*>(
305 switched_details->second->GetView());
307 if (view)
308 view->SetContentViewCore(this);
310 int new_pid = GetRenderProcessIdFromRenderViewHost(
311 web_contents_->GetRenderViewHost());
312 if (new_pid != old_pid) {
313 // Notify the Java side of the change of the current renderer process.
314 JNIEnv* env = AttachCurrentThread();
315 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
316 if (!obj.is_null()) {
317 Java_ContentViewCore_onRenderProcessSwap(env, obj.obj());
320 SetFocusInternal(HasFocus());
321 if (geolocation_needs_pause_)
322 PauseOrResumeGeolocation(true);
323 break;
325 case NOTIFICATION_RENDERER_PROCESS_CREATED: {
326 // Notify the Java side of the current renderer process.
327 RenderProcessHost* source_process_host =
328 Source<RenderProcessHost>(source).ptr();
329 RenderProcessHost* current_process_host =
330 web_contents_->GetRenderViewHost()->GetProcess();
332 if (source_process_host == current_process_host) {
333 JNIEnv* env = AttachCurrentThread();
334 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
335 if (!obj.is_null()) {
336 Java_ContentViewCore_onRenderProcessSwap(env, obj.obj());
339 break;
341 case NOTIFICATION_WEB_CONTENTS_CONNECTED: {
342 JNIEnv* env = AttachCurrentThread();
343 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
344 if (!obj.is_null()) {
345 Java_ContentViewCore_onWebContentsConnected(env, obj.obj());
347 break;
352 void ContentViewCoreImpl::RenderViewReady() {
353 if (device_orientation_ != 0)
354 SendOrientationChangeEventInternal();
357 RenderWidgetHostViewAndroid*
358 ContentViewCoreImpl::GetRenderWidgetHostViewAndroid() {
359 RenderWidgetHostView* rwhv = NULL;
360 if (web_contents_) {
361 rwhv = web_contents_->GetRenderWidgetHostView();
362 if (web_contents_->ShowingInterstitialPage()) {
363 rwhv = static_cast<InterstitialPageImpl*>(
364 web_contents_->GetInterstitialPage())->
365 GetRenderViewHost()->GetView();
368 return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
371 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() {
372 JNIEnv* env = AttachCurrentThread();
373 return java_ref_.get(env);
376 jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
377 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
378 if (!rwhva)
379 return SK_ColorWHITE;
380 return rwhva->GetCachedBackgroundColor();
383 void ContentViewCoreImpl::OnHide(JNIEnv* env, jobject obj) {
384 Hide();
387 void ContentViewCoreImpl::OnShow(JNIEnv* env, jobject obj) {
388 Show();
391 void ContentViewCoreImpl::Show() {
392 GetWebContents()->WasShown();
395 void ContentViewCoreImpl::Hide() {
396 GetWebContents()->WasHidden();
397 PauseVideo();
400 void ContentViewCoreImpl::PauseVideo() {
401 RenderViewHost* host = web_contents_->GetRenderViewHost();
402 if (host)
403 host->Send(new ViewMsg_PauseVideo(host->GetRoutingID()));
406 void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
407 geolocation_needs_pause_ = should_pause;
408 RenderViewHostImpl* rvh =
409 static_cast<RenderViewHostImpl*>(web_contents_->GetRenderViewHost());
410 if (rvh) {
411 scoped_refptr<GeolocationDispatcherHost> geolocation_dispatcher =
412 static_cast<RenderProcessHostImpl*>(
413 web_contents_->GetRenderProcessHost())->
414 geolocation_dispatcher_host();
415 if (geolocation_dispatcher.get()) {
416 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
417 base::Bind(&GeolocationDispatcherHost::PauseOrResume,
418 geolocation_dispatcher,
419 rvh->GetRoutingID(),
420 should_pause));
421 geolocation_needs_pause_ = false;
426 // All positions and sizes are in CSS pixels.
427 // Note that viewport_width/height is a best effort based.
428 // ContentViewCore has the actual information about the physical viewport size.
429 void ContentViewCoreImpl::UpdateFrameInfo(
430 const gfx::Vector2dF& scroll_offset,
431 float page_scale_factor,
432 const gfx::Vector2dF& page_scale_factor_limits,
433 const gfx::SizeF& content_size,
434 const gfx::SizeF& viewport_size,
435 const gfx::Vector2dF& controls_offset,
436 const gfx::Vector2dF& content_offset,
437 float overdraw_bottom_height) {
438 JNIEnv* env = AttachCurrentThread();
439 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
440 if (obj.is_null())
441 return;
443 if (window_android_) {
444 gfx::Vector2dF window_offset(
445 Java_ContentViewCore_getLocationInWindowX(env, obj.obj()),
446 Java_ContentViewCore_getLocationInWindowY(env, obj.obj()));
447 window_android_->set_content_offset(
448 gfx::ScaleVector2d(content_offset, dpi_scale_) + window_offset);
451 Java_ContentViewCore_updateFrameInfo(
452 env, obj.obj(),
453 scroll_offset.x(),
454 scroll_offset.y(),
455 page_scale_factor,
456 page_scale_factor_limits.x(),
457 page_scale_factor_limits.y(),
458 content_size.width(),
459 content_size.height(),
460 viewport_size.width(),
461 viewport_size.height(),
462 controls_offset.y(),
463 content_offset.y(),
464 overdraw_bottom_height);
467 void ContentViewCoreImpl::SetTitle(const base::string16& title) {
468 JNIEnv* env = AttachCurrentThread();
469 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
470 if (obj.is_null())
471 return;
472 ScopedJavaLocalRef<jstring> jtitle =
473 ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(title));
474 Java_ContentViewCore_setTitle(env, obj.obj(), jtitle.obj());
477 void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
478 JNIEnv* env = AttachCurrentThread();
479 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
480 if (obj.is_null())
481 return;
482 Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
485 void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds,
486 const std::vector<MenuItem>& items, int selected_item, bool multiple) {
487 JNIEnv* env = AttachCurrentThread();
488 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
489 if (j_obj.is_null())
490 return;
492 ScopedJavaLocalRef<jobject> bounds_rect(CreateJavaRect(env, bounds));
494 // For multi-select list popups we find the list of previous selections by
495 // iterating through the items. But for single selection popups we take the
496 // given |selected_item| as is.
497 ScopedJavaLocalRef<jintArray> selected_array;
498 if (multiple) {
499 scoped_ptr<jint[]> native_selected_array(new jint[items.size()]);
500 size_t selected_count = 0;
501 for (size_t i = 0; i < items.size(); ++i) {
502 if (items[i].checked)
503 native_selected_array[selected_count++] = i;
506 selected_array = ScopedJavaLocalRef<jintArray>(
507 env, env->NewIntArray(selected_count));
508 env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
509 native_selected_array.get());
510 } else {
511 selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
512 jint value = selected_item;
513 env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
516 ScopedJavaLocalRef<jintArray> enabled_array(env,
517 env->NewIntArray(items.size()));
518 std::vector<base::string16> labels;
519 labels.reserve(items.size());
520 for (size_t i = 0; i < items.size(); ++i) {
521 labels.push_back(items[i].label);
522 jint enabled =
523 (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP :
524 (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED :
525 POPUP_ITEM_TYPE_DISABLED));
526 env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled);
528 ScopedJavaLocalRef<jobjectArray> items_array(
529 base::android::ToJavaArrayOfStrings(env, labels));
530 Java_ContentViewCore_showSelectPopup(env, j_obj.obj(),
531 bounds_rect.obj(),
532 items_array.obj(),
533 enabled_array.obj(),
534 multiple,
535 selected_array.obj());
538 void ContentViewCoreImpl::HideSelectPopupMenu() {
539 JNIEnv* env = AttachCurrentThread();
540 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
541 if (!j_obj.is_null())
542 Java_ContentViewCore_hideSelectPopup(env, j_obj.obj());
545 void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
546 InputEventAckState ack_result) {
547 JNIEnv* env = AttachCurrentThread();
548 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
549 if (j_obj.is_null())
550 return;
552 switch (event.type) {
553 case WebInputEvent::GestureFlingStart:
554 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
555 // The view expects the fling velocity in pixels/s.
556 Java_ContentViewCore_onFlingStartEventConsumed(env, j_obj.obj(),
557 event.data.flingStart.velocityX * dpi_scale(),
558 event.data.flingStart.velocityY * dpi_scale());
559 } else {
560 // If a scroll ends with a fling, a SCROLL_END event is never sent.
561 // However, if that fling went unconsumed, we still need to let the
562 // listeners know that scrolling has ended.
563 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
566 if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
567 // The view expects the fling velocity in pixels/s.
568 Java_ContentViewCore_onFlingStartEventHadNoConsumer(env, j_obj.obj(),
569 event.data.flingStart.velocityX * dpi_scale(),
570 event.data.flingStart.velocityY * dpi_scale());
572 break;
573 case WebInputEvent::GestureFlingCancel:
574 Java_ContentViewCore_onFlingCancelEventAck(env, j_obj.obj());
575 break;
576 case WebInputEvent::GestureScrollBegin:
577 Java_ContentViewCore_onScrollBeginEventAck(env, j_obj.obj());
578 break;
579 case WebInputEvent::GestureScrollUpdate:
580 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
581 Java_ContentViewCore_onScrollUpdateGestureConsumed(env, j_obj.obj());
582 break;
583 case WebInputEvent::GestureScrollEnd:
584 Java_ContentViewCore_onScrollEndEventAck(env, j_obj.obj());
585 break;
586 case WebInputEvent::GesturePinchBegin:
587 Java_ContentViewCore_onPinchBeginEventAck(env, j_obj.obj());
588 break;
589 case WebInputEvent::GesturePinchEnd:
590 Java_ContentViewCore_onPinchEndEventAck(env, j_obj.obj());
591 break;
592 case WebInputEvent::GestureTap:
593 if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED) {
594 Java_ContentViewCore_onTapEventNotConsumed(
595 env, j_obj.obj(), event.x * dpi_scale(), event.y * dpi_scale());
597 break;
598 case WebInputEvent::GestureDoubleTap:
599 Java_ContentViewCore_onDoubleTapEventAck(env, j_obj.obj());
600 break;
601 default:
602 break;
606 bool ContentViewCoreImpl::FilterInputEvent(const blink::WebInputEvent& event) {
607 if (event.type != WebInputEvent::GestureTap &&
608 event.type != WebInputEvent::GestureDoubleTap &&
609 event.type != WebInputEvent::GestureLongTap &&
610 event.type != WebInputEvent::GestureLongPress)
611 return false;
613 JNIEnv* env = AttachCurrentThread();
614 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
615 if (j_obj.is_null())
616 return false;
618 const blink::WebGestureEvent& gesture =
619 static_cast<const blink::WebGestureEvent&>(event);
620 int gesture_type = ToGestureEventType(event.type);
621 return Java_ContentViewCore_filterTapOrPressEvent(env,
622 j_obj.obj(),
623 gesture_type,
624 gesture.x * dpi_scale(),
625 gesture.y * dpi_scale());
627 // TODO(jdduke): Also report double-tap UMA, crbug/347568.
630 bool ContentViewCoreImpl::HasFocus() {
631 JNIEnv* env = AttachCurrentThread();
632 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
633 if (obj.is_null())
634 return false;
635 return Java_ContentViewCore_hasFocus(env, obj.obj());
638 void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
639 JNIEnv* env = AttachCurrentThread();
640 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
641 if (obj.is_null())
642 return;
643 ScopedJavaLocalRef<jstring> jtext = ConvertUTF8ToJavaString(env, text);
644 Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
647 void ContentViewCoreImpl::OnSelectionBoundsChanged(
648 const ViewHostMsg_SelectionBounds_Params& params) {
649 JNIEnv* env = AttachCurrentThread();
650 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
651 if (obj.is_null())
652 return;
653 ScopedJavaLocalRef<jobject> anchor_rect_dip(
654 CreateJavaRect(env, params.anchor_rect));
655 ScopedJavaLocalRef<jobject> focus_rect_dip(
656 CreateJavaRect(env, params.focus_rect));
657 Java_ContentViewCore_onSelectionBoundsChanged(env, obj.obj(),
658 anchor_rect_dip.obj(),
659 params.anchor_dir,
660 focus_rect_dip.obj(),
661 params.focus_dir,
662 params.is_anchor_first);
665 void ContentViewCoreImpl::OnSelectionRootBoundsChanged(
666 const gfx::Rect& bounds) {
667 JNIEnv* env = AttachCurrentThread();
669 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
670 if (obj.is_null())
671 return;
673 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, bounds));
674 Java_ContentViewCore_setSelectionRootBounds(env,
675 obj.obj(),
676 rect_object.obj());
679 void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
680 JNIEnv* env = AttachCurrentThread();
681 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
682 if (obj.is_null())
683 return;
684 Java_ContentViewCore_showPastePopup(env, obj.obj(),
685 static_cast<jint>(x_dip),
686 static_cast<jint>(y_dip));
689 void ContentViewCoreImpl::GetScaledContentBitmap(
690 float scale,
691 jobject jbitmap_config,
692 gfx::Rect src_subrect,
693 const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
694 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
695 if (!view) {
696 result_callback.Run(false, SkBitmap());
697 return;
699 SkBitmap::Config skbitmap_format = gfx::ConvertToSkiaConfig(jbitmap_config);
700 view->GetScaledContentBitmap(scale, skbitmap_format, src_subrect,
701 result_callback);
704 void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
705 JNIEnv* env = AttachCurrentThread();
706 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
707 if (j_obj.is_null())
708 return;
709 ScopedJavaLocalRef<jstring> jcontent_url =
710 ConvertUTF8ToJavaString(env, content_url.spec());
711 Java_ContentViewCore_startContentIntent(env,
712 j_obj.obj(),
713 jcontent_url.obj());
716 void ContentViewCoreImpl::ShowDisambiguationPopup(
717 const gfx::Rect& target_rect,
718 const SkBitmap& zoomed_bitmap) {
719 JNIEnv* env = AttachCurrentThread();
721 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
722 if (obj.is_null())
723 return;
725 ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect));
727 ScopedJavaLocalRef<jobject> java_bitmap =
728 gfx::ConvertToJavaBitmap(&zoomed_bitmap);
729 DCHECK(!java_bitmap.is_null());
731 Java_ContentViewCore_showDisambiguationPopup(env,
732 obj.obj(),
733 rect_object.obj(),
734 java_bitmap.obj());
737 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
738 JNIEnv* env = AttachCurrentThread();
740 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
741 if (obj.is_null())
742 return ScopedJavaLocalRef<jobject>();
743 return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
746 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() {
747 JNIEnv* env = AttachCurrentThread();
749 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
750 if (obj.is_null())
751 return ScopedJavaLocalRef<jobject>();
753 return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj());
756 ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() {
757 JNIEnv* env = AttachCurrentThread();
759 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
760 if (obj.is_null())
761 return ScopedJavaLocalRef<jobject>();
763 return Java_ContentViewCore_getContext(env, obj.obj());
766 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
767 JNIEnv* env = AttachCurrentThread();
769 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
770 if (obj.is_null())
771 return true;
772 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
773 return Java_ContentViewCore_shouldBlockMediaRequest(env, obj.obj(),
774 j_url.obj());
777 void ContentViewCoreImpl::DidStopFlinging() {
778 JNIEnv* env = AttachCurrentThread();
780 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
781 if (!obj.is_null())
782 Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
785 gfx::Size ContentViewCoreImpl::GetViewSize() const {
786 gfx::Size size = GetViewportSizeDip();
787 gfx::Size offset = GetViewportSizeOffsetDip();
788 size.Enlarge(-offset.width(), -offset.height());
789 return size;
792 gfx::Size ContentViewCoreImpl::GetPhysicalBackingSize() const {
793 JNIEnv* env = AttachCurrentThread();
794 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
795 if (j_obj.is_null())
796 return gfx::Size();
797 return gfx::Size(
798 Java_ContentViewCore_getPhysicalBackingWidthPix(env, j_obj.obj()),
799 Java_ContentViewCore_getPhysicalBackingHeightPix(env, j_obj.obj()));
802 gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
803 JNIEnv* env = AttachCurrentThread();
804 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
805 if (j_obj.is_null())
806 return gfx::Size();
807 return gfx::Size(
808 Java_ContentViewCore_getViewportWidthPix(env, j_obj.obj()),
809 Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
812 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const {
813 JNIEnv* env = AttachCurrentThread();
814 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
815 if (j_obj.is_null())
816 return gfx::Size();
817 return gfx::Size(
818 Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()),
819 Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj()));
822 gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
823 return gfx::ToCeiledSize(
824 gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
827 gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const {
828 return gfx::ToCeiledSize(
829 gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / dpi_scale()));
832 float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const {
833 JNIEnv* env = AttachCurrentThread();
834 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
835 if (j_obj.is_null())
836 return 0.f;
837 return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj())
838 / dpi_scale();
841 void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
842 root_layer_->AddChild(layer);
845 void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
846 layer->RemoveFromParent();
849 void ContentViewCoreImpl::LoadUrl(
850 NavigationController::LoadURLParams& params) {
851 GetWebContents()->GetController().LoadURLWithParams(params);
854 ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
855 // view_android_ should never be null for Chrome.
856 DCHECK(view_android_);
857 return view_android_;
860 ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
861 // This should never be NULL for Chrome, but will be NULL for WebView.
862 DCHECK(window_android_);
863 return window_android_;
866 scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
867 return root_layer_.get();
870 // ----------------------------------------------------------------------------
871 // Methods called from Java via JNI
872 // ----------------------------------------------------------------------------
874 void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj,
875 jintArray indices) {
876 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
877 web_contents_->GetRenderViewHost());
878 DCHECK(rvhi);
879 if (indices == NULL) {
880 rvhi->DidCancelPopupMenu();
881 return;
884 int selected_count = env->GetArrayLength(indices);
885 std::vector<int> selected_indices;
886 jint* indices_ptr = env->GetIntArrayElements(indices, NULL);
887 for (int i = 0; i < selected_count; ++i)
888 selected_indices.push_back(indices_ptr[i]);
889 env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
890 rvhi->DidSelectPopupMenuItems(selected_indices);
893 void ContentViewCoreImpl::LoadUrl(
894 JNIEnv* env, jobject obj,
895 jstring url,
896 jint load_url_type,
897 jint transition_type,
898 jstring j_referrer_url,
899 jint referrer_policy,
900 jint ua_override_option,
901 jstring extra_headers,
902 jbyteArray post_data,
903 jstring base_url_for_data_url,
904 jstring virtual_url_for_data_url,
905 jboolean can_load_local_resources) {
906 DCHECK(url);
907 NavigationController::LoadURLParams params(
908 GURL(ConvertJavaStringToUTF8(env, url)));
910 params.load_type = static_cast<NavigationController::LoadURLType>(
911 load_url_type);
912 params.transition_type = PageTransitionFromInt(transition_type);
913 params.override_user_agent =
914 static_cast<NavigationController::UserAgentOverrideOption>(
915 ua_override_option);
917 if (extra_headers)
918 params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers);
920 if (post_data) {
921 std::vector<uint8> http_body_vector;
922 base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector);
923 params.browser_initiated_post_data =
924 base::RefCountedBytes::TakeVector(&http_body_vector);
927 if (base_url_for_data_url) {
928 params.base_url_for_data_url =
929 GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url));
932 if (virtual_url_for_data_url) {
933 params.virtual_url_for_data_url =
934 GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url));
937 params.can_load_local_resources = can_load_local_resources;
938 if (j_referrer_url) {
939 params.referrer = content::Referrer(
940 GURL(ConvertJavaStringToUTF8(env, j_referrer_url)),
941 static_cast<blink::WebReferrerPolicy>(referrer_policy));
944 LoadUrl(params);
947 ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL(
948 JNIEnv* env, jobject) const {
949 return ConvertUTF8ToJavaString(env, GetWebContents()->GetURL().spec());
952 jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) {
953 return GetWebContents()->GetBrowserContext()->IsOffTheRecord();
956 WebContents* ContentViewCoreImpl::GetWebContents() const {
957 return web_contents_;
960 void ContentViewCoreImpl::SetFocus(JNIEnv* env, jobject obj, jboolean focused) {
961 SetFocusInternal(focused);
964 void ContentViewCoreImpl::SetFocusInternal(bool focused) {
965 if (!GetRenderWidgetHostViewAndroid())
966 return;
968 if (focused)
969 GetRenderWidgetHostViewAndroid()->Focus();
970 else
971 GetRenderWidgetHostViewAndroid()->Blur();
974 void ContentViewCoreImpl::SendOrientationChangeEvent(JNIEnv* env,
975 jobject obj,
976 jint orientation) {
977 if (device_orientation_ != orientation) {
978 device_orientation_ = orientation;
979 SendOrientationChangeEventInternal();
983 jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
984 jobject obj,
985 jobject motion_event,
986 jlong time_ms,
987 jint android_action,
988 jint pointer_count,
989 jint history_size,
990 jint action_index,
991 jfloat pos_x_0,
992 jfloat pos_y_0,
993 jfloat pos_x_1,
994 jfloat pos_y_1,
995 jint pointer_id_0,
996 jint pointer_id_1,
997 jfloat touch_major_0,
998 jfloat touch_major_1) {
999 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1000 // Avoid synthesizing a touch event if it cannot be forwarded.
1001 if (!rwhv)
1002 return false;
1004 MotionEventAndroid event(1.f / dpi_scale(),
1005 env,
1006 motion_event,
1007 time_ms,
1008 android_action,
1009 pointer_count,
1010 history_size,
1011 action_index,
1012 pos_x_0,
1013 pos_y_0,
1014 pos_x_1,
1015 pos_y_1,
1016 pointer_id_0,
1017 pointer_id_1,
1018 touch_major_0,
1019 touch_major_1);
1021 return rwhv->OnTouchEvent(event);
1024 float ContentViewCoreImpl::GetDpiScale() const {
1025 return dpi_scale_;
1028 jboolean ContentViewCoreImpl::SendMouseMoveEvent(JNIEnv* env,
1029 jobject obj,
1030 jlong time_ms,
1031 jfloat x,
1032 jfloat y) {
1033 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1034 if (!rwhv)
1035 return false;
1037 blink::WebMouseEvent event = WebMouseEventBuilder::Build(
1038 WebInputEvent::MouseMove,
1039 blink::WebMouseEvent::ButtonNone,
1040 time_ms / 1000.0, x / dpi_scale(), y / dpi_scale(), 0, 1);
1042 rwhv->SendMouseEvent(event);
1043 return true;
1046 jboolean ContentViewCoreImpl::SendMouseWheelEvent(JNIEnv* env,
1047 jobject obj,
1048 jlong time_ms,
1049 jfloat x,
1050 jfloat y,
1051 jfloat vertical_axis) {
1052 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1053 if (!rwhv)
1054 return false;
1056 WebMouseWheelEventBuilder::Direction direction;
1057 if (vertical_axis > 0) {
1058 direction = WebMouseWheelEventBuilder::DIRECTION_UP;
1059 } else if (vertical_axis < 0) {
1060 direction = WebMouseWheelEventBuilder::DIRECTION_DOWN;
1061 } else {
1062 return false;
1064 blink::WebMouseWheelEvent event = WebMouseWheelEventBuilder::Build(
1065 direction, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1067 rwhv->SendMouseWheelEvent(event);
1068 return true;
1071 WebGestureEvent ContentViewCoreImpl::MakeGestureEvent(
1072 WebInputEvent::Type type, int64 time_ms, float x, float y) const {
1073 return WebGestureEventBuilder::Build(
1074 type, time_ms / 1000.0, x / dpi_scale(), y / dpi_scale());
1077 void ContentViewCoreImpl::SendGestureEvent(
1078 const blink::WebGestureEvent& event) {
1079 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1080 if (rwhv)
1081 rwhv->SendGestureEvent(event);
1084 void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
1085 jobject obj,
1086 jlong time_ms,
1087 jfloat x,
1088 jfloat y,
1089 jfloat hintx,
1090 jfloat hinty) {
1091 WebGestureEvent event = MakeGestureEvent(
1092 WebInputEvent::GestureScrollBegin, time_ms, x, y);
1093 event.data.scrollBegin.deltaXHint = hintx / dpi_scale();
1094 event.data.scrollBegin.deltaYHint = hinty / dpi_scale();
1096 SendGestureEvent(event);
1099 void ContentViewCoreImpl::ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1100 WebGestureEvent event = MakeGestureEvent(
1101 WebInputEvent::GestureScrollEnd, time_ms, 0, 0);
1102 SendGestureEvent(event);
1105 void ContentViewCoreImpl::ScrollBy(JNIEnv* env, jobject obj, jlong time_ms,
1106 jfloat x, jfloat y, jfloat dx, jfloat dy) {
1107 WebGestureEvent event = MakeGestureEvent(
1108 WebInputEvent::GestureScrollUpdate, time_ms, x, y);
1109 event.data.scrollUpdate.deltaX = -dx / dpi_scale();
1110 event.data.scrollUpdate.deltaY = -dy / dpi_scale();
1112 SendGestureEvent(event);
1115 void ContentViewCoreImpl::FlingStart(JNIEnv* env, jobject obj, jlong time_ms,
1116 jfloat x, jfloat y, jfloat vx, jfloat vy) {
1117 WebGestureEvent event = MakeGestureEvent(
1118 WebInputEvent::GestureFlingStart, time_ms, x, y);
1119 event.data.flingStart.velocityX = vx / dpi_scale();
1120 event.data.flingStart.velocityY = vy / dpi_scale();
1122 SendGestureEvent(event);
1125 void ContentViewCoreImpl::FlingCancel(JNIEnv* env, jobject obj, jlong time_ms) {
1126 WebGestureEvent event = MakeGestureEvent(
1127 WebInputEvent::GestureFlingCancel, time_ms, 0, 0);
1128 SendGestureEvent(event);
1131 void ContentViewCoreImpl::SingleTap(JNIEnv* env, jobject obj, jlong time_ms,
1132 jfloat x, jfloat y) {
1133 WebGestureEvent event = MakeGestureEvent(
1134 WebInputEvent::GestureTap, time_ms, x, y);
1135 event.data.tap.tapCount = 1;
1137 SendGestureEvent(event);
1140 void ContentViewCoreImpl::DoubleTap(JNIEnv* env, jobject obj, jlong time_ms,
1141 jfloat x, jfloat y) {
1142 WebGestureEvent event = MakeGestureEvent(
1143 WebInputEvent::GestureDoubleTap, time_ms, x, y);
1144 // Set the tap count to 1 even for DoubleTap, in order to be consistent with
1145 // double tap behavior on a mobile viewport. See crbug.com/234986 for context.
1146 event.data.tap.tapCount = 1;
1148 SendGestureEvent(event);
1151 void ContentViewCoreImpl::LongPress(JNIEnv* env, jobject obj, jlong time_ms,
1152 jfloat x, jfloat y) {
1153 WebGestureEvent event = MakeGestureEvent(
1154 WebInputEvent::GestureLongPress, time_ms, x, y);
1156 SendGestureEvent(event);
1159 void ContentViewCoreImpl::PinchBegin(JNIEnv* env, jobject obj, jlong time_ms,
1160 jfloat x, jfloat y) {
1161 WebGestureEvent event = MakeGestureEvent(
1162 WebInputEvent::GesturePinchBegin, time_ms, x, y);
1163 SendGestureEvent(event);
1166 void ContentViewCoreImpl::PinchEnd(JNIEnv* env, jobject obj, jlong time_ms) {
1167 WebGestureEvent event = MakeGestureEvent(
1168 WebInputEvent::GesturePinchEnd, time_ms, 0, 0);
1169 SendGestureEvent(event);
1172 void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms,
1173 jfloat anchor_x, jfloat anchor_y,
1174 jfloat delta) {
1175 WebGestureEvent event = MakeGestureEvent(
1176 WebInputEvent::GesturePinchUpdate, time_ms, anchor_x, anchor_y);
1177 event.data.pinchUpdate.scale = delta;
1179 SendGestureEvent(event);
1182 void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj,
1183 jfloat x1, jfloat y1,
1184 jfloat x2, jfloat y2) {
1185 if (!web_contents_)
1186 return;
1188 web_contents_->SelectRange(
1189 gfx::Point(x1 / dpi_scale(), y1 / dpi_scale()),
1190 gfx::Point(x2 / dpi_scale(), y2 / dpi_scale()));
1193 void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj,
1194 jfloat x, jfloat y) {
1195 if (GetRenderWidgetHostViewAndroid()) {
1196 GetRenderWidgetHostViewAndroid()->MoveCaret(
1197 gfx::Point(x / dpi_scale(), y / dpi_scale()));
1201 void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) {
1202 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1203 if (rwhv)
1204 rwhv->ResetGestureDetection();
1207 void ContentViewCoreImpl::SetDoubleTapSupportEnabled(JNIEnv* env,
1208 jobject obj,
1209 jboolean enabled) {
1210 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1211 if (rwhv)
1212 rwhv->SetDoubleTapSupportEnabled(enabled);
1215 void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env,
1216 jobject obj,
1217 jboolean enabled) {
1218 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1219 if (rwhv)
1220 rwhv->SetMultiTouchZoomSupportEnabled(enabled);
1223 void ContentViewCoreImpl::LoadIfNecessary(JNIEnv* env, jobject obj) {
1224 web_contents_->GetController().LoadIfNecessary();
1227 void ContentViewCoreImpl::RequestRestoreLoad(JNIEnv* env, jobject obj) {
1228 web_contents_->GetController().SetNeedsReload();
1231 void ContentViewCoreImpl::Reload(JNIEnv* env,
1232 jobject obj,
1233 jboolean check_for_repost) {
1234 if (web_contents_->GetController().NeedsReload())
1235 web_contents_->GetController().LoadIfNecessary();
1236 else
1237 web_contents_->GetController().Reload(check_for_repost);
1240 void ContentViewCoreImpl::ReloadIgnoringCache(JNIEnv* env,
1241 jobject obj,
1242 jboolean check_for_repost) {
1243 web_contents_->GetController().ReloadIgnoringCache(check_for_repost);
1246 void ContentViewCoreImpl::CancelPendingReload(JNIEnv* env, jobject obj) {
1247 web_contents_->GetController().CancelPendingReload();
1250 void ContentViewCoreImpl::ContinuePendingReload(JNIEnv* env, jobject obj) {
1251 web_contents_->GetController().ContinuePendingReload();
1254 void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) {
1255 // TODO(creis): Do callers of this need to know if it fails?
1256 if (web_contents_->GetController().CanPruneAllButLastCommitted())
1257 web_contents_->GetController().PruneAllButLastCommitted();
1260 void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
1261 JNIEnv* env,
1262 jobject obj,
1263 jboolean allow) {
1264 web_contents_->java_bridge_dispatcher_host_manager()
1265 ->SetAllowObjectContentsInspection(allow);
1268 void ContentViewCoreImpl::AddJavascriptInterface(
1269 JNIEnv* env,
1270 jobject /* obj */,
1271 jobject object,
1272 jstring name,
1273 jclass safe_annotation_clazz,
1274 jobject retained_object_set) {
1275 ScopedJavaLocalRef<jobject> scoped_object(env, object);
1276 ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz);
1277 JavaObjectWeakGlobalRef weak_retained_object_set(env, retained_object_set);
1279 // JavaBoundObject creates the NPObject with a ref count of 1, and
1280 // JavaBridgeDispatcherHostManager takes its own ref.
1281 JavaBridgeDispatcherHostManager* java_bridge =
1282 web_contents_->java_bridge_dispatcher_host_manager();
1283 java_bridge->SetRetainedObjectSet(weak_retained_object_set);
1284 NPObject* bound_object =
1285 JavaBoundObject::Create(scoped_object,
1286 scoped_clazz,
1287 java_bridge->AsWeakPtr(),
1288 java_bridge->GetAllowObjectContentsInspection());
1289 java_bridge->AddNamedObject(ConvertJavaStringToUTF16(env, name),
1290 bound_object);
1291 blink::WebBindings::releaseObject(bound_object);
1294 void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
1295 jobject /* obj */,
1296 jstring name) {
1297 web_contents_->java_bridge_dispatcher_host_manager()->RemoveNamedObject(
1298 ConvertJavaStringToUTF16(env, name));
1301 void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
1302 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1303 if (view) {
1304 RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
1305 view->GetRenderWidgetHost());
1306 host->SendScreenRects();
1307 view->WasResized();
1311 void ContentViewCoreImpl::ShowInterstitialPage(
1312 JNIEnv* env, jobject obj, jstring jurl, jlong delegate_ptr) {
1313 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
1314 InterstitialPageDelegateAndroid* delegate =
1315 reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
1316 InterstitialPage* interstitial = InterstitialPage::Create(
1317 web_contents_, false, url, delegate);
1318 delegate->set_interstitial_page(interstitial);
1319 interstitial->Show();
1322 jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env,
1323 jobject obj) {
1324 return web_contents_->ShowingInterstitialPage();
1327 jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env,
1328 jobject obj) {
1329 RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
1330 return view && view->HasValidFrame();
1333 void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) {
1334 RenderViewHost* host = web_contents_->GetRenderViewHost();
1335 if (!host)
1336 return;
1337 host->ExitFullscreen();
1340 void ContentViewCoreImpl::UpdateTopControlsState(JNIEnv* env,
1341 jobject obj,
1342 bool enable_hiding,
1343 bool enable_showing,
1344 bool animate) {
1345 RenderViewHost* host = web_contents_->GetRenderViewHost();
1346 if (!host)
1347 return;
1348 host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
1349 enable_hiding,
1350 enable_showing,
1351 animate));
1354 void ContentViewCoreImpl::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
1355 RenderViewHost* host = web_contents_->GetRenderViewHost();
1356 host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
1359 void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env,
1360 jobject obj) {
1361 RenderViewHost* host = web_contents_->GetRenderViewHost();
1362 host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
1363 host->GetRoutingID(), gfx::Rect()));
1366 namespace {
1368 static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj,
1369 jobject history,
1370 NavigationEntry* entry,
1371 int index) {
1372 // Get the details of the current entry
1373 ScopedJavaLocalRef<jstring> j_url(
1374 ConvertUTF8ToJavaString(env, entry->GetURL().spec()));
1375 ScopedJavaLocalRef<jstring> j_virtual_url(
1376 ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec()));
1377 ScopedJavaLocalRef<jstring> j_original_url(
1378 ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
1379 ScopedJavaLocalRef<jstring> j_title(
1380 ConvertUTF16ToJavaString(env, entry->GetTitle()));
1381 ScopedJavaLocalRef<jobject> j_bitmap;
1382 const FaviconStatus& status = entry->GetFavicon();
1383 if (status.valid && status.image.ToSkBitmap()->getSize() > 0)
1384 j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
1386 // Add the item to the list
1387 Java_ContentViewCore_addToNavigationHistory(
1388 env, obj, history, index, j_url.obj(), j_virtual_url.obj(),
1389 j_original_url.obj(), j_title.obj(), j_bitmap.obj());
1392 } // namespace
1394 int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env,
1395 jobject obj,
1396 jobject history) {
1397 // Iterate through navigation entries to populate the list
1398 const NavigationController& controller = web_contents_->GetController();
1399 int count = controller.GetEntryCount();
1400 for (int i = 0; i < count; ++i) {
1401 AddNavigationEntryToHistory(
1402 env, obj, history, controller.GetEntryAtIndex(i), i);
1405 return controller.GetCurrentEntryIndex();
1408 void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env,
1409 jobject obj,
1410 jobject history,
1411 jboolean is_forward,
1412 jint max_entries) {
1413 // Iterate through navigation entries to populate the list
1414 const NavigationController& controller = web_contents_->GetController();
1415 int count = controller.GetEntryCount();
1416 int num_added = 0;
1417 int increment_value = is_forward ? 1 : -1;
1418 for (int i = controller.GetCurrentEntryIndex() + increment_value;
1419 i >= 0 && i < count;
1420 i += increment_value) {
1421 if (num_added >= max_entries)
1422 break;
1424 AddNavigationEntryToHistory(
1425 env, obj, history, controller.GetEntryAtIndex(i), i);
1426 num_added++;
1430 ScopedJavaLocalRef<jstring>
1431 ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env,
1432 jobject obj) {
1433 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1434 if (entry == NULL)
1435 return ScopedJavaLocalRef<jstring>(env, NULL);
1436 return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec());
1439 long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
1440 RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
1441 if (!rwhva)
1442 return 0;
1443 return rwhva->GetNativeImeAdapter();
1446 namespace {
1447 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
1448 const base::Value* result) {
1449 JNIEnv* env = base::android::AttachCurrentThread();
1450 std::string json;
1451 base::JSONWriter::Write(result, &json);
1452 ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
1453 Java_ContentViewCore_onEvaluateJavaScriptResult(env,
1454 j_json.obj(),
1455 callback.obj());
1457 } // namespace
1459 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
1460 jobject obj,
1461 jstring script,
1462 jobject callback,
1463 jboolean start_renderer) {
1464 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
1465 DCHECK(rvh);
1467 if (start_renderer && !rvh->IsRenderViewLive()) {
1468 if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) {
1469 LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
1470 return;
1474 if (!callback) {
1475 // No callback requested.
1476 web_contents_->GetMainFrame()->ExecuteJavaScript(
1477 ConvertJavaStringToUTF16(env, script));
1478 return;
1481 // Secure the Java callback in a scoped object and give ownership of it to the
1482 // base::Callback.
1483 ScopedJavaGlobalRef<jobject> j_callback;
1484 j_callback.Reset(env, callback);
1485 content::RenderFrameHost::JavaScriptResultCallback c_callback =
1486 base::Bind(&JavaScriptResultCallback, j_callback);
1488 web_contents_->GetMainFrame()->ExecuteJavaScript(
1489 ConvertJavaStringToUTF16(env, script),
1490 c_callback);
1493 bool ContentViewCoreImpl::GetUseDesktopUserAgent(
1494 JNIEnv* env, jobject obj) {
1495 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1496 return entry && entry->GetIsOverridingUserAgent();
1499 void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
1500 int text_input_type,
1501 const std::string& text,
1502 int selection_start,
1503 int selection_end,
1504 int composition_start,
1505 int composition_end,
1506 bool show_ime_if_needed,
1507 bool is_non_ime_change) {
1508 JNIEnv* env = AttachCurrentThread();
1509 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1510 if (obj.is_null())
1511 return;
1513 ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
1514 Java_ContentViewCore_updateImeAdapter(env, obj.obj(),
1515 native_ime_adapter, text_input_type,
1516 jstring_text.obj(),
1517 selection_start, selection_end,
1518 composition_start, composition_end,
1519 show_ime_if_needed, is_non_ime_change);
1522 void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) {
1523 SSLHostState* state = SSLHostState::GetFor(
1524 web_contents_->GetController().GetBrowserContext());
1525 state->Clear();
1528 void ContentViewCoreImpl::SetUseDesktopUserAgent(
1529 JNIEnv* env,
1530 jobject obj,
1531 jboolean enabled,
1532 jboolean reload_on_state_change) {
1533 if (GetUseDesktopUserAgent(env, obj) == enabled)
1534 return;
1536 // Make sure the navigation entry actually exists.
1537 NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
1538 if (!entry)
1539 return;
1541 // Set the flag in the NavigationEntry.
1542 entry->SetIsOverridingUserAgent(enabled);
1544 // Send the override to the renderer.
1545 if (reload_on_state_change) {
1546 // Reloading the page will send the override down as part of the
1547 // navigation IPC message.
1548 NavigationControllerImpl& controller =
1549 static_cast<NavigationControllerImpl&>(web_contents_->GetController());
1550 controller.ReloadOriginalRequestURL(false);
1554 void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
1555 bool enabled) {
1556 RenderWidgetHostViewAndroid* host_view = GetRenderWidgetHostViewAndroid();
1557 if (!host_view)
1558 return;
1559 RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From(
1560 host_view->GetRenderWidgetHost());
1561 BrowserAccessibilityState* accessibility_state =
1562 BrowserAccessibilityState::GetInstance();
1563 if (enabled) {
1564 // This enables accessibility globally unless it was explicitly disallowed
1565 // by a command-line flag.
1566 accessibility_state->OnScreenReaderDetected();
1567 // If it was actually enabled globally, enable it for this RenderWidget now.
1568 if (accessibility_state->IsAccessibleBrowser() && host_impl)
1569 host_impl->AddAccessibilityMode(AccessibilityModeComplete);
1570 } else {
1571 accessibility_state->ResetAccessibilityMode();
1572 if (host_impl)
1573 host_impl->ResetAccessibilityMode();
1577 void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
1578 RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
1579 if (rwhv)
1580 rwhv->UpdateScreenInfo(GetViewAndroid());
1582 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
1583 web_contents_->GetRenderViewHost());
1584 rvhi->SendOrientationChangeEvent(device_orientation_);
1586 // TODO(mlamouri): temporary plumbing for Screen Orientation, this will change
1587 // in the future. It might leave ContentViewCoreImpl or simply replace the
1588 // SendOrientationChangeEvent call above.
1589 blink::WebScreenOrientationType orientation =
1590 blink::WebScreenOrientationPortraitPrimary;
1592 switch (device_orientation_) {
1593 case 0:
1594 orientation = blink::WebScreenOrientationPortraitPrimary;
1595 break;
1596 case 90:
1597 orientation = blink::WebScreenOrientationLandscapePrimary;
1598 break;
1599 case -90:
1600 orientation = blink::WebScreenOrientationLandscapeSecondary;
1601 break;
1602 case 180:
1603 orientation = blink::WebScreenOrientationPortraitSecondary;
1604 break;
1605 default:
1606 NOTREACHED();
1609 ScreenOrientationDispatcherHost* sodh =
1610 static_cast<RenderProcessHostImpl*>(web_contents_->
1611 GetRenderProcessHost())->screen_orientation_dispatcher_host();
1613 // sodh can be null if the RenderProcessHost is in the process of being
1614 // destroyed or not yet initialized.
1615 if (sodh)
1616 sodh->OnOrientationChange(orientation);
1619 void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
1620 jobject obj,
1621 jint x,
1622 jint y,
1623 jint width,
1624 jint height) {
1625 gfx::Rect rect(
1626 static_cast<int>(x / dpi_scale()),
1627 static_cast<int>(y / dpi_scale()),
1628 static_cast<int>((width > 0 && width < dpi_scale()) ?
1629 1 : (int)(width / dpi_scale())),
1630 static_cast<int>((height > 0 && height < dpi_scale()) ?
1631 1 : (int)(height / dpi_scale())));
1632 GetWebContents()->Send(new ViewMsg_ExtractSmartClipData(
1633 GetWebContents()->GetRoutingID(), rect));
1636 jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) {
1637 return GetRenderProcessIdFromRenderViewHost(
1638 web_contents_->GetRenderViewHost());
1641 void ContentViewCoreImpl::OnSmartClipDataExtracted(
1642 const base::string16& result) {
1643 JNIEnv* env = AttachCurrentThread();
1644 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1645 if (obj.is_null())
1646 return;
1647 ScopedJavaLocalRef<jstring> jresult = ConvertUTF16ToJavaString(env, result);
1648 Java_ContentViewCore_onSmartClipDataExtracted(
1649 env, obj.obj(), jresult.obj());
1652 void ContentViewCoreImpl::WebContentsDestroyed(WebContents* web_contents) {
1653 WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
1654 static_cast<WebContentsImpl*>(web_contents)->GetView());
1655 DCHECK(wcva);
1656 wcva->SetContentViewCore(NULL);
1659 // This is called for each ContentView.
1660 jlong Init(JNIEnv* env,
1661 jobject obj,
1662 jlong native_web_contents,
1663 jlong view_android,
1664 jlong window_android) {
1665 ContentViewCoreImpl* view = new ContentViewCoreImpl(
1666 env, obj,
1667 reinterpret_cast<WebContents*>(native_web_contents),
1668 reinterpret_cast<ui::ViewAndroid*>(view_android),
1669 reinterpret_cast<ui::WindowAndroid*>(window_android));
1670 return reinterpret_cast<intptr_t>(view);
1673 bool RegisterContentViewCore(JNIEnv* env) {
1674 return RegisterNativesImpl(env);
1677 } // namespace content