1 // Copyright (c) 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 "chrome/browser/android/tab_android.h" 6 7 #include "base/android/jni_android.h" 8 #include "base/android/jni_array.h" 9 #include "base/android/jni_string.h" 10 #include "base/debug/trace_event.h" 11 #include "chrome/browser/android/chrome_web_contents_delegate_android.h" 12 #include "chrome/browser/browser_about_handler.h" 13 #include "chrome/browser/chrome_notification_types.h" 14 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 15 #include "chrome/browser/favicon/favicon_tab_helper.h" 16 #include "chrome/browser/google/google_url_tracker_factory.h" 17 #include "chrome/browser/infobars/infobar_service.h" 18 #include "chrome/browser/prerender/prerender_contents.h" 19 #include "chrome/browser/prerender/prerender_manager.h" 20 #include "chrome/browser/prerender/prerender_manager_factory.h" 21 #include "chrome/browser/printing/print_view_manager_basic.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/profiles/profile_android.h" 24 #include "chrome/browser/search/instant_service.h" 25 #include "chrome/browser/search/instant_service_factory.h" 26 #include "chrome/browser/search/search.h" 27 #include "chrome/browser/sessions/session_tab_helper.h" 28 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h" 29 #include "chrome/browser/tab_contents/tab_util.h" 30 #include "chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h" 31 #include "chrome/browser/ui/android/context_menu_helper.h" 32 #include "chrome/browser/ui/android/infobars/infobar_container_android.h" 33 #include "chrome/browser/ui/android/tab_model/tab_model.h" 34 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" 35 #include "chrome/browser/ui/android/window_android_helper.h" 36 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 37 #include "chrome/browser/ui/search/instant_search_prerenderer.h" 38 #include "chrome/browser/ui/search/search_tab_helper.h" 39 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 40 #include "chrome/browser/ui/tab_helpers.h" 41 #include "chrome/browser/ui/toolbar/toolbar_model_impl.h" 42 #include "chrome/common/url_constants.h" 43 #include "components/google/core/browser/google_url_tracker.h" 44 #include "components/google/core/browser/google_util.h" 45 #include "components/infobars/core/infobar_container.h" 46 #include "components/url_fixer/url_fixer.h" 47 #include "content/public/browser/android/content_view_core.h" 48 #include "content/public/browser/navigation_entry.h" 49 #include "content/public/browser/notification_service.h" 50 #include "content/public/browser/render_process_host.h" 51 #include "content/public/browser/user_metrics.h" 52 #include "content/public/browser/web_contents.h" 53 #include "jni/Tab_jni.h" 54 #include "skia/ext/image_operations.h" 55 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" 56 #include "ui/base/resource/resource_bundle.h" 57 #include "ui/base/window_open_disposition.h" 58 #include "ui/gfx/android/device_display_info.h" 59 #include "ui/gfx/android/java_bitmap.h" 60 #include "ui/gfx/favicon_size.h" 61 #include "ui/gfx/image/image_skia.h" 62 63 using content::GlobalRequestID; 64 using content::NavigationController; 65 using content::WebContents; 66 67 namespace { 68 69 WebContents* CreateTargetContents(const chrome::NavigateParams& params, 70 const GURL& url) { 71 Profile* profile = params.initiating_profile; 72 73 if (profile->IsOffTheRecord() || params.disposition == OFF_THE_RECORD) { 74 profile = profile->GetOffTheRecordProfile(); 75 } 76 WebContents::CreateParams create_params( 77 profile, tab_util::GetSiteInstanceForNewTab(profile, url)); 78 if (params.source_contents) { 79 create_params.initial_size = 80 params.source_contents->GetContainerBounds().size(); 81 if (params.should_set_opener) 82 create_params.opener = params.source_contents; 83 } 84 if (params.disposition == NEW_BACKGROUND_TAB) 85 create_params.initially_hidden = true; 86 87 WebContents* target_contents = WebContents::Create(create_params); 88 89 return target_contents; 90 } 91 92 bool MaybeSwapWithPrerender(const GURL& url, chrome::NavigateParams* params) { 93 Profile* profile = 94 Profile::FromBrowserContext(params->target_contents->GetBrowserContext()); 95 96 prerender::PrerenderManager* prerender_manager = 97 prerender::PrerenderManagerFactory::GetForProfile(profile); 98 if (!prerender_manager) 99 return false; 100 return prerender_manager->MaybeUsePrerenderedPage(url, params); 101 } 102 103 } // namespace 104 105 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) { 106 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); 107 if (!core_tab_helper) 108 return NULL; 109 110 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); 111 if (!core_delegate) 112 return NULL; 113 114 return static_cast<TabAndroid*>(core_delegate); 115 } 116 117 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) { 118 return reinterpret_cast<TabAndroid*>(Java_Tab_getNativePtr(env, obj)); 119 } 120 121 void TabAndroid::AttachTabHelpers(content::WebContents* web_contents) { 122 DCHECK(web_contents); 123 124 TabHelpers::AttachTabHelpers(web_contents); 125 } 126 127 TabAndroid::TabAndroid(JNIEnv* env, jobject obj) 128 : weak_java_tab_(env, obj), 129 synced_tab_delegate_(new browser_sync::SyncedTabDelegateAndroid(this)) { 130 Java_Tab_setNativePtr(env, obj, reinterpret_cast<intptr_t>(this)); 131 } 132 133 TabAndroid::~TabAndroid() { 134 JNIEnv* env = base::android::AttachCurrentThread(); 135 Java_Tab_clearNativePtr(env, weak_java_tab_.get(env).obj()); 136 } 137 138 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() { 139 JNIEnv* env = base::android::AttachCurrentThread(); 140 return weak_java_tab_.get(env); 141 } 142 143 int TabAndroid::GetAndroidId() const { 144 JNIEnv* env = base::android::AttachCurrentThread(); 145 return Java_Tab_getId(env, weak_java_tab_.get(env).obj()); 146 } 147 148 int TabAndroid::GetSyncId() const { 149 JNIEnv* env = base::android::AttachCurrentThread(); 150 return Java_Tab_getSyncId(env, weak_java_tab_.get(env).obj()); 151 } 152 153 base::string16 TabAndroid::GetTitle() const { 154 JNIEnv* env = base::android::AttachCurrentThread(); 155 return base::android::ConvertJavaStringToUTF16( 156 Java_Tab_getTitle(env, weak_java_tab_.get(env).obj())); 157 } 158 159 GURL TabAndroid::GetURL() const { 160 JNIEnv* env = base::android::AttachCurrentThread(); 161 return GURL(base::android::ConvertJavaStringToUTF8( 162 Java_Tab_getUrl(env, weak_java_tab_.get(env).obj()))); 163 } 164 165 bool TabAndroid::LoadIfNeeded() { 166 JNIEnv* env = base::android::AttachCurrentThread(); 167 return Java_Tab_loadIfNeeded(env, weak_java_tab_.get(env).obj()); 168 } 169 170 content::ContentViewCore* TabAndroid::GetContentViewCore() const { 171 if (!web_contents()) 172 return NULL; 173 174 return content::ContentViewCore::FromWebContents(web_contents()); 175 } 176 177 Profile* TabAndroid::GetProfile() const { 178 if (!web_contents()) 179 return NULL; 180 181 return Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 182 } 183 184 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const { 185 return synced_tab_delegate_.get(); 186 } 187 188 void TabAndroid::SetWindowSessionID(SessionID::id_type window_id) { 189 session_window_id_.set_id(window_id); 190 191 if (!web_contents()) 192 return; 193 194 SessionTabHelper* session_tab_helper = 195 SessionTabHelper::FromWebContents(web_contents()); 196 session_tab_helper->SetWindowID(session_window_id_); 197 } 198 199 void TabAndroid::SetSyncId(int sync_id) { 200 JNIEnv* env = base::android::AttachCurrentThread(); 201 Java_Tab_setSyncId(env, weak_java_tab_.get(env).obj(), sync_id); 202 } 203 204 void TabAndroid::HandlePopupNavigation(chrome::NavigateParams* params) { 205 if (params->disposition != SUPPRESS_OPEN && 206 params->disposition != SAVE_TO_DISK && 207 params->disposition != IGNORE_ACTION) { 208 if (!params->url.is_empty()) { 209 bool was_blocked = false; 210 GURL url(params->url); 211 if (params->disposition == CURRENT_TAB) { 212 params->target_contents = web_contents_.get(); 213 if (!MaybeSwapWithPrerender(url, params)) { 214 NavigationController::LoadURLParams load_url_params(url); 215 MakeLoadURLParams(params, &load_url_params); 216 params->target_contents->GetController().LoadURLWithParams( 217 load_url_params); 218 } 219 } else { 220 params->target_contents = CreateTargetContents(*params, url); 221 NavigationController::LoadURLParams load_url_params(url); 222 MakeLoadURLParams(params, &load_url_params); 223 params->target_contents->GetController().LoadURLWithParams( 224 load_url_params); 225 web_contents_delegate_->AddNewContents(params->source_contents, 226 params->target_contents, 227 params->disposition, 228 params->window_bounds, 229 params->user_gesture, 230 &was_blocked); 231 if (was_blocked) 232 params->target_contents = NULL; 233 } 234 } 235 } 236 } 237 238 bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() { 239 NOTIMPLEMENTED(); 240 return false; 241 } 242 243 bool TabAndroid::HasPrerenderedUrl(GURL gurl) { 244 prerender::PrerenderManager* prerender_manager = GetPrerenderManager(); 245 if (!prerender_manager) 246 return false; 247 248 std::vector<content::WebContents*> contents = 249 prerender_manager->GetAllPrerenderingContents(); 250 prerender::PrerenderContents* prerender_contents; 251 for (size_t i = 0; i < contents.size(); ++i) { 252 prerender_contents = prerender_manager-> 253 GetPrerenderContents(contents.at(i)); 254 if (prerender_contents->prerender_url() == gurl && 255 prerender_contents->has_finished_loading()) { 256 return true; 257 } 258 } 259 return false; 260 } 261 262 void TabAndroid::MakeLoadURLParams( 263 chrome::NavigateParams* params, 264 NavigationController::LoadURLParams* load_url_params) { 265 load_url_params->referrer = params->referrer; 266 load_url_params->frame_tree_node_id = params->frame_tree_node_id; 267 load_url_params->redirect_chain = params->redirect_chain; 268 load_url_params->transition_type = params->transition; 269 load_url_params->extra_headers = params->extra_headers; 270 load_url_params->should_replace_current_entry = 271 params->should_replace_current_entry; 272 273 if (params->transferred_global_request_id != GlobalRequestID()) { 274 load_url_params->transferred_global_request_id = 275 params->transferred_global_request_id; 276 } 277 load_url_params->is_renderer_initiated = params->is_renderer_initiated; 278 279 // Only allows the browser-initiated navigation to use POST. 280 if (params->uses_post && !params->is_renderer_initiated) { 281 load_url_params->load_type = 282 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; 283 load_url_params->browser_initiated_post_data = 284 params->browser_initiated_post_data; 285 } 286 } 287 288 void TabAndroid::SwapTabContents(content::WebContents* old_contents, 289 content::WebContents* new_contents, 290 bool did_start_load, 291 bool did_finish_load) { 292 JNIEnv* env = base::android::AttachCurrentThread(); 293 294 // We need to notify the native InfobarContainer so infobars can be swapped. 295 InfoBarContainerAndroid* infobar_container = 296 reinterpret_cast<InfoBarContainerAndroid*>( 297 Java_Tab_getNativeInfoBarContainer( 298 env, 299 weak_java_tab_.get(env).obj())); 300 InfoBarService* new_infobar_service = 301 new_contents ? InfoBarService::FromWebContents(new_contents) : NULL; 302 infobar_container->ChangeInfoBarManager(new_infobar_service); 303 304 Java_Tab_swapWebContents( 305 env, 306 weak_java_tab_.get(env).obj(), 307 reinterpret_cast<intptr_t>(new_contents), 308 did_start_load, 309 did_finish_load); 310 } 311 312 void TabAndroid::DefaultSearchProviderChanged() { 313 // TODO(kmadhusu): Move this function definition to a common place and update 314 // BrowserInstantController::DefaultSearchProviderChanged to use the same. 315 if (!web_contents()) 316 return; 317 318 InstantService* instant_service = 319 InstantServiceFactory::GetForProfile(GetProfile()); 320 if (!instant_service) 321 return; 322 323 // Send new search URLs to the renderer. 324 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost(); 325 instant_service->SendSearchURLsToRenderer(rph); 326 327 // Reload the contents to ensure that it gets assigned to a non-previledged 328 // renderer. 329 if (!instant_service->IsInstantProcess(rph->GetID())) 330 return; 331 web_contents()->GetController().Reload(false); 332 333 // As the reload was not triggered by the user we don't want to close any 334 // infobars. We have to tell the InfoBarService after the reload, otherwise it 335 // would ignore this call when 336 // WebContentsObserver::DidStartNavigationToPendingEntry is invoked. 337 InfoBarService::FromWebContents(web_contents())->set_ignore_next_reload(); 338 } 339 340 void TabAndroid::OnWebContentsInstantSupportDisabled( 341 const content::WebContents* contents) { 342 DCHECK(contents); 343 if (web_contents() != contents) 344 return; 345 346 JNIEnv* env = base::android::AttachCurrentThread(); 347 Java_Tab_onWebContentsInstantSupportDisabled(env, 348 weak_java_tab_.get(env).obj()); 349 } 350 351 void TabAndroid::Observe(int type, 352 const content::NotificationSource& source, 353 const content::NotificationDetails& details) { 354 JNIEnv* env = base::android::AttachCurrentThread(); 355 switch (type) { 356 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: { 357 TabSpecificContentSettings* settings = 358 TabSpecificContentSettings::FromWebContents(web_contents()); 359 if (!settings->IsBlockageIndicated(CONTENT_SETTINGS_TYPE_POPUPS)) { 360 // TODO(dfalcantara): Create an InfoBarDelegate to keep the 361 // PopupBlockedInfoBar logic native-side instead of straddling the JNI 362 // boundary. 363 int num_popups = 0; 364 PopupBlockerTabHelper* popup_blocker_helper = 365 PopupBlockerTabHelper::FromWebContents(web_contents()); 366 if (popup_blocker_helper) 367 num_popups = popup_blocker_helper->GetBlockedPopupsCount(); 368 369 if (num_popups > 0) 370 PopupBlockedInfoBarDelegate::Create(web_contents(), num_popups); 371 372 settings->SetBlockageHasBeenIndicated(CONTENT_SETTINGS_TYPE_POPUPS); 373 } 374 break; 375 } 376 case chrome::NOTIFICATION_FAVICON_UPDATED: 377 Java_Tab_onFaviconUpdated(env, weak_java_tab_.get(env).obj()); 378 break; 379 case content::NOTIFICATION_NAV_ENTRY_CHANGED: 380 Java_Tab_onNavEntryChanged(env, weak_java_tab_.get(env).obj()); 381 break; 382 default: 383 NOTREACHED() << "Unexpected notification " << type; 384 break; 385 } 386 } 387 388 void TabAndroid::Destroy(JNIEnv* env, jobject obj) { 389 delete this; 390 } 391 392 void TabAndroid::InitWebContents(JNIEnv* env, 393 jobject obj, 394 jboolean incognito, 395 jobject jcontent_view_core, 396 jobject jweb_contents_delegate, 397 jobject jcontext_menu_populator) { 398 content::ContentViewCore* content_view_core = 399 content::ContentViewCore::GetNativeContentViewCore(env, 400 jcontent_view_core); 401 DCHECK(content_view_core); 402 DCHECK(content_view_core->GetWebContents()); 403 404 web_contents_.reset(content_view_core->GetWebContents()); 405 AttachTabHelpers(web_contents_.get()); 406 407 SetWindowSessionID(session_window_id_.id()); 408 409 session_tab_id_.set_id( 410 SessionTabHelper::FromWebContents(web_contents())->session_id().id()); 411 ContextMenuHelper::FromWebContents(web_contents())->SetPopulator( 412 jcontext_menu_populator); 413 WindowAndroidHelper::FromWebContents(web_contents())-> 414 SetWindowAndroid(content_view_core->GetWindowAndroid()); 415 CoreTabHelper::FromWebContents(web_contents())->set_delegate(this); 416 SearchTabHelper::FromWebContents(web_contents())->set_delegate(this); 417 web_contents_delegate_.reset( 418 new chrome::android::ChromeWebContentsDelegateAndroid( 419 env, jweb_contents_delegate)); 420 web_contents_delegate_->LoadProgressChanged(web_contents(), 0); 421 web_contents()->SetDelegate(web_contents_delegate_.get()); 422 423 notification_registrar_.Add( 424 this, 425 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 426 content::Source<content::WebContents>(web_contents())); 427 notification_registrar_.Add( 428 this, 429 chrome::NOTIFICATION_FAVICON_UPDATED, 430 content::Source<content::WebContents>(web_contents())); 431 notification_registrar_.Add( 432 this, 433 content::NOTIFICATION_NAV_ENTRY_CHANGED, 434 content::Source<content::NavigationController>( 435 &web_contents()->GetController())); 436 437 synced_tab_delegate_->SetWebContents(web_contents()); 438 439 // Verify that the WebContents this tab represents matches the expected 440 // off the record state. 441 CHECK_EQ(GetProfile()->IsOffTheRecord(), incognito); 442 443 InstantService* instant_service = 444 InstantServiceFactory::GetForProfile(GetProfile()); 445 if (instant_service) 446 instant_service->AddObserver(this); 447 } 448 449 void TabAndroid::DestroyWebContents(JNIEnv* env, 450 jobject obj, 451 jboolean delete_native) { 452 DCHECK(web_contents()); 453 454 notification_registrar_.Remove( 455 this, 456 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 457 content::Source<content::WebContents>(web_contents())); 458 notification_registrar_.Remove( 459 this, 460 chrome::NOTIFICATION_FAVICON_UPDATED, 461 content::Source<content::WebContents>(web_contents())); 462 notification_registrar_.Remove( 463 this, 464 content::NOTIFICATION_NAV_ENTRY_CHANGED, 465 content::Source<content::NavigationController>( 466 &web_contents()->GetController())); 467 468 InstantService* instant_service = 469 InstantServiceFactory::GetForProfile(GetProfile()); 470 if (instant_service) 471 instant_service->RemoveObserver(this); 472 473 web_contents()->SetDelegate(NULL); 474 475 if (delete_native) { 476 web_contents_.reset(); 477 synced_tab_delegate_->ResetWebContents(); 478 } else { 479 // Release the WebContents so it does not get deleted by the scoped_ptr. 480 ignore_result(web_contents_.release()); 481 } 482 } 483 484 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetProfileAndroid( 485 JNIEnv* env, 486 jobject obj) { 487 Profile* profile = GetProfile(); 488 if (!profile) 489 return base::android::ScopedJavaLocalRef<jobject>(); 490 ProfileAndroid* profile_android = ProfileAndroid::FromProfile(profile); 491 if (!profile_android) 492 return base::android::ScopedJavaLocalRef<jobject>(); 493 494 return profile_android->GetJavaObject(); 495 } 496 497 TabAndroid::TabLoadStatus TabAndroid::LoadUrl(JNIEnv* env, 498 jobject obj, 499 jstring url, 500 jstring j_extra_headers, 501 jbyteArray j_post_data, 502 jint page_transition, 503 jstring j_referrer_url, 504 jint referrer_policy, 505 jboolean is_renderer_initiated) { 506 if (!web_contents()) 507 return PAGE_LOAD_FAILED; 508 509 GURL gurl(base::android::ConvertJavaStringToUTF8(env, url)); 510 if (gurl.is_empty()) 511 return PAGE_LOAD_FAILED; 512 513 // If the page was prerendered, use it. 514 // Note in incognito mode, we don't have a PrerenderManager. 515 516 prerender::PrerenderManager* prerender_manager = 517 prerender::PrerenderManagerFactory::GetForProfile(GetProfile()); 518 if (prerender_manager) { 519 bool prefetched_page_loaded = HasPrerenderedUrl(gurl); 520 // Getting the load status before MaybeUsePrerenderedPage() b/c it resets. 521 chrome::NavigateParams params(NULL, web_contents()); 522 InstantSearchPrerenderer* prerenderer = 523 InstantSearchPrerenderer::GetForProfile(GetProfile()); 524 if (prerenderer) { 525 const base::string16& search_terms = 526 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl); 527 if (!search_terms.empty() && 528 prerenderer->CanCommitQuery(web_contents_.get(), search_terms)) { 529 prerenderer->Commit(search_terms); 530 531 if (prerenderer->UsePrerenderedPage(gurl, ¶ms)) 532 return FULL_PRERENDERED_PAGE_LOAD; 533 } 534 prerenderer->Cancel(); 535 } 536 if (prerender_manager->MaybeUsePrerenderedPage(gurl, ¶ms)) { 537 return prefetched_page_loaded ? 538 FULL_PRERENDERED_PAGE_LOAD : PARTIAL_PRERENDERED_PAGE_LOAD; 539 } 540 } 541 542 GURL fixed_url( 543 url_fixer::FixupURL(gurl.possibly_invalid_spec(), std::string())); 544 if (!fixed_url.is_valid()) 545 return PAGE_LOAD_FAILED; 546 547 if (!HandleNonNavigationAboutURL(fixed_url)) { 548 // Notify the GoogleURLTracker of searches, it might want to change the 549 // actual Google site used (for instance when in the UK, google.co.uk, when 550 // in the US google.com). 551 // Note that this needs to happen before we initiate the navigation as the 552 // GoogleURLTracker uses the navigation pending notification to trigger the 553 // infobar. 554 if (google_util::IsGoogleSearchUrl(fixed_url) && 555 (page_transition & ui::PAGE_TRANSITION_GENERATED)) { 556 GoogleURLTracker* tracker = 557 GoogleURLTrackerFactory::GetForProfile(GetProfile()); 558 if (tracker) 559 tracker->SearchCommitted(); 560 } 561 562 // Record UMA "ShowHistory" here. That way it'll pick up both user 563 // typing chrome://history as well as selecting from the drop down menu. 564 if (fixed_url.spec() == chrome::kChromeUIHistoryURL) { 565 content::RecordAction(base::UserMetricsAction("ShowHistory")); 566 } 567 568 content::NavigationController::LoadURLParams load_params(fixed_url); 569 if (j_extra_headers) { 570 load_params.extra_headers = base::android::ConvertJavaStringToUTF8( 571 env, 572 j_extra_headers); 573 } 574 if (j_post_data) { 575 load_params.load_type = 576 content::NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; 577 std::vector<uint8> post_data; 578 base::android::JavaByteArrayToByteVector(env, j_post_data, &post_data); 579 load_params.browser_initiated_post_data = 580 base::RefCountedBytes::TakeVector(&post_data); 581 } 582 load_params.transition_type = 583 ui::PageTransitionFromInt(page_transition); 584 if (j_referrer_url) { 585 load_params.referrer = content::Referrer( 586 GURL(base::android::ConvertJavaStringToUTF8(env, j_referrer_url)), 587 static_cast<blink::WebReferrerPolicy>(referrer_policy)); 588 } 589 const base::string16 search_terms = 590 chrome::ExtractSearchTermsFromURL(GetProfile(), gurl); 591 SearchTabHelper* search_tab_helper = 592 SearchTabHelper::FromWebContents(web_contents_.get()); 593 if (!search_terms.empty() && search_tab_helper && 594 search_tab_helper->SupportsInstant()) { 595 search_tab_helper->Submit(search_terms); 596 return DEFAULT_PAGE_LOAD; 597 } 598 load_params.is_renderer_initiated = is_renderer_initiated; 599 web_contents()->GetController().LoadURLWithParams(load_params); 600 } 601 return DEFAULT_PAGE_LOAD; 602 } 603 604 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env, 605 jobject obj) { 606 return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents()); 607 } 608 609 void TabAndroid::SetActiveNavigationEntryTitleForUrl(JNIEnv* env, 610 jobject obj, 611 jstring jurl, 612 jstring jtitle) { 613 DCHECK(web_contents()); 614 615 base::string16 title; 616 if (jtitle) 617 title = base::android::ConvertJavaStringToUTF16(env, jtitle); 618 619 std::string url; 620 if (jurl) 621 url = base::android::ConvertJavaStringToUTF8(env, jurl); 622 623 content::NavigationEntry* entry = 624 web_contents()->GetController().GetVisibleEntry(); 625 if (entry && url == entry->GetVirtualURL().spec()) 626 entry->SetTitle(title); 627 } 628 629 bool TabAndroid::Print(JNIEnv* env, jobject obj) { 630 if (!web_contents()) 631 return false; 632 633 printing::PrintViewManagerBasic::CreateForWebContents(web_contents()); 634 printing::PrintViewManagerBasic* print_view_manager = 635 printing::PrintViewManagerBasic::FromWebContents(web_contents()); 636 if (print_view_manager == NULL) 637 return false; 638 639 print_view_manager->PrintNow(); 640 return true; 641 } 642 643 ScopedJavaLocalRef<jobject> TabAndroid::GetFavicon(JNIEnv* env, jobject obj) { 644 ScopedJavaLocalRef<jobject> bitmap; 645 FaviconTabHelper* favicon_tab_helper = 646 FaviconTabHelper::FromWebContents(web_contents_.get()); 647 648 if (!favicon_tab_helper) 649 return bitmap; 650 651 // If the favicon isn't valid, it will return a default bitmap. 652 653 SkBitmap favicon = 654 favicon_tab_helper->GetFavicon() 655 .AsImageSkia() 656 .GetRepresentation( 657 ResourceBundle::GetSharedInstance().GetMaxScaleFactor()) 658 .sk_bitmap(); 659 660 if (favicon.empty()) { 661 favicon = favicon_tab_helper->GetFavicon().AsBitmap(); 662 } 663 664 if (!favicon.empty()) { 665 gfx::DeviceDisplayInfo device_info; 666 const float device_scale_factor = device_info.GetDIPScale(); 667 int target_size_dip = device_scale_factor * gfx::kFaviconSize; 668 if (favicon.width() != target_size_dip || 669 favicon.height() != target_size_dip) { 670 favicon = 671 skia::ImageOperations::Resize(favicon, 672 skia::ImageOperations::RESIZE_BEST, 673 target_size_dip, 674 target_size_dip); 675 } 676 677 bitmap = gfx::ConvertToJavaBitmap(&favicon); 678 } 679 return bitmap; 680 } 681 682 jboolean TabAndroid::IsFaviconValid(JNIEnv* env, jobject jobj) { 683 return web_contents() && 684 FaviconTabHelper::FromWebContents(web_contents())->FaviconIsValid(); 685 } 686 687 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const { 688 Profile* profile = GetProfile(); 689 if (!profile) 690 return NULL; 691 return prerender::PrerenderManagerFactory::GetForProfile(profile); 692 } 693 694 static void Init(JNIEnv* env, jobject obj) { 695 TRACE_EVENT0("native", "TabAndroid::Init"); 696 // This will automatically bind to the Java object and pass ownership there. 697 new TabAndroid(env, obj); 698 } 699 700 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) { 701 return RegisterNativesImpl(env); 702 } 703