1 // Copyright 2019 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 "weblayer/browser/tab_impl.h"
6 
7 #include <cmath>
8 
9 #include "base/auto_reset.h"
10 #include "base/guid.h"
11 #include "base/logging.h"
12 #include "base/no_destructor.h"
13 #include "base/task/thread_pool.h"
14 #include "base/time/default_tick_clock.h"
15 #include "cc/layers/layer.h"
16 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
17 #include "components/autofill/core/browser/autofill_manager.h"
18 #include "components/autofill/core/browser/autofill_provider.h"
19 #include "components/blocked_content/popup_blocker.h"
20 #include "components/blocked_content/popup_blocker_tab_helper.h"
21 #include "components/blocked_content/popup_opener_tab_helper.h"
22 #include "components/blocked_content/popup_tracker.h"
23 #include "components/captive_portal/core/buildflags.h"
24 #include "components/content_settings/browser/page_specific_content_settings.h"
25 #include "components/embedder_support/android/util/user_agent_utils.h"
26 #include "components/find_in_page/find_tab_helper.h"
27 #include "components/find_in_page/find_types.h"
28 #include "components/js_injection/browser/js_communication_host.h"
29 #include "components/js_injection/browser/web_message_host.h"
30 #include "components/js_injection/browser/web_message_host_factory.h"
31 #include "components/permissions/permission_manager.h"
32 #include "components/permissions/permission_request_manager.h"
33 #include "components/permissions/permission_result.h"
34 #include "components/prefs/pref_service.h"
35 #include "components/sessions/content/session_tab_helper.h"
36 #include "components/translate/core/browser/translate_manager.h"
37 #include "components/ukm/content/source_url_recorder.h"
38 #include "components/webrtc/media_stream_devices_controller.h"
39 #include "content/public/browser/browser_task_traits.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/context_menu_params.h"
42 #include "content/public/browser/file_select_listener.h"
43 #include "content/public/browser/navigation_controller.h"
44 #include "content/public/browser/navigation_entry.h"
45 #include "content/public/browser/navigation_handle.h"
46 #include "content/public/browser/render_frame_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/render_widget_host_view.h"
49 #include "content/public/browser/renderer_preferences_util.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/browser/web_contents_observer.h"
52 #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
53 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
54 #include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
55 #include "ui/base/window_open_disposition.h"
56 #include "weblayer/browser/autofill_client_impl.h"
57 #include "weblayer/browser/browser_context_impl.h"
58 #include "weblayer/browser/browser_impl.h"
59 #include "weblayer/browser/browser_process.h"
60 #include "weblayer/browser/content_browser_client_impl.h"
61 #include "weblayer/browser/favicon/favicon_fetcher_impl.h"
62 #include "weblayer/browser/favicon/favicon_tab_helper.h"
63 #include "weblayer/browser/file_select_helper.h"
64 #include "weblayer/browser/host_content_settings_map_factory.h"
65 #include "weblayer/browser/i18n_util.h"
66 #include "weblayer/browser/infobar_service.h"
67 #include "weblayer/browser/js_communication/web_message_host_factory_wrapper.h"
68 #include "weblayer/browser/navigation_controller_impl.h"
69 #include "weblayer/browser/navigation_entry_data.h"
70 #include "weblayer/browser/no_state_prefetch/prerender_tab_helper.h"
71 #include "weblayer/browser/page_load_metrics_initialize.h"
72 #include "weblayer/browser/page_specific_content_settings_delegate.h"
73 #include "weblayer/browser/password_manager_driver_factory.h"
74 #include "weblayer/browser/permissions/permission_manager_factory.h"
75 #include "weblayer/browser/persistence/browser_persister.h"
76 #include "weblayer/browser/popup_navigation_delegate_impl.h"
77 #include "weblayer/browser/profile_impl.h"
78 #include "weblayer/browser/translate_client_impl.h"
79 #include "weblayer/browser/user_agent.h"
80 #include "weblayer/browser/weblayer_features.h"
81 #include "weblayer/common/isolated_world_ids.h"
82 #include "weblayer/public/fullscreen_delegate.h"
83 #include "weblayer/public/js_communication/web_message.h"
84 #include "weblayer/public/js_communication/web_message_host_factory.h"
85 #include "weblayer/public/new_tab_delegate.h"
86 #include "weblayer/public/tab_observer.h"
87 
88 #if !defined(OS_ANDROID)
89 #include "ui/views/controls/webview/webview.h"
90 #endif
91 
92 #if defined(OS_ANDROID)
93 #include "base/android/callback_android.h"
94 #include "base/android/jni_array.h"
95 #include "base/android/jni_string.h"
96 #include "base/json/json_writer.h"
97 #include "base/trace_event/trace_event.h"
98 #include "components/autofill/android/provider/autofill_provider_android.h"
99 #include "components/browser_ui/sms/android/sms_infobar.h"
100 #include "components/download/content/public/context_menu_download.h"
101 #include "components/embedder_support/android/contextmenu/context_menu_builder.h"
102 #include "components/embedder_support/android/delegate/color_chooser_android.h"
103 #include "components/javascript_dialogs/tab_modal_dialog_manager.h"  // nogncheck
104 #include "components/translate/core/browser/translate_manager.h"
105 #include "ui/android/view_android.h"
106 #include "ui/gfx/android/java_bitmap.h"
107 #include "weblayer/browser/browser_controls_container_view.h"
108 #include "weblayer/browser/browser_controls_navigation_state_handler.h"
109 #include "weblayer/browser/controls_visibility_reason.h"
110 #include "weblayer/browser/java/jni/TabImpl_jni.h"
111 #include "weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h"
112 #include "weblayer/browser/js_communication/web_message_host_factory_proxy.h"
113 #include "weblayer/browser/translate_client_impl.h"
114 #include "weblayer/browser/url_bar/trusted_cdn_observer.h"
115 #include "weblayer/browser/weblayer_factory_impl_android.h"
116 #include "weblayer/browser/webrtc/media_stream_manager.h"
117 #endif
118 
119 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
120 #include "components/captive_portal/content/captive_portal_tab_helper.h"
121 #include "weblayer/browser/captive_portal_service_factory.h"
122 #endif
123 
124 #if defined(OS_ANDROID)
125 using base::android::AttachCurrentThread;
126 using base::android::JavaParamRef;
127 using base::android::ScopedJavaGlobalRef;
128 using base::android::ScopedJavaLocalRef;
129 #endif
130 
131 namespace weblayer {
132 
133 namespace {
134 
135 // Maximum size of data when calling SetData().
136 constexpr int kMaxDataSize = 4096;
137 
138 #if defined(OS_ANDROID)
139 bool g_system_autofill_disabled_for_testing = false;
140 
141 #endif
142 
NewTabTypeFromWindowDisposition(WindowOpenDisposition disposition)143 NewTabType NewTabTypeFromWindowDisposition(WindowOpenDisposition disposition) {
144   // WindowOpenDisposition has a *ton* of types, but the following are really
145   // the only ones that should be hit for this code path.
146   switch (disposition) {
147     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
148       return NewTabType::kForeground;
149     case WindowOpenDisposition::NEW_BACKGROUND_TAB:
150       return NewTabType::kBackground;
151     case WindowOpenDisposition::NEW_POPUP:
152       return NewTabType::kNewPopup;
153     case WindowOpenDisposition::NEW_WINDOW:
154       return NewTabType::kNewWindow;
155     default:
156       // The set of allowed types are in
157       // ContentTabClientImpl::CanCreateWindow().
158       NOTREACHED();
159       return NewTabType::kForeground;
160   }
161 }
162 
163 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
164 // Opens a captive portal login page in |web_contents|.
OpenCaptivePortalLoginTabInWebContents(content::WebContents * web_contents)165 void OpenCaptivePortalLoginTabInWebContents(
166     content::WebContents* web_contents) {
167   content::OpenURLParams params(
168       CaptivePortalServiceFactory::GetForBrowserContext(
169           web_contents->GetBrowserContext())
170           ->test_url(),
171       content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
172       ui::PAGE_TRANSITION_LINK, false);
173   web_contents->OpenURL(params);
174 }
175 #endif
176 
177 // Pointer value of this is used as a key in base::SupportsUserData for
178 // WebContents. Value of the key is an instance of |UserData|.
179 constexpr int kWebContentsUserDataKey = 0;
180 
181 struct UserData : public base::SupportsUserData::Data {
182   TabImpl* tab = nullptr;
183 };
184 
185 #if defined(OS_ANDROID)
HandleJavaScriptResult(const ScopedJavaGlobalRef<jobject> & callback,base::Value result)186 void HandleJavaScriptResult(const ScopedJavaGlobalRef<jobject>& callback,
187                             base::Value result) {
188   std::string json;
189   base::JSONWriter::Write(result, &json);
190   base::android::RunStringCallbackAndroid(callback, json);
191 }
192 
OnConvertedToJavaBitmap(const ScopedJavaGlobalRef<jobject> & value_callback,const ScopedJavaGlobalRef<jobject> & java_bitmap)193 void OnConvertedToJavaBitmap(const ScopedJavaGlobalRef<jobject>& value_callback,
194                              const ScopedJavaGlobalRef<jobject>& java_bitmap) {
195   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
196   TabImpl::ScreenShotErrors error =
197       java_bitmap ? TabImpl::ScreenShotErrors::kNone
198                   : TabImpl::ScreenShotErrors::kBitmapAllocationFailed;
199   Java_TabImpl_runCaptureScreenShotCallback(AttachCurrentThread(),
200                                             value_callback, java_bitmap,
201                                             static_cast<int>(error));
202 }
203 
204 // Convert SkBitmap to java Bitmap on a background thread since it involves a
205 // memcpy.
ConvertToJavaBitmapBackgroundThread(const SkBitmap & bitmap,base::OnceCallback<void (const ScopedJavaGlobalRef<jobject> &)> callback)206 void ConvertToJavaBitmapBackgroundThread(
207     const SkBitmap& bitmap,
208     base::OnceCallback<void(const ScopedJavaGlobalRef<jobject>&)> callback) {
209   // Make sure to only pass ScopedJavaGlobalRef between threads.
210   ScopedJavaGlobalRef<jobject> java_bitmap = ScopedJavaGlobalRef<jobject>(
211       gfx::ConvertToJavaBitmap(bitmap, gfx::OomBehavior::kReturnNullOnOom));
212   content::GetUIThreadTaskRunner({})->PostTask(
213       FROM_HERE, base::BindOnce(std::move(callback), std::move(java_bitmap)));
214 }
215 
OnScreenShotCaptured(const ScopedJavaGlobalRef<jobject> & value_callback,const SkBitmap & bitmap)216 void OnScreenShotCaptured(const ScopedJavaGlobalRef<jobject>& value_callback,
217                           const SkBitmap& bitmap) {
218   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219   if (bitmap.isNull() || bitmap.drawsNothing()) {
220     Java_TabImpl_runCaptureScreenShotCallback(
221         AttachCurrentThread(), value_callback, nullptr,
222         static_cast<int>(TabImpl::ScreenShotErrors::kCaptureFailed));
223     return;
224   }
225   // Not using PostTaskAndReplyWithResult to ensure ScopedJavaLocalRef is not
226   // passed between threads.
227   base::ThreadPool::PostTask(
228       FROM_HERE,
229       {base::TaskPriority::BEST_EFFORT,
230        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
231       base::BindOnce(&ConvertToJavaBitmapBackgroundThread, bitmap,
232                      base::BindOnce(&OnConvertedToJavaBitmap, value_callback)));
233 }
234 
235 #endif  // OS_ANDROID
236 
GetTabs()237 std::set<TabImpl*>& GetTabs() {
238   static base::NoDestructor<std::set<TabImpl*>> s_all_tab_impl;
239   return *s_all_tab_impl;
240 }
241 
242 // Simulates a WeakPtr for WebContents. Specifically if the WebContents
243 // supplied to the constructor is destroyed then web_contents() returns
244 // null.
245 class WebContentsTracker : public content::WebContentsObserver {
246  public:
WebContentsTracker(content::WebContents * web_contents)247   explicit WebContentsTracker(content::WebContents* web_contents)
248       : content::WebContentsObserver(web_contents) {}
249 };
250 
251 }  // namespace
252 
253 #if defined(OS_ANDROID)
254 
JNI_TabImpl_FromWebContents(JNIEnv * env,const base::android::JavaParamRef<jobject> & j_web_contents)255 static ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents(
256     JNIEnv* env,
257     const base::android::JavaParamRef<jobject>& j_web_contents) {
258   content::WebContents* web_contents =
259       content::WebContents::FromJavaWebContents(j_web_contents);
260   TabImpl* tab = TabImpl::FromWebContents(web_contents);
261   if (tab)
262     return ScopedJavaLocalRef<jobject>(tab->GetJavaTab());
263   return nullptr;
264 }
265 
JNI_TabImpl_DestroyContextMenuParams(JNIEnv * env,jlong native_context_menu_params)266 static void JNI_TabImpl_DestroyContextMenuParams(
267     JNIEnv* env,
268     jlong native_context_menu_params) {
269   // Note: this runs on the finalizer thread which isn't the UI thread.
270   auto* context_menu_params =
271       reinterpret_cast<content::ContextMenuParams*>(native_context_menu_params);
272   delete context_menu_params;
273 }
274 
TabImpl(ProfileImpl * profile,const JavaParamRef<jobject> & java_impl,std::unique_ptr<content::WebContents> web_contents)275 TabImpl::TabImpl(ProfileImpl* profile,
276                  const JavaParamRef<jobject>& java_impl,
277                  std::unique_ptr<content::WebContents> web_contents)
278     : TabImpl(profile, std::move(web_contents)) {
279   java_impl_ = java_impl;
280 }
281 #endif
282 
TabImpl(ProfileImpl * profile,std::unique_ptr<content::WebContents> web_contents,const std::string & guid)283 TabImpl::TabImpl(ProfileImpl* profile,
284                  std::unique_ptr<content::WebContents> web_contents,
285                  const std::string& guid)
286     : profile_(profile),
287       web_contents_(std::move(web_contents)),
288       guid_(guid.empty() ? base::GenerateGUID() : guid) {
289   GetTabs().insert(this);
290   DCHECK(web_contents_);
291   // This code path is hit when the page requests a new tab, which should
292   // only be possible from the same profile.
293   DCHECK_EQ(profile_->GetBrowserContext(), web_contents_->GetBrowserContext());
294 
295   // FaviconTabHelper adds a WebContentsObserver. Create FaviconTabHelper
296   // before |this| observes the WebContents to ensure favicons are reset before
297   // notifying weblayer observers of changes.
298   FaviconTabHelper::CreateForWebContents(web_contents_.get());
299 
300   UpdateRendererPrefs(false);
301   locale_change_subscription_ =
302       i18n::RegisterLocaleChangeCallback(base::BindRepeating(
303           &TabImpl::UpdateRendererPrefs, base::Unretained(this), true));
304 
305   std::unique_ptr<UserData> user_data = std::make_unique<UserData>();
306   user_data->tab = this;
307   web_contents_->SetUserData(&kWebContentsUserDataKey, std::move(user_data));
308 
309   web_contents_->SetDelegate(this);
310   Observe(web_contents_.get());
311 
312   navigation_controller_ = std::make_unique<NavigationControllerImpl>(this);
313 
314   find_in_page::FindTabHelper::CreateForWebContents(web_contents_.get());
315   GetFindTabHelper()->AddObserver(this);
316 
317   TranslateClientImpl::CreateForWebContents(web_contents_.get());
318 
319   sessions::SessionTabHelper::CreateForWebContents(
320       web_contents_.get(),
321       base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate));
322 
323   permissions::PermissionRequestManager::CreateForWebContents(
324       web_contents_.get());
325   content_settings::PageSpecificContentSettings::CreateForWebContents(
326       web_contents_.get(),
327       std::make_unique<PageSpecificContentSettingsDelegate>(
328           web_contents_.get()));
329   blocked_content::PopupBlockerTabHelper::CreateForWebContents(
330       web_contents_.get());
331   blocked_content::PopupOpenerTabHelper::CreateForWebContents(
332       web_contents_.get(), base::DefaultTickClock::GetInstance(),
333       HostContentSettingsMapFactory::GetForBrowserContext(
334           web_contents_->GetBrowserContext()));
335   PasswordManagerDriverFactory::CreateForWebContents(web_contents_.get());
336 
337   InitializePageLoadMetricsForWebContents(web_contents_.get());
338   ukm::InitializeSourceUrlRecorderForWebContents(web_contents_.get());
339 
340 #if defined(OS_ANDROID)
341   InfoBarService::CreateForWebContents(web_contents_.get());
342   javascript_dialogs::TabModalDialogManager::CreateForWebContents(
343       web_contents_.get(),
344       std::make_unique<JavaScriptTabModalDialogManagerDelegateAndroid>(
345           web_contents_.get()));
346 
347   browser_controls_navigation_state_handler_ =
348       std::make_unique<BrowserControlsNavigationStateHandler>(
349           web_contents_.get(), this);
350 
351   TrustedCDNObserver::CreateForWebContents(web_contents_.get());
352 #endif
353 
354 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
355   captive_portal::CaptivePortalTabHelper::CreateForWebContents(
356       web_contents_.get(),
357       CaptivePortalServiceFactory::GetForBrowserContext(
358           web_contents_->GetBrowserContext()),
359       base::BindRepeating(&OpenCaptivePortalLoginTabInWebContents,
360                           web_contents_.get()));
361 #endif
362 
363   // PrerenderTabHelper adds a WebContentsObserver.
364   PrerenderTabHelper::CreateForWebContents(web_contents_.get());
365 }
366 
~TabImpl()367 TabImpl::~TabImpl() {
368   DCHECK(!browser_);
369 
370   GetFindTabHelper()->RemoveObserver(this);
371 
372   // Delete the WebContents and related objects that may be observing
373   // the WebContents now to avoid calling back when this object is partially
374   // deleted. DidFinishNavigation() may be called while deleting WebContents,
375   // so stop observing first. Similarly WebContents destructor can callback to
376   // delegate such as NavigationStateChanged, so clear its Delegate as well.
377 #if defined(OS_ANDROID)
378   browser_controls_navigation_state_handler_.reset();
379 #endif
380   Observe(nullptr);
381   web_contents_->SetDelegate(nullptr);
382   if (navigation_controller_->should_delay_web_contents_deletion()) {
383     // Some user-data on WebContents directly or indirectly references this.
384     // Remove that linkage to avoid use-after-free.
385     web_contents_->RemoveUserData(&kWebContentsUserDataKey);
386     web_contents_->RemoveUserData(
387         autofill::ContentAutofillDriverFactory::
388             kContentAutofillDriverFactoryWebContentsUserDataKey);
389     // Have Profile handle the task posting to ensure the WebContents is
390     // deleted before Profile. To do otherwise means it would be possible for
391     // the Profile to outlive the WebContents, which is problematic (crash).
392     profile_->DeleteWebContentsSoon(std::move(web_contents_));
393   }
394   web_contents_.reset();
395   GetTabs().erase(this);
396 }
397 
398 // static
FromWebContents(content::WebContents * web_contents)399 TabImpl* TabImpl::FromWebContents(content::WebContents* web_contents) {
400   if (!web_contents)
401     return nullptr;
402 
403   UserData* user_data = reinterpret_cast<UserData*>(
404       web_contents->GetUserData(&kWebContentsUserDataKey));
405   return user_data ? user_data->tab : nullptr;
406 }
407 
408 // static
GetAllTabImpl()409 std::set<TabImpl*> TabImpl::GetAllTabImpl() {
410   return GetTabs();
411 }
412 
AddDataObserver(DataObserver * observer)413 void TabImpl::AddDataObserver(DataObserver* observer) {
414   data_observers_.AddObserver(observer);
415 }
416 
RemoveDataObserver(DataObserver * observer)417 void TabImpl::RemoveDataObserver(DataObserver* observer) {
418   data_observers_.RemoveObserver(observer);
419 }
420 
GetBrowser()421 Browser* TabImpl::GetBrowser() {
422   return browser_;
423 }
424 
SetErrorPageDelegate(ErrorPageDelegate * delegate)425 void TabImpl::SetErrorPageDelegate(ErrorPageDelegate* delegate) {
426   error_page_delegate_ = delegate;
427 }
428 
SetFullscreenDelegate(FullscreenDelegate * delegate)429 void TabImpl::SetFullscreenDelegate(FullscreenDelegate* delegate) {
430   if (delegate == fullscreen_delegate_)
431     return;
432 
433   const bool had_delegate = (fullscreen_delegate_ != nullptr);
434   const bool has_delegate = (delegate != nullptr);
435 
436   // If currently fullscreen, and the delegate is being set to null, force an
437   // exit now (otherwise the delegate can't take us out of fullscreen).
438   if (is_fullscreen_ && fullscreen_delegate_ && had_delegate != has_delegate)
439     OnExitFullscreen();
440 
441   fullscreen_delegate_ = delegate;
442   // Whether fullscreen is enabled depends upon whether there is a delegate. If
443   // having a delegate changed, then update the renderer (which is where
444   // fullscreen enabled is tracked).
445   if (had_delegate != has_delegate)
446     web_contents_->OnWebPreferencesChanged();
447 }
448 
SetNewTabDelegate(NewTabDelegate * delegate)449 void TabImpl::SetNewTabDelegate(NewTabDelegate* delegate) {
450   new_tab_delegate_ = delegate;
451 }
452 
SetGoogleAccountsDelegate(GoogleAccountsDelegate * delegate)453 void TabImpl::SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) {
454   google_accounts_delegate_ = delegate;
455 }
456 
AddObserver(TabObserver * observer)457 void TabImpl::AddObserver(TabObserver* observer) {
458   observers_.AddObserver(observer);
459 }
460 
RemoveObserver(TabObserver * observer)461 void TabImpl::RemoveObserver(TabObserver* observer) {
462   observers_.RemoveObserver(observer);
463 }
464 
GetNavigationController()465 NavigationController* TabImpl::GetNavigationController() {
466   return navigation_controller_.get();
467 }
468 
ExecuteScript(const base::string16 & script,bool use_separate_isolate,JavaScriptResultCallback callback)469 void TabImpl::ExecuteScript(const base::string16& script,
470                             bool use_separate_isolate,
471                             JavaScriptResultCallback callback) {
472   if (use_separate_isolate) {
473     web_contents_->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(
474         script, std::move(callback), ISOLATED_WORLD_ID_WEBLAYER);
475   } else {
476     content::RenderFrameHost::AllowInjectingJavaScript();
477     web_contents_->GetMainFrame()->ExecuteJavaScript(script,
478                                                      std::move(callback));
479   }
480 }
481 
GetGuid()482 const std::string& TabImpl::GetGuid() {
483   return guid_;
484 }
485 
SetData(const std::map<std::string,std::string> & data)486 void TabImpl::SetData(const std::map<std::string, std::string>& data) {
487   bool result = SetDataInternal(data);
488   DCHECK(result) << "Data given to SetData() was too large.";
489 }
490 
GetData()491 const std::map<std::string, std::string>& TabImpl::GetData() {
492   return data_;
493 }
494 
AddWebMessageHostFactory(std::unique_ptr<WebMessageHostFactory> factory,const base::string16 & js_object_name,const std::vector<std::string> & allowed_origin_rules)495 base::string16 TabImpl::AddWebMessageHostFactory(
496     std::unique_ptr<WebMessageHostFactory> factory,
497     const base::string16& js_object_name,
498     const std::vector<std::string>& allowed_origin_rules) {
499   if (!js_communication_host_) {
500     js_communication_host_ =
501         std::make_unique<js_injection::JsCommunicationHost>(
502             web_contents_.get());
503   }
504   return js_communication_host_->AddWebMessageHostFactory(
505       std::make_unique<WebMessageHostFactoryWrapper>(std::move(factory)),
506       js_object_name, allowed_origin_rules);
507 }
508 
RemoveWebMessageHostFactory(const base::string16 & js_object_name)509 void TabImpl::RemoveWebMessageHostFactory(
510     const base::string16& js_object_name) {
511   if (js_communication_host_)
512     js_communication_host_->RemoveWebMessageHostFactory(js_object_name);
513 }
514 
ExecuteScriptWithUserGestureForTests(const base::string16 & script)515 void TabImpl::ExecuteScriptWithUserGestureForTests(
516     const base::string16& script) {
517   web_contents_->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
518       script);
519 }
520 
CreateFaviconFetcher(FaviconFetcherDelegate * delegate)521 std::unique_ptr<FaviconFetcher> TabImpl::CreateFaviconFetcher(
522     FaviconFetcherDelegate* delegate) {
523   return std::make_unique<FaviconFetcherImpl>(web_contents_.get(), delegate);
524 }
525 
526 #if !defined(OS_ANDROID)
AttachToView(views::WebView * web_view)527 void TabImpl::AttachToView(views::WebView* web_view) {
528   web_view->SetWebContents(web_contents_.get());
529   web_contents_->Focus();
530 }
531 #endif
532 
WebPreferencesChanged()533 void TabImpl::WebPreferencesChanged() {
534   web_contents_->OnWebPreferencesChanged();
535 }
536 
SetWebPreferences(blink::web_pref::WebPreferences * prefs)537 void TabImpl::SetWebPreferences(blink::web_pref::WebPreferences* prefs) {
538   prefs->fullscreen_supported = !!fullscreen_delegate_;
539 
540   if (!browser_)
541     return;
542   browser_->SetWebPreferences(prefs);
543 }
544 
OnLosingActive()545 void TabImpl::OnLosingActive() {
546   if (is_fullscreen_)
547     web_contents_->ExitFullscreen(/* will_cause_resize */ false);
548 }
549 
IsActive()550 bool TabImpl::IsActive() {
551   return browser_->GetActiveTab() == this;
552 }
553 
ShowContextMenu(const content::ContextMenuParams & params)554 void TabImpl::ShowContextMenu(const content::ContextMenuParams& params) {
555 #if defined(OS_ANDROID)
556   Java_TabImpl_showContextMenu(
557       base::android::AttachCurrentThread(), java_impl_,
558       context_menu::BuildJavaContextMenuParams(params),
559       reinterpret_cast<jlong>(new content::ContextMenuParams(params)));
560 #endif
561 }
562 
563 #if defined(OS_ANDROID)
564 // static
DisableAutofillSystemIntegrationForTesting()565 void TabImpl::DisableAutofillSystemIntegrationForTesting() {
566   g_system_autofill_disabled_for_testing = true;
567 }
568 
JNI_TabImpl_CreateTab(JNIEnv * env,jlong profile,const JavaParamRef<jobject> & java_impl)569 static jlong JNI_TabImpl_CreateTab(JNIEnv* env,
570                                    jlong profile,
571                                    const JavaParamRef<jobject>& java_impl) {
572   ProfileImpl* profile_impl = reinterpret_cast<ProfileImpl*>(profile);
573   content::WebContents::CreateParams create_params(
574       profile_impl->GetBrowserContext());
575   create_params.initially_hidden = true;
576   return reinterpret_cast<intptr_t>(new TabImpl(
577       profile_impl, java_impl, content::WebContents::Create(create_params)));
578 }
579 
JNI_TabImpl_DeleteTab(JNIEnv * env,jlong tab)580 static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) {
581   TabImpl* tab_impl = reinterpret_cast<TabImpl*>(tab);
582   DCHECK(tab_impl);
583   // RemoveTabBeforeDestroyingFromJava() should have been called before this,
584   // which sets browser to null.
585   DCHECK(!tab_impl->browser());
586   delete tab_impl;
587 }
588 
GetWebContents(JNIEnv * env)589 ScopedJavaLocalRef<jobject> TabImpl::GetWebContents(JNIEnv* env) {
590   return web_contents_->GetJavaWebContents();
591 }
592 
SetBrowserControlsContainerViews(JNIEnv * env,jlong native_top_controls_container_view,jlong native_bottom_controls_container_view)593 void TabImpl::SetBrowserControlsContainerViews(
594     JNIEnv* env,
595     jlong native_top_controls_container_view,
596     jlong native_bottom_controls_container_view) {
597   top_controls_container_view_ =
598       reinterpret_cast<BrowserControlsContainerView*>(
599           native_top_controls_container_view);
600   bottom_controls_container_view_ =
601       reinterpret_cast<BrowserControlsContainerView*>(
602           native_bottom_controls_container_view);
603 }
604 
ExecuteScript(JNIEnv * env,const JavaParamRef<jstring> & script,bool use_separate_isolate,const JavaParamRef<jobject> & callback)605 void TabImpl::ExecuteScript(JNIEnv* env,
606                             const JavaParamRef<jstring>& script,
607                             bool use_separate_isolate,
608                             const JavaParamRef<jobject>& callback) {
609   ScopedJavaGlobalRef<jobject> jcallback(env, callback);
610   ExecuteScript(base::android::ConvertJavaStringToUTF16(script),
611                 use_separate_isolate,
612                 base::BindOnce(&HandleJavaScriptResult, jcallback));
613 }
614 
SetJavaImpl(JNIEnv * env,const JavaParamRef<jobject> & impl)615 void TabImpl::SetJavaImpl(JNIEnv* env, const JavaParamRef<jobject>& impl) {
616   // This should only be called early on and only once.
617   DCHECK(!java_impl_);
618   java_impl_ = impl;
619 }
620 
OnAutofillProviderChanged(JNIEnv * env,const JavaParamRef<jobject> & autofill_provider)621 void TabImpl::OnAutofillProviderChanged(
622     JNIEnv* env,
623     const JavaParamRef<jobject>& autofill_provider) {
624   if (g_system_autofill_disabled_for_testing)
625     return;
626 
627   if (!autofill_provider_) {
628     // The first invocation should be when instantiating the autofill
629     // infrastructure, at which point the Java-side object should not be null.
630     DCHECK(autofill_provider);
631 
632     // Initialize the native side of the autofill infrastructure.
633     autofill_provider_ = std::make_unique<autofill::AutofillProviderAndroid>(
634         autofill_provider, web_contents_.get());
635     InitializeAutofill();
636     return;
637   }
638 
639   // The AutofillProvider Java object has been changed; inform
640   // |autofill_provider_|.
641   auto* provider =
642       static_cast<autofill::AutofillProviderAndroid*>(autofill_provider_.get());
643   provider->OnJavaAutofillProviderChanged(env, autofill_provider);
644 }
645 
UpdateBrowserControlsConstraint(JNIEnv * env,jint constraint,jboolean animate)646 void TabImpl::UpdateBrowserControlsConstraint(JNIEnv* env,
647                                               jint constraint,
648                                               jboolean animate) {
649   current_browser_controls_visibility_constraint_ =
650       static_cast<content::BrowserControlsState>(constraint);
651   // Passing BOTH here means that it doesn't matter what state the controls are
652   // currently in; don't change the current state unless it's incompatible with
653   // the new constraint.
654   UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_BOTH, animate);
655 }
656 
GetGuid(JNIEnv * env)657 ScopedJavaLocalRef<jstring> TabImpl::GetGuid(JNIEnv* env) {
658   return base::android::ConvertUTF8ToJavaString(AttachCurrentThread(),
659                                                 GetGuid());
660 }
661 
PrepareForCaptureScreenShot(float scale,content::RenderWidgetHostView ** rwhv,gfx::Rect * src_rect,gfx::Size * output_size)662 TabImpl::ScreenShotErrors TabImpl::PrepareForCaptureScreenShot(
663     float scale,
664     content::RenderWidgetHostView** rwhv,
665     gfx::Rect* src_rect,
666     gfx::Size* output_size) {
667   if (scale <= 0.f || scale > 1.f)
668     return ScreenShotErrors::kScaleOutOfRange;
669 
670   if (!IsActive())
671     return ScreenShotErrors::kTabNotActive;
672 
673   if (web_contents_->GetVisibility() != content::Visibility::VISIBLE)
674     return ScreenShotErrors::kWebContentsNotVisible;
675 
676   if (!browser_ || !browser_->CompositorHasSurface())
677     return ScreenShotErrors::kNoSurface;
678 
679   *rwhv = web_contents_->GetTopLevelRenderWidgetHostView();
680   if (!*rwhv)
681     return ScreenShotErrors::kNoRenderWidgetHostView;
682 
683   if (!(*rwhv)->GetNativeView()->GetWindowAndroid())
684     return ScreenShotErrors::kNoWindowAndroid;
685 
686   *src_rect =
687       gfx::Rect(web_contents_->GetNativeView()->GetPhysicalBackingSize());
688   if (src_rect->IsEmpty())
689     return ScreenShotErrors::kEmptyViewport;
690 
691   const int reduced_height =
692       src_rect->height() -
693       top_controls_container_view_->GetContentHeightDelta() -
694       bottom_controls_container_view_->GetContentHeightDelta();
695   if (reduced_height <= 0)
696     return ScreenShotErrors::kHiddenByControls;
697   src_rect->set_height(reduced_height);
698 
699   *output_size = gfx::ScaleToCeiledSize(src_rect->size(), scale, scale);
700   if (output_size->IsEmpty())
701     return ScreenShotErrors::kScaledToEmpty;
702   return ScreenShotErrors::kNone;
703 }
704 
UpdateBrowserControlsState(content::BrowserControlsState new_state,bool animate)705 void TabImpl::UpdateBrowserControlsState(
706     content::BrowserControlsState new_state,
707     bool animate) {
708   if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest))
709     animate = false;
710   // The constraint is managed by Java code, so re-use the existing constraint
711   // and only update the desired state.
712   web_contents_->GetMainFrame()->UpdateBrowserControlsState(
713       current_browser_controls_visibility_constraint_, new_state, animate);
714 }
715 
CaptureScreenShot(JNIEnv * env,jfloat scale,const base::android::JavaParamRef<jobject> & value_callback)716 void TabImpl::CaptureScreenShot(
717     JNIEnv* env,
718     jfloat scale,
719     const base::android::JavaParamRef<jobject>& value_callback) {
720   content::RenderWidgetHostView* rwhv = nullptr;
721   gfx::Rect src_rect;
722   gfx::Size output_size;
723   ScreenShotErrors error =
724       PrepareForCaptureScreenShot(scale, &rwhv, &src_rect, &output_size);
725   if (error != ScreenShotErrors::kNone) {
726     Java_TabImpl_runCaptureScreenShotCallback(
727         env, ScopedJavaLocalRef<jobject>(value_callback),
728         ScopedJavaLocalRef<jobject>(), static_cast<int>(error));
729     return;
730   }
731 
732   rwhv->CopyFromSurface(
733       src_rect, output_size,
734       base::BindOnce(&OnScreenShotCaptured,
735                      ScopedJavaGlobalRef<jobject>(value_callback)));
736 }
737 
SetData(JNIEnv * env,const base::android::JavaParamRef<jobjectArray> & data)738 jboolean TabImpl::SetData(
739     JNIEnv* env,
740     const base::android::JavaParamRef<jobjectArray>& data) {
741   std::vector<std::string> flattened_map;
742   base::android::AppendJavaStringArrayToStringVector(env, data, &flattened_map);
743   std::map<std::string, std::string> data_map;
744   for (size_t i = 0; i < flattened_map.size(); i += 2) {
745     data_map.insert({flattened_map[i], flattened_map[i + 1]});
746   }
747   return SetDataInternal(data_map);
748 }
749 
GetData(JNIEnv * env)750 base::android::ScopedJavaLocalRef<jobjectArray> TabImpl::GetData(JNIEnv* env) {
751   std::vector<std::string> flattened_map;
752   for (const auto& kv : data_) {
753     flattened_map.push_back(kv.first);
754     flattened_map.push_back(kv.second);
755   }
756   return base::android::ToJavaArrayOfStrings(env, flattened_map);
757 }
758 
IsRendererControllingBrowserControlsOffsets(JNIEnv * env)759 jboolean TabImpl::IsRendererControllingBrowserControlsOffsets(JNIEnv* env) {
760   return browser_controls_navigation_state_handler_
761       ->IsRendererControllingOffsets();
762 }
763 
RegisterWebMessageCallback(JNIEnv * env,const base::android::JavaParamRef<jstring> & js_object_name,const base::android::JavaParamRef<jobjectArray> & js_origins,const base::android::JavaParamRef<jobject> & client)764 base::android::ScopedJavaLocalRef<jstring> TabImpl::RegisterWebMessageCallback(
765     JNIEnv* env,
766     const base::android::JavaParamRef<jstring>& js_object_name,
767     const base::android::JavaParamRef<jobjectArray>& js_origins,
768     const base::android::JavaParamRef<jobject>& client) {
769   auto proxy = std::make_unique<WebMessageHostFactoryProxy>(client);
770   std::vector<std::string> origins;
771   base::android::AppendJavaStringArrayToStringVector(env, js_origins, &origins);
772   base::string16 result = AddWebMessageHostFactory(
773       std::move(proxy),
774       base::android::ConvertJavaStringToUTF16(env, js_object_name), origins);
775   return base::android::ConvertUTF16ToJavaString(env, result);
776 }
777 
UnregisterWebMessageCallback(JNIEnv * env,const base::android::JavaParamRef<jstring> & js_object_name)778 void TabImpl::UnregisterWebMessageCallback(
779     JNIEnv* env,
780     const base::android::JavaParamRef<jstring>& js_object_name) {
781   base::string16 name;
782   base::android::ConvertJavaStringToUTF16(env, js_object_name, &name);
783   RemoveWebMessageHostFactory(name);
784 }
785 
CanTranslate(JNIEnv * env)786 jboolean TabImpl::CanTranslate(JNIEnv* env) {
787   return TranslateClientImpl::FromWebContents(web_contents())
788       ->GetTranslateManager()
789       ->CanManuallyTranslate();
790 }
791 
ShowTranslateUi(JNIEnv * env)792 void TabImpl::ShowTranslateUi(JNIEnv* env) {
793   TranslateClientImpl::FromWebContents(web_contents())
794       ->ManualTranslateWhenReady();
795 }
796 
RemoveTabFromBrowserBeforeDestroying(JNIEnv * env)797 void TabImpl::RemoveTabFromBrowserBeforeDestroying(JNIEnv* env) {
798   DCHECK(browser_);
799   browser_->RemoveTabBeforeDestroyingFromJava(this);
800 }
801 
SetTranslateTargetLanguage(JNIEnv * env,const base::android::JavaParamRef<jstring> & translate_target_lang)802 void TabImpl::SetTranslateTargetLanguage(
803     JNIEnv* env,
804     const base::android::JavaParamRef<jstring>& translate_target_lang) {
805   translate::TranslateManager* translate_manager =
806       TranslateClientImpl::FromWebContents(web_contents())
807           ->GetTranslateManager();
808   translate_manager->SetPredefinedTargetLanguage(
809       base::android::ConvertJavaStringToUTF8(env, translate_target_lang));
810 }
811 
SetDesktopUserAgentEnabled(JNIEnv * env,jboolean enable)812 void TabImpl::SetDesktopUserAgentEnabled(JNIEnv* env, jboolean enable) {
813   if (desktop_user_agent_enabled_ == enable)
814     return;
815 
816   desktop_user_agent_enabled_ = enable;
817 
818   // Reset state that an earlier call to Navigation::SetUserAgentString()
819   // could have modified.
820   embedder_support::SetDesktopUserAgentOverride(web_contents_.get(),
821                                                 GetUserAgentMetadata());
822   web_contents_->SetRendererInitiatedUserAgentOverrideOption(
823       content::NavigationController::UA_OVERRIDE_INHERIT);
824 
825   content::NavigationEntry* entry =
826       web_contents_->GetController().GetLastCommittedEntry();
827   if (!entry)
828     return;
829 
830   entry->SetIsOverridingUserAgent(enable);
831   web_contents_->NotifyPreferencesChanged();
832   web_contents_->GetController().Reload(
833       content::ReloadType::ORIGINAL_REQUEST_URL, true);
834 }
835 
IsDesktopUserAgentEnabled(JNIEnv * env)836 jboolean TabImpl::IsDesktopUserAgentEnabled(JNIEnv* env) {
837   auto* entry = web_contents_->GetController().GetLastCommittedEntry();
838   if (!entry)
839     return false;
840 
841   // The same user agent override mechanism is used for per-navigation user
842   // agent and desktop mode. Make sure not to return desktop mode for
843   // navigation entries which used a per-navigation user agent.
844   auto* entry_data = NavigationEntryData::Get(entry);
845   if (entry_data && entry_data->per_navigation_user_agent_override())
846     return false;
847 
848   return entry->GetIsOverridingUserAgent();
849 }
850 
Download(JNIEnv * env,jlong native_context_menu_params)851 void TabImpl::Download(JNIEnv* env, jlong native_context_menu_params) {
852   auto* context_menu_params =
853       reinterpret_cast<content::ContextMenuParams*>(native_context_menu_params);
854 
855   bool is_link = context_menu_params->media_type !=
856                      blink::ContextMenuDataMediaType::kImage &&
857                  context_menu_params->media_type !=
858                      blink::ContextMenuDataMediaType::kVideo;
859 
860   download::CreateContextMenuDownload(web_contents_.get(), *context_menu_params,
861                                       std::string(), is_link);
862 }
863 #endif  // OS_ANDROID
864 
OpenURLFromTab(content::WebContents * source,const content::OpenURLParams & params)865 content::WebContents* TabImpl::OpenURLFromTab(
866     content::WebContents* source,
867     const content::OpenURLParams& params) {
868   if (blocked_content::ConsiderForPopupBlocking(params.disposition)) {
869     bool blocked = blocked_content::MaybeBlockPopup(
870                        source, nullptr,
871                        std::make_unique<PopupNavigationDelegateImpl>(
872                            params, source, nullptr),
873                        &params, blink::mojom::WindowFeatures(),
874                        HostContentSettingsMapFactory::GetForBrowserContext(
875                            source->GetBrowserContext())) == nullptr;
876     if (blocked)
877       return nullptr;
878   }
879 
880   if (params.disposition == WindowOpenDisposition::CURRENT_TAB) {
881     source->GetController().LoadURLWithParams(
882         content::NavigationController::LoadURLParams(params));
883     return source;
884   }
885 
886   // All URLs not opening in the current tab will get a new tab.
887   std::unique_ptr<content::WebContents> new_tab_contents =
888       content::WebContents::Create(content::WebContents::CreateParams(
889           web_contents()->GetBrowserContext()));
890   WebContentsTracker tracker(new_tab_contents.get());
891   bool was_blocked = false;
892   AddNewContents(web_contents(), std::move(new_tab_contents), params.url,
893                  params.disposition, {}, params.user_gesture, &was_blocked);
894   if (was_blocked || !tracker.web_contents())
895     return nullptr;
896   tracker.web_contents()->GetController().LoadURLWithParams(
897       content::NavigationController::LoadURLParams(params));
898   return tracker.web_contents();
899 }
900 
ShowRepostFormWarningDialog(content::WebContents * source)901 void TabImpl::ShowRepostFormWarningDialog(content::WebContents* source) {
902 #if defined(OS_ANDROID)
903   Java_TabImpl_showRepostFormWarningDialog(base::android::AttachCurrentThread(),
904                                            java_impl_);
905 #else
906   source->GetController().CancelPendingReload();
907 #endif
908 }
909 
NavigationStateChanged(content::WebContents * source,content::InvalidateTypes changed_flags)910 void TabImpl::NavigationStateChanged(content::WebContents* source,
911                                      content::InvalidateTypes changed_flags) {
912   DCHECK_EQ(web_contents_.get(), source);
913   if (changed_flags & content::INVALIDATE_TYPE_URL) {
914     for (auto& observer : observers_)
915       observer.DisplayedUrlChanged(source->GetVisibleURL());
916     UpdateBrowserVisibleSecurityStateIfNecessary();
917   }
918 
919   // TODO(crbug.com/1064582): INVALIDATE_TYPE_TITLE is called only when a title
920   // is set on the active navigation entry, but not when the active entry
921   // changes, so check INVALIDATE_TYPE_LOAD here as well. However this should
922   // be fixed and INVALIDATE_TYPE_LOAD should be removed.
923   if (changed_flags &
924       (content::INVALIDATE_TYPE_TITLE | content::INVALIDATE_TYPE_LOAD)) {
925     base::string16 title = web_contents_->GetTitle();
926     if (title_ != title) {
927       title_ = title;
928       for (auto& observer : observers_)
929         observer.OnTitleUpdated(title);
930     }
931   }
932 }
933 
GetJavaScriptDialogManager(content::WebContents * web_contents)934 content::JavaScriptDialogManager* TabImpl::GetJavaScriptDialogManager(
935     content::WebContents* web_contents) {
936 #if defined(OS_ANDROID)
937   return javascript_dialogs::TabModalDialogManager::FromWebContents(
938       web_contents);
939 #else
940   return nullptr;
941 #endif
942 }
943 
OpenColorChooser(content::WebContents * web_contents,SkColor color,const std::vector<blink::mojom::ColorSuggestionPtr> & suggestions)944 content::ColorChooser* TabImpl::OpenColorChooser(
945     content::WebContents* web_contents,
946     SkColor color,
947     const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
948 #if defined(OS_ANDROID)
949   return new web_contents_delegate_android::ColorChooserAndroid(
950       web_contents, color, suggestions);
951 #else
952   return nullptr;
953 #endif
954 }
955 
CreateSmsPrompt(content::RenderFrameHost * render_frame_host,const url::Origin & origin,const std::string & one_time_code,base::OnceClosure on_confirm,base::OnceClosure on_cancel)956 void TabImpl::CreateSmsPrompt(content::RenderFrameHost* render_frame_host,
957                               const url::Origin& origin,
958                               const std::string& one_time_code,
959                               base::OnceClosure on_confirm,
960                               base::OnceClosure on_cancel) {
961 #if defined(OS_ANDROID)
962   auto* web_contents =
963       content::WebContents::FromRenderFrameHost(render_frame_host);
964   sms::SmsInfoBar::Create(
965       web_contents, InfoBarService::FromWebContents(web_contents),
966       InfoBarService::GetResourceIdMapper(), origin, one_time_code,
967       std::move(on_confirm), std::move(on_cancel));
968 #else
969   NOTREACHED();
970 #endif
971 }
972 
RunFileChooser(content::RenderFrameHost * render_frame_host,scoped_refptr<content::FileSelectListener> listener,const blink::mojom::FileChooserParams & params)973 void TabImpl::RunFileChooser(
974     content::RenderFrameHost* render_frame_host,
975     scoped_refptr<content::FileSelectListener> listener,
976     const blink::mojom::FileChooserParams& params) {
977   FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
978                                    params);
979 }
980 
GetTopControlsHeight()981 int TabImpl::GetTopControlsHeight() {
982 #if defined(OS_ANDROID)
983   return top_controls_container_view_
984              ? top_controls_container_view_->GetControlsHeight()
985              : 0;
986 #else
987   return 0;
988 #endif
989 }
990 
GetTopControlsMinHeight()991 int TabImpl::GetTopControlsMinHeight() {
992 #if defined(OS_ANDROID)
993   return top_controls_container_view_
994              ? top_controls_container_view_->GetMinHeight()
995              : 0;
996 #else
997   return 0;
998 #endif
999 }
1000 
GetBottomControlsHeight()1001 int TabImpl::GetBottomControlsHeight() {
1002 #if defined(OS_ANDROID)
1003   return bottom_controls_container_view_
1004              ? bottom_controls_container_view_->GetControlsHeight()
1005              : 0;
1006 #else
1007   return 0;
1008 #endif
1009 }
1010 
DoBrowserControlsShrinkRendererSize(content::WebContents * web_contents)1011 bool TabImpl::DoBrowserControlsShrinkRendererSize(
1012     content::WebContents* web_contents) {
1013 #if defined(OS_ANDROID)
1014   TRACE_EVENT0("weblayer", "Java_TabImpl_doBrowserControlsShrinkRendererSize");
1015   return Java_TabImpl_doBrowserControlsShrinkRendererSize(AttachCurrentThread(),
1016                                                           java_impl_);
1017 #else
1018   return false;
1019 #endif
1020 }
1021 
ShouldAnimateBrowserControlsHeightChanges()1022 bool TabImpl::ShouldAnimateBrowserControlsHeightChanges() {
1023 #if defined(OS_ANDROID)
1024   return top_controls_container_view_
1025              ? top_controls_container_view_
1026                    ->ShouldAnimateBrowserControlsHeightChanges()
1027              : false;
1028 #else
1029   return false;
1030 #endif
1031 }
1032 
OnlyExpandTopControlsAtPageTop()1033 bool TabImpl::OnlyExpandTopControlsAtPageTop() {
1034 #if defined(OS_ANDROID)
1035   return top_controls_container_view_
1036              ? top_controls_container_view_->OnlyExpandControlsAtPageTop()
1037              : false;
1038 #else
1039   return false;
1040 #endif
1041 }
1042 
RequestMediaAccessPermission(content::WebContents * web_contents,const content::MediaStreamRequest & request,content::MediaResponseCallback callback)1043 void TabImpl::RequestMediaAccessPermission(
1044     content::WebContents* web_contents,
1045     const content::MediaStreamRequest& request,
1046     content::MediaResponseCallback callback) {
1047 #if defined(OS_ANDROID)
1048   MediaStreamManager::FromWebContents(web_contents)
1049       ->RequestMediaAccessPermission(request, std::move(callback));
1050 #else
1051   std::move(callback).Run(
1052       {}, blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
1053 #endif
1054 }
1055 
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type)1056 bool TabImpl::CheckMediaAccessPermission(
1057     content::RenderFrameHost* render_frame_host,
1058     const GURL& security_origin,
1059     blink::mojom::MediaStreamType type) {
1060   DCHECK(type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
1061          type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
1062   ContentSettingsType content_settings_type =
1063       type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE
1064           ? ContentSettingsType::MEDIASTREAM_MIC
1065           : ContentSettingsType::MEDIASTREAM_CAMERA;
1066   return PermissionManagerFactory::GetForBrowserContext(
1067              content::WebContents::FromRenderFrameHost(render_frame_host)
1068                  ->GetBrowserContext())
1069              ->GetPermissionStatusForFrame(content_settings_type,
1070                                            render_frame_host, security_origin)
1071              .content_setting == CONTENT_SETTING_ALLOW;
1072 }
1073 
EnterFullscreenModeForTab(content::RenderFrameHost * requesting_frame,const blink::mojom::FullscreenOptions & options)1074 void TabImpl::EnterFullscreenModeForTab(
1075     content::RenderFrameHost* requesting_frame,
1076     const blink::mojom::FullscreenOptions& options) {
1077   // TODO: support |options|.
1078   is_fullscreen_ = true;
1079   auto exit_fullscreen_closure = base::BindOnce(&TabImpl::OnExitFullscreen,
1080                                                 weak_ptr_factory_.GetWeakPtr());
1081   base::AutoReset<bool> reset(&processing_enter_fullscreen_, true);
1082   fullscreen_delegate_->EnterFullscreen(std::move(exit_fullscreen_closure));
1083 #if defined(OS_ANDROID)
1084   // Make sure browser controls cannot show when the tab is fullscreen.
1085   SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
1086                                content::BROWSER_CONTROLS_STATE_HIDDEN);
1087 #endif
1088 }
1089 
ExitFullscreenModeForTab(content::WebContents * web_contents)1090 void TabImpl::ExitFullscreenModeForTab(content::WebContents* web_contents) {
1091   is_fullscreen_ = false;
1092   fullscreen_delegate_->ExitFullscreen();
1093 #if defined(OS_ANDROID)
1094   // Attempt to show browser controls when exiting fullscreen.
1095   SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
1096                                content::BROWSER_CONTROLS_STATE_BOTH);
1097 #endif
1098 }
1099 
IsFullscreenForTabOrPending(const content::WebContents * web_contents)1100 bool TabImpl::IsFullscreenForTabOrPending(
1101     const content::WebContents* web_contents) {
1102   return is_fullscreen_;
1103 }
1104 
GetDisplayMode(const content::WebContents * web_contents)1105 blink::mojom::DisplayMode TabImpl::GetDisplayMode(
1106     const content::WebContents* web_contents) {
1107   return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen
1108                         : blink::mojom::DisplayMode::kBrowser;
1109 }
1110 
AddNewContents(content::WebContents * source,std::unique_ptr<content::WebContents> new_contents,const GURL & target_url,WindowOpenDisposition disposition,const gfx::Rect & initial_rect,bool user_gesture,bool * was_blocked)1111 void TabImpl::AddNewContents(content::WebContents* source,
1112                              std::unique_ptr<content::WebContents> new_contents,
1113                              const GURL& target_url,
1114                              WindowOpenDisposition disposition,
1115                              const gfx::Rect& initial_rect,
1116                              bool user_gesture,
1117                              bool* was_blocked) {
1118   if (!new_tab_delegate_) {
1119     *was_blocked = true;
1120     return;
1121   }
1122 
1123   // At this point the |new_contents| is beyond the popup blocker, but we use
1124   // the same logic for determining if the popup tracker needs to be attached.
1125   if (source && blocked_content::ConsiderForPopupBlocking(disposition)) {
1126     blocked_content::PopupTracker::CreateForWebContents(new_contents.get(),
1127                                                         source, disposition);
1128   }
1129 
1130   new_tab_delegate_->OnNewTab(browser_->CreateTab(std::move(new_contents)),
1131                               NewTabTypeFromWindowDisposition(disposition));
1132 }
1133 
CloseContents(content::WebContents * source)1134 void TabImpl::CloseContents(content::WebContents* source) {
1135   // The only time that |browser_| is null is during shutdown, and this callback
1136   // shouldn't come in at that time.
1137   DCHECK(browser_);
1138 
1139 #if defined(OS_ANDROID)
1140   JNIEnv* env = AttachCurrentThread();
1141   Java_TabImpl_handleCloseFromWebContents(env, java_impl_);
1142   // The above call resulted in the destruction of this; nothing to do but
1143   // return.
1144 #else
1145   browser_->DestroyTab(this);
1146 #endif
1147 }
1148 
FindReply(content::WebContents * web_contents,int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)1149 void TabImpl::FindReply(content::WebContents* web_contents,
1150                         int request_id,
1151                         int number_of_matches,
1152                         const gfx::Rect& selection_rect,
1153                         int active_match_ordinal,
1154                         bool final_update) {
1155   GetFindTabHelper()->HandleFindReply(request_id, number_of_matches,
1156                                       selection_rect, active_match_ordinal,
1157                                       final_update);
1158 }
1159 
1160 #if defined(OS_ANDROID)
1161 // FindMatchRectsReply and OnFindResultAvailable forward find-related results to
1162 // the Java TabImpl. The find actions themselves are initiated directly from
1163 // Java via FindInPageBridge.
FindMatchRectsReply(content::WebContents * web_contents,int version,const std::vector<gfx::RectF> & rects,const gfx::RectF & active_rect)1164 void TabImpl::FindMatchRectsReply(content::WebContents* web_contents,
1165                                   int version,
1166                                   const std::vector<gfx::RectF>& rects,
1167                                   const gfx::RectF& active_rect) {
1168   JNIEnv* env = AttachCurrentThread();
1169   // Create the details object.
1170   ScopedJavaLocalRef<jobject> details_object =
1171       Java_TabImpl_createFindMatchRectsDetails(
1172           env, version, rects.size(),
1173           ScopedJavaLocalRef<jobject>(Java_TabImpl_createRectF(
1174               env, active_rect.x(), active_rect.y(), active_rect.right(),
1175               active_rect.bottom())));
1176 
1177   // Add the rects.
1178   for (size_t i = 0; i < rects.size(); ++i) {
1179     const gfx::RectF& rect = rects[i];
1180     Java_TabImpl_setMatchRectByIndex(
1181         env, details_object, i,
1182         ScopedJavaLocalRef<jobject>(Java_TabImpl_createRectF(
1183             env, rect.x(), rect.y(), rect.right(), rect.bottom())));
1184   }
1185 
1186   Java_TabImpl_onFindMatchRectsAvailable(env, java_impl_, details_object);
1187 }
1188 #endif
1189 
RenderProcessGone(base::TerminationStatus status)1190 void TabImpl::RenderProcessGone(base::TerminationStatus status) {
1191 #if defined(OS_ANDROID)
1192   // If a renderer process is lost when the tab is not visible, indicate to the
1193   // WebContents that it should automatically reload the next time it becomes
1194   // visible.
1195   JNIEnv* env = AttachCurrentThread();
1196   if (Java_TabImpl_willAutomaticallyReloadAfterCrashImpl(env, java_impl_))
1197     web_contents()->GetController().SetNeedsReload();
1198 #endif
1199 
1200   for (auto& observer : observers_)
1201     observer.OnRenderProcessGone();
1202 }
1203 
OnFindResultAvailable(content::WebContents * web_contents)1204 void TabImpl::OnFindResultAvailable(content::WebContents* web_contents) {
1205 #if defined(OS_ANDROID)
1206   const find_in_page::FindNotificationDetails& find_result =
1207       GetFindTabHelper()->find_result();
1208   JNIEnv* env = AttachCurrentThread();
1209   Java_TabImpl_onFindResultAvailable(
1210       env, java_impl_, find_result.number_of_matches(),
1211       find_result.active_match_ordinal(), find_result.final_update());
1212 #endif
1213 }
1214 
1215 #if defined(OS_ANDROID)
OnBrowserControlsStateStateChanged(ControlsVisibilityReason reason,content::BrowserControlsState state)1216 void TabImpl::OnBrowserControlsStateStateChanged(
1217     ControlsVisibilityReason reason,
1218     content::BrowserControlsState state) {
1219   SetBrowserControlsConstraint(reason, state);
1220 }
1221 
OnUpdateBrowserControlsStateBecauseOfProcessSwitch(bool did_commit)1222 void TabImpl::OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
1223     bool did_commit) {
1224   // This matches the logic of updateAfterRendererProcessSwitch() and
1225   // updateEnabledState() in Chrome's TabBrowserControlsConstraintsHelper.
1226   if (did_commit &&
1227       current_browser_controls_visibility_constraint_ ==
1228           content::BROWSER_CONTROLS_STATE_SHOWN &&
1229       top_controls_container_view_ &&
1230       top_controls_container_view_->IsFullyVisible()) {
1231     // The top-control is fully visible, don't animate this else the controls
1232     // bounce around.
1233     UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_SHOWN, false);
1234   } else {
1235     if (did_commit && current_browser_controls_visibility_constraint_ ==
1236                           content::BROWSER_CONTROLS_STATE_BOTH) {
1237       // If the current state is BROWSER_CONTROLS_STATE_BOTH, then
1238       // TabImpl::UpdateBrowserControlsState() is going to call
1239       // WebContents::UpdateBrowserControlsState() with both current and
1240       // constraints set to BROWSER_CONTROLS_STATE_BOTH. cc does
1241       // nothing in this case. During a navigation the top-view needs to be
1242       // shown. To force the top-view to show, supply
1243       // BROWSER_CONTROLS_STATE_SHOWN. This path is only hit if top-view
1244       // is configured to only-expand-at-top, as in this case the top-view isn't
1245       // forced shown during a page load.
1246       //
1247       // It's entirely possible the scroll offset is changed as part of the
1248       // loading process (such as happens with back/forward navigation or
1249       // links part way down a page). Trying to detect this and compensate
1250       // here is likely to be racy, so the top-view is always shown.
1251       const bool animate =
1252           !base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest);
1253       web_contents_->GetMainFrame()->UpdateBrowserControlsState(
1254           content::BROWSER_CONTROLS_STATE_BOTH,
1255           content::BROWSER_CONTROLS_STATE_SHOWN, animate);
1256       // This falls through to call UpdateBrowserControlsState() again to
1257       // ensure the constraint is set back to BOTH.
1258     }
1259     UpdateBrowserControlsState(
1260         content::BROWSER_CONTROLS_STATE_BOTH,
1261         current_browser_controls_visibility_constraint_ !=
1262             content::BROWSER_CONTROLS_STATE_HIDDEN);
1263   }
1264 }
1265 
1266 #endif
1267 
DidChangeVisibleSecurityState()1268 void TabImpl::DidChangeVisibleSecurityState() {
1269   UpdateBrowserVisibleSecurityStateIfNecessary();
1270 }
1271 
UpdateBrowserVisibleSecurityStateIfNecessary()1272 void TabImpl::UpdateBrowserVisibleSecurityStateIfNecessary() {
1273   if (browser_ && browser_->GetActiveTab() == this)
1274     browser_->VisibleSecurityStateOfActiveTabChanged();
1275 }
1276 
OnExitFullscreen()1277 void TabImpl::OnExitFullscreen() {
1278   // If |processing_enter_fullscreen_| is true, it means the callback is being
1279   // called while processing EnterFullscreenModeForTab(). WebContents doesn't
1280   // deal well with this. FATAL as Android generally doesn't run with DCHECKs.
1281   LOG_IF(FATAL, processing_enter_fullscreen_)
1282       << "exiting fullscreen while entering fullscreen is not supported";
1283   web_contents_->ExitFullscreen(/* will_cause_resize */ false);
1284 }
1285 
UpdateRendererPrefs(bool should_sync_prefs)1286 void TabImpl::UpdateRendererPrefs(bool should_sync_prefs) {
1287   blink::RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
1288   content::UpdateFontRendererPreferencesFromSystemSettings(prefs);
1289   prefs->accept_languages = i18n::GetAcceptLangs();
1290   if (should_sync_prefs)
1291     web_contents_->SyncRendererPrefs();
1292 }
1293 
1294 #if defined(OS_ANDROID)
SetBrowserControlsConstraint(ControlsVisibilityReason reason,content::BrowserControlsState constraint)1295 void TabImpl::SetBrowserControlsConstraint(
1296     ControlsVisibilityReason reason,
1297     content::BrowserControlsState constraint) {
1298   Java_TabImpl_setBrowserControlsVisibilityConstraint(
1299       base::android::AttachCurrentThread(), java_impl_,
1300       static_cast<int>(reason), constraint);
1301 }
1302 #endif
1303 
InitializeAutofillForTests(std::unique_ptr<autofill::AutofillProvider> provider)1304 void TabImpl::InitializeAutofillForTests(
1305     std::unique_ptr<autofill::AutofillProvider> provider) {
1306   DCHECK(!autofill_provider_);
1307 
1308   autofill_provider_ = std::move(provider);
1309   InitializeAutofill();
1310 }
1311 
InitializeAutofill()1312 void TabImpl::InitializeAutofill() {
1313   DCHECK(autofill_provider_);
1314 
1315   content::WebContents* web_contents = web_contents_.get();
1316   DCHECK(
1317       !autofill::ContentAutofillDriverFactory::FromWebContents(web_contents));
1318 
1319   AutofillClientImpl::CreateForWebContents(web_contents);
1320   autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
1321       web_contents, AutofillClientImpl::FromWebContents(web_contents),
1322       i18n::GetApplicationLocale(),
1323       autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
1324       autofill_provider_.get());
1325 }
1326 
GetFindTabHelper()1327 find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() {
1328   return find_in_page::FindTabHelper::FromWebContents(web_contents_.get());
1329 }
1330 
1331 // static
GetSessionServiceTabHelperDelegate(content::WebContents * web_contents)1332 sessions::SessionTabHelperDelegate* TabImpl::GetSessionServiceTabHelperDelegate(
1333     content::WebContents* web_contents) {
1334   TabImpl* tab = FromWebContents(web_contents);
1335   return (tab && tab->browser_) ? tab->browser_->browser_persister() : nullptr;
1336 }
1337 
SetDataInternal(const std::map<std::string,std::string> & data)1338 bool TabImpl::SetDataInternal(const std::map<std::string, std::string>& data) {
1339   int total_size = 0;
1340   for (const auto& kv : data)
1341     total_size += kv.first.size() + kv.second.size();
1342   if (total_size > kMaxDataSize)
1343     return false;
1344   data_ = data;
1345   for (auto& observer : data_observers_)
1346     observer.OnDataChanged(this, data_);
1347   return true;
1348 }
1349 
1350 }  // namespace weblayer
1351