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