blob: a6671b0335aa33bee6d7566b190570fa638d7f15 [file] [log] [blame]
// 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 "base/auto_reset.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_provider.h"
#include "components/captive_portal/core/buildflags.h"
#include "components/find_in_page/find_tab_helper.h"
#include "components/find_in_page/find_types.h"
#include "components/sessions/content/session_tab_helper.h"
#include "content/public/browser/file_select_listener.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/renderer_preferences_util.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
#include "ui/base/window_open_disposition.h"
#include "weblayer/browser/autofill_client_impl.h"
#include "weblayer/browser/browser_impl.h"
#include "weblayer/browser/file_select_helper.h"
#include "weblayer/browser/i18n_util.h"
#include "weblayer/browser/isolated_world_ids.h"
#include "weblayer/browser/navigation_controller_impl.h"
#include "weblayer/browser/persistence/browser_persister.h"
#include "weblayer/browser/profile_impl.h"
#include "weblayer/public/download_delegate.h"
#include "weblayer/public/fullscreen_delegate.h"
#include "weblayer/public/new_tab_delegate.h"
#include "weblayer/public/tab_observer.h"
#if !defined(OS_ANDROID)
#include "ui/views/controls/webview/webview.h"
#endif
#if defined(OS_ANDROID)
#include "base/android/callback_android.h"
#include "base/android/jni_string.h"
#include "base/json/json_writer.h"
#include "base/trace_event/trace_event.h"
#include "components/autofill/android/autofill_provider_android.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 "ui/android/view_android.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/top_controls_container_view.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 defined(OS_ANDROID)
using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
#endif
namespace weblayer {
namespace {
#if defined(OS_ANDROID)
const base::Feature kImmediatelyHideBrowserControlsForTest{
"ImmediatelyHideBrowserControlsForTest", base::FEATURE_DISABLED_BY_DEFAULT};
// The time that must elapse after a navigation before the browser controls can
// be hidden. This value matches what chrome has in
// TabStateBrowserControlsVisibilityDelegate.
base::TimeDelta GetBrowserControlsAllowHideDelay() {
if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest))
return base::TimeDelta();
return base::TimeDelta::FromSeconds(3);
}
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) {
// In Chrome this opens in a new tab, but WebLayer's TabImpl has no support
// for opening new tabs (its OpenURLFromTab() method DCHECKs if the
// disposition is not |CURRENT_TAB|).
// TODO(crbug.com/1047130): Revisit if TabImpl gets support for opening URLs
// in new tabs.
content::OpenURLParams params(
CaptivePortalServiceFactory::GetForBrowserContext(
web_contents->GetBrowserContext())
->test_url(),
content::Referrer(), WindowOpenDisposition::CURRENT_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* controller = nullptr;
};
#if defined(OS_ANDROID)
Tab* g_last_tab;
void HandleJavaScriptResult(
const base::android::ScopedJavaGlobalRef<jobject>& callback,
base::Value result) {
std::string json;
base::JSONWriter::Write(result, &json);
base::android::RunStringCallbackAndroid(callback, json);
}
#endif
} // namespace
#if defined(OS_ANDROID)
TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef<jobject>& java_impl)
: TabImpl(profile) {
java_impl_ = java_impl;
}
#endif
TabImpl::TabImpl(ProfileImpl* profile,
std::unique_ptr<content::WebContents> web_contents)
: profile_(profile), web_contents_(std::move(web_contents)) {
#if defined(OS_ANDROID)
g_last_tab = this;
#endif
if (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());
} else {
content::WebContents::CreateParams create_params(
profile_->GetBrowserContext());
web_contents_ = content::WebContents::Create(create_params);
}
UpdateRendererPrefs(false);
locale_change_subscription_ =
i18n::RegisterLocaleChangeCallback(base::BindRepeating(
&TabImpl::UpdateRendererPrefs, base::Unretained(this), true));
std::unique_ptr<UserData> user_data = std::make_unique<UserData>();
user_data->controller = this;
web_contents_->SetUserData(&kWebContentsUserDataKey, std::move(user_data));
web_contents_->SetDelegate(this);
Observe(web_contents_.get());
navigation_controller_ = std::make_unique<NavigationControllerImpl>(this);
find_in_page::FindTabHelper::CreateForWebContents(web_contents_.get());
GetFindTabHelper()->AddObserver(this);
sessions::SessionTabHelper::CreateForWebContents(
web_contents_.get(),
base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate,
base::Unretained(this)));
#if defined(OS_ANDROID)
javascript_dialogs::TabModalDialogManager::CreateForWebContents(
web_contents_.get(),
std::make_unique<JavaScriptTabModalDialogManagerDelegateAndroid>(
web_contents_.get()));
#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
}
TabImpl::~TabImpl() {
DCHECK(!browser_);
GetFindTabHelper()->RemoveObserver(this);
// Destruct WebContents now to avoid it calling back when this object is
// partially destructed. DidFinishNavigation can be called while destroying
// WebContents, so stop observing first.
Observe(nullptr);
web_contents_.reset();
}
// static
TabImpl* TabImpl::FromWebContents(content::WebContents* web_contents) {
return reinterpret_cast<UserData*>(
web_contents->GetUserData(&kWebContentsUserDataKey))
->controller;
}
void TabImpl::SetDownloadDelegate(DownloadDelegate* delegate) {
download_delegate_ = delegate;
}
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).
content::RenderViewHost* host = web_contents_->GetRenderViewHost();
if (had_delegate != has_delegate && host)
host->OnWebkitPreferencesChanged();
}
void TabImpl::SetNewTabDelegate(NewTabDelegate* delegate) {
new_tab_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 base::string16& script,
bool use_separate_isolate,
JavaScriptResultCallback callback) {
if (use_separate_isolate) {
web_contents_->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(
script, std::move(callback), ISOLATED_WORLD_ID_WEBLAYER);
} else {
content::RenderFrameHost::AllowInjectingJavaScript();
web_contents_->GetMainFrame()->ExecuteJavaScript(script,
std::move(callback));
}
}
void TabImpl::ExecuteScriptWithUserGestureForTests(
const base::string16& script) {
web_contents_->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
script);
}
#if !defined(OS_ANDROID)
void TabImpl::AttachToView(views::WebView* web_view) {
web_view->SetWebContents(web_contents_.get());
web_contents_->Focus();
}
#endif
bool TabImpl::IsActive() {
return browser_->GetActiveTab() == this;
}
void TabImpl::ShowContextMenu(const content::ContextMenuParams& params) {
#if defined(OS_ANDROID)
Java_TabImpl_showContextMenu(
base::android::AttachCurrentThread(), java_impl_,
context_menu::BuildJavaContextMenuParams(params));
#endif
}
#if defined(OS_ANDROID)
// static
void TabImpl::DisableAutofillSystemIntegrationForTesting() {
g_system_autofill_disabled_for_testing = true;
}
static jlong JNI_TabImpl_CreateTab(JNIEnv* env,
jlong profile,
const JavaParamRef<jobject>& java_impl) {
return reinterpret_cast<intptr_t>(
new TabImpl(reinterpret_cast<ProfileImpl*>(profile), java_impl));
}
static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) {
std::unique_ptr<Tab> owned_tab;
TabImpl* tab_impl = reinterpret_cast<TabImpl*>(tab);
DCHECK(tab_impl);
if (tab_impl->browser())
owned_tab = tab_impl->browser()->RemoveTab(tab_impl);
else
owned_tab.reset(tab_impl);
}
ScopedJavaLocalRef<jobject> TabImpl::GetWebContents(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
return web_contents_->GetJavaWebContents();
}
void TabImpl::SetTopControlsContainerView(
JNIEnv* env,
const JavaParamRef<jobject>& caller,
jlong native_top_controls_container_view) {
top_controls_container_view_ = reinterpret_cast<TopControlsContainerView*>(
native_top_controls_container_view);
}
void TabImpl::ExecuteScript(JNIEnv* env,
const JavaParamRef<jstring>& script,
bool use_separate_isolate,
const JavaParamRef<jobject>& callback) {
base::android::ScopedJavaGlobalRef<jobject> jcallback(env, callback);
ExecuteScript(base::android::ConvertJavaStringToUTF16(script),
use_separate_isolate,
base::BindOnce(&HandleJavaScriptResult, jcallback));
}
void TabImpl::SetJavaImpl(JNIEnv* env, const JavaParamRef<jobject>& impl) {
// This should only be called early on and only once.
DCHECK(!java_impl_);
java_impl_ = impl;
}
void TabImpl::OnAutofillProviderChanged(
JNIEnv* env,
const JavaParamRef<jobject>& autofill_provider) {
if (g_system_autofill_disabled_for_testing)
return;
if (!autofill_provider_) {
// The first invocation should be when instantiating the autofill
// infrastructure, at which point the Java-side object should not be null.
DCHECK(autofill_provider);
// Initialize the native side of the autofill infrastructure.
autofill_provider_ = std::make_unique<autofill::AutofillProviderAndroid>(
autofill_provider, web_contents_.get());
InitializeAutofill();
return;
}
// The AutofillProvider Java object has been changed; inform
// |autofill_provider_|.
auto* provider =
static_cast<autofill::AutofillProviderAndroid*>(autofill_provider_.get());
provider->OnJavaAutofillProviderChanged(env, autofill_provider);
}
void TabImpl::UpdateBrowserControlsState(JNIEnv* env, jint constraint) {
auto state_constraint =
static_cast<content::BrowserControlsState>(constraint);
content::BrowserControlsState current_state =
content::BROWSER_CONTROLS_STATE_SHOWN;
// Animate unless hiding the controls. Show the controls now, unless that's
// not allowed.
bool animate = true;
if (state_constraint == content::BROWSER_CONTROLS_STATE_HIDDEN) {
current_state = content::BROWSER_CONTROLS_STATE_BOTH;
animate = false;
}
web_contents_->GetMainFrame()->UpdateBrowserControlsState(
state_constraint, current_state, animate);
if (web_contents_->ShowingInterstitialPage()) {
web_contents_->GetInterstitialPage()
->GetMainFrame()
->UpdateBrowserControlsState(state_constraint, current_state, animate);
}
}
#endif
content::WebContents* TabImpl::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
NOTIMPLEMENTED();
return nullptr;
}
source->GetController().LoadURLWithParams(
content::NavigationController::LoadURLParams(params));
return source;
}
void TabImpl::DidNavigateMainFramePostCommit(
content::WebContents* web_contents) {
for (auto& observer : observers_)
observer.DisplayedUrlChanged(web_contents->GetVisibleURL());
}
content::JavaScriptDialogManager* TabImpl::GetJavaScriptDialogManager(
content::WebContents* web_contents) {
#if defined(OS_ANDROID)
// Simply ignore javascript dialog requests from non-foremost tabs.
// TODO(crbug.com/1025256): revisit this behavior.
if (!IsActive())
return nullptr;
return javascript_dialogs::TabModalDialogManager::FromWebContents(
web_contents);
#else
return nullptr;
#endif
}
content::ColorChooser* TabImpl::OpenColorChooser(
content::WebContents* web_contents,
SkColor color,
const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
#if defined(OS_ANDROID)
return new web_contents_delegate_android::ColorChooserAndroid(
web_contents, color, suggestions);
#else
return nullptr;
#endif
}
void TabImpl::RunFileChooser(
content::RenderFrameHost* render_frame_host,
std::unique_ptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) {
FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
params);
}
int TabImpl::GetTopControlsHeight() {
#if defined(OS_ANDROID)
return top_controls_container_view_
? top_controls_container_view_->GetTopControlsHeight()
: 0;
#else
return 0;
#endif
}
bool TabImpl::DoBrowserControlsShrinkRendererSize(
const content::WebContents* web_contents) {
#if defined(OS_ANDROID)
TRACE_EVENT0("weblayer", "Java_TabImpl_doBrowserControlsShrinkRendererSize");
return Java_TabImpl_doBrowserControlsShrinkRendererSize(AttachCurrentThread(),
java_impl_);
#else
return false;
#endif
}
bool TabImpl::EmbedsFullscreenWidget() {
return true;
}
void TabImpl::EnterFullscreenModeForTab(
content::WebContents* web_contents,
const GURL& origin,
const blink::mojom::FullscreenOptions& options) {
// TODO: support |options|.
is_fullscreen_ = true;
auto exit_fullscreen_closure = base::BindOnce(&TabImpl::OnExitFullscreen,
weak_ptr_factory_.GetWeakPtr());
base::AutoReset<bool> reset(&processing_enter_fullscreen_, true);
fullscreen_delegate_->EnterFullscreen(std::move(exit_fullscreen_closure));
#if defined(OS_ANDROID)
// Make sure browser controls cannot show when the tab is fullscreen.
SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
content::BROWSER_CONTROLS_STATE_HIDDEN);
#endif
}
void TabImpl::ExitFullscreenModeForTab(content::WebContents* web_contents) {
is_fullscreen_ = false;
fullscreen_delegate_->ExitFullscreen();
#if defined(OS_ANDROID)
// Attempt to show browser controls when exiting fullscreen.
SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
content::BROWSER_CONTROLS_STATE_BOTH);
#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<content::WebContents> new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
if (!new_tab_delegate_)
return;
std::unique_ptr<Tab> tab =
std::make_unique<TabImpl>(profile_, std::move(new_contents));
new_tab_delegate_->OnNewTab(std::move(tab),
NewTabTypeFromWindowDisposition(disposition));
}
void TabImpl::CloseContents(content::WebContents* source) {
if (new_tab_delegate_)
new_tab_delegate_->CloseTab();
}
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 defined(OS_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<gfx::RectF>& rects,
const gfx::RectF& active_rect) {
JNIEnv* env = AttachCurrentThread();
// Create the details object.
ScopedJavaLocalRef<jobject> details_object =
Java_TabImpl_createFindMatchRectsDetails(
env, version, rects.size(),
ScopedJavaLocalRef<jobject>(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<jobject>(Java_TabImpl_createRectF(
env, rect.x(), rect.y(), rect.right(), rect.bottom())));
}
Java_TabImpl_onFindMatchRectsAvailable(env, java_impl_, details_object);
}
#endif
void TabImpl::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
#if defined(OS_ANDROID)
if (navigation_handle->IsInMainFrame() &&
!navigation_handle->IsSameDocument()) {
// Force the browser controls to show initially, then allow hiding after a
// short delay.
SetBrowserControlsConstraint(ControlsVisibilityReason::kPostNavigation,
content::BROWSER_CONTROLS_STATE_SHOWN);
update_browser_controls_state_timer_.Start(
FROM_HERE, GetBrowserControlsAllowHideDelay(),
base::BindOnce(&TabImpl::SetBrowserControlsConstraint,
base::Unretained(this),
ControlsVisibilityReason::kPostNavigation,
content::BROWSER_CONTROLS_STATE_BOTH));
}
#endif
}
void TabImpl::RenderProcessGone(base::TerminationStatus status) {
for (auto& observer : observers_)
observer.OnRenderProcessGone();
}
void TabImpl::OnFindResultAvailable(content::WebContents* web_contents) {
#if defined(OS_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
}
void TabImpl::DidChangeVisibleSecurityState() {
if (browser_) {
if (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::mojom::RendererPreferences* prefs =
web_contents_->GetMutableRendererPrefs();
content::UpdateFontRendererPreferencesFromSystemSettings(prefs);
prefs->accept_languages = i18n::GetAcceptLangs();
if (should_sync_prefs)
web_contents_->SyncRendererPrefs();
}
#if defined(OS_ANDROID)
void TabImpl::SetBrowserControlsConstraint(
ControlsVisibilityReason reason,
content::BrowserControlsState constraint) {
Java_TabImpl_setBrowserControlsVisibilityConstraint(
base::android::AttachCurrentThread(), java_impl_,
static_cast<int>(reason), constraint);
}
#endif
std::unique_ptr<Tab> Tab::Create(Profile* profile) {
return std::make_unique<TabImpl>(static_cast<ProfileImpl*>(profile));
}
#if defined(OS_ANDROID)
Tab* Tab::GetLastTabForTesting() {
return g_last_tab;
}
#endif
void TabImpl::InitializeAutofillForTests(
std::unique_ptr<autofill::AutofillProvider> provider) {
DCHECK(!autofill_provider_);
autofill_provider_ = std::move(provider);
InitializeAutofill();
}
void TabImpl::InitializeAutofill() {
DCHECK(autofill_provider_);
content::WebContents* web_contents = web_contents_.get();
DCHECK(
!autofill::ContentAutofillDriverFactory::FromWebContents(web_contents));
AutofillClientImpl::CreateForWebContents(web_contents);
autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
web_contents, AutofillClientImpl::FromWebContents(web_contents),
i18n::GetApplicationLocale(),
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
autofill_provider_.get());
}
find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() {
return find_in_page::FindTabHelper::FromWebContents(web_contents_.get());
}
sessions::SessionTabHelperDelegate* TabImpl::GetSessionServiceTabHelperDelegate(
content::WebContents* web_contents) {
DCHECK_EQ(web_contents, web_contents_.get());
return browser_ ? browser_->browser_persister() : nullptr;
}
} // namespace weblayer