Home | History | Annotate | Download | only in native
      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 "android_webview/native/aw_contents.h"
      6 
      7 #include <limits>
      8 
      9 #include "android_webview/browser/aw_browser_context.h"
     10 #include "android_webview/browser/aw_browser_main_parts.h"
     11 #include "android_webview/browser/gpu_memory_buffer_factory_impl.h"
     12 #include "android_webview/browser/in_process_view_renderer.h"
     13 #include "android_webview/browser/net_disk_cache_remover.h"
     14 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
     15 #include "android_webview/common/aw_hit_test_data.h"
     16 #include "android_webview/native/aw_autofill_manager_delegate.h"
     17 #include "android_webview/native/aw_browser_dependency_factory.h"
     18 #include "android_webview/native/aw_contents_client_bridge.h"
     19 #include "android_webview/native/aw_contents_io_thread_client_impl.h"
     20 // START: Printing fork b/10190508
     21 #include "android_webview/native/aw_pdf_exporter.h"
     22 // END: Printing fork b/10190508
     23 #include "android_webview/native/aw_picture.h"
     24 #include "android_webview/native/aw_web_contents_delegate.h"
     25 #include "android_webview/native/java_browser_view_renderer_helper.h"
     26 #include "android_webview/native/state_serializer.h"
     27 #include "android_webview/public/browser/draw_gl.h"
     28 #include "base/android/jni_android.h"
     29 #include "base/android/jni_array.h"
     30 #include "base/android/jni_string.h"
     31 #include "base/android/scoped_java_ref.h"
     32 #include "base/atomicops.h"
     33 #include "base/bind.h"
     34 #include "base/callback.h"
     35 #include "base/memory/memory_pressure_listener.h"
     36 #include "base/message_loop/message_loop.h"
     37 #include "base/pickle.h"
     38 #include "base/strings/string16.h"
     39 #include "base/supports_user_data.h"
     40 #include "components/autofill/content/browser/autofill_driver_impl.h"
     41 #include "components/autofill/core/browser/autofill_manager.h"
     42 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
     43 #include "components/navigation_interception/intercept_navigation_delegate.h"
     44 #include "content/public/browser/android/content_view_core.h"
     45 #include "content/public/browser/browser_thread.h"
     46 #include "content/public/browser/cert_store.h"
     47 #include "content/public/browser/favicon_status.h"
     48 #include "content/public/browser/navigation_entry.h"
     49 #include "content/public/browser/render_process_host.h"
     50 #include "content/public/browser/render_view_host.h"
     51 #include "content/public/browser/web_contents.h"
     52 #include "content/public/common/renderer_preferences.h"
     53 #include "content/public/common/ssl_status.h"
     54 #include "jni/AwContents_jni.h"
     55 #include "net/cert/x509_certificate.h"
     56 #include "third_party/skia/include/core/SkPicture.h"
     57 #include "ui/base/l10n/l10n_util_android.h"
     58 #include "ui/gfx/android/java_bitmap.h"
     59 #include "ui/gfx/font_render_params_linux.h"
     60 #include "ui/gfx/image/image.h"
     61 #include "ui/gfx/size.h"
     62 
     63 struct AwDrawSWFunctionTable;
     64 struct AwDrawGLFunctionTable;
     65 
     66 using autofill::AutofillDriverImpl;
     67 using autofill::AutofillManager;
     68 using base::android::AttachCurrentThread;
     69 using base::android::ConvertJavaStringToUTF16;
     70 using base::android::ConvertJavaStringToUTF8;
     71 using base::android::ConvertUTF16ToJavaString;
     72 using base::android::ConvertUTF8ToJavaString;
     73 using base::android::JavaRef;
     74 using base::android::ScopedJavaGlobalRef;
     75 using base::android::ScopedJavaLocalRef;
     76 using navigation_interception::InterceptNavigationDelegate;
     77 using content::BrowserThread;
     78 using content::ContentViewCore;
     79 using content::WebContents;
     80 
     81 extern "C" {
     82 static AwDrawGLFunction DrawGLFunction;
     83 static void DrawGLFunction(int view_context,
     84                            AwDrawGLInfo* draw_info,
     85                            void* spare) {
     86   // |view_context| is the value that was returned from the java
     87   // AwContents.onPrepareDrawGL; this cast must match the code there.
     88   reinterpret_cast<android_webview::BrowserViewRenderer*>(view_context)->DrawGL(
     89       draw_info);
     90 }
     91 }
     92 
     93 namespace android_webview {
     94 
     95 namespace {
     96 
     97 bool g_should_download_favicons = false;
     98 
     99 JavaBrowserViewRendererHelper* java_renderer_helper() {
    100   return JavaBrowserViewRendererHelper::GetInstance();
    101 }
    102 
    103 const void* kAwContentsUserDataKey = &kAwContentsUserDataKey;
    104 
    105 class AwContentsUserData : public base::SupportsUserData::Data {
    106  public:
    107   AwContentsUserData(AwContents* ptr) : contents_(ptr) {}
    108 
    109   static AwContents* GetContents(WebContents* web_contents) {
    110     if (!web_contents)
    111       return NULL;
    112     AwContentsUserData* data = reinterpret_cast<AwContentsUserData*>(
    113         web_contents->GetUserData(kAwContentsUserDataKey));
    114     return data ? data->contents_ : NULL;
    115   }
    116 
    117  private:
    118   AwContents* contents_;
    119 };
    120 
    121 base::subtle::Atomic32 g_instance_count = 0;
    122 
    123 // TODO(boliu): Deduplicate with chrome/ code.
    124 content::RendererPreferencesHintingEnum GetRendererPreferencesHintingEnum(
    125     gfx::FontRenderParams::Hinting hinting) {
    126   switch (hinting) {
    127     case gfx::FontRenderParams::HINTING_NONE:
    128       return content::RENDERER_PREFERENCES_HINTING_NONE;
    129     case gfx::FontRenderParams::HINTING_SLIGHT:
    130       return content::RENDERER_PREFERENCES_HINTING_SLIGHT;
    131     case gfx::FontRenderParams::HINTING_MEDIUM:
    132       return content::RENDERER_PREFERENCES_HINTING_MEDIUM;
    133     case gfx::FontRenderParams::HINTING_FULL:
    134       return content::RENDERER_PREFERENCES_HINTING_FULL;
    135     default:
    136       NOTREACHED() << "Unhandled hinting style " << hinting;
    137       return content::RENDERER_PREFERENCES_HINTING_SYSTEM_DEFAULT;
    138   }
    139 }
    140 
    141 // TODO(boliu): Deduplicate with chrome/ code.
    142 content::RendererPreferencesSubpixelRenderingEnum
    143 GetRendererPreferencesSubpixelRenderingEnum(
    144     gfx::FontRenderParams::SubpixelRendering subpixel_rendering) {
    145   switch (subpixel_rendering) {
    146     case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
    147       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_NONE;
    148     case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
    149       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_RGB;
    150     case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
    151       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_BGR;
    152     case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
    153       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VRGB;
    154     case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
    155       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_VBGR;
    156     default:
    157       NOTREACHED() << "Unhandled subpixel rendering style "
    158                    << subpixel_rendering;
    159       return content::RENDERER_PREFERENCES_SUBPIXEL_RENDERING_SYSTEM_DEFAULT;
    160   }
    161 }
    162 
    163 }  // namespace
    164 
    165 // static
    166 AwContents* AwContents::FromWebContents(WebContents* web_contents) {
    167   return AwContentsUserData::GetContents(web_contents);
    168 }
    169 
    170 // static
    171 AwContents* AwContents::FromID(int render_process_id, int render_view_id) {
    172   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    173   const content::RenderViewHost* rvh =
    174       content::RenderViewHost::FromID(render_process_id, render_view_id);
    175   if (!rvh) return NULL;
    176   content::WebContents* web_contents =
    177       content::WebContents::FromRenderViewHost(rvh);
    178   if (!web_contents) return NULL;
    179   return FromWebContents(web_contents);
    180 }
    181 
    182 AwContents::AwContents(scoped_ptr<WebContents> web_contents)
    183     : web_contents_(web_contents.Pass()),
    184       browser_view_renderer_(
    185           new InProcessViewRenderer(this, java_renderer_helper(),
    186                                     web_contents_.get())) {
    187   base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, 1);
    188   icon_helper_.reset(new IconHelper(web_contents_.get()));
    189   icon_helper_->SetListener(this);
    190   web_contents_->SetUserData(kAwContentsUserDataKey,
    191                              new AwContentsUserData(this));
    192   render_view_host_ext_.reset(
    193       new AwRenderViewHostExt(this, web_contents_.get()));
    194 
    195   AwAutofillManagerDelegate* autofill_manager_delegate =
    196       AwAutofillManagerDelegate::FromWebContents(web_contents_.get());
    197   if (autofill_manager_delegate)
    198     InitAutofillIfNecessary(autofill_manager_delegate->GetSaveFormData());
    199 
    200   SetAndroidWebViewRendererPrefs();
    201 }
    202 
    203 void AwContents::SetJavaPeers(JNIEnv* env,
    204                               jobject obj,
    205                               jobject aw_contents,
    206                               jobject web_contents_delegate,
    207                               jobject contents_client_bridge,
    208                               jobject io_thread_client,
    209                               jobject intercept_navigation_delegate) {
    210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    211   // The |aw_content| param is technically spurious as it duplicates |obj| but
    212   // is passed over anyway to make the binding more explicit.
    213   java_ref_ = JavaObjectWeakGlobalRef(env, aw_contents);
    214 
    215   web_contents_delegate_.reset(
    216       new AwWebContentsDelegate(env, web_contents_delegate));
    217   web_contents_->SetDelegate(web_contents_delegate_.get());
    218 
    219   contents_client_bridge_.reset(
    220       new AwContentsClientBridge(env, contents_client_bridge));
    221   AwContentsClientBridgeBase::Associate(web_contents_.get(),
    222                                         contents_client_bridge_.get());
    223 
    224   AwContentsIoThreadClientImpl::Associate(
    225       web_contents_.get(), ScopedJavaLocalRef<jobject>(env, io_thread_client));
    226 
    227   InterceptNavigationDelegate::Associate(
    228       web_contents_.get(),
    229       make_scoped_ptr(new InterceptNavigationDelegate(
    230           env, intercept_navigation_delegate)));
    231 
    232   // Finally, having setup the associations, release any deferred requests
    233   int child_id = web_contents_->GetRenderProcessHost()->GetID();
    234   int route_id = web_contents_->GetRoutingID();
    235   AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id);
    236 }
    237 
    238 void AwContents::SetSaveFormData(bool enabled) {
    239   InitAutofillIfNecessary(enabled);
    240   // We need to check for the existence, since autofill_manager_delegate
    241   // may not be created when the setting is false.
    242   if (AutofillDriverImpl::FromWebContents(web_contents_.get())) {
    243     AwAutofillManagerDelegate::FromWebContents(web_contents_.get())->
    244         SetSaveFormData(enabled);
    245   }
    246 }
    247 
    248 void AwContents::InitAutofillIfNecessary(bool enabled) {
    249   // Do not initialize if the feature is not enabled.
    250   if (!enabled)
    251     return;
    252   // Check if the autofill driver already exists.
    253   content::WebContents* web_contents = web_contents_.get();
    254   if (AutofillDriverImpl::FromWebContents(web_contents))
    255     return;
    256 
    257   AwBrowserContext::FromWebContents(web_contents)->
    258       CreateUserPrefServiceIfNecessary();
    259   AwAutofillManagerDelegate::CreateForWebContents(web_contents);
    260   AutofillDriverImpl::CreateForWebContentsAndDelegate(
    261       web_contents,
    262       AwAutofillManagerDelegate::FromWebContents(web_contents),
    263       l10n_util::GetDefaultLocale(),
    264       AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
    265 }
    266 
    267 void AwContents::SetAndroidWebViewRendererPrefs() {
    268   content::RendererPreferences* prefs =
    269       web_contents_->GetMutableRendererPrefs();
    270   prefs->tap_multiple_targets_strategy =
    271       content::TAP_MULTIPLE_TARGETS_STRATEGY_NONE;
    272 
    273   // TODO(boliu): Deduplicate with chrome/ code.
    274   const gfx::FontRenderParams& params = gfx::GetDefaultWebKitFontRenderParams();
    275   prefs->should_antialias_text = params.antialiasing;
    276   prefs->use_subpixel_positioning = params.subpixel_positioning;
    277   prefs->hinting = GetRendererPreferencesHintingEnum(params.hinting);
    278   prefs->use_autohinter = params.autohinter;
    279   prefs->use_bitmaps = params.use_bitmaps;
    280   prefs->subpixel_rendering =
    281       GetRendererPreferencesSubpixelRenderingEnum(params.subpixel_rendering);
    282 
    283   content::RenderViewHost* host = web_contents_->GetRenderViewHost();
    284   if (host)
    285     host->SyncRendererPrefs();
    286 }
    287 
    288 void AwContents::SetAwAutofillManagerDelegate(jobject delegate) {
    289   JNIEnv* env = AttachCurrentThread();
    290   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    291   if (obj.is_null())
    292     return;
    293   Java_AwContents_setAwAutofillManagerDelegate(env, obj.obj(), delegate);
    294 }
    295 
    296 AwContents::~AwContents() {
    297   DCHECK(AwContents::FromWebContents(web_contents_.get()) == this);
    298   web_contents_->RemoveUserData(kAwContentsUserDataKey);
    299   if (find_helper_.get())
    300     find_helper_->SetListener(NULL);
    301   if (icon_helper_.get())
    302     icon_helper_->SetListener(NULL);
    303   base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, -1);
    304 }
    305 
    306 jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
    307   DCHECK(web_contents_);
    308   return reinterpret_cast<jint>(web_contents_.get());
    309 }
    310 
    311 void AwContents::Destroy(JNIEnv* env, jobject obj) {
    312   java_ref_.reset();
    313   // We do not delete AwContents immediately. Some applications try to delete
    314   // Webview in ShouldOverrideUrlLoading callback, which is a sync IPC from
    315   // Webkit.
    316   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
    317   // When the last WebView is destroyed free all discardable memory allocated by
    318   // Chromium, because the app process may continue to run for a long time
    319   // without ever using another WebView.
    320   if (base::subtle::NoBarrier_Load(&g_instance_count) == 0) {
    321     base::MemoryPressureListener::NotifyMemoryPressure(
    322         base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
    323   }
    324 }
    325 
    326 static jint Init(JNIEnv* env, jclass, jobject browser_context) {
    327   // TODO(joth): Use |browser_context| to get the native BrowserContext, rather
    328   // than hard-code the default instance lookup here.
    329   scoped_ptr<WebContents> web_contents(content::WebContents::Create(
    330       content::WebContents::CreateParams(AwBrowserContext::GetDefault())));
    331   // Return an 'uninitialized' instance; most work is deferred until the
    332   // subsequent SetJavaPeers() call.
    333   return reinterpret_cast<jint>(new AwContents(web_contents.Pass()));
    334 }
    335 
    336 static void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) {
    337   BrowserViewRenderer::SetAwDrawSWFunctionTable(
    338       reinterpret_cast<AwDrawSWFunctionTable*>(function_table));
    339 }
    340 
    341 static void SetAwDrawGLFunctionTable(JNIEnv* env, jclass, jint function_table) {
    342   GpuMemoryBufferFactoryImpl::SetAwDrawGLFunctionTable(
    343       reinterpret_cast<AwDrawGLFunctionTable*>(function_table));
    344 }
    345 
    346 static jint GetAwDrawGLFunction(JNIEnv* env, jclass) {
    347   return reinterpret_cast<jint>(&DrawGLFunction);
    348 }
    349 
    350 // static
    351 jint GetNativeInstanceCount(JNIEnv* env, jclass) {
    352   return base::subtle::NoBarrier_Load(&g_instance_count);
    353 }
    354 
    355 jint AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) {
    356   return reinterpret_cast<jint>(browser_view_renderer_.get());
    357 }
    358 
    359 namespace {
    360 void DocumentHasImagesCallback(const ScopedJavaGlobalRef<jobject>& message,
    361                                bool has_images) {
    362   Java_AwContents_onDocumentHasImagesResponse(AttachCurrentThread(),
    363                                               has_images,
    364                                               message.obj());
    365 }
    366 }  // namespace
    367 
    368 void AwContents::DocumentHasImages(JNIEnv* env, jobject obj, jobject message) {
    369   ScopedJavaGlobalRef<jobject> j_message;
    370   j_message.Reset(env, message);
    371   render_view_host_ext_->DocumentHasImages(
    372       base::Bind(&DocumentHasImagesCallback, j_message));
    373 }
    374 
    375 namespace {
    376 void GenerateMHTMLCallback(ScopedJavaGlobalRef<jobject>* callback,
    377                            const base::FilePath& path, int64 size) {
    378   JNIEnv* env = AttachCurrentThread();
    379   // Android files are UTF8, so the path conversion below is safe.
    380   Java_AwContents_generateMHTMLCallback(
    381       env,
    382       ConvertUTF8ToJavaString(env, path.AsUTF8Unsafe()).obj(),
    383       size, callback->obj());
    384 }
    385 }  // namespace
    386 
    387 void AwContents::GenerateMHTML(JNIEnv* env, jobject obj,
    388                                jstring jpath, jobject callback) {
    389   ScopedJavaGlobalRef<jobject>* j_callback = new ScopedJavaGlobalRef<jobject>();
    390   j_callback->Reset(env, callback);
    391   web_contents_->GenerateMHTML(
    392       base::FilePath(ConvertJavaStringToUTF8(env, jpath)),
    393       base::Bind(&GenerateMHTMLCallback, base::Owned(j_callback)));
    394 }
    395 
    396 // START: Printing fork b/10190508
    397 void AwContents::CreatePdfExporter(JNIEnv* env,
    398                                    jobject obj,
    399                                    jobject pdfExporter) {
    400 
    401   pdf_exporter_.reset(
    402       new AwPdfExporter(env,
    403                         pdfExporter,
    404                         browser_view_renderer_.get(),
    405                         web_contents_.get()));
    406 }
    407 // END: Printing fork b/10190508
    408 
    409 bool AwContents::OnReceivedHttpAuthRequest(const JavaRef<jobject>& handler,
    410                                            const std::string& host,
    411                                            const std::string& realm) {
    412   JNIEnv* env = AttachCurrentThread();
    413   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    414   if (obj.is_null())
    415     return false;
    416 
    417   ScopedJavaLocalRef<jstring> jhost = ConvertUTF8ToJavaString(env, host);
    418   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
    419   Java_AwContents_onReceivedHttpAuthRequest(env, obj.obj(), handler.obj(),
    420       jhost.obj(), jrealm.obj());
    421   return true;
    422 }
    423 
    424 void AwContents::AddVisitedLinks(JNIEnv* env,
    425                                    jobject obj,
    426                                    jobjectArray jvisited_links) {
    427   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    428   std::vector<string16> visited_link_strings;
    429   base::android::AppendJavaStringArrayToStringVector(
    430       env, jvisited_links, &visited_link_strings);
    431 
    432   std::vector<GURL> visited_link_gurls;
    433   for (std::vector<string16>::const_iterator itr = visited_link_strings.begin();
    434        itr != visited_link_strings.end();
    435        ++itr) {
    436     visited_link_gurls.push_back(GURL(*itr));
    437   }
    438 
    439   AwBrowserContext::FromWebContents(web_contents_.get())
    440       ->AddVisitedURLs(visited_link_gurls);
    441 }
    442 
    443 bool RegisterAwContents(JNIEnv* env) {
    444   return RegisterNativesImpl(env) >= 0;
    445 }
    446 
    447 namespace {
    448 
    449 void ShowGeolocationPromptHelperTask(const JavaObjectWeakGlobalRef& java_ref,
    450                                      const GURL& origin) {
    451   JNIEnv* env = AttachCurrentThread();
    452   ScopedJavaLocalRef<jobject> j_ref = java_ref.get(env);
    453   if (j_ref.obj()) {
    454     ScopedJavaLocalRef<jstring> j_origin(
    455         ConvertUTF8ToJavaString(env, origin.spec()));
    456     Java_AwContents_onGeolocationPermissionsShowPrompt(env,
    457                                                        j_ref.obj(),
    458                                                        j_origin.obj());
    459   }
    460 }
    461 
    462 void ShowGeolocationPromptHelper(const JavaObjectWeakGlobalRef& java_ref,
    463                                  const GURL& origin) {
    464   JNIEnv* env = AttachCurrentThread();
    465   if (java_ref.get(env).obj()) {
    466     content::BrowserThread::PostTask(
    467         content::BrowserThread::UI,
    468         FROM_HERE,
    469         base::Bind(&ShowGeolocationPromptHelperTask,
    470                    java_ref,
    471                    origin));
    472   }
    473 }
    474 
    475 } // anonymous namespace
    476 
    477 void AwContents::ShowGeolocationPrompt(const GURL& requesting_frame,
    478                                        base::Callback<void(bool)> callback) {
    479   GURL origin = requesting_frame.GetOrigin();
    480   bool show_prompt = pending_geolocation_prompts_.empty();
    481   pending_geolocation_prompts_.push_back(OriginCallback(origin, callback));
    482   if (show_prompt) {
    483     ShowGeolocationPromptHelper(java_ref_, origin);
    484   }
    485 }
    486 
    487 // Invoked from Java
    488 void AwContents::InvokeGeolocationCallback(JNIEnv* env,
    489                                            jobject obj,
    490                                            jboolean value,
    491                                            jstring origin) {
    492   GURL callback_origin(base::android::ConvertJavaStringToUTF16(env, origin));
    493   if (callback_origin.GetOrigin() ==
    494       pending_geolocation_prompts_.front().first) {
    495     pending_geolocation_prompts_.front().second.Run(value);
    496     pending_geolocation_prompts_.pop_front();
    497     if (!pending_geolocation_prompts_.empty()) {
    498       ShowGeolocationPromptHelper(java_ref_,
    499                                   pending_geolocation_prompts_.front().first);
    500     }
    501   }
    502 }
    503 
    504 void AwContents::HideGeolocationPrompt(const GURL& origin) {
    505   bool removed_current_outstanding_callback = false;
    506   std::list<OriginCallback>::iterator it = pending_geolocation_prompts_.begin();
    507   while (it != pending_geolocation_prompts_.end()) {
    508     if ((*it).first == origin.GetOrigin()) {
    509       if (it == pending_geolocation_prompts_.begin()) {
    510         removed_current_outstanding_callback = true;
    511       }
    512       it = pending_geolocation_prompts_.erase(it);
    513     } else {
    514       ++it;
    515     }
    516   }
    517 
    518   if (removed_current_outstanding_callback) {
    519     JNIEnv* env = AttachCurrentThread();
    520     ScopedJavaLocalRef<jobject> j_ref = java_ref_.get(env);
    521     if (j_ref.obj()) {
    522       Java_AwContents_onGeolocationPermissionsHidePrompt(env, j_ref.obj());
    523     }
    524     if (!pending_geolocation_prompts_.empty()) {
    525       ShowGeolocationPromptHelper(java_ref_,
    526                             pending_geolocation_prompts_.front().first);
    527     }
    528   }
    529 }
    530 
    531 void AwContents::FindAllAsync(JNIEnv* env, jobject obj, jstring search_string) {
    532   GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string));
    533 }
    534 
    535 void AwContents::FindNext(JNIEnv* env, jobject obj, jboolean forward) {
    536   GetFindHelper()->FindNext(forward);
    537 }
    538 
    539 void AwContents::ClearMatches(JNIEnv* env, jobject obj) {
    540   GetFindHelper()->ClearMatches();
    541 }
    542 
    543 void AwContents::ClearCache(
    544     JNIEnv* env,
    545     jobject obj,
    546     jboolean include_disk_files) {
    547   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    548   render_view_host_ext_->ClearCache();
    549 
    550   if (include_disk_files) {
    551     RemoveHttpDiskCache(web_contents_->GetBrowserContext(),
    552                         web_contents_->GetRoutingID());
    553   }
    554 }
    555 
    556 FindHelper* AwContents::GetFindHelper() {
    557   if (!find_helper_.get()) {
    558     find_helper_.reset(new FindHelper(web_contents_.get()));
    559     find_helper_->SetListener(this);
    560   }
    561   return find_helper_.get();
    562 }
    563 
    564 void AwContents::OnFindResultReceived(int active_ordinal,
    565                                       int match_count,
    566                                       bool finished) {
    567   JNIEnv* env = AttachCurrentThread();
    568   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    569   if (obj.is_null())
    570     return;
    571 
    572   Java_AwContents_onFindResultReceived(
    573       env, obj.obj(), active_ordinal, match_count, finished);
    574 }
    575 
    576 bool AwContents::ShouldDownloadFavicon(const GURL& icon_url) {
    577   return g_should_download_favicons;
    578 }
    579 
    580 void AwContents::OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap) {
    581   JNIEnv* env = AttachCurrentThread();
    582   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    583   if (obj.is_null())
    584     return;
    585 
    586   content::NavigationEntry* entry =
    587       web_contents_->GetController().GetActiveEntry();
    588 
    589   if (entry) {
    590     entry->GetFavicon().valid = true;
    591     entry->GetFavicon().url = icon_url;
    592     entry->GetFavicon().image = gfx::Image::CreateFrom1xBitmap(bitmap);
    593   }
    594 
    595   Java_AwContents_onReceivedIcon(
    596       env, obj.obj(), gfx::ConvertToJavaBitmap(&bitmap).obj());
    597 }
    598 
    599 void AwContents::OnReceivedTouchIconUrl(const std::string& url,
    600                                         bool precomposed) {
    601   JNIEnv* env = AttachCurrentThread();
    602   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    603   if (obj.is_null())
    604     return;
    605 
    606   Java_AwContents_onReceivedTouchIconUrl(
    607       env, obj.obj(), ConvertUTF8ToJavaString(env, url).obj(), precomposed);
    608 }
    609 
    610 bool AwContents::RequestDrawGL(jobject canvas) {
    611   JNIEnv* env = AttachCurrentThread();
    612   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    613   if (obj.is_null())
    614     return false;
    615   return Java_AwContents_requestDrawGL(env, obj.obj(), canvas);
    616 }
    617 
    618 void AwContents::PostInvalidate() {
    619   JNIEnv* env = AttachCurrentThread();
    620   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    621   if (!obj.is_null())
    622     Java_AwContents_postInvalidateOnAnimation(env, obj.obj());
    623 }
    624 
    625 void AwContents::UpdateGlobalVisibleRect() {
    626   JNIEnv* env = AttachCurrentThread();
    627   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    628   if (!obj.is_null())
    629     Java_AwContents_updateGlobalVisibleRect(env, obj.obj());
    630 }
    631 
    632 void AwContents::OnNewPicture() {
    633   JNIEnv* env = AttachCurrentThread();
    634   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    635   if (!obj.is_null())
    636     Java_AwContents_onNewPicture(env, obj.obj());
    637 }
    638 
    639 base::android::ScopedJavaLocalRef<jbyteArray>
    640     AwContents::GetCertificate(JNIEnv* env,
    641                                jobject obj) {
    642   content::NavigationEntry* entry =
    643       web_contents_->GetController().GetActiveEntry();
    644   if (!entry)
    645     return ScopedJavaLocalRef<jbyteArray>();
    646   // Get the certificate
    647   int cert_id = entry->GetSSL().cert_id;
    648   scoped_refptr<net::X509Certificate> cert;
    649   bool ok = content::CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
    650   if (!ok)
    651     return ScopedJavaLocalRef<jbyteArray>();
    652 
    653   // Convert the certificate and return it
    654   std::string der_string;
    655   net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
    656   return base::android::ToJavaByteArray(env,
    657       reinterpret_cast<const uint8*>(der_string.data()), der_string.length());
    658 }
    659 
    660 void AwContents::RequestNewHitTestDataAt(JNIEnv* env, jobject obj,
    661                                          jint x, jint y) {
    662   render_view_host_ext_->RequestNewHitTestDataAt(x, y);
    663 }
    664 
    665 void AwContents::UpdateLastHitTestData(JNIEnv* env, jobject obj) {
    666   if (!render_view_host_ext_->HasNewHitTestData()) return;
    667 
    668   const AwHitTestData& data = render_view_host_ext_->GetLastHitTestData();
    669   render_view_host_ext_->MarkHitTestDataRead();
    670 
    671   // Make sure to null the Java object if data is empty/invalid.
    672   ScopedJavaLocalRef<jstring> extra_data_for_type;
    673   if (data.extra_data_for_type.length())
    674     extra_data_for_type = ConvertUTF8ToJavaString(
    675         env, data.extra_data_for_type);
    676 
    677   ScopedJavaLocalRef<jstring> href;
    678   if (data.href.length())
    679     href = ConvertUTF16ToJavaString(env, data.href);
    680 
    681   ScopedJavaLocalRef<jstring> anchor_text;
    682   if (data.anchor_text.length())
    683     anchor_text = ConvertUTF16ToJavaString(env, data.anchor_text);
    684 
    685   ScopedJavaLocalRef<jstring> img_src;
    686   if (data.img_src.is_valid())
    687     img_src = ConvertUTF8ToJavaString(env, data.img_src.spec());
    688 
    689   Java_AwContents_updateHitTestData(env,
    690                                     obj,
    691                                     data.type,
    692                                     extra_data_for_type.obj(),
    693                                     href.obj(),
    694                                     anchor_text.obj(),
    695                                     img_src.obj());
    696 }
    697 
    698 void AwContents::OnSizeChanged(JNIEnv* env, jobject obj,
    699                                int w, int h, int ow, int oh) {
    700   browser_view_renderer_->OnSizeChanged(w, h);
    701 }
    702 
    703 void AwContents::SetViewVisibility(JNIEnv* env, jobject obj, bool visible) {
    704   browser_view_renderer_->SetViewVisibility(visible);
    705 }
    706 
    707 void AwContents::SetWindowVisibility(JNIEnv* env, jobject obj, bool visible) {
    708   browser_view_renderer_->SetWindowVisibility(visible);
    709 }
    710 
    711 void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
    712   browser_view_renderer_->SetIsPaused(paused);
    713   if (paused) {
    714     ContentViewCore* cvc =
    715         ContentViewCore::FromWebContents(web_contents_.get());
    716     if (cvc)
    717       cvc->PauseVideo();
    718   }
    719 }
    720 
    721 void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
    722   browser_view_renderer_->OnAttachedToWindow(w, h);
    723 }
    724 
    725 void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
    726   browser_view_renderer_->OnDetachedFromWindow();
    727 }
    728 
    729 base::android::ScopedJavaLocalRef<jbyteArray>
    730 AwContents::GetOpaqueState(JNIEnv* env, jobject obj) {
    731   // Required optimization in WebViewClassic to not save any state if
    732   // there has been no navigations.
    733   if (!web_contents_->GetController().GetEntryCount())
    734     return ScopedJavaLocalRef<jbyteArray>();
    735 
    736   Pickle pickle;
    737   if (!WriteToPickle(*web_contents_, &pickle)) {
    738     return ScopedJavaLocalRef<jbyteArray>();
    739   } else {
    740     return base::android::ToJavaByteArray(env,
    741        reinterpret_cast<const uint8*>(pickle.data()), pickle.size());
    742   }
    743 }
    744 
    745 jboolean AwContents::RestoreFromOpaqueState(
    746     JNIEnv* env, jobject obj, jbyteArray state) {
    747   // TODO(boliu): This copy can be optimized out if this is a performance
    748   // problem.
    749   std::vector<uint8> state_vector;
    750   base::android::JavaByteArrayToByteVector(env, state, &state_vector);
    751 
    752   Pickle pickle(reinterpret_cast<const char*>(state_vector.begin()),
    753                 state_vector.size());
    754   PickleIterator iterator(pickle);
    755 
    756   return RestoreFromPickle(&iterator, web_contents_.get());
    757 }
    758 
    759 bool AwContents::OnDraw(JNIEnv* env,
    760                         jobject obj,
    761                         jobject canvas,
    762                         jboolean is_hardware_accelerated,
    763                         jint scroll_x,
    764                         jint scroll_y,
    765                         jint clip_left,
    766                         jint clip_top,
    767                         jint clip_right,
    768                         jint clip_bottom) {
    769   return browser_view_renderer_->OnDraw(
    770       canvas,
    771       is_hardware_accelerated,
    772       gfx::Vector2d(scroll_x, scroll_y),
    773       gfx::Rect(
    774           clip_left, clip_top, clip_right - clip_left, clip_bottom - clip_top));
    775 }
    776 
    777 void AwContents::SetGlobalVisibleRect(JNIEnv* env,
    778                                       jobject obj,
    779                                       jint visible_left,
    780                                       jint visible_top,
    781                                       jint visible_right,
    782                                       jint visible_bottom) {
    783   browser_view_renderer_->SetGlobalVisibleRect(
    784       gfx::Rect(visible_left,
    785                 visible_top,
    786                 visible_right - visible_left,
    787                 visible_bottom - visible_top));
    788 }
    789 
    790 void AwContents::SetPendingWebContentsForPopup(
    791     scoped_ptr<content::WebContents> pending) {
    792   if (pending_contents_.get()) {
    793     // TODO(benm): Support holding multiple pop up window requests.
    794     LOG(WARNING) << "Blocking popup window creation as an outstanding "
    795                  << "popup window is still pending.";
    796     base::MessageLoop::current()->DeleteSoon(FROM_HERE, pending.release());
    797     return;
    798   }
    799   pending_contents_.reset(new AwContents(pending.Pass()));
    800 }
    801 
    802 void AwContents::FocusFirstNode(JNIEnv* env, jobject obj) {
    803   web_contents_->FocusThroughTabTraversal(false);
    804 }
    805 
    806 void AwContents::SetBackgroundColor(JNIEnv* env, jobject obj, jint color) {
    807   render_view_host_ext_->SetBackgroundColor(color);
    808 }
    809 
    810 jint AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
    811   return reinterpret_cast<jint>(pending_contents_.release());
    812 }
    813 
    814 gfx::Point AwContents::GetLocationOnScreen() {
    815   JNIEnv* env = AttachCurrentThread();
    816   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    817   if (obj.is_null())
    818     return gfx::Point();
    819   std::vector<int> location;
    820   base::android::JavaIntArrayToIntVector(
    821       env,
    822       Java_AwContents_getLocationOnScreen(env, obj.obj()).obj(),
    823       &location);
    824   return gfx::Point(location[0], location[1]);
    825 }
    826 
    827 void AwContents::SetMaxContainerViewScrollOffset(gfx::Vector2d new_value) {
    828   JNIEnv* env = AttachCurrentThread();
    829   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    830   if (obj.is_null())
    831     return;
    832   Java_AwContents_setMaxContainerViewScrollOffset(
    833       env, obj.obj(), new_value.x(), new_value.y());
    834 }
    835 
    836 void AwContents::ScrollContainerViewTo(gfx::Vector2d new_value) {
    837   JNIEnv* env = AttachCurrentThread();
    838   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    839   if (obj.is_null())
    840     return;
    841   Java_AwContents_scrollContainerViewTo(
    842       env, obj.obj(), new_value.x(), new_value.y());
    843 }
    844 
    845 bool AwContents::IsFlingActive() const {
    846   JNIEnv* env = AttachCurrentThread();
    847   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    848   if (obj.is_null())
    849     return false;
    850   return Java_AwContents_isFlingActive(env, obj.obj());
    851 }
    852 
    853 void AwContents::SetPageScaleFactor(float page_scale_factor) {
    854   JNIEnv* env = AttachCurrentThread();
    855   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    856   if (obj.is_null())
    857     return;
    858   Java_AwContents_setPageScaleFactor(env, obj.obj(), page_scale_factor);
    859 }
    860 
    861 void AwContents::SetContentsSize(gfx::SizeF contents_size_dip) {
    862   JNIEnv* env = AttachCurrentThread();
    863   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    864   if (obj.is_null())
    865     return;
    866   Java_AwContents_setContentsSize(
    867       env, obj.obj(), contents_size_dip.width(), contents_size_dip.height());
    868 }
    869 
    870 void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) {
    871   JNIEnv* env = AttachCurrentThread();
    872   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    873   if (obj.is_null())
    874     return;
    875   Java_AwContents_didOverscroll(
    876       env, obj.obj(), overscroll_delta.x(), overscroll_delta.y());
    877 }
    878 
    879 void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale) {
    880   browser_view_renderer_->SetDipScale(dip_scale);
    881 }
    882 
    883 void AwContents::SetFixedLayoutSize(JNIEnv* env,
    884                                     jobject obj,
    885                                     jint width_dip,
    886                                     jint height_dip) {
    887   render_view_host_ext_->SetFixedLayoutSize(gfx::Size(width_dip, height_dip));
    888 }
    889 
    890 void AwContents::ScrollTo(JNIEnv* env, jobject obj, jint x, jint y) {
    891   browser_view_renderer_->ScrollTo(gfx::Vector2d(x, y));
    892 }
    893 
    894 void AwContents::OnWebLayoutPageScaleFactorChanged(float page_scale_factor) {
    895   JNIEnv* env = AttachCurrentThread();
    896   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    897   if (obj.is_null())
    898     return;
    899   Java_AwContents_onWebLayoutPageScaleFactorChanged(env, obj.obj(),
    900                                                          page_scale_factor);
    901 }
    902 
    903 void AwContents::OnWebLayoutContentsSizeChanged(
    904     const gfx::Size& contents_size) {
    905   JNIEnv* env = AttachCurrentThread();
    906   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
    907   if (obj.is_null())
    908     return;
    909   Java_AwContents_onWebLayoutContentsSizeChanged(
    910       env, obj.obj(), contents_size.width(), contents_size.height());
    911 }
    912 
    913 jint AwContents::CapturePicture(JNIEnv* env,
    914                                 jobject obj,
    915                                 int width,
    916                                 int height) {
    917   return reinterpret_cast<jint>(new AwPicture(
    918       browser_view_renderer_->CapturePicture(width, height)));
    919 }
    920 
    921 void AwContents::EnableOnNewPicture(JNIEnv* env,
    922                                     jobject obj,
    923                                     jboolean enabled) {
    924   browser_view_renderer_->EnableOnNewPicture(enabled);
    925 }
    926 
    927 void AwContents::SetJsOnlineProperty(JNIEnv* env,
    928                                      jobject obj,
    929                                      jboolean network_up) {
    930   render_view_host_ext_->SetJsOnlineProperty(network_up);
    931 }
    932 
    933 void AwContents::TrimMemory(JNIEnv* env, jobject obj, jint level) {
    934   browser_view_renderer_->TrimMemory(level);
    935 }
    936 
    937 void SetShouldDownloadFavicons(JNIEnv* env, jclass jclazz) {
    938   g_should_download_favicons = true;
    939 }
    940 
    941 }  // namespace android_webview
    942