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