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