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 AwContentsIoThreadClientImpl::RegisterPendingContents(web_contents_.get()); 195 196 AwAutofillManagerDelegate* autofill_manager_delegate = 197 AwAutofillManagerDelegate::FromWebContents(web_contents_.get()); 198 if (autofill_manager_delegate) 199 InitAutofillIfNecessary(autofill_manager_delegate->GetSaveFormData()); 200 201 SetAndroidWebViewRendererPrefs(); 202 } 203 204 void AwContents::SetJavaPeers(JNIEnv* env, 205 jobject obj, 206 jobject aw_contents, 207 jobject web_contents_delegate, 208 jobject contents_client_bridge, 209 jobject io_thread_client, 210 jobject intercept_navigation_delegate) { 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 212 // The |aw_content| param is technically spurious as it duplicates |obj| but 213 // is passed over anyway to make the binding more explicit. 214 java_ref_ = JavaObjectWeakGlobalRef(env, aw_contents); 215 216 web_contents_delegate_.reset( 217 new AwWebContentsDelegate(env, web_contents_delegate)); 218 web_contents_->SetDelegate(web_contents_delegate_.get()); 219 220 contents_client_bridge_.reset( 221 new AwContentsClientBridge(env, contents_client_bridge)); 222 AwContentsClientBridgeBase::Associate(web_contents_.get(), 223 contents_client_bridge_.get()); 224 225 AwContentsIoThreadClientImpl::Associate( 226 web_contents_.get(), ScopedJavaLocalRef<jobject>(env, io_thread_client)); 227 int child_id = web_contents_->GetRenderProcessHost()->GetID(); 228 int route_id = web_contents_->GetRoutingID(); 229 AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id); 230 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 232 InterceptNavigationDelegate::Associate( 233 web_contents_.get(), 234 make_scoped_ptr(new InterceptNavigationDelegate( 235 env, intercept_navigation_delegate))); 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