diff --git a/infra/PATCHES.md b/infra/PATCHES.md index 0cdd99a9..2f9e38ac 100644 --- a/infra/PATCHES.md +++ b/infra/PATCHES.md @@ -15,7 +15,7 @@ Ink > https://chromium.googlesource.com/chromium/src/third_party/+/c4f7a938fcdc7 - Implemented with the args.gn flag "enable_ink = true" Adds PDF annotation features present in CrOS. MPEG-DASH > https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP - - Implemented with the args.gn flags "enable_hls_sample_aes = true" and "enable_mse_mpeg2ts_stream_parser = true" + - Implemented via the args.gn flags "enable_hls_demuxer = true" and "enable_mse_mpeg2ts_stream_parser = true" Enable JPEG XL Image File Format by Default Patch - Made by me. @@ -23,7 +23,13 @@ Enable JPEG XL Image File Format by Default Patch Enable Live Caption (SODA) on all builds Patch - Made by me. -V8 Font Rendering Patch > https://github.com/saiarcot895/chromium-ubuntu-build/blob/master/debian/patches/fix-font-rendering.patch +Enable AutoPlay of WebAudio, when AutoPlay is normally disallowed + - Made by me. + +Reversion of some Chrome Refresh 2023 UI elements (most notably the restoration of the tab search button to the right side of the tabstrip) + - Made by me. + + REMOVED ~~V8 Font Rendering Patch > https://github.com/saiarcot895/chromium-ubuntu-build/blob/master/debian/patches/fix-font-rendering.patch~~ - Fixes font rendering in certain instances. VAAPI Patch > https://github.com/saiarcot895/chromium-ubuntu-build/blob/master/debian/patches/enable-vaapi-on-linux.diff @@ -63,8 +69,10 @@ Enable Fingerprinting Protection Patch - Made by me. Show full URLs by Default Patch > https://github.com/Alex313031/thorium/blob/74219f27911e133483c3ab85c70ba4360ea98423/src/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc#L292 + - Made by me. Disable Privacy Sandbox (previously known as FLOC) Patch > https://github.com/ungoogled-software/ungoogled-chromium/blob/master/patches/core/ungoogled-chromium/disable-privacy-sandbox.patch + - Modified from UnGoogled patch Disable Google API Key Warning Infobar Patch > https://github.com/Eloston/ungoogled-chromium/blob/master/patches/extra/debian/disable/google-api-warning.patch & https://github.com/Eloston/ungoogled-chromium/blob/master/patches/extra/inox-patchset/0013-disable-missing-key-warning.patch - Modified by me. @@ -185,7 +193,7 @@ Enable AC3 and EAC3 for HEVC Patch - https://github.com/Muril-o/electron-chromiu - https://github.com/Alex313031/thorium/commit/a2e49dd2fe00e4c6fa882a41e8a1a27f93bedfff AND - https://github.com/Alex313031/thorium/commit/7d0b4f045ce0e16ea9edb05a4dc056a1d4583752#diff-09b3d55a8198fc42186bfd6bf5869fe78b8edad6f67e75b78228446f1d7cf66f -Show the Apps button in Bookmarks Bar by Default Patch - Made by me. +Show the Apps button in Bookmarks Bar by Default Patch - Made by me. NOTE: Now only enabled in the legacy builds after M120. Add autocomplete for chrome://flags > https://github.com/bromite/bromite/blob/master/build/patches/Offer-builtin-autocomplete-for-chrome-flags.patch @@ -224,6 +232,9 @@ Enable Middle Click Autoscroll on ALL Platforms - https://github.com/Alex313031/ Patches to enable truly Portable usage > Disable Encryption and Machine ID - https://github.com/ungoogled-software/ungoogled-chromium-windows/blob/master/patches/ungoogled-chromium/windows/windows-disable-encryption.patch - https://github.com/ungoogled-software/ungoogled-chromium-windows/blob/master/patches/ungoogled-chromium/windows/windows-disable-machine-id.patch + > Also added a patch by win32ss from Supermium to allow reversion of a portable profile back to a normal, encrypted one: + - https://github.com/win32ss/supermium/commit/697055c2e65074bf50d30c58e124ddfe293c3f8c AND + - https://github.com/win32ss/supermium/commit/1e2e02118f5f014cb1761f6ae05e86ab4304f924 Android Patches from Bromite: - https://github.com/bromite/bromite/blob/master/build/patches/do-not-add-suffix-to-package-name.patch diff --git a/src/chrome/browser/thorium_flag_entries.h b/src/chrome/browser/thorium_flag_entries.h index 6df44c05..2dd7c816 100644 --- a/src/chrome/browser/thorium_flag_entries.h +++ b/src/chrome/browser/thorium_flag_entries.h @@ -215,6 +215,12 @@ "Disable Machine ID", "Disables use of a generated machine-specific ID to lock the user data directory to that machine. This is used to enable portable user data directories. Enabled for Thorium Portable.", kOsDesktop, SINGLE_VALUE_TYPE("disable-machine-id")}, + {"revert-from-portable", + "Prevent Data Loss When Changing User Profile Portable State", + "When moving a Thorium user profile from one drive to another (or one system to another), enable this flag before moving the profile directory. It should also be used " + "when migrating a portable profile back to a normal, non-portable profile (i.e. when disabling the `chrome://flags#disable-encryption` and/or the `chrome://flags#disable-machine-id` flags " + "after being previously enabled). This mostly ensures that extensions, extension data, and some other data are not lost during the migration.", + kOsDesktop, SINGLE_VALUE_TYPE("disable-machine-id")}, #if BUILDFLAG(IS_LINUX) {"password-store", diff --git a/src/chrome/browser/ui/browser.cc b/src/chrome/browser/ui/browser.cc index 0768272e..b3cb1678 100644 --- a/src/chrome/browser/ui/browser.cc +++ b/src/chrome/browser/ui/browser.cc @@ -109,6 +109,7 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_ui_prefs.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/browser_window_features.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/chrome_select_file_policy.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" @@ -123,6 +124,7 @@ #include "chrome/browser/ui/overscroll_pref_manager.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "chrome/browser/ui/search/search_tab_helper.h" +#include "chrome/browser/ui/signin/cookie_clear_on_exit_migration_notice.h" #include "chrome/browser/ui/singleton_tabs.h" #include "chrome/browser/ui/status_bubble.h" #include "chrome/browser/ui/sync/browser_synced_window_delegate.h" @@ -133,6 +135,7 @@ #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" +#include "chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_menu_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -140,6 +143,7 @@ #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/unload_controller.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/frame/contents_web_view.h" #include "chrome/browser/ui/views/message_box_dialog.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" @@ -177,7 +181,6 @@ #include "components/keep_alive_registry/scoped_keep_alive.h" #include "components/omnibox/browser/location_bar_model.h" #include "components/omnibox/browser/location_bar_model_impl.h" -#include "components/omnibox/browser/omnibox_prefs.h" #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" #include "components/page_load_metrics/common/page_load_metrics.mojom.h" #include "components/paint_preview/buildflags/buildflags.h" @@ -232,6 +235,7 @@ #include "third_party/blink/public/mojom/frame/blocked_navigation_types.mojom.h" #include "third_party/blink/public/mojom/frame/frame.mojom.h" #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" +#include "third_party/blink/public/mojom/page/draggable_region.mojom.h" #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h" #include "third_party/blink/public/mojom/window_features/window_features.mojom.h" #include "ui/base/l10n/l10n_util.h" @@ -356,6 +360,43 @@ bool IsOnKioskSplashScreen() { #endif } +// Returns a pair [last_window, last_window_for_profile] indicating if `browser` +// is the only browser in total and for this profile. +// Ignores browsers that are in the process of closing. +std::pair IsLastWindow(const Browser& browser) { + bool last_window = true; + bool last_window_for_profile = true; + for (Browser* other_browser : *BrowserList::GetInstance()) { + // Don't count this browser window or any other in the process of closing. + // Window closing may be delayed, and windows that are in the process of + // closing don't count against our totals. + if (other_browser == &browser || + other_browser->IsAttemptingToCloseBrowser()) { + continue; + } + + last_window = false; + + if (other_browser->profile() == browser.profile()) { + last_window_for_profile = false; + break; + } + } + + return {last_window, last_window_for_profile}; +} + +// Returns whether the cookie migration notice should be shown: the migration +// is not complete, and this is the last browser window open for this profile. +bool ShouldShowCookieMigrationNoticeForBrowser(const Browser& browser) { + if (!CanShowCookieClearOnExitMigrationNotice(browser)) { + return false; + } + + auto [last_window, last_window_for_profile] = IsLastWindow(browser); + return last_window_for_profile; +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -418,6 +459,19 @@ Browser::CreateParams Browser::CreateParams::CreateForAppPopup( profile, user_gesture); } +// static +Browser::CreateParams Browser::CreateParams::CreateForPictureInPicture( + const std::string& app_name, + bool trusted_source, + Profile* profile, + bool user_gesture) { + Browser::CreateParams browser_params(Browser::TYPE_PICTURE_IN_PICTURE, + profile, user_gesture); + browser_params.app_name = app_name; + browser_params.trusted_source = trusted_source; + return browser_params; +} + // static Browser::CreateParams Browser::CreateParams::CreateForDevTools( Profile* profile) { @@ -448,12 +502,6 @@ Browser::CreationStatus Browser::GetCreationStatusForProfile(Profile* profile) { return CreationStatus::kOk; } -#if BUILDFLAG(ENABLE_EXTENSIONS) -// static -const char* Browser::url_elision_extension_id_ = - "jknemblkbdhdcpllfgbfekkdciegfboi"; -#endif // BUILDFLAG(ENABLE_EXTENSIONS) - // static Browser* Browser::Create(const CreateParams& params) { // If this is failing, a caller is trying to create a browser when creation is @@ -495,12 +543,15 @@ Browser::Browser(const CreateParams& params) new BrowserContentSettingBubbleModelDelegate(this)), location_bar_model_delegate_(new BrowserLocationBarModelDelegate(this)), location_bar_model_(std::make_unique( - location_bar_model_delegate_.get(), content::kMaxURLDisplayChars)), + location_bar_model_delegate_.get(), + content::kMaxURLDisplayChars)), live_tab_context_(new BrowserLiveTabContext(this)), synced_window_delegate_(new BrowserSyncedWindowDelegate(this)), app_controller_(web_app::MaybeCreateAppBrowserController(this)), bookmark_bar_state_(BookmarkBar::HIDDEN), command_controller_(new chrome::BrowserCommandController(this)), + tab_group_deletion_dialog_controller_( + std::make_unique(this)), window_has_shown_(false), user_title_(params.user_title), signin_view_controller_(this), @@ -549,6 +600,12 @@ Browser::Browser(const CreateParams& params) if (params.skip_window_init_for_testing) return; + // BrowserWindowFeatures need to be initialized before browser window + // creation, so that the features can be used in creating components + // in browser window. + features_ = BrowserWindowFeatures::CreateBrowserWindowFeatures(); + features_->Init(this); + window_ = params.window ? params.window.get() : CreateBrowserWindow(std::unique_ptr(this), params.user_gesture, @@ -576,25 +633,6 @@ Browser::Browser(const CreateParams& params) ->ListenToFullScreenChanges(); } -#if BUILDFLAG(ENABLE_EXTENSIONS) - // Temporary migration code: if users have the Suspicious Site Reporter - // extension installed, which has the effect of disabling URL elisions in the - // omnibox, set the pref that disables URL elisions. This is so that we can - // eventually deprecate this extension without reverting its users to elided - // URL display. - // TODO(crbug/324934130): remove this code and deprecate the extension in - // ~M125 or so. - if (!profile_->GetPrefs() - ->FindPreference(omnibox::kPreventUrlElisionsInOmnibox) - ->IsManaged() && - extensions::ExtensionRegistry::Get(profile_) - ->enabled_extensions() - .Contains(url_elision_extension_id_)) { - profile_->GetPrefs()->SetBoolean(omnibox::kPreventUrlElisionsInOmnibox, - true); - } -#endif // BUILDFLAG(ENABLE_EXTENSIONS) - BrowserList::AddBrowser(this); } @@ -607,14 +645,17 @@ Browser::~Browser() { // The tab strip should not have any tabs at this point. // - // TODO(crbug.com/1407055): This DCHECK doesn't always pass. - // TODO(crbug.com/1434387): convert this to CHECK. + // TODO(crbug.com/40887606): This DCHECK doesn't always pass. + // TODO(crbug.com/40064092): convert this to CHECK. DCHECK(tab_strip_model_->empty()); // Destroy the BrowserCommandController before removing the browser, so that // it doesn't act on any notifications that are sent as a result of removing // the browser. command_controller_.reset(); + // Destroy ExclusiveAccessManager, which depends on `window_` which may be + // destroyed by RemoveBrowser(). + exclusive_access_manager_.reset(); BrowserList::RemoveBrowser(this); // If closing the window is going to trigger a shutdown, then we need to @@ -625,7 +666,8 @@ Browser::~Browser() { if (!browser_defaults::kBrowserAliveWithNoWindows && OkToCloseWithInProgressDownloads(&num_downloads) == DownloadCloseType::kBrowserShutdown) { - DownloadCoreService::CancelAllDownloads(); + DownloadCoreService::CancelAllDownloads( + DownloadCoreService::CancelDownloadsTrigger::kShutdown); } SessionServiceBase* service = GetAppropriateSessionServiceForProfile(this); @@ -660,7 +702,7 @@ Browser::~Browser() { // Non-primary OffTheRecord profiles should not be destroyed directly by // Browser (e.g. for offscreen tabs, https://crbug.com/664351). // - // TODO(crbug.com/1153922): Use ScopedProfileKeepAlive for Incognito too, + // TODO(crbug.com/40159237): Use ScopedProfileKeepAlive for Incognito too, // instead of separate logic for Incognito and regular profiles. if (profile_->IsIncognitoProfile() && !BrowserList::IsOffTheRecordBrowserInUse(profile_) && @@ -897,14 +939,31 @@ Browser::WarnBeforeClosingResult Browser::MaybeWarnBeforeClosing( // before-unload handlers by setting `force_skip_warning_user_on_close_` to // true or there are no pending downloads we need to prompt about) then // there's no need to warn. - if (force_skip_warning_user_on_close_ || CanCloseWithInProgressDownloads()) { + if (force_skip_warning_user_on_close_) { if (CanCloseWithMultipleTabs()) return WarnBeforeClosingResult::kOkToClose; } + // `CanCloseWithInProgressDownloads()` may trigger a modal dialog. + bool can_close_with_downloads = CanCloseWithInProgressDownloads(); + if (can_close_with_downloads && + !ShouldShowCookieMigrationNoticeForBrowser(*this)) { + return WarnBeforeClosingResult::kOkToClose; + } + + // If there is no download warning, show the cookie migration notice now. + // Otherwise, the download warning is being shown. Cookie migration notice + // will be shown after, if needed. + if (can_close_with_downloads) { + ShowCookieClearOnExitMigrationNotice( + *this, base::BindOnce(&Browser::CookieMigrationNoticeResponse, + weak_factory_.GetWeakPtr())); + } + DCHECK(!warn_before_closing_callback_) << "Tried to close window during close warning; dialog should be modal."; warn_before_closing_callback_ = std::move(warn_callback); + return WarnBeforeClosingResult::kDoNotClose; } @@ -998,6 +1057,21 @@ void Browser::ClearForceShowBookmarkBarFlag(ForceShowBookmarkBarFlag flag) { UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_FORCE_SHOW); } +views::WebView* Browser::GetWebView() { + return window_->GetContentsWebView(); +} + +void Browser::OpenURL(const GURL& gurl, WindowOpenDisposition disposition) { + OpenURL(content::OpenURLParams(gurl, content::Referrer(), disposition, + ui::PAGE_TRANSITION_LINK, + /*is_renderer_initiated=*/false), + /*navigation_handle_callback=*/{}); +} + +const SessionID& Browser::GetSessionID() { + return session_id_; +} + void Browser::OnWindowClosing() { if (const auto closing_status = HandleBeforeClose(); closing_status != BrowserClosingStatus::kPermitted) { @@ -1069,23 +1143,11 @@ Browser::DownloadCloseType Browser::OkToCloseWithInProgressDownloads( // Figure out how many windows are open total, and associated with this // profile, that are relevant for the ok-to-close decision. - int profile_window_count = 0; - int total_window_count = 0; - for (Browser* browser : *BrowserList::GetInstance()) { - // Don't count this browser window or any other in the process of closing. - // Window closing may be delayed, and windows that are in the process of - // closing don't count against our totals. - if (browser == this || browser->IsAttemptingToCloseBrowser()) - continue; - - if (browser->profile() == profile()) - profile_window_count++; - total_window_count++; - } + auto [last_window, last_window_for_profile] = IsLastWindow(*this); // If there aren't any other windows, we're at browser shutdown, // which would cancel all current downloads. - if (total_window_count == 0) { + if (last_window) { *num_downloads_blocking = total_download_count; return DownloadCloseType::kBrowserShutdown; } @@ -1095,7 +1157,7 @@ Browser::DownloadCloseType Browser::OkToCloseWithInProgressDownloads( // those downloads would be cancelled by our window (-> profile) close. DownloadCoreService* download_core_service = DownloadCoreServiceFactory::GetForBrowserContext(profile()); - if ((profile_window_count == 0) && + if (last_window_for_profile && (download_core_service->BlockingShutdownCount() > 0) && (profile()->IsIncognitoProfile() || profile()->IsGuestSession())) { *num_downloads_blocking = download_core_service->BlockingShutdownCount(); @@ -1241,12 +1303,15 @@ void Browser::UnregisterKeepAlive() { /////////////////////////////////////////////////////////////////////////////// // Browser, PageNavigator implementation: -WebContents* Browser::OpenURL(const OpenURLParams& params) { +WebContents* Browser::OpenURL( + const OpenURLParams& params, + base::OnceCallback + navigation_handle_callback) { #if DCHECK_IS_ON() DCHECK(params.Valid()); #endif - return OpenURLFromTab(nullptr, params); + return OpenURLFromTab(nullptr, params, std::move(navigation_handle_callback)); } /////////////////////////////////////////////////////////////////////////////// @@ -1323,10 +1388,7 @@ void Browser::OnTabGroupChanged(const TabGroupChange& change) { ->visual_data(); const tab_groups::SavedTabGroupKeyedService* const saved_tab_group_keyed_service = - base::FeatureList::IsEnabled(features::kTabGroupsSave) - ? tab_groups::SavedTabGroupServiceFactory::GetForProfile( - profile_) - : nullptr; + tab_groups::SavedTabGroupServiceFactory::GetForProfile(profile_); std::optional saved_guid; if (saved_tab_group_keyed_service) { @@ -1499,7 +1561,7 @@ void Browser::CreateSmsPrompt(content::RenderFrameHost*, const std::string& one_time_code, base::OnceClosure on_confirm, base::OnceClosure on_cancel) { - // TODO(crbug.com/1015645): implementation left pending deliberately. + // TODO(crbug.com/40103792): implementation left pending deliberately. std::move(on_confirm).Run(); } @@ -1577,32 +1639,6 @@ void Browser::UpdateInspectedWebContentsIfNecessary( } } -std::unique_ptr Browser::SwapWebContents( - content::WebContents* old_contents, - std::unique_ptr new_contents) { - // Copies the background color and contents of the old WebContents to a new - // one that replaces it on the screen. This allows the new WebContents to - // have something to show before having loaded any contents. As a result, we - // avoid flashing white when navigating from a site with a dark background to - // another site with a dark background. - if (old_contents && new_contents) { - RenderWidgetHostView* old_view = - old_contents->GetPrimaryMainFrame()->GetView(); - RenderWidgetHostView* new_view = - new_contents->GetPrimaryMainFrame()->GetView(); - if (old_view && new_view) - new_view->TakeFallbackContentFrom(old_view); - } - - // Clear the task manager tag. The TabStripModel will associate its own task - // manager tag. - task_manager::WebContentsTags::ClearTag(new_contents.get()); - - int index = tab_strip_model_->GetIndexOfWebContents(old_contents); - DCHECK_NE(TabStripModel::kNoTab, index); - return tab_strip_model_->ReplaceWebContentsAt(index, std::move(new_contents)); -} - bool Browser::ShouldShowStaleContentOnEviction(content::WebContents* source) { #if BUILDFLAG(IS_CHROMEOS_ASH) return source == tab_strip_model_->GetActiveWebContents(); @@ -1611,10 +1647,9 @@ bool Browser::ShouldShowStaleContentOnEviction(content::WebContents* source) { #endif // BUILDFLAG(IS_CHROMEOS_ASH) } -// TODO(crbug.com/1198344): Remove this. +// TODO(crbug.com/40177301): Remove this. void Browser::MediaWatchTimeChanged( - const content::MediaPlayerWatchTime& watch_time) { -} + const content::MediaPlayerWatchTime& watch_time) {} bool Browser::IsPointerLocked() const { return exclusive_access_manager_->pointer_lock_controller() @@ -1644,8 +1679,11 @@ void Browser::OnWindowDidShow() { /////////////////////////////////////////////////////////////////////////////// // Browser, content::WebContentsDelegate implementation: -WebContents* Browser::OpenURLFromTab(WebContents* source, - const OpenURLParams& params) { +WebContents* Browser::OpenURLFromTab( + WebContents* source, + const OpenURLParams& params, + base::OnceCallback + navigation_handle_callback) { TRACE_EVENT1("navigation", "Browser::OpenURLFromTab", "source", source); #if DCHECK_IS_ON() DCHECK(params.Valid()); @@ -1654,7 +1692,8 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, if (is_type_devtools()) { DevToolsWindow* window = DevToolsWindow::AsDevToolsWindow(source); DCHECK(window); - return window->OpenURLFromTab(source, params); + return window->OpenURLFromTab(source, params, + std::move(navigation_handle_callback)); } #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -1688,7 +1727,12 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, chrome::ConfigureTabGroupForNavigation(popup_delegate->nav_params()); - Navigate(popup_delegate->nav_params()); + base::WeakPtr navigation_handle = + Navigate(popup_delegate->nav_params()); + + if (navigation_handle_callback && navigation_handle) { + std::move(navigation_handle_callback).Run(*navigation_handle); + } content::WebContents* navigated_or_inserted_contents = popup_delegate->nav_params()->navigated_or_inserted_contents; @@ -1856,19 +1900,22 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) { GetStatusBubble()->SetURL(url); } -void Browser::ContentsMouseEvent(WebContents* source, - bool motion, - bool exited) { - exclusive_access_manager_->OnUserInput(); +void Browser::ContentsMouseEvent(WebContents* source, const ui::Event& event) { + const ui::EventType type = event.type(); + const bool exited = type == ui::ET_MOUSE_EXITED; + // Disregard synthesized events, and mouse enter and exit, which may occur + // without explicit user input events during window state changes. + if (type != ui::ET_MOUSE_ENTERED && !exited && !event.IsSynthesized()) { + exclusive_access_manager_->OnUserInput(); + } // Mouse motion events update the status bubble, if it exists. - if (!GetStatusBubble() || (!motion && !exited)) - return; - - if (source == tab_strip_model_->GetActiveWebContents()) { + if (GetStatusBubble() && source == tab_strip_model_->GetActiveWebContents() && + (type == ui::ET_MOUSE_MOVED || exited)) { GetStatusBubble()->MouseMoved(exited); - if (exited) + if (exited) { GetStatusBubble()->SetURL(GURL()); + } } } @@ -2044,6 +2091,14 @@ bool Browser::ShouldUseInstancedSystemMediaControls() const { return is_type_app() || is_type_app_popup(); } +void Browser::DraggableRegionsChanged( + const std::vector& regions, + content::WebContents* contents) { + if (app_controller_) { + app_controller_->DraggableRegionsChanged(regions, contents); + } +} + void Browser::DidFinishNavigation( content::WebContents* web_contents, content::NavigationHandle* navigation_handle) { @@ -2107,15 +2162,14 @@ ui::WindowShowState Browser::GetWindowShowState() const { } bool Browser::CanEnterFullscreenModeForTab( - content::RenderFrameHost* requesting_frame, - const blink::mojom::FullscreenOptions& options) { + content::RenderFrameHost* requesting_frame) { // If the tab strip isn't editable then a drag session is in progress, and it // is not safe to enter fullscreen. https://crbug.com/1315080 if (!tab_strip_model_delegate_->IsTabStripEditable()) return false; return exclusive_access_manager_->fullscreen_controller() - ->CanEnterFullscreenModeForTab(requesting_frame, options.display_id); + ->CanEnterFullscreenModeForTab(requesting_frame); } void Browser::EnterFullscreenModeForTab( @@ -2473,7 +2527,8 @@ void Browser::FileSelected(const ui::SelectedFileInfo& file_info, return; OpenURL(OpenURLParams(url, Referrer(), WindowOpenDisposition::CURRENT_TAB, - ui::PAGE_TRANSITION_TYPED, false)); + ui::PAGE_TRANSITION_TYPED, false), + /*navigation_handle_callback=*/{}); } void Browser::FileSelectionCanceled(void* params) { @@ -2515,7 +2570,7 @@ void Browser::OnTabInsertedAt(WebContents* contents, int index) { // added to it. This is because scheduling the delete can not be undone, and // proper cleanup is not done if a WebContents is added once delete it // scheduled (WebContents is leaked, unload handlers aren't checked...). - // TODO(crbug.com/1434387): this should check that `is_delete_scheduled_` is + // TODO(crbug.com/40064092): this should check that `is_delete_scheduled_` is // false. DUMP_WILL_BE_CHECK(!is_delete_scheduled_); @@ -2736,7 +2791,7 @@ void Browser::ScheduleUIUpdate(WebContents* source, unsigned changed_flags) { // WebContents may in some rare cases send updates after they've been detached // from the tabstrip but before they are deleted, causing a potential crash if // we proceed. For now bail out. - // TODO(crbug.com/1007379) Figure out a safe way to detach browser delegate + // TODO(crbug.com/40100269) Figure out a safe way to detach browser delegate // from WebContents when it's removed so this doesn't happen - then put a // DCHECK back here. if (tab_strip_model_->GetIndexOfWebContents(source) == TabStripModel::kNoTab) @@ -2846,7 +2901,7 @@ void Browser::ProcessPendingUIUpdates() { // hidden. if (flags & content::INVALIDATE_TYPE_TAB) { UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE); - // TODO(crbug.com/1062235): Ideally, we should simply ask the state to + // TODO(crbug.com/40122780): Ideally, we should simply ask the state to // update, and doing that in an appropriate and efficient manner. window()->UpdatePageActionIcon(PageActionIconType::kPwaInstall); } @@ -3016,8 +3071,15 @@ bool Browser::CanCloseWithMultipleTabs() { void Browser::InProgressDownloadResponse(bool cancel_downloads) { if (cancel_downloads) { cancel_download_confirmation_state_ = RESPONSE_RECEIVED; - std::move(warn_before_closing_callback_) - .Run(WarnBeforeClosingResult::kOkToClose); + + if (ShouldShowCookieMigrationNoticeForBrowser(*this)) { + ShowCookieClearOnExitMigrationNotice( + *this, base::BindOnce(&Browser::CookieMigrationNoticeResponse, + weak_factory_.GetWeakPtr())); + } else { + std::move(warn_before_closing_callback_) + .Run(WarnBeforeClosingResult::kOkToClose); + } return; } @@ -3049,6 +3111,12 @@ void Browser::MultitabResponse(chrome::MessageBoxResult result) { .Run(WarnBeforeClosingResult::kDoNotClose); } +void Browser::CookieMigrationNoticeResponse(bool proceed_closing) { + std::move(warn_before_closing_callback_) + .Run(proceed_closing ? WarnBeforeClosingResult::kOkToClose + : WarnBeforeClosingResult::kDoNotClose); +} + void Browser::FinishWarnBeforeClosing(WarnBeforeClosingResult result) { switch (result) { case WarnBeforeClosingResult::kOkToClose: @@ -3187,12 +3255,12 @@ bool Browser::AppBrowserSupportsWindowFeature(WindowFeature feature, // current page can be shown when browsing a url that is not inside the app. // Note: Final determination of whether or not the toolbar is shown is made // by the |AppBrowserController|. - // TODO(crbug.com/992834): Make this control the visibility of Browser + // TODO(crbug.com/40639933): Make this control the visibility of Browser // Controls more generally. case FEATURE_TOOLBAR: return true; case FEATURE_TITLEBAR: - // TODO(crbug.com/992834): Make this control the visibility of + // TODO(crbug.com/40639933): Make this control the visibility of // CustomTabBarView. case FEATURE_LOCATIONBAR: return check_can_support || !fullscreen; @@ -3250,7 +3318,7 @@ bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, case TYPE_APP: if (app_controller_) return AppBrowserSupportsWindowFeature(feature, check_can_support); - // TODO(crbug.com/992834): Change legacy apps to TYPE_APP_POPUP. + // TODO(crbug.com/40639933): Change legacy apps to TYPE_APP_POPUP. return AppPopupBrowserSupportsWindowFeature(feature, check_can_support); case TYPE_DEVTOOLS: case TYPE_APP_POPUP: @@ -3426,9 +3494,3 @@ BackgroundContents* Browser::CreateBackgroundContents( return contents; } - -#if BUILDFLAG(ENABLE_EXTENSIONS) -void Browser::SetURLElisionExtensionIDForTesting(const char* extension_id) { - url_elision_extension_id_ = extension_id; -} -#endif // BUILDFLAG(ENABLE_EXTENSIONS) diff --git a/src/chrome/browser/ui/browser.h b/src/chrome/browser/ui/browser.h index 9f73331d..191d48f3 100644 --- a/src/chrome/browser/ui/browser.h +++ b/src/chrome/browser/ui/browser.h @@ -27,6 +27,7 @@ #include "chrome/browser/ui/bookmarks/bookmark_bar.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper_observer.h" #include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" #include "chrome/browser/ui/simple_message_box.h" #include "chrome/browser/ui/signin/signin_view_controller.h" @@ -43,6 +44,7 @@ #include "content/public/browser/web_contents_delegate.h" #include "extensions/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h" +#include "third_party/blink/public/mojom/page/draggable_region.mojom-forward.h" #include "ui/base/page_transition_types.h" #include "ui/base/ui_base_types.h" #include "ui/base/window_open_disposition.h" @@ -61,6 +63,7 @@ class BrowserSyncedWindowDelegate; class BrowserLocationBarModelDelegate; class BrowserLiveTabContext; class BrowserWindow; +class BrowserWindowFeatures; class ExclusiveAccessManager; class FindBarController; class LocationBarModel; @@ -73,6 +76,10 @@ class TabStripModel; class TabStripModelDelegate; class TabMenuModelDelegate; +namespace tab_groups { +class DeletionDialogController; +} + namespace blink { enum class ProtocolHandlerSecurityLevel; } @@ -116,6 +123,10 @@ enum class BrowserClosingStatus { kDeniedUnloadHandlersNeedTime }; +// An instance of this class represents a single browser window on Desktop. All +// features that are scoped to a browser window should have lifetime semantics +// scoped to an instance of this class, usually via direct or indirect ownership +// of a std::unique_ptr. See BrowserWindowFeatures and TabFeatures. class Browser : public TabStripModelObserver, public WebContentsCollection::Observer, public content::WebContentsDelegate, @@ -126,11 +137,15 @@ class Browser : public TabStripModelObserver, public content::PageNavigator, public ThemeServiceObserver, public translate::ContentTranslateDriver::TranslationObserver, - public ui::SelectFileDialog::Listener { + public ui::SelectFileDialog::Listener, + public BrowserWindowInterface { public: // SessionService::WindowType mirrors these values. If you add to this // enum, look at SessionService::WindowType to see if it needs to be // updated. + // TODO(https://crbug.com/331031753): Several of these existing Window Types + // likely should not have been using Browser as a base to begin with and + // should be migrated. Please refrain from adding new types. enum Type { // Normal tabbed non-app browser (previously TYPE_TABBED). TYPE_NORMAL, @@ -174,10 +189,10 @@ class Browser : public TabStripModelObserver, FEATURE_TOOLBAR = 1 << 2, FEATURE_LOCATIONBAR = 1 << 3, FEATURE_BOOKMARKBAR = 1 << 4, - // TODO(crbug.com/992834): Add FEATURE_PAGECONTROLS to describe the presence - // of per-page controls such as Content Settings Icons, which should be - // decoupled from FEATURE_LOCATIONBAR as they have independent presence in - // Web App browsers. + // TODO(crbug.com/40639933): Add FEATURE_PAGECONTROLS to describe the + // presence of per-page controls such as Content Settings Icons, which + // should be decoupled from FEATURE_LOCATIONBAR as they have independent + // presence in Web App browsers. }; // The context for a download blocked notification from @@ -258,6 +273,11 @@ class Browser : public TabStripModelObserver, Profile* profile, bool user_gesture); + static CreateParams CreateForPictureInPicture(const std::string& app_name, + bool trusted_source, + Profile* profile, + bool user_gesture); + static CreateParams CreateForDevTools(Profile* profile); // The browser type. @@ -459,6 +479,16 @@ class Browser : public TabStripModelObserver, #endif // Never nullptr. + // + // When the last tab is removed, the browser attempts to close, see + // TabStripEmpty(). + // TODO(https://crbug.com/331031753): Several existing Browser::Types never + // show a tab strip, yet are forced to work with the tab strip API to deal + // with the previous condition. This creates confusing control flow both for + // the tab strip and this class. One or both of the following should happen: + // (1) tab_strip_model_ should become an optional member. + // (2) Variations of Browser::Type that never show a tab strip should not use + // this class. TabStripModel* tab_strip_model() const { return tab_strip_model_.get(); } // Never nullptr. @@ -474,6 +504,12 @@ class Browser : public TabStripModelObserver, chrome::BrowserCommandController* command_controller() { return command_controller_.get(); } + + tab_groups::DeletionDialogController* tab_group_deletion_dialog_controller() + const { + return tab_group_deletion_dialog_controller_.get(); + } + SessionID session_id() const { return session_id_; } bool omit_from_session_restore() const { return omit_from_session_restore_; } bool should_trigger_session_restore() const { @@ -499,6 +535,9 @@ class Browser : public TabStripModelObserver, SigninViewController* signin_view_controller() { return &signin_view_controller_; } + BrowserWindowFeatures* browser_window_features() const { + return features_.get(); + } base::WeakPtr AsWeakPtr(); base::WeakPtr AsWeakPtr() const; @@ -621,7 +660,7 @@ class Browser : public TabStripModelObserver, // // Note that there are other cases that may delay closing, such as downloads, // but that is done before any of these steps. - // TODO(https://crbug.com/1434387): See about unifying IsBrowserClosing() and + // TODO(crbug.com/40064092): See about unifying IsBrowserClosing() and // is_delete_scheduled(). bool IsAttemptingToCloseBrowser() const; bool IsBrowserClosing() const; @@ -681,10 +720,6 @@ class Browser : public TabStripModelObserver, // Saving can be disabled e.g. for the DevTools window. bool CanSaveContents(content::WebContents* web_contents) const; - std::unique_ptr SwapWebContents( - content::WebContents* old_contents, - std::unique_ptr new_contents); - // Returns whether favicon should be shown. bool ShouldDisplayFavicon(content::WebContents* web_contents) const; @@ -706,7 +741,10 @@ class Browser : public TabStripModelObserver, // Interface implementations //////////////////////////////////////////////// // Overridden from content::PageNavigator: - content::WebContents* OpenURL(const content::OpenURLParams& params) override; + content::WebContents* OpenURL( + const content::OpenURLParams& params, + base::OnceCallback + navigation_handle_callback) override; // Overridden from TabStripModelObserver: void OnTabStripModelChanged( @@ -778,6 +816,9 @@ class Browser : public TabStripModelObserver, void InitiatePreview(content::WebContents& web_contents, const GURL& url) override; bool ShouldUseInstancedSystemMediaControls() const override; + void DraggableRegionsChanged( + const std::vector& regions, + content::WebContents* contents) override; bool is_type_normal() const { return type_ == TYPE_NORMAL; } bool is_type_popup() const { return type_ == TYPE_POPUP; } @@ -809,11 +850,6 @@ class Browser : public TabStripModelObserver, bool ShouldRunUnloadListenerBeforeClosing(content::WebContents* web_contents); bool RunUnloadListenerBeforeClosing(content::WebContents* web_contents); - // Set if the browser is currently participating in a tab dragging process. - // This information is used to decide if fast resize will be used during - // dragging. - void SetIsInTabDragging(bool is_in_tab_dragging); - // Sets the browser's user title. Setting it to an empty string clears it. void SetWindowUserTitle(const std::string& user_title); @@ -828,6 +864,11 @@ class Browser : public TabStripModelObserver, void SetForceShowBookmarkBarFlag(ForceShowBookmarkBarFlag flag); void ClearForceShowBookmarkBarFlag(ForceShowBookmarkBarFlag flag); + // BrowserWindowInterface overrides: + views::WebView* GetWebView() override; + void OpenURL(const GURL& gurl, WindowOpenDisposition disposition) override; + const SessionID& GetSessionID() override; + private: friend class BrowserTest; friend class ExclusiveAccessTest; @@ -845,9 +886,6 @@ class Browser : public TabStripModelObserver, FRIEND_TEST_ALL_PREFIXES(ExclusiveAccessTest, TabEntersPresentationModeFromWindowed); FRIEND_TEST_ALL_PREFIXES(BrowserCloseTest, LastGuest); -#if BUILDFLAG(ENABLE_EXTENSIONS) - FRIEND_TEST_ALL_PREFIXES(BrowserTest, URLElisionExtensionSetsPref); -#endif // BUILDFLAG(ENABLE_EXTENSIONS) // Used to describe why a tab is being detached. This is used by // TabDetachedAtImpl. @@ -892,7 +930,9 @@ class Browser : public TabStripModelObserver, // Overridden from content::WebContentsDelegate: content::WebContents* OpenURLFromTab( content::WebContents* source, - const content::OpenURLParams& params) override; + const content::OpenURLParams& params, + base::OnceCallback + navigation_handle_callback) override; void NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) override; void VisibleSecurityStateChanged(content::WebContents* source) override; @@ -910,8 +950,7 @@ class Browser : public TabStripModelObserver, const gfx::Rect& bounds) override; void UpdateTargetURL(content::WebContents* source, const GURL& url) override; void ContentsMouseEvent(content::WebContents* source, - bool motion, - bool exited) override; + const ui::Event& event) override; void ContentsZoomChange(bool zoom_in) override; bool TakeFocus(content::WebContents* source, bool reverse) override; void BeforeUnloadFired(content::WebContents* source, @@ -973,8 +1012,7 @@ class Browser : public TabStripModelObserver, void RestoreFromWebAPI() override; ui::WindowShowState GetWindowShowState() const override; bool CanEnterFullscreenModeForTab( - content::RenderFrameHost* requesting_frame, - const blink::mojom::FullscreenOptions& options) override; + content::RenderFrameHost* requesting_frame) override; void EnterFullscreenModeForTab( content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) override; @@ -1143,6 +1181,11 @@ class Browser : public TabStripModelObserver, // MessageBox for when the window is closing if more than one tab is open void MultitabResponse(chrome::MessageBoxResult result); + // Called when the user has decided whether to proceed or not with the browser + // closure, in case the cookie migration notice was shown. |proceed_closing| + // is true if the browser can be closed. + void CookieMigrationNoticeResponse(bool proceed_closing); + // Called when all warnings have completed when attempting to close the // browser directly (e.g. via hotkey, close button, terminate signal, etc.) // Used as a WarnBeforeClosingCallback by HandleBeforeClose(). @@ -1238,8 +1281,6 @@ class Browser : public TabStripModelObserver, const content::StoragePartitionConfig& partition_config, content::SessionStorageNamespace* session_storage_namespace); - void SetURLElisionExtensionIDForTesting(const char* extension_id); - // Data members ///////////////////////////////////////////////////////////// PrefChangeRegistrar profile_pref_registrar_; @@ -1312,6 +1353,8 @@ class Browser : public TabStripModelObserver, // when the browser is closed with in-progress downloads. CancelDownloadConfirmationState cancel_download_confirmation_state_; + // State used to figure out whether we should prompt the user for confirmation + // when the browser is closed with multiple tabs open. CancelDownloadConfirmationState close_multitab_confirmation_state_; ///////////////////////////////////////////////////////////////////////////// @@ -1370,6 +1413,10 @@ class Browser : public TabStripModelObserver, std::unique_ptr command_controller_; + // Dialog controller that handles the showing of the deletion dialog. + std::unique_ptr + tab_group_deletion_dialog_controller_; + // True if the browser window has been shown at least once. bool window_has_shown_; @@ -1415,13 +1462,7 @@ class Browser : public TabStripModelObserver, int force_show_bookmark_bar_flags_ = ForceShowBookmarkBarFlag::kNone; -#if BUILDFLAG(ENABLE_EXTENSIONS) - // ID of an extension that historically was used to prevent URL elision in the - // omnibox, and now is being deprecated by migration to a pref. Only set by - // tests. - // TODO(crbug/324934130): remove after ~M125 or so. - static const char* url_elision_extension_id_; -#endif // BUILDFLAG(ENABLE_EXTENSIONS) + std::unique_ptr features_; // The following factory is used for chrome update coalescing. base::WeakPtrFactory chrome_updater_factory_{this}; diff --git a/src/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/src/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc index 4255bdc7..ce296c4c 100644 --- a/src/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc +++ b/src/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc @@ -20,7 +20,6 @@ #include "components/google/core/common/google_util.h" #include "components/offline_pages/buildflags/buildflags.h" #include "components/omnibox/browser/autocomplete_input.h" -#include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_prefs.h" #include "components/omnibox/common/omnibox_features.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -180,15 +179,11 @@ const gfx::VectorIcon* ChromeLocationBarModelDelegate::GetVectorIconOverride() GetURL(&url); if (url.SchemeIs(content::kChromeUIScheme)) { - return (OmniboxFieldTrial::IsChromeRefreshIconsEnabled()) - ? &omnibox::kProductChromeRefreshIcon - : &omnibox::kProductIcon; + return &omnibox::kProductChromeRefreshIcon; } if (url.SchemeIs(extensions::kExtensionScheme)) { - return (OmniboxFieldTrial::IsChromeRefreshIconsEnabled()) - ? &vector_icons::kExtensionChromeRefreshIcon - : &omnibox::kExtensionAppIcon; + return &vector_icons::kExtensionChromeRefreshIcon; } #endif diff --git a/src/chrome/browser/ui/views/accelerator_table.cc b/src/chrome/browser/ui/views/accelerator_table.cc index 56d8fd42..719bff66 100644 --- a/src/chrome/browser/ui/views/accelerator_table.cc +++ b/src/chrome/browser/ui/views/accelerator_table.cc @@ -159,7 +159,7 @@ const AcceleratorMapping kAcceleratorMap[] = { IDC_SHOW_AVATAR_MENU}, // Platform-specific key maps. -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) {ui::VKEY_BROWSER_BACK, ui::EF_NONE, IDC_BACK}, {ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, IDC_FORWARD}, {ui::VKEY_BROWSER_HOME, ui::EF_NONE, IDC_HOME}, @@ -168,8 +168,7 @@ const AcceleratorMapping kAcceleratorMap[] = { {ui::VKEY_BROWSER_REFRESH, ui::EF_SHIFT_DOWN, IDC_RELOAD_BYPASSING_CACHE}, {ui::VKEY_CLOSE, ui::EF_NONE, IDC_CLOSE_TAB}, {ui::VKEY_NEW, ui::EF_NONE, IDC_NEW_TAB}, -#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || - // BUILDFLAG(IS_FUCHSIA) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS) // Chrome OS supports the print key, however XKB conflates the print diff --git a/src/chrome/browser/ui/views/toolbar/toolbar_view.cc b/src/chrome/browser/ui/views/toolbar/toolbar_view.cc index 04e61c10..b2a62bc3 100644 --- a/src/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/src/chrome/browser/ui/views/toolbar/toolbar_view.cc @@ -68,6 +68,7 @@ #include "chrome/browser/ui/views/page_action/page_action_icon_container.h" #include "chrome/browser/ui/views/page_action/page_action_icon_controller.h" #include "chrome/browser/ui/views/performance_controls/battery_saver_button.h" +#include "chrome/browser/ui/views/performance_controls/performance_intervention_button.h" #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_toolbar_icon_view.h" #include "chrome/browser/ui/views/side_panel/side_panel_toolbar_container.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" @@ -231,6 +232,8 @@ ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view) container_view_ = AddChildView(std::make_unique()); + SetAccessibleRole(ax::mojom::Role::kToolbar); + if (display_mode_ == DisplayMode::NORMAL) { container_view_->SetBackground( std::make_unique(browser_view)); @@ -438,6 +441,12 @@ void ToolbarView::Init() { std::make_unique(browser_view_)); } + if (base::FeatureList::IsEnabled( + performance_manager::features::kPerformanceIntervention)) { + performance_intervention_button_ = container_view_->AddChildView( + std::make_unique()); + } + if (cast) cast_ = container_view_->AddChildView(std::move(cast)); @@ -480,13 +489,14 @@ void ToolbarView::Init() { const std::string sab_value = base::CommandLine::ForCurrentProcess()-> GetSwitchValueASCII("show-avatar-button"); - if (sab_value == "always") + if (sab_value == "always") { show_avatar_toolbar_button = true; - else if (sab_value == "incognito-and-guest") + } else if (sab_value == "incognito-and-guest") { show_avatar_toolbar_button = browser_->profile()->IsIncognitoProfile() || browser_->profile()->IsGuestSession(); - else if (sab_value == "never") + } else if (sab_value == "never") { show_avatar_toolbar_button = false; + } avatar_->SetVisible(show_avatar_toolbar_button); @@ -532,6 +542,13 @@ void ToolbarView::Init() { location_bar_->Init(); + show_forward_button_.Init( + prefs::kShowForwardButton, prefs, + base::BindRepeating(&ToolbarView::OnShowForwardButtonChanged, + base::Unretained(this))); + + forward_->SetVisible(show_forward_button_.GetValue()); + show_home_button_.Init( prefs::kShowHomeButton, prefs, base::BindRepeating(&ToolbarView::OnShowHomeButtonChanged, @@ -738,7 +755,8 @@ bool ToolbarView::GetAcceleratorForCommandId( //////////////////////////////////////////////////////////////////////////////// // ToolbarView, views::View overrides: -gfx::Size ToolbarView::CalculatePreferredSize() const { +gfx::Size ToolbarView::CalculatePreferredSize( + const views::SizeBounds& available_size) const { gfx::Size size; switch (display_mode_) { case DisplayMode::CUSTOM_TAB: @@ -753,7 +771,7 @@ gfx::Size ToolbarView::CalculatePreferredSize() const { // the toolbar to report an unreasonable height (see crbug.com/985909), we // cap the height at the size of known child views (location bar and back // button) plus margins. - // TODO(crbug.com/1033627): Figure out why the height reports incorrectly + // TODO(crbug.com/40663413): Figure out why the height reports incorrectly // on some installations. if (layout_manager_ && location_bar_->GetVisible()) { const int max_height = @@ -782,7 +800,7 @@ gfx::Size ToolbarView::GetMinimumSize() const { // the toolbar to report an unreasonable height (see crbug.com/985909), we // cap the height at the size of known child views (location bar and back // button) plus margins. - // TODO(crbug.com/1033627): Figure out why the height reports incorrectly + // TODO(crbug.com/40663413): Figure out why the height reports incorrectly // on some installations. if (layout_manager_ && location_bar_->GetVisible()) { const int max_height = @@ -838,7 +856,7 @@ void ToolbarView::Layout(PassKey) { // to the overflow state determined by the first pass. // TODO(pengchaocai): Explore possible optimizations. if (toolbar_controller_) { - // TODO(crbug.com/1499021) Move this logic into LayoutManager. + // TODO(crbug.com/40939901) Move this logic into LayoutManager. views::ManualLayoutUtil manual_layout_util(layout_manager_); const bool was_overflow_button_visible = toolbar_controller_->overflow_button()->GetVisible(); @@ -1024,7 +1042,7 @@ void ToolbarView::InitLayout() { if (base::FeatureList::IsEnabled(features::kResponsiveToolbar)) { constexpr int kToolbarFlexOrderStart = 1; - // TODO(crbug.com/1479588): Ignore containers till issue addressed. + // TODO(crbug.com/40929989): Ignore containers till issue addressed. toolbar_controller_ = std::make_unique( ToolbarController::GetDefaultResponsiveElements(browser_), ToolbarController::GetDefaultOverflowOrder(), kToolbarFlexOrderStart, @@ -1111,6 +1129,16 @@ void ToolbarView::UpdateTypeAndSeverity( } app_menu_button_->SetAccessibleName(accname_app); app_menu_button_->SetTypeAndSeverity(type_and_severity); + + if (base::FeatureList::IsEnabled(features::kDefaultBrowserPromptRefresh) && + DefaultBrowserPromptManager::GetInstance()->get_show_app_menu_prompt()) { + // Anytime the default chip is eligible to be shown, log whether the prompt + // was actually shown. This helps us understand how often it is pre-empted. + base::UmaHistogramBoolean( + "DefaultBrowser.AppMenu.DefaultChipShown", + type_and_severity.type == + AppMenuIconController::IconType::DEFAULT_BROWSER_PROMPT); + } } SkColor ToolbarView::GetDefaultColorForSeverity( @@ -1180,7 +1208,8 @@ views::AccessiblePaneView* ToolbarView::GetAsAccessiblePaneView() { return this; } -views::View* ToolbarView::GetAnchorView(PageActionIconType type) { +views::View* ToolbarView::GetAnchorView( + std::optional type) { return location_bar_; } @@ -1249,10 +1278,13 @@ void ToolbarView::LoadImages() { extensions_container_->UpdateAllIcons(); } +void ToolbarView::OnShowForwardButtonChanged() { + forward_->SetVisible(show_forward_button_.GetValue()); + InvalidateLayout(); +} + void ToolbarView::OnShowHomeButtonChanged() { home_->SetVisible(show_home_button_.GetValue()); - DeprecatedLayoutImmediately(); - SchedulePaint(); } void ToolbarView::OnTouchUiChanged() { diff --git a/src/components/download/internal/common/base_file.cc b/src/components/download/internal/common/base_file.cc index 4ed0c135..cfb978e7 100644 --- a/src/components/download/internal/common/base_file.cc +++ b/src/components/download/internal/common/base_file.cc @@ -7,6 +7,7 @@ #include #include +#include "base/containers/heap_array.h" #include "base/files/file.h" #include "base/files/file_util.h" #include "base/format_macros.h" @@ -225,12 +226,12 @@ bool BaseFile::ValidateDataInFile(int64_t offset, if (data_len <= 0) return true; - std::unique_ptr buffer(new char[data_len]); - int bytes_read = file_.Read(offset, buffer.get(), data_len); + auto buffer = base::HeapArray::Uninit(data_len); + int bytes_read = file_.Read(offset, buffer.data(), buffer.size()); if (bytes_read < 0 || static_cast(bytes_read) < data_len) return false; - return memcmp(data, buffer.get(), data_len) == 0; + return memcmp(data, buffer.data(), buffer.size()) == 0; } DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) { diff --git a/src/components/metrics/machine_id_provider_nonwin.cc b/src/components/metrics/machine_id_provider_nonwin.cc index 65d5c244..93ee049c 100644 --- a/src/components/metrics/machine_id_provider_nonwin.cc +++ b/src/components/metrics/machine_id_provider_nonwin.cc @@ -24,9 +24,6 @@ bool MachineIdProvider::HasId() { // On non-windows, the machine id is based on the hardware model name. // This will suffice as users are unlikely to change to the same machine model. std::string MachineIdProvider::GetMachineId() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch("disable-machine-id")) { - return std::string(); - } // Gets hardware model name. (e.g. 'Macbook Pro 16,1', 'iPhone 9,3') std::string hardware_model_name = base::SysInfo::HardwareModelName(); diff --git a/src/components/metrics/machine_id_provider_win.cc b/src/components/metrics/machine_id_provider_win.cc index 449324e7..3a2d83cd 100644 --- a/src/components/metrics/machine_id_provider_win.cc +++ b/src/components/metrics/machine_id_provider_win.cc @@ -5,6 +5,7 @@ #include "components/metrics/machine_id_provider.h" #include + #include #include diff --git a/src/components/os_crypt/async/browser/dpapi_key_provider.cc b/src/components/os_crypt/async/browser/dpapi_key_provider.cc index 3d053798..9cf17645 100644 --- a/src/components/os_crypt/async/browser/dpapi_key_provider.cc +++ b/src/components/os_crypt/async/browser/dpapi_key_provider.cc @@ -126,4 +126,8 @@ bool DPAPIKeyProvider::UseForEncryption() { return true; } +bool DPAPIKeyProvider::IsCompatibleWithOsCryptSync() { + return true; +} + } // namespace os_crypt_async diff --git a/src/components/os_crypt/sync/os_crypt_win.cc b/src/components/os_crypt/sync/os_crypt_win.cc index 33b46c53..e90585f1 100644 --- a/src/components/os_crypt/sync/os_crypt_win.cc +++ b/src/components/os_crypt/sync/os_crypt_win.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/os_crypt/sync/os_crypt.h" + #include #include "base/base64.h" @@ -16,7 +18,6 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/win/wincrypt_shim.h" -#include "components/os_crypt/sync/os_crypt.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/version_info/version_info.h" diff --git a/src/content/browser/BUILD.gn b/src/content/browser/BUILD.gn index ceda35b4..92f38903 100644 --- a/src/content/browser/BUILD.gn +++ b/src/content/browser/BUILD.gn @@ -63,7 +63,6 @@ source_set("browser") { "//base", "//base:base_static", "//base:clang_profiling_buildflags", - "//base/third_party/dynamic_annotations", "//base/tracing/protos:chrome_track_event_resources", "//build:branding_buildflags", "//build:chromecast_buildflags", @@ -111,6 +110,7 @@ source_set("browser") { "//components/url_formatter", "//components/variations", "//components/variations/net", + "//components/version_info", "//components/viz/client", "//components/viz/common", "//components/viz/host", @@ -222,10 +222,12 @@ source_set("browser") { "//services/video_capture:lib", "//services/video_capture/public/cpp", "//services/video_capture/public/mojom:constants", + "//services/video_effects/public/mojom:mojom", "//services/viz/privileged/mojom", "//services/viz/public/cpp/gpu", "//services/viz/public/mojom", - "//services/webnn/public/mojom", + "//services/webnn:webnn_service", + "//services/webnn:webnn_switches", "//skia", "//skia/public/mojom", "//storage/browser", @@ -277,6 +279,7 @@ source_set("browser") { "//ui/events/devices", "//ui/events/gestures/blink", "//ui/gfx", + "//ui/gfx:color_utils", "//ui/gfx/animation", "//ui/gfx/geometry", "//ui/gfx/geometry/mojom", @@ -414,8 +417,6 @@ source_set("browser") { "aggregation_service/report_scheduler_timer.h", "attribution_reporting/aggregatable_attribution_utils.cc", "attribution_reporting/aggregatable_attribution_utils.h", - "attribution_reporting/aggregatable_histogram_contribution.cc", - "attribution_reporting/aggregatable_histogram_contribution.h", "attribution_reporting/attribution_background_registrations_id.h", "attribution_reporting/attribution_beacon_id.h", "attribution_reporting/attribution_config.cc", @@ -485,7 +486,6 @@ source_set("browser") { "attribution_reporting/storable_source.h", "attribution_reporting/store_source_result.cc", "attribution_reporting/store_source_result.h", - "attribution_reporting/store_source_result_internal.h", "attribution_reporting/stored_source.cc", "attribution_reporting/stored_source.h", "audio/audio_service.cc", @@ -761,8 +761,6 @@ source_set("browser") { "cookie_store/cookie_store_host.h", "cookie_store/cookie_store_manager.cc", "cookie_store/cookie_store_manager.h", - "coop_related_group.cc", - "coop_related_group.h", "data_url_loader_factory.cc", "data_url_loader_factory.h", "device/device_service.cc", @@ -889,6 +887,8 @@ source_set("browser") { "devtools/protocol/tracing_handler.h", "devtools/render_frame_devtools_agent_host.cc", "devtools/render_frame_devtools_agent_host.h", + "devtools/request_body_collector.cc", + "devtools/request_body_collector.h", "devtools/service_worker_devtools_agent_host.cc", "devtools/service_worker_devtools_agent_host.h", "devtools/service_worker_devtools_manager.cc", @@ -1159,6 +1159,8 @@ source_set("browser") { "interest_group/interest_group_permissions_checker.h", "interest_group/interest_group_priority_util.cc", "interest_group/interest_group_priority_util.h", + "interest_group/interest_group_real_time_report_util.cc", + "interest_group/interest_group_real_time_report_util.h", "interest_group/interest_group_storage.cc", "interest_group/interest_group_storage.h", "interest_group/interest_group_update.cc", @@ -1333,11 +1335,8 @@ source_set("browser") { "memory_pressure/user_level_memory_pressure_signal_generator.cc", "memory_pressure/user_level_memory_pressure_signal_generator.h", "message_port_provider.cc", - "metrics/histogram_controller.cc", - "metrics/histogram_controller.h", "metrics/histogram_shared_memory_config.cc", "metrics/histogram_shared_memory_config.h", - "metrics/histogram_subscriber.h", "metrics/histogram_synchronizer.cc", "metrics/histogram_synchronizer.h", "metrics/histograms_internals_ui.cc", @@ -1350,6 +1349,10 @@ source_set("browser") { "ml/ml_service_factory.h", "ml/ml_service_impl.cc", "ml/ml_service_impl.h", + "model_execution/mock_model_execution_session.cc", + "model_execution/mock_model_execution_session.h", + "model_execution/mock_model_manager.cc", + "model_execution/mock_model_manager.h", "mojo_binder_policy_applier.cc", "mojo_binder_policy_applier.h", "mojo_binder_policy_map_impl.cc", @@ -1363,8 +1366,6 @@ source_set("browser") { "network/cookie_store_factory.cc", "network/cross_origin_embedder_policy_reporter.cc", "network/cross_origin_embedder_policy_reporter.h", - "network/cross_origin_opener_policy_reporter.cc", - "network/cross_origin_opener_policy_reporter.h", "network/http_cache_backend_file_operations_factory.cc", "network/http_cache_backend_file_operations_factory.h", "network/network_errors_listing_ui.cc", @@ -1511,6 +1512,7 @@ source_set("browser") { "preloading/preloading.h", "preloading/preloading_attempt_impl.cc", "preloading/preloading_attempt_impl.h", + "preloading/preloading_confidence.h", "preloading/preloading_config.cc", "preloading/preloading_config.h", "preloading/preloading_data_impl.cc", @@ -1545,6 +1547,8 @@ source_set("browser") { "preloading/prerender/prerender_navigation_utils.h", "preloading/prerender/prerender_new_tab_handle.cc", "preloading/prerender/prerender_new_tab_handle.h", + "preloading/prerender/prerender_no_vary_search_commit_deferring_condition.cc", + "preloading/prerender/prerender_no_vary_search_commit_deferring_condition.h", "preloading/prerender/prerender_subframe_navigation_throttle.cc", "preloading/prerender/prerender_subframe_navigation_throttle.h", "preloading/prerenderer.h", @@ -1635,11 +1639,6 @@ source_set("browser") { "renderer_host/concurrent_navigations_commit_deferring_condition.h", "renderer_host/cookie_utils.cc", "renderer_host/cookie_utils.h", - "renderer_host/coop_swap_result.h", - "renderer_host/cross_origin_opener_policy_access_report_manager.cc", - "renderer_host/cross_origin_opener_policy_access_report_manager.h", - "renderer_host/cross_origin_opener_policy_status.cc", - "renderer_host/cross_origin_opener_policy_status.h", "renderer_host/cross_process_frame_connector.cc", "renderer_host/cross_process_frame_connector.h", "renderer_host/cursor_manager.cc", @@ -1822,10 +1821,6 @@ source_set("browser") { "renderer_host/page_impl.h", "renderer_host/page_lifecycle_state_manager.cc", "renderer_host/page_lifecycle_state_manager.h", - "renderer_host/pending_beacon_host.cc", - "renderer_host/pending_beacon_host.h", - "renderer_host/pending_beacon_service.cc", - "renderer_host/pending_beacon_service.h", "renderer_host/policy_container_host.cc", "renderer_host/policy_container_host.h", "renderer_host/private_network_access_util.cc", @@ -1879,8 +1874,6 @@ source_set("browser") { "renderer_host/render_widget_host_view_aura.h", "renderer_host/render_widget_host_view_base.cc", "renderer_host/render_widget_host_view_base.h", - "renderer_host/render_widget_host_view_base_observer.cc", - "renderer_host/render_widget_host_view_base_observer.h", "renderer_host/render_widget_host_view_child_frame.cc", "renderer_host/render_widget_host_view_child_frame.h", "renderer_host/render_widget_targeter.cc", @@ -1916,8 +1909,6 @@ source_set("browser") { "resource_context_impl.cc", "resource_context_impl.h", "resource_coordinator_service.cc", - "runtime_feature_state/runtime_feature_state_document_data.cc", - "runtime_feature_state/runtime_feature_state_document_data.h", "scheduler/browser_io_thread_delegate.cc", "scheduler/browser_io_thread_delegate.h", "scheduler/browser_task_executor.cc", @@ -1952,6 +1943,15 @@ source_set("browser") { "screenlock_monitor/screenlock_monitor_device_source.h", "screenlock_monitor/screenlock_monitor_source.cc", "screenlock_monitor/screenlock_monitor_source.h", + "security/coop/coop_related_group.cc", + "security/coop/coop_related_group.h", + "security/coop/coop_swap_result.h", + "security/coop/cross_origin_opener_policy_access_report_manager.cc", + "security/coop/cross_origin_opener_policy_access_report_manager.h", + "security/coop/cross_origin_opener_policy_reporter.cc", + "security/coop/cross_origin_opener_policy_reporter.h", + "security/coop/cross_origin_opener_policy_status.cc", + "security/coop/cross_origin_opener_policy_status.h", "service_process_host_impl.cc", "service_worker/embedded_worker_instance.cc", "service_worker/embedded_worker_instance.h", @@ -2096,6 +2096,8 @@ source_set("browser") { "speech/speech_recognition_dispatcher_host.h", "speech/speech_recognition_manager_impl.cc", "speech/speech_recognition_manager_impl.h", + "speech/speech_recognition_session.cc", + "speech/speech_recognition_session.h", "speech/speech_recognizer.h", "speech/speech_synthesis_impl.cc", "speech/speech_synthesis_impl.h", @@ -2339,11 +2341,11 @@ source_set("browser") { ] } - # TODO(crbug.com/1327384): Remove `permissions_common`. + # TODO(crbug.com/40226169): Remove `permissions_common`. # DO NOT add unrelated entries to this block. deps += [ "//components/permissions:permissions_common" ] - # TODO(crbug.com/1327384): Remove `permission_util.*`. + # TODO(crbug.com/40226169): Remove `permission_util.*`. # DO NOT add unrelated entries to this block. sources += [ "permissions/permission_util.cc", @@ -2637,6 +2639,10 @@ source_set("browser") { ] } else if (is_ios) { sources += [ + "accessibility/browser_accessibility_ios.h", + "accessibility/browser_accessibility_ios.mm", + "accessibility/browser_accessibility_manager_ios.h", + "accessibility/browser_accessibility_manager_ios.mm", "child_process_launcher_helper_ios.mm", "date_time_chooser/ios/date_time_chooser_coordinator.h", "date_time_chooser/ios/date_time_chooser_coordinator.mm", @@ -2660,6 +2666,10 @@ source_set("browser") { "renderer_host/popup_menu_helper_ios.mm", "renderer_host/render_widget_host_view_ios.h", "renderer_host/render_widget_host_view_ios.mm", + "renderer_host/render_widget_host_view_ios_uiview.h", + "renderer_host/render_widget_host_view_ios_uiview.mm", + "renderer_host/render_widget_host_view_ios_uiview_textinput.h", + "renderer_host/render_widget_host_view_ios_uiview_textinput.mm", "renderer_host/web_menu_runner_ios.h", "renderer_host/web_menu_runner_ios.mm", "speech/tts_ios.mm", @@ -2817,12 +2827,8 @@ source_set("browser") { "speech/tts_win.cc", "utility_sandbox_delegate_win.cc", ] - defines += [ - # This prevents the inclusion of atlhost.h which paired - # with the windows 8 sdk it does the wrong thing. - "__ATLHOST_H__", - ] deps += [ + "//components/app_launch_prefetch", "//content/utility:delegate_data", "//services/screen_ai/public/cpp:utilities", "//third_party/blink/public/common:font_unique_name_table_proto", @@ -3043,6 +3049,7 @@ source_set("browser") { "android/content_url_loader_factory.cc", "android/content_url_loader_factory.h", "android/content_view_statics.cc", + "android/content_web_feature_usage_utils_android.cc", "android/devtools_auth.cc", "android/dialog_overlay_impl.cc", "android/dialog_overlay_impl.h", @@ -3305,11 +3312,23 @@ source_set("browser") { "picture_in_picture/document_picture_in_picture_window_controller_impl.h", ] + if (!is_fuchsia) { + sources += [ + "speech/soda_speech_recognition_engine_impl.cc", + "speech/soda_speech_recognition_engine_impl.h", + ] + } + deps += [ + "//components/soda:constants", + "//components/soda:soda", + "//components/soda:utils", "//components/speech:speech", "//components/vector_icons", "//components/webauthn/json", "//content/browser/tracing:resources", + "//media/mojo/mojom:speech_recognition", + "//ui/base", ] } diff --git a/src/content/browser/file_system_access/file_system_access_safe_move_helper.cc b/src/content/browser/file_system_access/file_system_access_safe_move_helper.cc index a35110b0..650963df 100644 --- a/src/content/browser/file_system_access/file_system_access_safe_move_helper.cc +++ b/src/content/browser/file_system_access/file_system_access_safe_move_helper.cc @@ -203,7 +203,7 @@ bool FileSystemAccessSafeMoveHelper::RequireAfterWriteChecks() const { if (!source_url().IsInSameFileSystem(dest_url())) return true; - // TODO(crbug.com/1250534): Properly handle directory moves here, for + // TODO(crbug.com/40198034): Properly handle directory moves here, for // which extension checks don't make sense. auto source_extension = source_url().path().Extension(); auto dest_extension = dest_url().path().Extension(); diff --git a/src/content/browser/file_system_access/file_system_access_safe_move_helper.h b/src/content/browser/file_system_access/file_system_access_safe_move_helper.h index e50f92a2..08704604 100644 --- a/src/content/browser/file_system_access/file_system_access_safe_move_helper.h +++ b/src/content/browser/file_system_access/file_system_access_safe_move_helper.h @@ -15,7 +15,7 @@ namespace content { -// TODO(crbug.com/1250534): Support safely moving directories. For now, this +// TODO(crbug.com/40198034): Support safely moving directories. For now, this // class only supports moving files. Moving directories will require running // safe browsing checks on all files before moving. // diff --git a/src/media/filters/win/media_foundation_audio_decoder.cc b/src/media/filters/win/media_foundation_audio_decoder.cc new file mode 100644 index 00000000..551787e2 --- /dev/null +++ b/src/media/filters/win/media_foundation_audio_decoder.cc @@ -0,0 +1,612 @@ +// Copyright 2024 The Chromium Authors and Alex313031 + +// TODO: Alex313031 - DELETE AFTER M127!! + +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/filters/win/media_foundation_audio_decoder.h" + +#include +#include +#include +#include + +#include "base/auto_reset.h" +#include "base/containers/span.h" +#include "base/containers/span_writer.h" +#include "base/functional/bind.h" +#include "base/logging.h" +#include "base/task/bind_post_task.h" +#include "base/win/scoped_co_mem.h" +#include "base/win/windows_version.h" +#include "media/base/audio_buffer.h" +#include "media/base/audio_discard_helper.h" +#include "media/base/audio_sample_types.h" +#include "media/base/limits.h" +#include "media/base/status.h" +#include "media/base/timestamp_constants.h" +#include "media/base/win/mf_helpers.h" +#include "media/base/win/mf_initializer.h" + +namespace media { + +namespace { + +bool CodecSupportsFloatOutput(AudioCodec codec) { +#if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO) + if (codec == AudioCodec::kAC3 || codec == AudioCodec::kEAC3) { + return true; + } +#endif +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + if (codec == AudioCodec::kAAC) { + return true; + } +#endif +#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) + if (codec == AudioCodec::kAC4) { + return true; + } +#endif + return false; +} + +bool CodecSupportsFormat(const AudioDecoderConfig& config, + const WAVEFORMATEX& format) { + if (config.channels() == format.nChannels && + config.samples_per_second() == static_cast(format.nSamplesPerSec)) { + return true; + } + + // Sometimes HE-AAC configurations may be off by a factor of two, so allow + // such cases -- they'll reconfigure upon first decoded frame. + if (config.codec() == AudioCodec::kAAC && + 2 * config.channels() == format.nChannels && + 2 * config.samples_per_second() == + static_cast(format.nSamplesPerSec)) { + return true; + } + + // For AC3/EAC3, we expect channel config changes, no need to compare channels + // here. + if ((config.codec() == AudioCodec::kAC3 || + config.codec() == AudioCodec::kEAC3) && + config.samples_per_second() == static_cast(format.nSamplesPerSec)) { + return true; + } + + if (config.codec() == AudioCodec::kAC4) { + return true; + } + + return false; +} + +std::optional GetTypeInfo( + const AudioDecoderConfig& config) { + switch (config.codec()) { +#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + case AudioCodec::kDTSXP2: + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, MFAudioFormat_DTS_UHD}; + case AudioCodec::kDTS: + case AudioCodec::kDTSE: + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, MFAudioFormat_DTS_RAW}; +#endif +#if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO) + case AudioCodec::kAC3: + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, MFAudioFormat_Dolby_AC3}; + case AudioCodec::kEAC3: + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, + MFAudioFormat_Dolby_DDPlus}; +#endif +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + case AudioCodec::kAAC: + if (config.profile() == AudioCodecProfile::kXHE_AAC && + base::win::GetVersion() >= base::win::Version::WIN11_22H2) { + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, MFAudioFormat_AAC}; + } + [[fallthrough]]; +#endif +#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) + case AudioCodec::kAC4: + return MFT_REGISTER_TYPE_INFO{MFMediaType_Audio, MFAudioFormat_Dolby_AC4}; +#endif // BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) + default: + return std::nullopt; + } +} + +bool PopulateInputSample(IMFSample* sample, const DecoderBuffer& input) { + Microsoft::WRL::ComPtr buffer; + HRESULT hr = sample->GetBufferByIndex(0, &buffer); + RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", false); + + DWORD max_length = 0; + DWORD current_length = 0; + uint8_t* destination_ptr = nullptr; + hr = buffer->Lock(&destination_ptr, &max_length, ¤t_length); + RETURN_ON_HR_FAILURE(hr, "Failed to lock buffer", false); + // SAFETY: IMFMediaBuffer::Lock returns a pointer that points to at least + // `max_length` many bytes. + // https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediabuffer-lock + auto destination = UNSAFE_BUFFERS(base::span(destination_ptr, max_length)); + + RETURN_ON_FAILURE(!current_length, "Input length is zero", false); + RETURN_ON_FAILURE(input.size() <= max_length, "Input length is too long", + false); + destination.first(input.size()).copy_from(input); + + hr = buffer->SetCurrentLength(input.size()); + RETURN_ON_HR_FAILURE(hr, "Failed to set buffer length", false); + + hr = buffer->Unlock(); + RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", false); + + RETURN_ON_HR_FAILURE( + sample->SetSampleTime(input.timestamp().InNanoseconds() / 100), + "Failed to set input timestamp", false); + RETURN_ON_HR_FAILURE( + sample->SetSampleDuration(input.duration().InNanoseconds() / 100), + "Failed to set input duration", false); + return true; +} + +int GetBytesPerFrame(AudioCodec codec) { + switch (codec) { +#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + // DTS Sound Unbound MFT v1.3 supports 24-bit PCM output only + case AudioCodec::kDTS: + case AudioCodec::kDTSE: + case AudioCodec::kDTSXP2: + return 3; +#endif // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + default: + return 4; + } +} + +} // namespace + +// static +std::unique_ptr +MediaFoundationAudioDecoder::Create() { + return InitializeMediaFoundation() + ? std::make_unique() + : nullptr; +} + +MediaFoundationAudioDecoder::MediaFoundationAudioDecoder() = default; + +MediaFoundationAudioDecoder::~MediaFoundationAudioDecoder() = default; + +AudioDecoderType MediaFoundationAudioDecoder::GetDecoderType() const { + return AudioDecoderType::kMediaFoundation; +} + +void MediaFoundationAudioDecoder::Initialize(const AudioDecoderConfig& config, + CdmContext* cdm_context, + InitCB init_cb, + const OutputCB& output_cb, + const WaitingCB& waiting_cb) { + if (config.is_encrypted()) { + std::move(init_cb).Run( + DecoderStatus(DecoderStatus::Codes::kUnsupportedEncryptionMode, + "MFT Codec does not support encrypted content")); + return; + } + + config_ = config; + output_cb_ = output_cb; + + base::BindPostTaskToCurrentDefault(std::move(init_cb)) + .Run(CreateDecoder() + ? DecoderStatus(OkStatus()) + : DecoderStatus(DecoderStatus::Codes::kUnsupportedCodec)); +} + +void MediaFoundationAudioDecoder::Decode(scoped_refptr buffer, + DecodeCB decode_cb) { + DecodeCB decode_cb_bound = + base::BindPostTaskToCurrentDefault(std::move(decode_cb)); + + if (buffer->end_of_stream()) { + switch (decoder_->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0)) { + case S_OK: { + OutputStatus rc; + do { + rc = PumpOutput(PumpState::kNormal); + } while (rc == OutputStatus::kSuccess); + // Return kOk if more input is needed since this is end of stream + std::move(decode_cb_bound) + .Run(rc == OutputStatus::kFailed ? DecoderStatus::Codes::kFailed + : DecoderStatus::Codes::kOk); + return; + } + case MF_E_TRANSFORM_TYPE_NOT_SET: + std::move(decode_cb_bound) + .Run(DecoderStatus::Codes::kPlatformDecodeFailure); + return; + default: + std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed); + return; + } + } + + if (buffer->is_encrypted()) { + DLOG(ERROR) << "Encrypted buffer not supported"; + std::move(decode_cb_bound) + .Run(DecoderStatus::Codes::kUnsupportedEncryptionMode); + return; + } + + if (buffer->timestamp() == kNoTimestamp) { + DLOG(ERROR) << "Received a buffer without timestamps!"; + std::move(decode_cb_bound).Run(DecoderStatus::Codes::kMissingTimestamp); + return; + } + + if (has_reset_) { + ResetTimestampState(); + has_reset_ = false; + } + + auto sample = CreateEmptySampleWithBuffer(buffer->size(), 0); + if (!sample) { + std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed); + return; + } + + if (!PopulateInputSample(sample.Get(), *buffer)) { + std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed); + return; + } + + auto hr = decoder_->ProcessInput(0, sample.Get(), 0); + if (hr != S_OK && hr != MF_E_NOTACCEPTING) { + DecoderStatus::Codes rc; + switch (hr) { + case MF_E_NO_SAMPLE_DURATION: + rc = DecoderStatus::Codes::kDecoderStreamInErrorState; + break; + case MF_E_TRANSFORM_TYPE_NOT_SET: + rc = DecoderStatus::Codes::kPlatformDecodeFailure; + break; + case MF_E_NO_SAMPLE_TIMESTAMP: + rc = DecoderStatus::Codes::kMissingTimestamp; + break; + default: + rc = DecoderStatus::Codes::kFailed; + break; + } + // Drop remaining samples on error, no need to call PumpOutput + std::move(decode_cb_bound).Run(rc); + return; + } + + current_buffer_time_info_ = buffer->time_info(); + + bool decoded_frame_this_loop = false; + OutputStatus rc; + do { + rc = PumpOutput(PumpState::kNormal); + if (rc == OutputStatus::kNeedMoreInput) + break; + if (rc == OutputStatus::kFailed) { + std::move(decode_cb_bound).Run(DecoderStatus::Codes::kFailed); + return; + } + decoded_frame_this_loop = true; + } while (rc == OutputStatus::kSuccess); + + // Even if we didn't decode a frame this loop, we should still send the packet + // to the discard helper for caching. + if (!decoded_frame_this_loop && !buffer->end_of_stream()) { + const bool result = + discard_helper_->ProcessBuffers(current_buffer_time_info_, nullptr); + DCHECK(!result); + } + + std::move(decode_cb_bound).Run(OkStatus()); +} + +void MediaFoundationAudioDecoder::Reset(base::OnceClosure reset_cb) { + has_reset_ = true; + auto hr = decoder_->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0); + if (hr != S_OK) { + DLOG(ERROR) << "Reset failed with \"" << PrintHr(hr) << "\""; + } + base::BindPostTaskToCurrentDefault(std::move(reset_cb)).Run(); +} + +bool MediaFoundationAudioDecoder::NeedsBitstreamConversion() const { + // DTS does not require any header/bit stream conversion + return false; +} + +bool MediaFoundationAudioDecoder::CreateDecoder() { + auto type_info = GetTypeInfo(config_); + + // This shouldn't be possible outside of tests since production code will use + // the MediaFoundationAudioDecoder::Create() which enforces this. + if (!type_info || !InitializeMediaFoundation()) { + return false; + } + + // Find the decoder factory. + // + // Note: It'd be nice if there was an asynchronous MFT (to avoid the need + // for a codec pump), but alas MFT_ENUM_FLAG_ASYNC_MFT returns no matches :( + base::win::ScopedCoMem acts; + UINT32 acts_num = 0; + MFTEnumEx(MFT_CATEGORY_AUDIO_DECODER, + MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | + MFT_ENUM_FLAG_SORTANDFILTER, + &type_info.value(), nullptr, &acts, &acts_num); + if (acts_num < 1) { + return false; + } + + // Create the decoder from the factory. Activate the first MFT object. + RETURN_ON_HR_FAILURE(acts[0]->ActivateObject(IID_PPV_ARGS(&decoder_)), + "Failed to activate MFT", false); + + // Release all activated and unactivated object after creating the decoder + for (UINT32 curr_act = 0; curr_act < acts_num; ++curr_act) { + acts[curr_act]->Release(); + } + + Microsoft::WRL::ComPtr input_type; + auto hr = E_NOTIMPL; + if (config_.codec() == AudioCodec::kAAC) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + hr = GetAacAudioType(config_, &input_type); +#endif + } else { + hr = GetDefaultAudioType(config_, &input_type); + } + + RETURN_ON_HR_FAILURE(hr, "Failed to create IMFMediaType for input data", + false); + RETURN_ON_HR_FAILURE(decoder_->SetInputType(0, input_type.Get(), 0), + "Failed to set input type for IMFTransform", false); + + return ConfigureOutput(); +} + +bool MediaFoundationAudioDecoder::ConfigureOutput() { + // Reset sample staging buffer before configure output, in case stream + // configuration changed. + output_sample_.Reset(); + Microsoft::WRL::ComPtr output_type; + for (uint32_t i = 0; + SUCCEEDED(decoder_->GetOutputAvailableType(0, i, &output_type)); ++i) { + GUID out_type; + RETURN_ON_HR_FAILURE(output_type->GetGUID(MF_MT_MAJOR_TYPE, &out_type), + "Failed to get output main type", false); + GUID out_subtype; + RETURN_ON_HR_FAILURE(output_type->GetGUID(MF_MT_SUBTYPE, &out_subtype), + "Failed to get output subtype", false); + +#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + // Configuration specific to DTS Sound Unbound MFT v1.3.0 + // DTS-CA 5.1 (6 channels) + constexpr uint32_t DTS_5_1 = 2; + // DTS:X P2 5.1 (6 channels) or 5.1.4 (downmix to 6 channels) + constexpr uint32_t DTSX_5_1_DOWNMIX = 3; + + if ((out_subtype == MFAudioFormat_PCM) && + ((config_.codec() == AudioCodec::kDTS && i == DTS_5_1) || + (config_.codec() == AudioCodec::kDTSE && i == DTS_5_1) || + (config_.codec() == AudioCodec::kDTSXP2 && i == DTSX_5_1_DOWNMIX))) { + RETURN_ON_HR_FAILURE(decoder_->SetOutputType(0, output_type.Get(), 0), + "Failed to set output type IMFTransform", false); + + RETURN_ON_HR_FAILURE( + output_type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &channel_count_), + "Failed to get output channel count", false); + + MFT_OUTPUT_STREAM_INFO info = {0}; + RETURN_ON_HR_FAILURE(decoder_->GetOutputStreamInfo(0, &info), + "Failed to get output stream info", false); + + if (channel_count_ == 6) { + output_sample_ = + CreateEmptySampleWithBuffer(info.cbSize, info.cbAlignment); + RETURN_ON_FAILURE(!!output_sample_, "Failed to create staging sample", + false); + } + } +#endif // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + + if (CodecSupportsFloatOutput(config_.codec()) && + out_subtype == MFAudioFormat_Float) { + base::win::ScopedCoMem wave_format; + UINT32 wave_format_size; + RETURN_ON_HR_FAILURE( + MFCreateWaveFormatExFromMFMediaType(output_type.Get(), &wave_format, + &wave_format_size), + "Failed to get waveformat for media type", false); + if (CodecSupportsFormat(config_, *wave_format)) { + RETURN_ON_HR_FAILURE(decoder_->SetOutputType(0, output_type.Get(), 0), + "Failed to set output type IMFTransform", false); + + MFT_OUTPUT_STREAM_INFO info = {0}; + RETURN_ON_HR_FAILURE(decoder_->GetOutputStreamInfo(0, &info), + "Failed to get output stream info", false); + + output_sample_ = + CreateEmptySampleWithBuffer(info.cbSize, info.cbAlignment); + RETURN_ON_FAILURE(!!output_sample_, "Failed to create staging sample", + false); + + channel_count_ = wave_format->nChannels; + } + } + + if (!output_sample_) { + output_type.Reset(); + continue; + } + + // Check the optional channel mask argument. + ChannelConfig mask = 0u; + auto hr = output_type->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &mask); + if (hr == MF_E_ATTRIBUTENOTFOUND) { + channel_layout_ = GuessChannelLayout(channel_count_); + } else { + RETURN_ON_HR_FAILURE(hr, "Failed to get output channel mask", false); + channel_layout_ = ChannelConfigToChannelLayout(mask); + + RETURN_ON_FAILURE(static_cast(ChannelLayoutToChannelCount( + channel_layout_)) == channel_count_ || + channel_layout_ == CHANNEL_LAYOUT_DISCRETE, + "Channel layout and channel count don't match", false); + } + + const auto current_sample_rate = sample_rate_; + RETURN_ON_HR_FAILURE( + output_type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate_), + "Failed to get output sample rate", false); + + RETURN_ON_FAILURE( + channel_count_ > 0 && channel_count_ <= limits::kMaxChannels, + "Channel count is not supported", false); + + RETURN_ON_FAILURE(sample_rate_ >= limits::kMinSampleRate && + sample_rate_ <= limits::kMaxSampleRate, + "Sample rate is not supported", false); + + if (current_sample_rate != sample_rate_) { + ResetTimestampState(); + } + decoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); + return true; + } + + return false; +} + +MediaFoundationAudioDecoder::OutputStatus +MediaFoundationAudioDecoder::PumpOutput(PumpState pump_state) { + // Unlike video, the audio MFT requires that we provide the output sample + // instead of allocating it for us. + MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; + output_data_buffer.pSample = output_sample_.Get(); + + DWORD status = 0; + auto hr = decoder_->ProcessOutput(0, 1, &output_data_buffer, &status); + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { + DVLOG(3) << __func__ << "More input needed to decode outputs."; + return OutputStatus::kNeedMoreInput; + } + + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && + pump_state != PumpState::kStreamChange) { + if (!ConfigureOutput()) { + return OutputStatus::kFailed; + } + + DVLOG(1) << "New config: ch=" << channel_count_ << ", sr=" << sample_rate_ + << " (" << config_.AsHumanReadableString() << ")"; + PumpOutput(PumpState::kStreamChange); + return OutputStatus::kStreamChange; + } + + RETURN_ON_HR_FAILURE(hr, "Failed to process output", OutputStatus::kFailed); + + // Unused, but must be released. + IMFCollection* events = output_data_buffer.pEvents; + if (events) + events->Release(); + + Microsoft::WRL::ComPtr output_buffer; + RETURN_ON_HR_FAILURE( + output_sample_->ConvertToContiguousBuffer(&output_buffer), + "Failed to map sample into a contiguous output buffer", + OutputStatus::kFailed); + + DWORD current_length = 0; + uint8_t* destination_ptr = nullptr; + RETURN_ON_HR_FAILURE( + output_buffer->Lock(&destination_ptr, NULL, ¤t_length), + "Failed to lock output buffer", OutputStatus::kFailed); + // SAFETY: IMFMediaBuffer::Lock returns a pointer that points to at least + // `current_length` many bytes (and up to a larger max, which we discard). + // https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediabuffer-lock + auto destination = + UNSAFE_BUFFERS(base::span(destination_ptr, current_length)); + + // Output is always configured to be interleaved float. + int sample_byte_len = GetBytesPerFrame(config_.codec()); + size_t frames = (current_length / sample_byte_len / channel_count_); + RETURN_ON_FAILURE(frames > 0u, "Invalid output buffer size", + OutputStatus::kFailed); + + if (!pool_) + pool_ = base::MakeRefCounted(); + + scoped_refptr audio_buffer; + +#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + // DTS Sound Unbound MFT v1.3.0 outputs 24-bit PCM samples, and will + // be converted to 32-bit float + if (config_.codec() == AudioCodec::kDTS || + config_.codec() == AudioCodec::kDTSE || + config_.codec() == AudioCodec::kDTSXP2) { + audio_buffer = + AudioBuffer::CreateBuffer(kSampleFormatF32, channel_layout_, + channel_count_, sample_rate_, frames, pool_); + auto channel_data = base::SpanWriter( + // TODO(crbug.com/40284755): channel_data() should be an array of spans, + // not unbounded pointers. This span is constructed unsoundly. + UNSAFE_BUFFERS(base::span(audio_buffer->channel_data()[0u], + frames * channel_count_ * 4u))); + for (uint64_t i = 0; i < frames; i++) { + for (uint64_t ch = 0; ch < channel_count_; ch++) { + auto a = static_cast(destination[0u]); + auto b = static_cast(destination[1u]); + auto c = static_cast(destination[2u]); + int32_t pcmi = (int32_t{a} << 8) & 0xff00; + pcmi |= (int32_t{b} << 16) & 0xff0000; + pcmi |= (int32_t{c} << 24) & 0xff000000; + destination = destination.subspan(3u); + CHECK(channel_data.Write(base::byte_span_from_ref( + SignedInt32SampleTypeTraits::ToFloat(pcmi)))); + } + } + } +#endif // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) + + if (CodecSupportsFloatOutput(config_.codec())) { + audio_buffer = AudioBuffer::CopyFrom( + kSampleFormatF32, channel_layout_, channel_count_, sample_rate_, frames, + // Sample format `kSampleFormatF32` is not planar, so it only reads from + // the first pointer in the data array. Thus we give it a pointer to the + // `destination_ptr` and it won't go past it. + &destination_ptr, base::TimeDelta(), pool_); + } + + RETURN_ON_FAILURE(!!audio_buffer, "Failed to create output buffer", + OutputStatus::kFailed); + + // Important to reset length to 0 since we reuse a same output buffer + output_buffer->SetCurrentLength(0); + output_buffer->Unlock(); + + if (discard_helper_->ProcessBuffers(current_buffer_time_info_, + audio_buffer.get())) { + base::BindPostTaskToCurrentDefault(output_cb_).Run(std::move(audio_buffer)); + } + + return OutputStatus::kSuccess; +} + +void MediaFoundationAudioDecoder::ResetTimestampState() { + discard_helper_ = + std::make_unique(sample_rate_, config_.codec_delay(), + /*delayed_discard=*/true); + discard_helper_->Reset(config_.codec_delay()); +} + +} // namespace media