blob: f0d0efdffe0196555a59eccc822fbeba441e4b48 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/tabs/model/tab_helper_util.h"
#import "base/feature_list.h"
#import "components/breadcrumbs/core/breadcrumbs_status.h"
#import "components/commerce/ios/browser/commerce_tab_helper.h"
#import "components/data_sharing/public/features.h"
#import "components/favicon/core/favicon_service.h"
#import "components/favicon/ios/web_favicon_driver.h"
#import "components/history/core/browser/top_sites.h"
#import "components/history/ios/browser/web_state_top_sites_observer.h"
#import "components/keyed_service/core/service_access_type.h"
#import "components/language/ios/browser/ios_language_detection_tab_helper.h"
#import "components/omnibox/common/omnibox_features.h"
#import "components/safe_browsing/core/common/features.h"
#import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
#import "components/supervised_user/core/common/features.h"
#import "components/ukm/ios/ukm_url_recorder.h"
#import "components/webauthn/ios/features.h"
#import "components/webauthn/ios/passkey_tab_helper.h"
#import "ios/chrome/browser/app_launcher/model/app_launcher_abuse_detector.h"
#import "ios/chrome/browser/app_launcher/model/app_launcher_tab_helper.h"
#import "ios/chrome/browser/autofill/model/autofill_tab_helper.h"
#import "ios/chrome/browser/autofill/model/bottom_sheet/autofill_bottom_sheet_tab_helper.h"
#import "ios/chrome/browser/autofill/model/form_suggestion_tab_helper.h"
#import "ios/chrome/browser/browser_container/model/edit_menu_tab_helper.h"
#import "ios/chrome/browser/collaboration/model/data_sharing_tab_helper.h"
#import "ios/chrome/browser/commerce/model/price_alert_util.h"
#import "ios/chrome/browser/commerce/model/price_notifications/price_notifications_tab_helper.h"
#import "ios/chrome/browser/commerce/model/push_notification/push_notification_feature.h"
#import "ios/chrome/browser/commerce/model/shopping_persisted_data_tab_helper.h"
#import "ios/chrome/browser/commerce/model/shopping_service_factory.h"
#import "ios/chrome/browser/complex_tasks/model/ios_task_tab_helper.h"
#import "ios/chrome/browser/contextual_panel/model/contextual_panel_model_service.h"
#import "ios/chrome/browser/contextual_panel/model/contextual_panel_model_service_factory.h"
#import "ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h"
#import "ios/chrome/browser/crash_report/model/breadcrumbs/breadcrumb_manager_tab_helper.h"
#import "ios/chrome/browser/dom_distiller/model/distiller_service_factory.h"
#import "ios/chrome/browser/download/model/ar_quick_look_tab_helper.h"
#import "ios/chrome/browser/download/model/document_download_tab_helper.h"
#import "ios/chrome/browser/download/model/download_manager_tab_helper.h"
#import "ios/chrome/browser/download/model/pass_kit_tab_helper.h"
#import "ios/chrome/browser/download/model/safari_download_tab_helper.h"
#import "ios/chrome/browser/download/model/vcard_tab_helper.h"
#import "ios/chrome/browser/drive/model/drive_tab_helper.h"
#import "ios/chrome/browser/favicon/model/favicon_service_factory.h"
#import "ios/chrome/browser/find_in_page/model/find_tab_helper.h"
#import "ios/chrome/browser/find_in_page/model/java_script_find_tab_helper.h"
#import "ios/chrome/browser/find_in_page/model/util.h"
#import "ios/chrome/browser/follow/model/follow_tab_helper.h"
#import "ios/chrome/browser/history/model/history_service_factory.h"
#import "ios/chrome/browser/history/model/history_tab_helper.h"
#import "ios/chrome/browser/history/model/top_sites_factory.h"
#import "ios/chrome/browser/https_upgrades/model/https_only_mode_upgrade_tab_helper.h"
#import "ios/chrome/browser/https_upgrades/model/https_upgrade_service_factory.h"
#import "ios/chrome/browser/https_upgrades/model/typed_navigation_upgrade_tab_helper.h"
#import "ios/chrome/browser/infobars/model/infobar_badge_tab_helper.h"
#import "ios/chrome/browser/infobars/model/infobar_manager_impl.h"
#import "ios/chrome/browser/infobars/model/overlays/default_infobar_overlay_request_factory.h"
#import "ios/chrome/browser/infobars/model/overlays/infobar_overlay_request_inserter.h"
#import "ios/chrome/browser/infobars/model/overlays/infobar_overlay_tab_helper.h"
#import "ios/chrome/browser/infobars/model/overlays/translate_overlay_tab_helper.h"
#import "ios/chrome/browser/intelligence/bwg/model/bwg_tab_helper.h"
#import "ios/chrome/browser/intelligence/features/features.h"
#import "ios/chrome/browser/itunes_urls/model/itunes_urls_handler_tab_helper.h"
#import "ios/chrome/browser/lens/model/lens_tab_helper.h"
#import "ios/chrome/browser/lens_overlay/coordinator/lens_overlay_availability.h"
#import "ios/chrome/browser/lens_overlay/model/lens_overlay_tab_helper.h"
#import "ios/chrome/browser/link_to_text/model/link_to_text_tab_helper.h"
#import "ios/chrome/browser/metrics/model/pageload_foreground_duration_tab_helper.h"
#import "ios/chrome/browser/mini_map/model/mini_map_tab_helper.h"
#import "ios/chrome/browser/ntp/model/new_tab_page_tab_helper.h"
#import "ios/chrome/browser/optimization_guide/model/optimization_guide_service.h"
#import "ios/chrome/browser/optimization_guide/model/optimization_guide_service_factory.h"
#import "ios/chrome/browser/optimization_guide/model/optimization_guide_tab_helper.h"
#import "ios/chrome/browser/optimization_guide/model/optimization_guide_validation_tab_helper.h"
#import "ios/chrome/browser/overlays/model/public/overlay_request_queue.h"
#import "ios/chrome/browser/overscroll_actions/model/overscroll_actions_tab_helper.h"
#import "ios/chrome/browser/page_info/model/about_this_site_tab_helper.h"
#import "ios/chrome/browser/page_info/ui_bundled/features.h"
#import "ios/chrome/browser/passwords/model/password_controller.h"
#import "ios/chrome/browser/passwords/model/password_tab_helper.h"
#import "ios/chrome/browser/passwords/model/well_known_change_password_tab_helper.h"
#import "ios/chrome/browser/permissions/model/permissions_tab_helper.h"
#import "ios/chrome/browser/policy_url_blocking/model/policy_url_blocking_tab_helper.h"
#import "ios/chrome/browser/reader_mode/model/features.h"
#import "ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.h"
#import "ios/chrome/browser/reading_list/model/offline_page_tab_helper.h"
#import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h"
#import "ios/chrome/browser/reading_list/model/reading_list_web_state_observer.h"
#import "ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.h"
#import "ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.h"
#import "ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_tab_helper.h"
#import "ios/chrome/browser/search_engines/model/search_engine_tab_helper.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/sharing/model/share_file_download_tab_helper.h"
#import "ios/chrome/browser/snapshots/model/snapshot_source_tab_helper.h"
#import "ios/chrome/browser/snapshots/model/snapshot_tab_helper.h"
#import "ios/chrome/browser/ssl/model/captive_portal_tab_helper.h"
#import "ios/chrome/browser/supervised_user/model/supervised_user_error_container.h"
#import "ios/chrome/browser/supervised_user/model/supervised_user_url_filter_tab_helper.h"
#import "ios/chrome/browser/tabs/model/ios_chrome_synced_tab_delegate.h"
#import "ios/chrome/browser/translate/model/chrome_ios_translate_client.h"
#import "ios/chrome/browser/voice/model/voice_search_navigations_tab_helper.h"
#import "ios/chrome/browser/web/model/annotations/annotations_tab_helper.h"
#import "ios/chrome/browser/web/model/blocked_popup_tab_helper.h"
#import "ios/chrome/browser/web/model/font_size/font_size_tab_helper.h"
#import "ios/chrome/browser/web/model/image_fetch/image_fetch_tab_helper.h"
#import "ios/chrome/browser/web/model/invalid_url_tab_helper.h"
#import "ios/chrome/browser/web/model/load_timing_tab_helper.h"
#import "ios/chrome/browser/web/model/page_placeholder_tab_helper.h"
#import "ios/chrome/browser/web/model/print/print_tab_helper.h"
#import "ios/chrome/browser/web/model/repost_form_tab_helper.h"
#import "ios/chrome/browser/web/model/sad_tab_tab_helper.h"
#import "ios/chrome/browser/web/model/web_performance_metrics/web_performance_metrics_tab_helper.h"
#import "ios/chrome/browser/web/model/web_view_proxy/web_view_proxy_tab_helper.h"
#import "ios/chrome/browser/web_selection/model/web_selection_tab_helper.h"
#import "ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h"
#import "ios/chrome/browser/webui/model/net_export_tab_helper.h"
#import "ios/components/security_interstitials/https_only_mode/feature.h"
#import "ios/components/security_interstitials/https_only_mode/https_only_mode_container.h"
#import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h"
#import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
#import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_allow_list.h"
#import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.h"
#import "ios/components/security_interstitials/safe_browsing/safe_browsing_client.h"
#import "ios/components/security_interstitials/safe_browsing/safe_browsing_query_manager.h"
#import "ios/components/security_interstitials/safe_browsing/safe_browsing_tab_helper.h"
#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
#import "ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h"
#import "ios/web/common/annotations_utils.h"
#import "ios/web/public/find_in_page/java_script_find_in_page_manager.h"
#import "ios/web/public/web_state.h"
namespace {
// Returns whether the `flag` is set in `mask`.
constexpr bool IsTabHelperFilterMaskSet(TabHelperFilter mask,
TabHelperFilter flag) {
return (mask & flag) == flag;
}
} // namespace
void AttachTabHelpers(web::WebState* web_state, TabHelperFilter filter_flags) {
ProfileIOS* const profile =
ProfileIOS::FromBrowserState(web_state->GetBrowserState());
const bool is_off_the_record = profile->IsOffTheRecord();
const bool for_prerender =
IsTabHelperFilterMaskSet(filter_flags, TabHelperFilter::kPrerender);
const bool for_lens_overlay =
IsTabHelperFilterMaskSet(filter_flags, TabHelperFilter::kLensOverlay);
// When adding a new tab helper, please consider whether it should be filtered
// out when the web_state is presented in the following context:
// - kPrerender: Tab helpers that are not required or not used for navigation
// should be filtered out.
// - kBottomSheet: The bottom sheet is overlayed on the BVC, tab helpers that
// rely on BVC's toolbar entry points should be filtered out.
//
// When a web state is presented by the BVC, AttachTabHelpers is called to
// attach all tab helpers. (the method is idempotent, so it is okay to call it
// multiple times for the same WebState).
OverlayRequestQueue::CreateForWebState(web_state);
VoiceSearchNavigationTabHelper::CreateForWebState(web_state);
InfoBarManagerImpl::CreateForWebState(web_state);
if (IsNativeFindInPageAvailable()) {
FindTabHelper::CreateForWebState(web_state);
} else {
web::JavaScriptFindInPageManager::CreateForWebState(web_state);
JavaScriptFindTabHelper::CreateForWebState(web_state);
}
if (!for_lens_overlay) {
HistoryTabHelper::CreateForWebState(web_state);
} else if (base::FeatureList::IsEnabled(kLensOverlayNavigationHistory)) {
HistoryTabHelper::CreateForWebState(web_state);
HistoryTabHelper::FromWebState(web_state)->EnableLensURLProcessing();
}
LoadTimingTabHelper::CreateForWebState(web_state);
OverscrollActionsTabHelper::CreateForWebState(web_state);
IOSTaskTabHelper::CreateForWebState(web_state);
if (!for_lens_overlay && IsPriceAlertsEligibleForWebState(web_state)) {
ShoppingPersistedDataTabHelper::CreateForWebState(web_state);
}
commerce::CommerceTabHelper::CreateForWebState(
web_state, is_off_the_record,
commerce::ShoppingServiceFactory::GetForProfile(profile));
if (!for_lens_overlay && !for_prerender) {
// Since LensTabHelper listens for a custom scheme, it needs to be
// created before AppLauncherTabHelper, which will filter out
// unhandled schemes.
LensTabHelper::CreateForWebState(web_state);
if (IsLensOverlayAvailable(profile->GetPrefs())) {
LensOverlayTabHelper::CreateForWebState(web_state);
}
AppLauncherTabHelper::CreateForWebState(
web_state, [[AppLauncherAbuseDetector alloc] init], is_off_the_record);
if (IsReaderModeAvailable()) {
ReaderModeTabHelper::CreateForWebState(
web_state, DistillerServiceFactory::GetForProfile(profile));
}
}
security_interstitials::IOSBlockingPageTabHelper::CreateForWebState(
web_state);
password_manager::WellKnownChangePasswordTabHelper::CreateForWebState(
web_state);
InvalidUrlTabHelper::CreateForWebState(web_state);
if (!for_lens_overlay) {
InfobarOverlayRequestInserter::CreateForWebState(
web_state, &DefaultInfobarOverlayRequestFactory);
InfobarOverlayTabHelper::CreateForWebState(web_state);
TranslateOverlayTabHelper::CreateForWebState(web_state);
}
if (ios::provider::IsTextZoomEnabled()) {
FontSizeTabHelper::CreateForWebState(web_state);
}
if (breadcrumbs::IsEnabled(GetApplicationContext()->GetLocalState())) {
BreadcrumbManagerTabHelper::CreateForWebState(web_state);
}
AnnotationsTabHelper::CreateForWebState(web_state);
SafeBrowsingClient* client =
SafeBrowsingClientFactory::GetForProfile(profile);
SafeBrowsingQueryManager::CreateForWebState(web_state, client);
SafeBrowsingTabHelper::CreateForWebState(web_state, client);
SafeBrowsingUrlAllowList::CreateForWebState(web_state);
SafeBrowsingUnsafeResourceContainer::CreateForWebState(web_state);
TailoredSecurityTabHelper::CreateForWebState(
web_state, TailoredSecurityServiceFactory::GetForProfile(profile));
PolicyUrlBlockingTabHelper::CreateForWebState(web_state);
// Supervised user services are not supported for off-the-record browser
// state.
if (!is_off_the_record) {
SupervisedUserURLFilterTabHelper::CreateForWebState(web_state);
SupervisedUserErrorContainer::CreateForWebState(web_state);
}
ImageFetchTabHelper::CreateForWebState(web_state);
NewTabPageTabHelper::CreateForWebState(web_state);
ShareFileDownloadTabHelper::CreateForWebState(web_state);
OptimizationGuideTabHelper::CreateForWebState(web_state);
OptimizationGuideValidationTabHelper::CreateForWebState(web_state);
ProfileIOS* original_profile = profile->GetOriginalProfile();
favicon::WebFaviconDriver::CreateForWebState(
web_state, ios::FaviconServiceFactory::GetForProfile(
original_profile, ServiceAccessType::IMPLICIT_ACCESS));
history::WebStateTopSitesObserver::CreateForWebState(
web_state, ios::TopSitesFactory::GetForProfile(original_profile).get());
// Depends on favicon::WebFaviconDriver, must be created after it.
SearchEngineTabHelper::CreateForWebState(web_state);
ukm::InitializeSourceUrlRecorderForWebState(web_state);
// Download tab helpers.
DownloadManagerTabHelper::CreateForWebState(web_state);
SafariDownloadTabHelper::CreateForWebState(web_state);
VcardTabHelper::CreateForWebState(web_state);
DocumentDownloadTabHelper::CreateForWebState(web_state);
PageloadForegroundDurationTabHelper::CreateForWebState(web_state);
LookalikeUrlTabHelper::CreateForWebState(web_state);
LookalikeUrlTabAllowList::CreateForWebState(web_state);
LookalikeUrlContainer::CreateForWebState(web_state);
// TODO(crbug.com/41360476): pre-rendered WebState have lots of unnecessary
// tab helpers for historical reasons. For the moment, AttachTabHelpers
// allows to inhibit the creation of some of them. Once PreloadController
// has been refactored to only create the necessary tab helpers, this
// condition can be removed.
if (!for_lens_overlay && !for_prerender) {
SadTabTabHelper::CreateForWebState(
web_state, SadTabTabHelper::kDefaultRepeatFailureInterval);
SnapshotTabHelper::CreateForWebState(web_state);
SnapshotSourceTabHelper::CreateForWebState(web_state);
PagePlaceholderTabHelper::CreateForWebState(web_state);
ChromeIOSTranslateClient::CreateForWebState(web_state);
PasswordTabHelper::CreateForWebState(web_state);
AutofillBottomSheetTabHelper::CreateForWebState(web_state);
AutofillTabHelper::CreateForWebState(web_state);
}
if (!for_lens_overlay) {
InfobarBadgeTabHelper::GetOrCreateForWebState(web_state);
if (base::FeatureList::IsEnabled(kIOSPasskeyShim)) {
PasskeyTabHelper::CreateForWebState(
web_state, IOSPasskeyModelFactory::GetForProfile(profile));
}
}
if (base::FeatureList::IsEnabled(kSharedHighlightingIOS)) {
LinkToTextTabHelper::CreateForWebState(web_state);
}
WebSelectionTabHelper::CreateForWebState(web_state);
WebPerformanceMetricsTabHelper::CreateForWebState(web_state);
OfflinePageTabHelper::CreateForWebState(
web_state, ReadingListModelFactory::GetForProfile(profile));
PermissionsTabHelper::CreateForWebState(web_state);
RepostFormTabHelper::CreateForWebState(web_state);
HttpsOnlyModeUpgradeTabHelper::CreateForWebState(
web_state, profile->GetPrefs(),
HttpsUpgradeServiceFactory::GetForProfile(profile));
HttpsOnlyModeContainer::CreateForWebState(web_state);
if (!for_prerender &&
base::FeatureList::IsEnabled(omnibox::kDefaultTypedNavigationsToHttps)) {
TypedNavigationUpgradeTabHelper::CreateForWebState(
web_state, HttpsUpgradeServiceFactory::GetForProfile(profile));
}
if (!is_off_the_record) {
FollowTabHelper::CreateForWebState(web_state);
}
if (!for_lens_overlay && !is_off_the_record) {
PriceNotificationsTabHelper::CreateForWebState(web_state);
}
if (!for_lens_overlay && IsContextualPanelEnabled()) {
ContextualPanelModelService* model_service =
ContextualPanelModelServiceFactory::GetForProfile(profile);
ContextualPanelTabHelper::CreateForWebState(web_state,
model_service->models());
}
if (!for_lens_overlay && !is_off_the_record &&
IsAboutThisSiteFeatureEnabled()) {
if (auto* optimization_guide_decider =
OptimizationGuideServiceFactory::GetForProfile(profile)) {
AboutThisSiteTabHelper::CreateForWebState(web_state,
optimization_guide_decider);
}
}
if (!is_off_the_record && !for_prerender) {
if (data_sharing::features::ShouldInterceptUrlForVersioning()) {
DataSharingTabHelper::CreateForWebState(web_state);
}
}
EditMenuTabHelper::CreateForWebState(web_state);
if (!is_off_the_record &&
base::FeatureList::IsEnabled(kIOSMiniMapUniversalLink)) {
MiniMapTabHelper::CreateForWebState(web_state);
}
if (!is_off_the_record && !for_prerender && IsPageActionMenuEnabled()) {
BwgTabHelper::CreateForWebState(web_state);
}
WebViewProxyTabHelper::CreateForWebState(web_state);
}