• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CreateTargetContents(const chrome::NavigateParams & params,const GURL & url)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 
MaybeSwapWithPrerender(const GURL & url,chrome::NavigateParams * params)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 
FromWebContents(content::WebContents * web_contents)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 
GetNativeTab(JNIEnv * env,jobject obj)117 TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, jobject obj) {
118   return reinterpret_cast<TabAndroid*>(Java_Tab_getNativePtr(env, obj));
119 }
120 
AttachTabHelpers(content::WebContents * web_contents)121 void TabAndroid::AttachTabHelpers(content::WebContents* web_contents) {
122   DCHECK(web_contents);
123 
124   TabHelpers::AttachTabHelpers(web_contents);
125 }
126 
TabAndroid(JNIEnv * env,jobject obj)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 
~TabAndroid()133 TabAndroid::~TabAndroid() {
134   JNIEnv* env = base::android::AttachCurrentThread();
135   Java_Tab_clearNativePtr(env, weak_java_tab_.get(env).obj());
136 }
137 
GetJavaObject()138 base::android::ScopedJavaLocalRef<jobject> TabAndroid::GetJavaObject() {
139   JNIEnv* env = base::android::AttachCurrentThread();
140   return weak_java_tab_.get(env);
141 }
142 
GetAndroidId() const143 int TabAndroid::GetAndroidId() const {
144   JNIEnv* env = base::android::AttachCurrentThread();
145   return Java_Tab_getId(env, weak_java_tab_.get(env).obj());
146 }
147 
GetSyncId() const148 int TabAndroid::GetSyncId() const {
149   JNIEnv* env = base::android::AttachCurrentThread();
150   return Java_Tab_getSyncId(env, weak_java_tab_.get(env).obj());
151 }
152 
GetTitle() const153 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 
GetURL() const159 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 
LoadIfNeeded()165 bool TabAndroid::LoadIfNeeded() {
166   JNIEnv* env = base::android::AttachCurrentThread();
167   return Java_Tab_loadIfNeeded(env, weak_java_tab_.get(env).obj());
168 }
169 
GetContentViewCore() const170 content::ContentViewCore* TabAndroid::GetContentViewCore() const {
171   if (!web_contents())
172     return NULL;
173 
174   return content::ContentViewCore::FromWebContents(web_contents());
175 }
176 
GetProfile() const177 Profile* TabAndroid::GetProfile() const {
178   if (!web_contents())
179     return NULL;
180 
181   return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
182 }
183 
GetSyncedTabDelegate() const184 browser_sync::SyncedTabDelegate* TabAndroid::GetSyncedTabDelegate() const {
185   return synced_tab_delegate_.get();
186 }
187 
SetWindowSessionID(SessionID::id_type window_id)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 
SetSyncId(int sync_id)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 
HandlePopupNavigation(chrome::NavigateParams * params)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 
ShouldWelcomePageLinkToTermsOfService()238 bool TabAndroid::ShouldWelcomePageLinkToTermsOfService() {
239   NOTIMPLEMENTED();
240   return false;
241 }
242 
HasPrerenderedUrl(GURL gurl)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 
MakeLoadURLParams(chrome::NavigateParams * params,NavigationController::LoadURLParams * load_url_params)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 
SwapTabContents(content::WebContents * old_contents,content::WebContents * new_contents,bool did_start_load,bool did_finish_load)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 
DefaultSearchProviderChanged()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 
OnWebContentsInstantSupportDisabled(const content::WebContents * contents)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 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
Destroy(JNIEnv * env,jobject obj)388 void TabAndroid::Destroy(JNIEnv* env, jobject obj) {
389   delete this;
390 }
391 
InitWebContents(JNIEnv * env,jobject obj,jboolean incognito,jobject jcontent_view_core,jobject jweb_contents_delegate,jobject jcontext_menu_populator)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 
DestroyWebContents(JNIEnv * env,jobject obj,jboolean delete_native)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 
GetProfileAndroid(JNIEnv * env,jobject obj)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 
LoadUrl(JNIEnv * env,jobject obj,jstring url,jstring j_extra_headers,jbyteArray j_post_data,jint page_transition,jstring j_referrer_url,jint referrer_policy,jboolean is_renderer_initiated)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, &params))
532           return FULL_PRERENDERED_PAGE_LOAD;
533       }
534       prerenderer->Cancel();
535     }
536     if (prerender_manager->MaybeUsePrerenderedPage(gurl, &params)) {
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 
GetSecurityLevel(JNIEnv * env,jobject obj)604 ToolbarModel::SecurityLevel TabAndroid::GetSecurityLevel(JNIEnv* env,
605                                                          jobject obj) {
606   return ToolbarModelImpl::GetSecurityLevelForWebContents(web_contents());
607 }
608 
SetActiveNavigationEntryTitleForUrl(JNIEnv * env,jobject obj,jstring jurl,jstring jtitle)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 
Print(JNIEnv * env,jobject obj)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 
GetFavicon(JNIEnv * env,jobject obj)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 
IsFaviconValid(JNIEnv * env,jobject jobj)682 jboolean TabAndroid::IsFaviconValid(JNIEnv* env, jobject jobj) {
683   return web_contents() &&
684       FaviconTabHelper::FromWebContents(web_contents())->FaviconIsValid();
685 }
686 
GetPrerenderManager() const687 prerender::PrerenderManager* TabAndroid::GetPrerenderManager() const {
688   Profile* profile = GetProfile();
689   if (!profile)
690     return NULL;
691   return prerender::PrerenderManagerFactory::GetForProfile(profile);
692 }
693 
Init(JNIEnv * env,jobject obj)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 
RegisterTabAndroid(JNIEnv * env)700 bool TabAndroid::RegisterTabAndroid(JNIEnv* env) {
701   return RegisterNativesImpl(env);
702 }
703