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