// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "weblayer/browser/tab_impl.h" #include #include "base/auto_reset.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/feature_list.h" #include "base/guid.h" #include "base/logging.h" #include "base/no_destructor.h" #include "base/task/thread_pool.h" #include "base/time/default_tick_clock.h" #include "build/build_config.h" #include "cc/layers/layer.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/common/autofill_features.h" #include "components/blocked_content/popup_blocker.h" #include "components/blocked_content/popup_blocker_tab_helper.h" #include "components/blocked_content/popup_opener_tab_helper.h" #include "components/blocked_content/popup_tracker.h" #include "components/captive_portal/core/buildflags.h" #include "components/content_settings/browser/page_specific_content_settings.h" #include "components/embedder_support/user_agent_utils.h" #include "components/find_in_page/find_tab_helper.h" #include "components/find_in_page/find_types.h" #include "components/infobars/content/content_infobar_manager.h" #include "components/js_injection/browser/js_communication_host.h" #include "components/js_injection/browser/web_message_host.h" #include "components/js_injection/browser/web_message_host_factory.h" #include "components/permissions/permission_manager.h" #include "components/permissions/permission_request_manager.h" #include "components/permissions/permission_result.h" #include "components/prefs/pref_service.h" #include "components/safe_browsing/core/browser/db/database_manager.h" #include "components/sessions/content/session_tab_helper.h" #include "components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h" #include "components/subresource_filter/content/browser/ruleset_service.h" #include "components/translate/core/browser/translate_manager.h" #include "components/ukm/content/source_url_recorder.h" #include "components/webapps/browser/installable/installable_manager.h" #include "components/webrtc/media_stream_devices_controller.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/context_menu_params.h" #include "content/public/browser/file_select_listener.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/permission_controller.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/renderer_preferences_util.h" #include "content/public/browser/web_contents.h" #include "third_party/blink/public/common/permissions/permission_utils.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" #include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h" #include "third_party/blink/public/mojom/window_features/window_features.mojom.h" #include "ui/base/window_open_disposition.h" #include "weblayer/browser/autofill_client_impl.h" #include "weblayer/browser/browser_context_impl.h" #include "weblayer/browser/browser_impl.h" #include "weblayer/browser/browser_process.h" #include "weblayer/browser/content_browser_client_impl.h" #include "weblayer/browser/favicon/favicon_fetcher_impl.h" #include "weblayer/browser/favicon/favicon_tab_helper.h" #include "weblayer/browser/file_select_helper.h" #include "weblayer/browser/host_content_settings_map_factory.h" #include "weblayer/browser/i18n_util.h" #include "weblayer/browser/js_communication/web_message_host_factory_wrapper.h" #include "weblayer/browser/navigation_controller_impl.h" #include "weblayer/browser/navigation_entry_data.h" #include "weblayer/browser/no_state_prefetch/prerender_tab_helper.h" #include "weblayer/browser/page_load_metrics_initialize.h" #include "weblayer/browser/page_specific_content_settings_delegate.h" #include "weblayer/browser/password_manager_driver_factory.h" #include "weblayer/browser/persistence/browser_persister.h" #include "weblayer/browser/popup_navigation_delegate_impl.h" #include "weblayer/browser/profile_impl.h" #include "weblayer/browser/safe_browsing/safe_browsing_service.h" #include "weblayer/browser/subresource_filter_profile_context_factory.h" #include "weblayer/browser/translate_client_impl.h" #include "weblayer/browser/weblayer_features.h" #include "weblayer/common/isolated_world_ids.h" #include "weblayer/public/fullscreen_delegate.h" #include "weblayer/public/js_communication/web_message.h" #include "weblayer/public/js_communication/web_message_host_factory.h" #include "weblayer/public/new_tab_delegate.h" #include "weblayer/public/tab_observer.h" #if !BUILDFLAG(IS_ANDROID) #include "ui/views/controls/webview/webview.h" #endif #if BUILDFLAG(IS_ANDROID) #include "base/android/callback_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/json/json_writer.h" #include "base/trace_event/trace_event.h" #include "components/android_autofill/browser/android_autofill_manager.h" #include "components/android_autofill/browser/autofill_provider.h" #include "components/android_autofill/browser/autofill_provider_android.h" #include "components/browser_ui/sms/android/sms_infobar.h" #include "components/download/content/public/context_menu_download.h" #include "components/embedder_support/android/contextmenu/context_menu_builder.h" #include "components/embedder_support/android/delegate/color_chooser_android.h" #include "components/javascript_dialogs/tab_modal_dialog_manager.h" // nogncheck #include "components/safe_browsing/android/remote_database_manager.h" #include "components/safe_browsing/content/browser/safe_browsing_navigation_observer.h" #include "components/safe_browsing/content/browser/safe_browsing_tab_observer.h" #include "components/site_engagement/content/site_engagement_helper.h" #include "components/site_engagement/content/site_engagement_service.h" #include "components/translate/core/browser/translate_manager.h" #include "ui/android/view_android.h" #include "ui/gfx/android/java_bitmap.h" #include "weblayer/browser/browser_controls_container_view.h" #include "weblayer/browser/browser_controls_navigation_state_handler.h" #include "weblayer/browser/controls_visibility_reason.h" #include "weblayer/browser/java/jni/TabImpl_jni.h" #include "weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h" #include "weblayer/browser/js_communication/web_message_host_factory_proxy.h" #include "weblayer/browser/safe_browsing/safe_browsing_navigation_observer_manager_factory.h" #include "weblayer/browser/safe_browsing/weblayer_safe_browsing_tab_observer_delegate.h" #include "weblayer/browser/translate_client_impl.h" #include "weblayer/browser/url_bar/trusted_cdn_observer.h" #include "weblayer/browser/webapps/weblayer_app_banner_manager_android.h" #include "weblayer/browser/weblayer_factory_impl_android.h" #include "weblayer/browser/webrtc/media_stream_manager.h" #include "weblayer/common/features.h" #endif #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) #include "components/captive_portal/content/captive_portal_tab_helper.h" #include "weblayer/browser/captive_portal_service_factory.h" #endif #if BUILDFLAG(IS_ANDROID) using base::android::AttachCurrentThread; using base::android::JavaParamRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; #endif namespace weblayer { namespace { // Maximum size of data when calling SetData(). constexpr int kMaxDataSize = 4096; #if BUILDFLAG(IS_ANDROID) bool g_system_autofill_disabled_for_testing = false; #endif NewTabType NewTabTypeFromWindowDisposition(WindowOpenDisposition disposition) { // WindowOpenDisposition has a *ton* of types, but the following are really // the only ones that should be hit for this code path. switch (disposition) { case WindowOpenDisposition::NEW_FOREGROUND_TAB: return NewTabType::kForeground; case WindowOpenDisposition::NEW_BACKGROUND_TAB: return NewTabType::kBackground; case WindowOpenDisposition::NEW_POPUP: return NewTabType::kNewPopup; case WindowOpenDisposition::NEW_WINDOW: return NewTabType::kNewWindow; default: // The set of allowed types are in // ContentTabClientImpl::CanCreateWindow(). NOTREACHED(); return NewTabType::kForeground; } } #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) // Opens a captive portal login page in |web_contents|. void OpenCaptivePortalLoginTabInWebContents( content::WebContents* web_contents) { content::OpenURLParams params( CaptivePortalServiceFactory::GetForBrowserContext( web_contents->GetBrowserContext()) ->test_url(), content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, false); web_contents->OpenURL(params); } #endif // Pointer value of this is used as a key in base::SupportsUserData for // WebContents. Value of the key is an instance of |UserData|. constexpr int kWebContentsUserDataKey = 0; struct UserData : public base::SupportsUserData::Data { TabImpl* tab = nullptr; }; #if BUILDFLAG(IS_ANDROID) void HandleJavaScriptResult(const ScopedJavaGlobalRef& callback, base::Value result) { std::string json; base::JSONWriter::Write(result, &json); base::android::RunStringCallbackAndroid(callback, json); } void OnConvertedToJavaBitmap(const ScopedJavaGlobalRef& value_callback, const ScopedJavaGlobalRef& java_bitmap) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); TabImpl::ScreenShotErrors error = java_bitmap ? TabImpl::ScreenShotErrors::kNone : TabImpl::ScreenShotErrors::kBitmapAllocationFailed; Java_TabImpl_runCaptureScreenShotCallback(AttachCurrentThread(), value_callback, java_bitmap, static_cast(error)); } // Convert SkBitmap to java Bitmap on a background thread since it involves a // memcpy. void ConvertToJavaBitmapBackgroundThread( const SkBitmap& bitmap, base::OnceCallback&)> callback) { // Make sure to only pass ScopedJavaGlobalRef between threads. ScopedJavaGlobalRef java_bitmap = ScopedJavaGlobalRef( gfx::ConvertToJavaBitmap(bitmap, gfx::OomBehavior::kReturnNullOnOom)); content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(std::move(callback), std::move(java_bitmap))); } void OnScreenShotCaptured(const ScopedJavaGlobalRef& value_callback, const SkBitmap& bitmap) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (bitmap.isNull() || bitmap.drawsNothing()) { Java_TabImpl_runCaptureScreenShotCallback( AttachCurrentThread(), value_callback, nullptr, static_cast(TabImpl::ScreenShotErrors::kCaptureFailed)); return; } // Not using PostTaskAndReplyWithResult to ensure ScopedJavaLocalRef is not // passed between threads. base::ThreadPool::PostTask( FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::BindOnce(&ConvertToJavaBitmapBackgroundThread, bitmap, base::BindOnce(&OnConvertedToJavaBitmap, value_callback))); } #endif // BUILDFLAG(IS_ANDROID) std::set& GetTabs() { static base::NoDestructor> s_all_tab_impl; return *s_all_tab_impl; } // Returns a scoped refptr to the SafeBrowsingService's database manager, if // available. Otherwise returns nullptr. const scoped_refptr GetDatabaseManagerFromSafeBrowsingService() { #if BUILDFLAG(IS_ANDROID) SafeBrowsingService* safe_browsing_service = BrowserProcess::GetInstance()->GetSafeBrowsingService(); return scoped_refptr( safe_browsing_service->GetSafeBrowsingDBManager()); #else return nullptr; #endif } // Creates a ContentSubresourceFilterWebContentsHelper for |web_contents|, // passing it the needed embedder-level state. void CreateContentSubresourceFilterWebContentsHelper( content::WebContents* web_contents) { subresource_filter::RulesetService* ruleset_service = BrowserProcess::GetInstance()->subresource_filter_ruleset_service(); subresource_filter::VerifiedRulesetDealer::Handle* dealer = ruleset_service ? ruleset_service->GetRulesetDealer() : nullptr; subresource_filter::ContentSubresourceFilterWebContentsHelper:: CreateForWebContents( web_contents, SubresourceFilterProfileContextFactory::GetForBrowserContext( web_contents->GetBrowserContext()), GetDatabaseManagerFromSafeBrowsingService(), dealer); } } // namespace #if BUILDFLAG(IS_ANDROID) static ScopedJavaLocalRef JNI_TabImpl_FromWebContents( JNIEnv* env, const base::android::JavaParamRef& j_web_contents) { content::WebContents* web_contents = content::WebContents::FromJavaWebContents(j_web_contents); TabImpl* tab = TabImpl::FromWebContents(web_contents); if (tab) return ScopedJavaLocalRef(tab->GetJavaTab()); return nullptr; } static void JNI_TabImpl_DestroyContextMenuParams( JNIEnv* env, jlong native_context_menu_params) { // Note: this runs on the finalizer thread which isn't the UI thread. auto* context_menu_params = reinterpret_cast(native_context_menu_params); delete context_menu_params; } TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef& java_impl, std::unique_ptr web_contents) : TabImpl(profile, std::move(web_contents)) { java_impl_ = java_impl; } #endif TabImpl::TabImpl(ProfileImpl* profile, std::unique_ptr web_contents, const std::string& guid) : profile_(profile), web_contents_(std::move(web_contents)), guid_(guid.empty() ? base::GenerateGUID() : guid) { GetTabs().insert(this); DCHECK(web_contents_); // This code path is hit when the page requests a new tab, which should // only be possible from the same profile. DCHECK_EQ(profile_->GetBrowserContext(), web_contents_->GetBrowserContext()); // FaviconTabHelper adds a WebContentsObserver. Create FaviconTabHelper // before |this| observes the WebContents to ensure favicons are reset before // notifying weblayer observers of changes. FaviconTabHelper::CreateForWebContents(web_contents_.get()); UpdateRendererPrefs(false); locale_change_subscription_ = i18n::RegisterLocaleChangeCallback(base::BindRepeating( &TabImpl::UpdateRendererPrefs, base::Unretained(this), true)); std::unique_ptr user_data = std::make_unique(); user_data->tab = this; web_contents_->SetUserData(&kWebContentsUserDataKey, std::move(user_data)); web_contents_->SetDelegate(this); Observe(web_contents_.get()); navigation_controller_ = std::make_unique(this); find_in_page::FindTabHelper::CreateForWebContents(web_contents_.get()); GetFindTabHelper()->AddObserver(this); TranslateClientImpl::CreateForWebContents(web_contents_.get()); #if BUILDFLAG(IS_ANDROID) // infobars::ContentInfoBarManager must be created before // SubresourceFilterClientImpl as the latter depends on it. infobars::ContentInfoBarManager::CreateForWebContents(web_contents_.get()); #endif CreateContentSubresourceFilterWebContentsHelper(web_contents_.get()); sessions::SessionTabHelper::CreateForWebContents( web_contents_.get(), base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate)); permissions::PermissionRequestManager::CreateForWebContents( web_contents_.get()); content_settings::PageSpecificContentSettings::CreateForWebContents( web_contents_.get(), std::make_unique( web_contents_.get())); blocked_content::PopupBlockerTabHelper::CreateForWebContents( web_contents_.get()); blocked_content::PopupOpenerTabHelper::CreateForWebContents( web_contents_.get(), base::DefaultTickClock::GetInstance(), HostContentSettingsMapFactory::GetForBrowserContext( web_contents_->GetBrowserContext())); PasswordManagerDriverFactory::CreateForWebContents(web_contents_.get()); InitializePageLoadMetricsForWebContents(web_contents_.get()); ukm::InitializeSourceUrlRecorderForWebContents(web_contents_.get()); #if BUILDFLAG(IS_ANDROID) javascript_dialogs::TabModalDialogManager::CreateForWebContents( web_contents_.get(), std::make_unique( web_contents_.get())); browser_controls_navigation_state_handler_ = std::make_unique( web_contents_.get(), this); TrustedCDNObserver::CreateForWebContents(web_contents_.get()); if (base::FeatureList::IsEnabled( features::kWebLayerClientSidePhishingDetection)) { safe_browsing::SafeBrowsingTabObserver::CreateForWebContents( web_contents_.get(), std::make_unique()); } if (site_engagement::SiteEngagementService::IsEnabled()) { site_engagement::SiteEngagementService::Helper::CreateForWebContents( web_contents_.get()); } auto* browser_context = static_cast(web_contents_->GetBrowserContext()); safe_browsing::SafeBrowsingNavigationObserver::MaybeCreateForWebContents( web_contents_.get(), HostContentSettingsMapFactory::GetForBrowserContext(browser_context), SafeBrowsingNavigationObserverManagerFactory::GetForBrowserContext( browser_context), browser_context->pref_service(), BrowserProcess::GetInstance()->GetSafeBrowsingService()); #endif #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) captive_portal::CaptivePortalTabHelper::CreateForWebContents( web_contents_.get(), CaptivePortalServiceFactory::GetForBrowserContext( web_contents_->GetBrowserContext()), base::BindRepeating(&OpenCaptivePortalLoginTabInWebContents, web_contents_.get())); #endif // PrerenderTabHelper adds a WebContentsObserver. PrerenderTabHelper::CreateForWebContents(web_contents_.get()); webapps::InstallableManager::CreateForWebContents(web_contents_.get()); #if BUILDFLAG(IS_ANDROID) // Must be created after InstallableManager. WebLayerAppBannerManagerAndroid::CreateForWebContents(web_contents_.get()); #endif } TabImpl::~TabImpl() { DCHECK(!browser_); GetFindTabHelper()->RemoveObserver(this); // Delete the WebContents and related objects that may be observing // the WebContents now to avoid calling back when this object is partially // deleted. DidFinishNavigation() may be called while deleting WebContents, // so stop observing first. Similarly WebContents destructor can callback to // delegate such as NavigationStateChanged, so clear its Delegate as well. #if BUILDFLAG(IS_ANDROID) browser_controls_navigation_state_handler_.reset(); #endif Observe(nullptr); web_contents_->SetDelegate(nullptr); if (navigation_controller_->should_delay_web_contents_deletion()) { // Some user-data on WebContents directly or indirectly references this. // Remove that linkage to avoid use-after-free. web_contents_->RemoveUserData(&kWebContentsUserDataKey); web_contents_->RemoveUserData( autofill::ContentAutofillDriverFactory:: kContentAutofillDriverFactoryWebContentsUserDataKey); // Have Profile handle the task posting to ensure the WebContents is // deleted before Profile. To do otherwise means it would be possible for // the Profile to outlive the WebContents, which is problematic (crash). profile_->DeleteWebContentsSoon(std::move(web_contents_)); } web_contents_.reset(); GetTabs().erase(this); } // static TabImpl* TabImpl::FromWebContents(content::WebContents* web_contents) { if (!web_contents) return nullptr; UserData* user_data = reinterpret_cast( web_contents->GetUserData(&kWebContentsUserDataKey)); return user_data ? user_data->tab : nullptr; } // static std::set TabImpl::GetAllTabImpl() { return GetTabs(); } void TabImpl::AddDataObserver(DataObserver* observer) { data_observers_.AddObserver(observer); } void TabImpl::RemoveDataObserver(DataObserver* observer) { data_observers_.RemoveObserver(observer); } Browser* TabImpl::GetBrowser() { return browser_; } void TabImpl::SetErrorPageDelegate(ErrorPageDelegate* delegate) { error_page_delegate_ = delegate; } void TabImpl::SetFullscreenDelegate(FullscreenDelegate* delegate) { if (delegate == fullscreen_delegate_) return; const bool had_delegate = (fullscreen_delegate_ != nullptr); const bool has_delegate = (delegate != nullptr); // If currently fullscreen, and the delegate is being set to null, force an // exit now (otherwise the delegate can't take us out of fullscreen). if (is_fullscreen_ && fullscreen_delegate_ && had_delegate != has_delegate) OnExitFullscreen(); fullscreen_delegate_ = delegate; // Whether fullscreen is enabled depends upon whether there is a delegate. If // having a delegate changed, then update the renderer (which is where // fullscreen enabled is tracked). if (had_delegate != has_delegate) web_contents_->OnWebPreferencesChanged(); } void TabImpl::SetNewTabDelegate(NewTabDelegate* delegate) { new_tab_delegate_ = delegate; } void TabImpl::SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) { google_accounts_delegate_ = delegate; } void TabImpl::AddObserver(TabObserver* observer) { observers_.AddObserver(observer); } void TabImpl::RemoveObserver(TabObserver* observer) { observers_.RemoveObserver(observer); } NavigationController* TabImpl::GetNavigationController() { return navigation_controller_.get(); } void TabImpl::ExecuteScript(const std::u16string& script, bool use_separate_isolate, JavaScriptResultCallback callback) { if (use_separate_isolate) { web_contents_->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld( script, std::move(callback), ISOLATED_WORLD_ID_WEBLAYER); } else { content::RenderFrameHost::AllowInjectingJavaScript(); web_contents_->GetPrimaryMainFrame()->ExecuteJavaScript( script, std::move(callback)); } } const std::string& TabImpl::GetGuid() { return guid_; } void TabImpl::SetData(const std::map& data) { bool result = SetDataInternal(data); DCHECK(result) << "Data given to SetData() was too large."; } const std::map& TabImpl::GetData() { return data_; } std::u16string TabImpl::AddWebMessageHostFactory( std::unique_ptr factory, const std::u16string& js_object_name, const std::vector& allowed_origin_rules) { if (!js_communication_host_) { js_communication_host_ = std::make_unique( web_contents_.get()); } return js_communication_host_->AddWebMessageHostFactory( std::make_unique(std::move(factory)), js_object_name, allowed_origin_rules); } void TabImpl::RemoveWebMessageHostFactory( const std::u16string& js_object_name) { if (js_communication_host_) js_communication_host_->RemoveWebMessageHostFactory(js_object_name); } void TabImpl::ExecuteScriptWithUserGestureForTests( const std::u16string& script) { web_contents_->GetPrimaryMainFrame() ->ExecuteJavaScriptWithUserGestureForTests(script, base::NullCallback()); } std::unique_ptr TabImpl::CreateFaviconFetcher( FaviconFetcherDelegate* delegate) { return std::make_unique(web_contents_.get(), delegate); } void TabImpl::SetTranslateTargetLanguage( const std::string& translate_target_lang) { translate::TranslateManager* translate_manager = TranslateClientImpl::FromWebContents(web_contents()) ->GetTranslateManager(); translate_manager->SetPredefinedTargetLanguage( translate_target_lang, /*should_auto_translate=*/true); } #if !BUILDFLAG(IS_ANDROID) void TabImpl::AttachToView(views::WebView* web_view) { web_view->SetWebContents(web_contents_.get()); web_contents_->Focus(); } #endif void TabImpl::WebPreferencesChanged() { web_contents_->OnWebPreferencesChanged(); } void TabImpl::SetWebPreferences(blink::web_pref::WebPreferences* prefs) { prefs->fullscreen_supported = !!fullscreen_delegate_; if (!browser_) return; browser_->SetWebPreferences(prefs); } void TabImpl::OnGainedActive() { web_contents()->GetController().LoadIfNecessary(); if (enter_fullscreen_on_gained_active_) EnterFullscreenImpl(); } void TabImpl::OnLosingActive() { if (is_fullscreen_) web_contents_->ExitFullscreen(/* will_cause_resize */ false); } bool TabImpl::IsActive() { return browser_->GetActiveTab() == this; } void TabImpl::ShowContextMenu(const content::ContextMenuParams& params) { #if BUILDFLAG(IS_ANDROID) Java_TabImpl_showContextMenu( base::android::AttachCurrentThread(), java_impl_, context_menu::BuildJavaContextMenuParams(params), reinterpret_cast(new content::ContextMenuParams(params))); #endif } #if BUILDFLAG(IS_ANDROID) // static void TabImpl::DisableAutofillSystemIntegrationForTesting() { g_system_autofill_disabled_for_testing = true; } static jlong JNI_TabImpl_CreateTab(JNIEnv* env, jlong profile, const JavaParamRef& java_impl) { ProfileImpl* profile_impl = reinterpret_cast(profile); content::WebContents::CreateParams create_params( profile_impl->GetBrowserContext()); create_params.initially_hidden = true; return reinterpret_cast(new TabImpl( profile_impl, java_impl, content::WebContents::Create(create_params))); } static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) { TabImpl* tab_impl = reinterpret_cast(tab); DCHECK(tab_impl); // RemoveTabBeforeDestroyingFromJava() should have been called before this, // which sets browser to null. DCHECK(!tab_impl->browser()); delete tab_impl; } ScopedJavaLocalRef TabImpl::GetWebContents(JNIEnv* env) { return web_contents_->GetJavaWebContents(); } void TabImpl::SetBrowserControlsContainerViews( JNIEnv* env, jlong native_top_controls_container_view, jlong native_bottom_controls_container_view) { top_controls_container_view_ = reinterpret_cast( native_top_controls_container_view); bottom_controls_container_view_ = reinterpret_cast( native_bottom_controls_container_view); } void TabImpl::ExecuteScript(JNIEnv* env, const JavaParamRef& script, bool use_separate_isolate, const JavaParamRef& callback) { ScopedJavaGlobalRef jcallback(env, callback); ExecuteScript(base::android::ConvertJavaStringToUTF16(script), use_separate_isolate, base::BindOnce(&HandleJavaScriptResult, jcallback)); } void TabImpl::SetJavaImpl(JNIEnv* env, const JavaParamRef& impl) { // This should only be called early on and only once. DCHECK(!java_impl_); java_impl_ = impl; } void TabImpl::InitializeAutofillIfNecessary(JNIEnv* env) { if (g_system_autofill_disabled_for_testing) return; if (!autofill::ContentAutofillDriverFactory::FromWebContents( web_contents_.get())) { InitializeAutofillDriver(); } } void TabImpl::UpdateBrowserControlsConstraint(JNIEnv* env, jint constraint, jboolean animate) { current_browser_controls_visibility_constraint_ = static_cast(constraint); // Passing BOTH here means that it doesn't matter what state the controls are // currently in; don't change the current state unless it's incompatible with // the new constraint. UpdateBrowserControlsState(cc::BrowserControlsState::kBoth, animate); } ScopedJavaLocalRef TabImpl::GetGuid(JNIEnv* env) { return base::android::ConvertUTF8ToJavaString(AttachCurrentThread(), GetGuid()); } TabImpl::ScreenShotErrors TabImpl::PrepareForCaptureScreenShot( float scale, content::RenderWidgetHostView** rwhv, gfx::Rect* src_rect, gfx::Size* output_size) { if (scale <= 0.f || scale > 1.f) return ScreenShotErrors::kScaleOutOfRange; if (!IsActive()) return ScreenShotErrors::kTabNotActive; if (web_contents_->GetVisibility() != content::Visibility::VISIBLE) return ScreenShotErrors::kWebContentsNotVisible; if (!browser_ || !browser_->CompositorHasSurface()) return ScreenShotErrors::kNoSurface; *rwhv = web_contents_->GetTopLevelRenderWidgetHostView(); if (!*rwhv) return ScreenShotErrors::kNoRenderWidgetHostView; if (!(*rwhv)->GetNativeView()->GetWindowAndroid()) return ScreenShotErrors::kNoWindowAndroid; *src_rect = gfx::Rect(web_contents_->GetNativeView()->GetPhysicalBackingSize()); if (src_rect->IsEmpty()) return ScreenShotErrors::kEmptyViewport; const int reduced_height = src_rect->height() - top_controls_container_view_->GetContentHeightDelta() - bottom_controls_container_view_->GetContentHeightDelta(); if (reduced_height <= 0) return ScreenShotErrors::kHiddenByControls; src_rect->set_height(reduced_height); *output_size = gfx::ScaleToCeiledSize(src_rect->size(), scale, scale); if (output_size->IsEmpty()) return ScreenShotErrors::kScaledToEmpty; return ScreenShotErrors::kNone; } void TabImpl::UpdateBrowserControlsState(cc::BrowserControlsState new_state, bool animate) { if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest)) animate = false; // The constraint is managed by Java code, so re-use the existing constraint // and only update the desired state. web_contents_->UpdateBrowserControlsState( current_browser_controls_visibility_constraint_, new_state, animate); } void TabImpl::CaptureScreenShot( JNIEnv* env, jfloat scale, const base::android::JavaParamRef& value_callback) { content::RenderWidgetHostView* rwhv = nullptr; gfx::Rect src_rect; gfx::Size output_size; ScreenShotErrors error = PrepareForCaptureScreenShot(scale, &rwhv, &src_rect, &output_size); if (error != ScreenShotErrors::kNone) { Java_TabImpl_runCaptureScreenShotCallback( env, ScopedJavaLocalRef(value_callback), ScopedJavaLocalRef(), static_cast(error)); return; } rwhv->CopyFromSurface( src_rect, output_size, base::BindOnce(&OnScreenShotCaptured, ScopedJavaGlobalRef(value_callback))); } jboolean TabImpl::SetData( JNIEnv* env, const base::android::JavaParamRef& data) { std::vector flattened_map; base::android::AppendJavaStringArrayToStringVector(env, data, &flattened_map); std::map data_map; for (size_t i = 0; i < flattened_map.size(); i += 2) { data_map.insert({flattened_map[i], flattened_map[i + 1]}); } return SetDataInternal(data_map); } base::android::ScopedJavaLocalRef TabImpl::GetData(JNIEnv* env) { std::vector flattened_map; for (const auto& kv : data_) { flattened_map.push_back(kv.first); flattened_map.push_back(kv.second); } return base::android::ToJavaArrayOfStrings(env, flattened_map); } jboolean TabImpl::IsRendererControllingBrowserControlsOffsets(JNIEnv* env) { return browser_controls_navigation_state_handler_ ->IsRendererControllingOffsets(); } base::android::ScopedJavaLocalRef TabImpl::RegisterWebMessageCallback( JNIEnv* env, const base::android::JavaParamRef& js_object_name, const base::android::JavaParamRef& js_origins, const base::android::JavaParamRef& client) { auto proxy = std::make_unique(client); std::vector origins; base::android::AppendJavaStringArrayToStringVector(env, js_origins, &origins); std::u16string result = AddWebMessageHostFactory( std::move(proxy), base::android::ConvertJavaStringToUTF16(env, js_object_name), origins); return base::android::ConvertUTF16ToJavaString(env, result); } void TabImpl::UnregisterWebMessageCallback( JNIEnv* env, const base::android::JavaParamRef& js_object_name) { std::u16string name; base::android::ConvertJavaStringToUTF16(env, js_object_name, &name); RemoveWebMessageHostFactory(name); } jboolean TabImpl::CanTranslate(JNIEnv* env) { return TranslateClientImpl::FromWebContents(web_contents()) ->GetTranslateManager() ->CanManuallyTranslate(); } void TabImpl::ShowTranslateUi(JNIEnv* env) { TranslateClientImpl::FromWebContents(web_contents()) ->ShowTranslateUiWhenReady(); } void TabImpl::RemoveTabFromBrowserBeforeDestroying(JNIEnv* env) { DCHECK(browser_); browser_->RemoveTabBeforeDestroyingFromJava(this); } void TabImpl::SetTranslateTargetLanguage( JNIEnv* env, const base::android::JavaParamRef& translate_target_lang) { SetTranslateTargetLanguage( base::android::ConvertJavaStringToUTF8(env, translate_target_lang)); } void TabImpl::SetDesktopUserAgentEnabled(JNIEnv* env, jboolean enable) { if (desktop_user_agent_enabled_ == enable) return; desktop_user_agent_enabled_ = enable; // Reset state that an earlier call to Navigation::SetUserAgentString() // could have modified. embedder_support::SetDesktopUserAgentOverride( web_contents_.get(), embedder_support::GetUserAgentMetadata(), /* override_in_new_tabs= */ false); web_contents_->SetRendererInitiatedUserAgentOverrideOption( content::NavigationController::UA_OVERRIDE_INHERIT); content::NavigationEntry* entry = web_contents_->GetController().GetLastCommittedEntry(); if (!entry) return; entry->SetIsOverridingUserAgent(enable); web_contents_->NotifyPreferencesChanged(); web_contents_->GetController().Reload( content::ReloadType::ORIGINAL_REQUEST_URL, true); } jboolean TabImpl::IsDesktopUserAgentEnabled(JNIEnv* env) { auto* entry = web_contents_->GetController().GetLastCommittedEntry(); if (!entry) return false; // The same user agent override mechanism is used for per-navigation user // agent and desktop mode. Make sure not to return desktop mode for // navigation entries which used a per-navigation user agent. auto* entry_data = NavigationEntryData::Get(entry); if (entry_data && entry_data->per_navigation_user_agent_override()) return false; return entry->GetIsOverridingUserAgent(); } void TabImpl::Download(JNIEnv* env, jlong native_context_menu_params) { auto* context_menu_params = reinterpret_cast(native_context_menu_params); bool is_link = context_menu_params->media_type != blink::mojom::ContextMenuDataMediaType::kImage && context_menu_params->media_type != blink::mojom::ContextMenuDataMediaType::kVideo; download::CreateContextMenuDownload(web_contents_.get(), *context_menu_params, std::string(), is_link); } #endif // BUILDFLAG(IS_ANDROID) content::WebContents* TabImpl::OpenURLFromTab( content::WebContents* source, const content::OpenURLParams& params) { if (blocked_content::ConsiderForPopupBlocking(params.disposition)) { bool blocked = blocked_content::MaybeBlockPopup( source, nullptr, std::make_unique( params, source, nullptr), ¶ms, blink::mojom::WindowFeatures(), HostContentSettingsMapFactory::GetForBrowserContext( source->GetBrowserContext())) == nullptr; if (blocked) return nullptr; } if (params.disposition == WindowOpenDisposition::CURRENT_TAB) { source->GetController().LoadURLWithParams( content::NavigationController::LoadURLParams(params)); return source; } // All URLs not opening in the current tab will get a new tab. std::unique_ptr new_tab_contents = content::WebContents::Create(content::WebContents::CreateParams( web_contents()->GetBrowserContext())); base::WeakPtr new_tab_contents_weak_ptr( new_tab_contents->GetWeakPtr()); bool was_blocked = false; AddNewContents(web_contents(), std::move(new_tab_contents), params.url, params.disposition, {}, params.user_gesture, &was_blocked); if (was_blocked || !new_tab_contents_weak_ptr) return nullptr; new_tab_contents_weak_ptr->GetController().LoadURLWithParams( content::NavigationController::LoadURLParams(params)); return new_tab_contents_weak_ptr.get(); } void TabImpl::ShowRepostFormWarningDialog(content::WebContents* source) { #if BUILDFLAG(IS_ANDROID) Java_TabImpl_showRepostFormWarningDialog(base::android::AttachCurrentThread(), java_impl_); #else source->GetController().CancelPendingReload(); #endif } void TabImpl::NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) { DCHECK_EQ(web_contents_.get(), source); if (changed_flags & content::INVALIDATE_TYPE_URL) { for (auto& observer : observers_) observer.DisplayedUrlChanged(source->GetVisibleURL()); UpdateBrowserVisibleSecurityStateIfNecessary(); } // TODO(crbug.com/1064582): INVALIDATE_TYPE_TITLE is called only when a title // is set on the active navigation entry, but not when the active entry // changes, so check INVALIDATE_TYPE_LOAD here as well. However this should // be fixed and INVALIDATE_TYPE_LOAD should be removed. if (changed_flags & (content::INVALIDATE_TYPE_TITLE | content::INVALIDATE_TYPE_LOAD)) { std::u16string title = web_contents_->GetTitle(); if (title_ != title) { title_ = title; for (auto& observer : observers_) observer.OnTitleUpdated(title); } } } content::JavaScriptDialogManager* TabImpl::GetJavaScriptDialogManager( content::WebContents* web_contents) { #if BUILDFLAG(IS_ANDROID) return javascript_dialogs::TabModalDialogManager::FromWebContents( web_contents); #else return nullptr; #endif } #if BUILDFLAG(IS_ANDROID) std::unique_ptr TabImpl::OpenColorChooser( content::WebContents* web_contents, SkColor color, const std::vector& suggestions) { return std::make_unique( web_contents, color, suggestions); } #endif void TabImpl::CreateSmsPrompt(content::RenderFrameHost* render_frame_host, const std::vector& origin_list, const std::string& one_time_code, base::OnceClosure on_confirm, base::OnceClosure on_cancel) { #if BUILDFLAG(IS_ANDROID) auto* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); sms::SmsInfoBar::Create( web_contents, infobars::ContentInfoBarManager::FromWebContents(web_contents), origin_list, one_time_code, std::move(on_confirm), std::move(on_cancel)); #else NOTREACHED(); #endif } void TabImpl::RunFileChooser( content::RenderFrameHost* render_frame_host, scoped_refptr listener, const blink::mojom::FileChooserParams& params) { FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener), params); } int TabImpl::GetTopControlsHeight() { #if BUILDFLAG(IS_ANDROID) return top_controls_container_view_ ? top_controls_container_view_->GetControlsHeight() : 0; #else return 0; #endif } int TabImpl::GetTopControlsMinHeight() { #if BUILDFLAG(IS_ANDROID) return top_controls_container_view_ ? top_controls_container_view_->GetMinHeight() : 0; #else return 0; #endif } int TabImpl::GetBottomControlsHeight() { #if BUILDFLAG(IS_ANDROID) return bottom_controls_container_view_ ? bottom_controls_container_view_->GetControlsHeight() : 0; #else return 0; #endif } bool TabImpl::DoBrowserControlsShrinkRendererSize( content::WebContents* web_contents) { #if BUILDFLAG(IS_ANDROID) TRACE_EVENT0("weblayer", "Java_TabImpl_doBrowserControlsShrinkRendererSize"); return Java_TabImpl_doBrowserControlsShrinkRendererSize(AttachCurrentThread(), java_impl_); #else return false; #endif } bool TabImpl::ShouldAnimateBrowserControlsHeightChanges() { #if BUILDFLAG(IS_ANDROID) return top_controls_container_view_ ? top_controls_container_view_ ->ShouldAnimateBrowserControlsHeightChanges() : false; #else return false; #endif } bool TabImpl::OnlyExpandTopControlsAtPageTop() { #if BUILDFLAG(IS_ANDROID) return top_controls_container_view_ ? top_controls_container_view_->OnlyExpandControlsAtPageTop() : false; #else return false; #endif } bool TabImpl::IsBackForwardCacheSupported() { return true; } void TabImpl::RequestMediaAccessPermission( content::WebContents* web_contents, const content::MediaStreamRequest& request, content::MediaResponseCallback callback) { #if BUILDFLAG(IS_ANDROID) MediaStreamManager::FromWebContents(web_contents) ->RequestMediaAccessPermission(request, std::move(callback)); #else std::move(callback).Run(blink::mojom::StreamDevicesSet(), blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr); #endif } bool TabImpl::CheckMediaAccessPermission( content::RenderFrameHost* render_frame_host, const GURL& security_origin, blink::mojom::MediaStreamType type) { DCHECK(type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE || type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE); blink::PermissionType permission_type = type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ? blink::PermissionType::AUDIO_CAPTURE : blink::PermissionType::VIDEO_CAPTURE; // TODO(crbug.com/1321100): Remove `security_origin`. if (render_frame_host->GetLastCommittedOrigin().GetURL() != security_origin) { return false; } // It is OK to ignore `security_origin` because it will be calculated from // `render_frame_host` and we always ignore `requesting_origin` for // `AUDIO_CAPTURE` and `VIDEO_CAPTURE`. // `render_frame_host->GetMainFrame()->GetLastCommittedOrigin()` will be used // instead. return render_frame_host->GetBrowserContext() ->GetPermissionController() ->GetPermissionStatusForCurrentDocument(permission_type, render_frame_host) == blink::mojom::PermissionStatus::GRANTED; } void TabImpl::EnterFullscreenModeForTab( content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) { // TODO(crbug.com/1232147): support |options|. if (is_fullscreen_) { // Typically EnterFullscreenModeForTab() should not be called consecutively, // but there may be corner cases with oopif that lead to multiple // consecutive calls. Avoid notifying the delegate in this case. return; } is_fullscreen_ = true; if (!IsActive()) { // Process the request the tab is made active. enter_fullscreen_on_gained_active_ = true; return; } EnterFullscreenImpl(); } void TabImpl::ExitFullscreenModeForTab(content::WebContents* web_contents) { weak_ptr_factory_for_fullscreen_exit_.InvalidateWeakPtrs(); is_fullscreen_ = false; if (enter_fullscreen_on_gained_active_) enter_fullscreen_on_gained_active_ = false; else fullscreen_delegate_->ExitFullscreen(); #if BUILDFLAG(IS_ANDROID) // Attempt to show browser controls when exiting fullscreen. SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen, cc::BrowserControlsState::kBoth); #endif } bool TabImpl::IsFullscreenForTabOrPending( const content::WebContents* web_contents) { return is_fullscreen_; } blink::mojom::DisplayMode TabImpl::GetDisplayMode( const content::WebContents* web_contents) { return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen : blink::mojom::DisplayMode::kBrowser; } void TabImpl::AddNewContents(content::WebContents* source, std::unique_ptr new_contents, const GURL& target_url, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, bool* was_blocked) { if (!new_tab_delegate_) { *was_blocked = true; return; } // At this point the |new_contents| is beyond the popup blocker, but we use // the same logic for determining if the popup tracker needs to be attached. if (source && blocked_content::ConsiderForPopupBlocking(disposition)) { blocked_content::PopupTracker::CreateForWebContents(new_contents.get(), source, disposition); } new_tab_delegate_->OnNewTab(browser_->CreateTab(std::move(new_contents)), NewTabTypeFromWindowDisposition(disposition)); } void TabImpl::CloseContents(content::WebContents* source) { // The only time that |browser_| is null is during shutdown, and this callback // shouldn't come in at that time. DCHECK(browser_); #if BUILDFLAG(IS_ANDROID) JNIEnv* env = AttachCurrentThread(); Java_TabImpl_handleCloseFromWebContents(env, java_impl_); // The above call resulted in the destruction of this; nothing to do but // return. #else browser_->DestroyTab(this); #endif } void TabImpl::FindReply(content::WebContents* web_contents, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) { GetFindTabHelper()->HandleFindReply(request_id, number_of_matches, selection_rect, active_match_ordinal, final_update); } #if BUILDFLAG(IS_ANDROID) // FindMatchRectsReply and OnFindResultAvailable forward find-related results to // the Java TabImpl. The find actions themselves are initiated directly from // Java via FindInPageBridge. void TabImpl::FindMatchRectsReply(content::WebContents* web_contents, int version, const std::vector& rects, const gfx::RectF& active_rect) { JNIEnv* env = AttachCurrentThread(); // Create the details object. ScopedJavaLocalRef details_object = Java_TabImpl_createFindMatchRectsDetails( env, version, rects.size(), ScopedJavaLocalRef(Java_TabImpl_createRectF( env, active_rect.x(), active_rect.y(), active_rect.right(), active_rect.bottom()))); // Add the rects. for (size_t i = 0; i < rects.size(); ++i) { const gfx::RectF& rect = rects[i]; Java_TabImpl_setMatchRectByIndex( env, details_object, i, ScopedJavaLocalRef(Java_TabImpl_createRectF( env, rect.x(), rect.y(), rect.right(), rect.bottom()))); } Java_TabImpl_onFindMatchRectsAvailable(env, java_impl_, details_object); } #endif void TabImpl::PrimaryMainFrameRenderProcessGone( base::TerminationStatus status) { #if BUILDFLAG(IS_ANDROID) // If a renderer process is lost when the tab is not visible, indicate to the // WebContents that it should automatically reload the next time it becomes // visible. JNIEnv* env = AttachCurrentThread(); if (Java_TabImpl_willAutomaticallyReloadAfterCrashImpl(env, java_impl_)) web_contents()->GetController().SetNeedsReload(); #endif for (auto& observer : observers_) observer.OnRenderProcessGone(); } void TabImpl::OnFindResultAvailable(content::WebContents* web_contents) { #if BUILDFLAG(IS_ANDROID) const find_in_page::FindNotificationDetails& find_result = GetFindTabHelper()->find_result(); JNIEnv* env = AttachCurrentThread(); Java_TabImpl_onFindResultAvailable( env, java_impl_, find_result.number_of_matches(), find_result.active_match_ordinal(), find_result.final_update()); #endif } #if BUILDFLAG(IS_ANDROID) void TabImpl::OnBrowserControlsStateStateChanged( ControlsVisibilityReason reason, cc::BrowserControlsState state) { SetBrowserControlsConstraint(reason, state); } void TabImpl::OnUpdateBrowserControlsStateBecauseOfProcessSwitch( bool did_commit) { // This matches the logic of updateAfterRendererProcessSwitch() and // updateEnabledState() in Chrome's TabBrowserControlsConstraintsHelper. if (did_commit && current_browser_controls_visibility_constraint_ == cc::BrowserControlsState::kShown && top_controls_container_view_ && top_controls_container_view_->IsFullyVisible()) { // The top-control is fully visible, don't animate this else the controls // bounce around. UpdateBrowserControlsState(cc::BrowserControlsState::kShown, false); } else { if (did_commit && current_browser_controls_visibility_constraint_ == cc::BrowserControlsState::kBoth) { // If the current state is kBoth, then // TabImpl::UpdateBrowserControlsState() is going to call // WebContents::UpdateBrowserControlsState() with both current and // constraints set to kBoth. cc does // nothing in this case. During a navigation the top-view needs to be // shown. To force the top-view to show, supply // kShown. This path is only hit if top-view // is configured to only-expand-at-top, as in this case the top-view isn't // forced shown during a page load. // // It's entirely possible the scroll offset is changed as part of the // loading process (such as happens with back/forward navigation or // links part way down a page). Trying to detect this and compensate // here is likely to be racy, so the top-view is always shown. const bool animate = !base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest); web_contents_->UpdateBrowserControlsState( cc::BrowserControlsState::kBoth, cc::BrowserControlsState::kShown, animate); // This falls through to call UpdateBrowserControlsState() again to // ensure the constraint is set back to BOTH. } UpdateBrowserControlsState( cc::BrowserControlsState::kBoth, current_browser_controls_visibility_constraint_ != cc::BrowserControlsState::kHidden); } } #endif void TabImpl::DidChangeVisibleSecurityState() { UpdateBrowserVisibleSecurityStateIfNecessary(); } void TabImpl::UpdateBrowserVisibleSecurityStateIfNecessary() { if (browser_ && browser_->GetActiveTab() == this) browser_->VisibleSecurityStateOfActiveTabChanged(); } void TabImpl::OnExitFullscreen() { // If |processing_enter_fullscreen_| is true, it means the callback is being // called while processing EnterFullscreenModeForTab(). WebContents doesn't // deal well with this. FATAL as Android generally doesn't run with DCHECKs. LOG_IF(FATAL, processing_enter_fullscreen_) << "exiting fullscreen while entering fullscreen is not supported"; web_contents_->ExitFullscreen(/* will_cause_resize */ false); } void TabImpl::UpdateRendererPrefs(bool should_sync_prefs) { blink::RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs(); content::UpdateFontRendererPreferencesFromSystemSettings(prefs); prefs->accept_languages = i18n::GetAcceptLangs(); if (should_sync_prefs) web_contents_->SyncRendererPrefs(); } #if BUILDFLAG(IS_ANDROID) void TabImpl::SetBrowserControlsConstraint( ControlsVisibilityReason reason, cc::BrowserControlsState constraint) { Java_TabImpl_setBrowserControlsVisibilityConstraint( base::android::AttachCurrentThread(), java_impl_, static_cast(reason), static_cast(constraint)); } void TabImpl::InitializeAutofillForTests() { InitializeAutofillDriver(); } void TabImpl::InitializeAutofillDriver() { content::WebContents* web_contents = web_contents_.get(); DCHECK( !autofill::ContentAutofillDriverFactory::FromWebContents(web_contents)); DCHECK(autofill::AutofillProvider::FromWebContents(web_contents)); AutofillClientImpl::CreateForWebContents(web_contents); autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, AutofillClientImpl::FromWebContents(web_contents), base::BindRepeating(&autofill::AndroidDriverInitHook, AutofillClientImpl::FromWebContents(web_contents), autofill::AutofillManager::EnableDownloadManager( !autofill::AutofillProvider:: is_download_manager_disabled_for_testing()))); } #endif // BUILDFLAG(IS_ANDROID) find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() { return find_in_page::FindTabHelper::FromWebContents(web_contents_.get()); } // static sessions::SessionTabHelperDelegate* TabImpl::GetSessionServiceTabHelperDelegate( content::WebContents* web_contents) { TabImpl* tab = FromWebContents(web_contents); return (tab && tab->browser_) ? tab->browser_->browser_persister() : nullptr; } bool TabImpl::SetDataInternal(const std::map& data) { int total_size = 0; for (const auto& kv : data) total_size += kv.first.size() + kv.second.size(); if (total_size > kMaxDataSize) return false; data_ = data; for (auto& observer : data_observers_) observer.OnDataChanged(this, data_); return true; } void TabImpl::EnterFullscreenImpl() { // This ensures the existing callback is ignored. weak_ptr_factory_for_fullscreen_exit_.InvalidateWeakPtrs(); auto exit_fullscreen_closure = base::BindOnce(&TabImpl::OnExitFullscreen, weak_ptr_factory_for_fullscreen_exit_.GetWeakPtr()); base::AutoReset reset(&processing_enter_fullscreen_, true); fullscreen_delegate_->EnterFullscreen(std::move(exit_fullscreen_closure)); #if BUILDFLAG(IS_ANDROID) // Make sure browser controls cannot show when the tab is fullscreen. SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen, cc::BrowserControlsState::kHidden); #endif } } // namespace weblayer