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