diff --git a/.gn b/.gn index 44a11ec..51dfb64 100644 --- a/.gn +++ b/.gn
@@ -12,6 +12,10 @@ # for python3.exe and python3.bat. script_executable = "python3" +# This reduces the number of stamp actions, use phony rule as far as possible +# instead. +no_stamp_files = true + # These arguments override the default values for items in a declare_args # block. "gn args" in turn can override these. #
diff --git a/BUILD.gn b/BUILD.gn index 09bc9bd..3586f7420 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -1157,6 +1157,12 @@ } else { args += [ "--timeout-multiplier=1" ] } + if (is_chrome_branded) { + args += [ + "--driver-name", + "Google Chrome", + ] + } data_deps = [ ":blink_web_tests_expectations", ":blink_web_tests_support_data",
diff --git a/DEPS b/DEPS index 6dda21a..bfea3475 100644 --- a/DEPS +++ b/DEPS
@@ -248,7 +248,7 @@ # luci-go CIPD package version. # Make sure the revision is uploaded by infra-packagers builder. # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console - 'luci_go': 'git_revision:5845c6112f584c023a47776b31c3b6f08f562fb8', + 'luci_go': 'git_revision:1d383421736c86faeb7dea6d2039d8ea2ef6d648', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -304,15 +304,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '20b42bf48559cef3d1f6ca6ee92b872cf3dc8d90', + 'skia_revision': '132c9e886e6d34136b892314dece368b3cebbb0a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '3babfc4ae2a1ceb3454a1f0d19073263f67829df', + 'v8_revision': '68c1142d37c4edb8e02e022dd8fbacaf396c4dd9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '621bba6cc6a80cf910157c157beb21796e62e7d8', + 'angle_revision': '34201e0d441070446108a655d9ad0b32c4c7d88a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -364,7 +364,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Emoji Segmenter # and whatever else without interference from each other. - 'emoji_segmenter_revision': '9ba6d25d0d9313569665d4a9d2b34f0f39f9a50e', + 'emoji_segmenter_revision': 'b2c045838114ee993bd8f9830caf40a9500a79e5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling OTS # and whatever else without interference from each other. @@ -420,7 +420,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'f37b8fcef30b699ddb1b270bdeee84055016c8c8', + 'dawn_revision': 'd3b7a448690d9a1e0f9fa7b1b300235ff378cffd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -468,7 +468,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'cros_components_revision': '4610f51c64c848f5f8d7198a07a8f733ba716ce4', + 'cros_components_revision': 'e8c2d53fcc6214e81e8bcbea308eba65cc65e7ed', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1287,12 +1287,12 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '58ce7a7d34a0a9c1ea7730c874094b0ca039f4eb', + '6d0049883faa7e13155ac288d96597b4bb7a5477', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + 'bb849512794519eb3e1c6d1b4386ecbccb7d9076', + 'url': Var('chromium_git') + '/website.git' + '@' + '098e573ad7d9decf03efa002eb1b4ee0d474e7a2', }, 'src/ios/third_party/earl_grey2/src': { @@ -1760,13 +1760,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3a7d070966a55bd1bb113e2ec262ddeffe144c6b', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '62fc3a1d244368a430ffd7a6b55377a6dfd5e348', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'c3f733925a3b742db17d2dfae5610f14180cb99a', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'eaa06ed5d71844de4663a3e8208c48e0de0bc980', 'condition': 'checkout_src_internal', }, @@ -2528,7 +2528,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@230418ea04675aa41ffc7fee5a06640ba5ce1684', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3763a16adf089ba25715e5587104f6890acf88c7', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@79c4235085c5eb86ed78b034d94e03f7b3b5daef', 'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3', 'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@efb6b4099ddb8fa60f62956dee592c4b94ec6a49', @@ -2537,7 +2537,7 @@ 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@c758bac8bf1580b5018adafd3a2ec709237b0134', 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@4c63e845962ff3b197855f3ae4907a47d0863f5a', 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@fbb4db92c6b2ac09003b2b8e5ceb978f4f2dda71', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@0bcac3621c4a742f7187b0a10ecab5088d42c2e8', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@9abfdd2897a8a130524bb31caf934440804068d2', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -2577,7 +2577,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a5065e398d2430c83e17ef9cbad6eae31d1efa8f', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'af8f6264cad70562649792288834422df5e05995', + Var('webrtc_git') + '/src.git' + '@' + 'b2a2b1b51e18436d32531f80bfc509ebebc12e9e', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -2706,7 +2706,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/boca_app/app', - 'version': 'rqwhe7yUBE7rMWmGZU0IL4otI76ddmh2Dmgi2LGCXJ4C', + 'version': 'iy4cYvCP-YwBAP4wSrHiPTcufSnQ1K3bqyzHircxewMC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -2761,7 +2761,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'kYkYnjLM4TH_rUv0XOvJX4nYEU5Fvq2XXX2QojHNXTAC', + 'version': 'jDpIeYyvm44oXKrVSg7rctKXY5wS9_G_iIpKOpnZjBwC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4645,7 +4645,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '04d3d919e6e9c04f692abbab2c1b817075bf7d49', + 'ef95707679427db9a0d94d329299e6222658b4b6', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/ash/webui/recorder_app_ui/resources.h b/ash/webui/recorder_app_ui/resources.h index 7e3fda2..53b0172df 100644 --- a/ash/webui/recorder_app_ui/resources.h +++ b/ash/webui/recorder_app_ui/resources.h
@@ -11,6 +11,8 @@ namespace ash { const webui::LocalizedString kLocalizedStrings[] = { + {"backToMainButtonTooltip", IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP}, + {"closeDialogButtonTooltip", IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP}, {"exportDialogAudioFormatWebmOption", IDS_RECORDER_EXPORT_DIALOG_AUDIO_FORMAT_WEBM_OPTION}, {"exportDialogAudioHeader", IDS_RECORDER_EXPORT_DIALOG_AUDIO_HEADER}, @@ -29,6 +31,10 @@ IDS_RECORDER_GEN_AI_ERROR_TITLE_SUGGESTION_TRUST_AND_SAFETY_LABEL}, {"genAiExperimentBadge", IDS_RECORDER_GEN_AI_EXPERIMENT_BADGE}, {"genAiLearnMoreLink", IDS_RECORDER_GEN_AI_LEARN_MORE_LINK}, + {"genaiNegativeFeedbackButtonTooltip", + IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP}, + {"genaiPositiveFeedbackButtonTooltip", + IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP}, {"mainRecordingBarLandmarkAriaLabel", IDS_RECORDER_MAIN_RECORDING_BAR_LANDMARK_ARIA_LABEL}, {"mainRecordingsListLandmarkAriaLabel", @@ -78,13 +84,32 @@ IDS_RECORDER_ONBOARDING_DIALOG_WELCOME_HEADER}, {"onboardingDialogWelcomeNextButton", IDS_RECORDER_ONBOARDING_DIALOG_WELCOME_NEXT_BUTTON}, + {"playbackBackwardButtonTooltip", + IDS_RECORDER_PLAYBACK_BACKWARD_BUTTON_TOOLTIP}, {"playbackControlsLandmarkAriaLabel", IDS_RECORDER_PLAYBACK_CONTROLS_LANDMARK_ARIA_LABEL}, + {"playbackForwardButtonTooltip", + IDS_RECORDER_PLAYBACK_FORWARD_BUTTON_TOOLTIP}, + {"playbackHideTranscriptButtonTooltip", + IDS_RECORDER_PLAYBACK_HIDE_TRANSCRIPT_BUTTON_TOOLTIP}, + {"playbackMenuButtonTooltip", IDS_RECORDER_PLAYBACK_MENU_BUTTON_TOOLTIP}, {"playbackMenuDeleteOption", IDS_RECORDER_PLAYBACK_MENU_DELETE_OPTION}, {"playbackMenuExportOption", IDS_RECORDER_PLAYBACK_MENU_EXPORT_OPTION}, {"playbackMenuShowDetailOption", IDS_RECORDER_PLAYBACK_MENU_SHOW_DETAIL_OPTION}, + {"playbackMuteButtonTooltip", IDS_RECORDER_PLAYBACK_MUTE_BUTTON_TOOLTIP}, + {"playbackPauseButtonTooltip", IDS_RECORDER_PLAYBACK_PAUSE_BUTTON_TOOLTIP}, + {"playbackPlayButtonTooltip", IDS_RECORDER_PLAYBACK_PLAY_BUTTON_TOOLTIP}, + {"playbackSeekSliderAriaLabel", + IDS_RECORDER_PLAYBACK_SEEK_SLIDER_ARIA_LABEL}, + {"playbackShowTranscriptButtonTooltip", + IDS_RECORDER_PLAYBACK_SHOW_TRANSCRIPT_BUTTON_TOOLTIP}, + {"playbackSpeedButtonTooltip", IDS_RECORDER_PLAYBACK_SPEED_BUTTON_TOOLTIP}, {"playbackSpeedNormalOption", IDS_RECORDER_PLAYBACK_SPEED_NORMAL_OPTION}, + {"playbackTranscriptLandmarkAriaLabel", + IDS_RECORDER_PLAYBACK_TRANSCRIPT_LANDMARK_ARIA_LABEL}, + {"playbackVolumeAriaLabel", IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL}, + {"recordDeleteButtonTooltip", IDS_RECORDER_RECORD_DELETE_BUTTON_TOOLTIP}, {"recordDeleteDialogCancelButton", IDS_RECORDER_RECORD_DELETE_DIALOG_CANCEL_BUTTON}, {"recordDeleteDialogCurrentHeader", @@ -109,10 +134,15 @@ {"recordInfoDialogHeader", IDS_RECORDER_RECORD_INFO_DIALOG_HEADER}, {"recordInfoDialogSizeLabel", IDS_RECORDER_RECORD_INFO_DIALOG_SIZE_LABEL}, {"recordInfoDialogTitleLabel", IDS_RECORDER_RECORD_INFO_DIALOG_TITLE_LABEL}, + {"recordMenuButtonTooltip", IDS_RECORDER_RECORD_MENU_BUTTON_TOOLTIP}, {"recordMenuDeleteOption", IDS_RECORDER_RECORD_MENU_DELETE_OPTION}, {"recordMenuToggleTranscriptionOption", IDS_RECORDER_RECORD_MENU_TOGGLE_TRANSCRIPTION_OPTION}, + {"recordMuteButtonTooltip", IDS_RECORDER_RECORD_MUTE_BUTTON_TOOLTIP}, + {"recordPauseButtonTooltip", IDS_RECORDER_RECORD_PAUSE_BUTTON_TOOLTIP}, {"recordStopButton", IDS_RECORDER_RECORD_STOP_BUTTON}, + {"recordTranscriptButtonTooltip", + IDS_RECORDER_RECORD_TRANSCRIPT_BUTTON_TOOLTIP}, {"recordTranscriptionEntryPointDescription", IDS_RECORDER_RECORD_TRANSCRIPTION_ENTRY_POINT_DESCRIPTION}, {"recordTranscriptionEntryPointDisableButton", @@ -193,6 +223,8 @@ IDS_RECORDER_SUMMARY_DOWNLOADING_PROGRESS_DESCRIPTION}, {"summaryHeader", IDS_RECORDER_SUMMARY_HEADER}, {"titleRenameTooltip", IDS_RECORDER_TITLE_RENAME_TOOLTIP}, + {"titleSuggestionButtonTooltip", + IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP}, {"titleSuggestionHeader", IDS_RECORDER_TITLE_SUGGESTION_HEADER}, {"transcriptionAutoscrollButton", IDS_RECORDER_TRANSCRIPTION_AUTOSCROLL_BUTTON},
diff --git a/ash/webui/recorder_app_ui/resources/components/genai-feedback-buttons.ts b/ash/webui/recorder_app_ui/resources/components/genai-feedback-buttons.ts index 64b7dae..8eb6721 100644 --- a/ash/webui/recorder_app_ui/resources/components/genai-feedback-buttons.ts +++ b/ash/webui/recorder_app_ui/resources/components/genai-feedback-buttons.ts
@@ -8,6 +8,7 @@ import {css, CSSResultGroup, html} from 'chrome://resources/mwc/lit/index.js'; +import {i18n} from '../core/i18n.js'; import {usePlatformHandler} from '../core/lit/context.js'; import {ReactiveLitElement} from '../core/reactive/lit.js'; import {signal} from '../core/reactive/signal.js'; @@ -91,6 +92,7 @@ size="small" .selected=${rating === UserRating.THUMB_UP} @click=${this.onThumbUpClick} + aria-label=${i18n.genaiPositiveFeedbackButtonTooltip} > <cra-icon name="thumb_up" slot="icon"></cra-icon> <cra-icon name="thumb_up_filled" slot="selectedIcon"></cra-icon> @@ -100,6 +102,7 @@ size="small" .selected=${rating === UserRating.THUMB_DOWN} @click=${this.onThumbDownClick} + aria-label=${i18n.genaiNegativeFeedbackButtonTooltip} > <cra-icon name="thumb_down" slot="icon"></cra-icon> <cra-icon name="thumb_down_filled" slot="selectedIcon"></cra-icon>
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts b/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts index 5b6242e..9218efd 100644 --- a/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts +++ b/ash/webui/recorder_app_ui/resources/components/recording-title-suggestion.ts
@@ -212,6 +212,7 @@ size="small" shape="circle" @click=${this.onCloseClick} + aria-label=${i18n.closeDialogButtonTooltip} > <cra-icon slot="icon" name="close"></cra-icon> </cra-icon-button>
diff --git a/ash/webui/recorder_app_ui/resources/components/recording-title.ts b/ash/webui/recorder_app_ui/resources/components/recording-title.ts index 03b4ac0..9b41577 100644 --- a/ash/webui/recorder_app_ui/resources/components/recording-title.ts +++ b/ash/webui/recorder_app_ui/resources/components/recording-title.ts
@@ -266,6 +266,7 @@ shape="circle" @click=${this.openSuggestionDialog} ${ref(this.suggestTitleButton)} + aria-label=${i18n.titleSuggestionButtonTooltip} > <cra-icon slot="icon" name="pen_spark"></cra-icon> </cra-icon-button>`;
diff --git a/ash/webui/recorder_app_ui/resources/components/secondary-button.ts b/ash/webui/recorder_app_ui/resources/components/secondary-button.ts index 3735a4a6..fc1f2d1 100644 --- a/ash/webui/recorder_app_ui/resources/components/secondary-button.ts +++ b/ash/webui/recorder_app_ui/resources/components/secondary-button.ts
@@ -7,7 +7,6 @@ import { css, html, - ifDefined, LitElement, PropertyDeclarations, } from 'chrome://resources/mwc/lit/index.js'; @@ -42,10 +41,7 @@ override ariaLabel: string|null = null; override render(): RenderResult { - return html`<cra-icon-button - shape="circle" - aria-label=${ifDefined(this.ariaLabel)} - > + return html`<cra-icon-button shape="circle" .ariaLabel=${this.ariaLabel}> <slot slot="icon" name="icon"></slot> </cra-icon-button>`; }
diff --git a/ash/webui/recorder_app_ui/resources/core/i18n.ts b/ash/webui/recorder_app_ui/resources/core/i18n.ts index 40d9af3..cd09233 100644 --- a/ash/webui/recorder_app_ui/resources/core/i18n.ts +++ b/ash/webui/recorder_app_ui/resources/core/i18n.ts
@@ -4,8 +4,9 @@ import {join} from 'chrome://resources/mwc/lit/index.js'; -import {usePlatformHandler} from './lit/context.js'; -import {forceCast, upcast} from './utils/type_utils.js'; +import {PlatformHandler} from '../platforms/index.js'; + +import {forceCast} from './utils/type_utils.js'; type I18nArgType = number|string; @@ -18,6 +19,8 @@ } const noArgStringNames = [ + 'backToMainButtonTooltip', + 'closeDialogButtonTooltip', 'exportDialogAudioFormatWebmOption', 'exportDialogAudioHeader', 'exportDialogCancelButton', @@ -31,6 +34,8 @@ 'genAiErrorTitleSuggestionTrustAndSafetyLabel', 'genAiExperimentBadge', 'genAiLearnMoreLink', + 'genaiNegativeFeedbackButtonTooltip', + 'genaiPositiveFeedbackButtonTooltip', 'mainRecordingBarLandmarkAriaLabel', 'mainRecordingsListLandmarkAriaLabel', 'mainSearchLandmarkAriaLabel', @@ -56,11 +61,24 @@ 'onboardingDialogWelcomeDescription', 'onboardingDialogWelcomeHeader', 'onboardingDialogWelcomeNextButton', + 'playbackBackwardButtonTooltip', 'playbackControlsLandmarkAriaLabel', + 'playbackForwardButtonTooltip', + 'playbackHideTranscriptButtonTooltip', + 'playbackMenuButtonTooltip', 'playbackMenuDeleteOption', 'playbackMenuExportOption', 'playbackMenuShowDetailOption', + 'playbackMuteButtonTooltip', + 'playbackPauseButtonTooltip', + 'playbackPlayButtonTooltip', + 'playbackSeekSliderAriaLabel', + 'playbackShowTranscriptButtonTooltip', + 'playbackSpeedButtonTooltip', 'playbackSpeedNormalOption', + 'playbackTranscriptLandmarkAriaLabel', + 'playbackVolumeAriaLabel', + 'recordDeleteButtonTooltip', 'recordDeleteDialogCancelButton', 'recordDeleteDialogCurrentHeader', 'recordDeleteDialogDeleteButton', @@ -76,9 +94,13 @@ 'recordInfoDialogHeader', 'recordInfoDialogSizeLabel', 'recordInfoDialogTitleLabel', + 'recordMenuButtonTooltip', 'recordMenuDeleteOption', 'recordMenuToggleTranscriptionOption', + 'recordMuteButtonTooltip', + 'recordPauseButtonTooltip', 'recordStopButton', + 'recordTranscriptButtonTooltip', 'recordTranscriptionEntryPointDescription', 'recordTranscriptionEntryPointDisableButton', 'recordTranscriptionEntryPointEnableButton', @@ -120,6 +142,7 @@ 'summaryDownloadModelHeader', 'summaryHeader', 'titleRenameTooltip', + 'titleSuggestionButtonTooltip', 'titleSuggestionHeader', 'transcriptionAutoscrollButton', 'transcriptionNoSpeechText', @@ -142,7 +165,17 @@ } satisfies Record<string, I18nArgType[]>; type WithArgsStringNames = typeof withArgsStringNames; -type I18nType = Record<NoArgStringName, string>&{ +function getI18nString(name: string): string { + return PlatformHandler.getStringF(name); +} + +function createI18nStringFormatter(name: string) { + return (...args: I18nArgType[]) => { + return PlatformHandler.getStringF(name, ...args); + }; +} + +type I18nObjectType = Record<NoArgStringName, string>&{ [k in keyof WithArgsStringNames]: (...args: WithArgsStringNames[k]) => string; }; @@ -153,32 +186,15 @@ * i18n.foo // For strings without arguments. * i18n.bar('arg1', 2) // For strings with arguments. */ -// TODO(pihsun): Have some initialize code to initialize i18n to a concrete -// object instead of having it as a proxy. Since it use usePlatformHandler() -// which are not available at module import time, we'll need to initialize it -// separately similar to other context states. -// -// forceCast: The proxy wrapper changed the type of the target. -export const i18n = forceCast<I18nType>( - new Proxy( - {}, - { - get(_target, name) { - if (typeof name !== 'string') { - return; - } - if (upcast<readonly string[]>(noArgStringNames).includes(name)) { - return usePlatformHandler().getStringF(name); - } - if (Object.hasOwn(withArgsStringNames, name)) { - return (...args: I18nArgType[]) => { - return usePlatformHandler().getStringF(name, ...args); - }; - } - return undefined; - }, - }, - ), +// forceCast: TypeScript can't deduce type for Object.fromEntries correctly. +export const i18n = forceCast<I18nObjectType>( + Object.fromEntries([ + ...noArgStringNames.map((name) => [name, getI18nString(name)] as const), + ...Object.keys(withArgsStringNames) + .map( + (name) => [name, createI18nStringFormatter(name)] as const, + ), + ]), ); /**
diff --git a/ash/webui/recorder_app_ui/resources/core/platform_handler.ts b/ash/webui/recorder_app_ui/resources/core/platform_handler.ts index 6add418..4f40c85 100644 --- a/ash/webui/recorder_app_ui/resources/core/platform_handler.ts +++ b/ash/webui/recorder_app_ui/resources/core/platform_handler.ts
@@ -10,6 +10,21 @@ export abstract class PlatformHandler { /** + * Returns the formatted localized string by given `id` and `args`. + * + * This is the lower level function that is used to implement the `i18n` + * helper in core/i18n.ts, and shouldn't be directly used. + * The `i18n` helper provides better typing and should be used instead. + * + * This is declared as `static` so it can be directly use at module import + * time, and all implementations should ensure that it can be called at + * module import time. + */ + static getStringF(_id: string, ..._args: Array<number|string>): string { + throw new Error('getStringF not implemented'); + } + + /** * Initializes the platform handler. * * This should only be called once when the app starts. @@ -49,15 +64,6 @@ abstract getMicrophoneInfo(deviceId: string): Promise<InternalMicInfo>; /** - * Returns the formatted localized string by given `id` and `args`. - * - * This is the lower level function that is used to implement the `i18n` - * helper in core/i18n.ts, and shouldn't be directly used. - * The `i18n` helper provides better typing and should be used instead. - */ - abstract getStringF(id: string, ...args: Array<number|string>): string; - - /** * Renders the UI needed on the dev page. */ abstract renderDevUi(): RenderResult;
diff --git a/ash/webui/recorder_app_ui/resources/core/state/route.ts b/ash/webui/recorder_app_ui/resources/core/state/route.ts index e211f0bf..76712b49 100644 --- a/ash/webui/recorder_app_ui/resources/core/state/route.ts +++ b/ash/webui/recorder_app_ui/resources/core/state/route.ts
@@ -4,22 +4,112 @@ import {signal} from '../reactive/signal.js'; -export const currentRoute = signal<URL|null>(null); +interface RouteInfo<ParameterKey extends string> { + path: string; + parameterKeys: ParameterKey[]; +} -function updateRoute() { - currentRoute.value = new URL(window.location.href); +type ExtractParameterKey<T> = T extends RouteInfo<infer K>? K : never; + +function createRoute<ParameterKey extends string>( + path: string, + parameterKeys: ParameterKey[], +): RouteInfo<ParameterKey> { + return {path, parameterKeys}; } /** - * Navigates to the given "path". + * Routes of all the pages. + * + * This only defines the route path and necessary parameters, and what component + * to actual render is defined in pages/recorder-app.ts. + */ +const routes = { + index: createRoute('/', []), + playback: createRoute('/playback', ['id']), + record: createRoute('/record', ['includeSystemAudio', 'micId']), + dev: createRoute('/dev', []), + test: createRoute('/test', []), +} as const; + +type Routes = typeof routes; +type RouteNames = keyof Routes; + +interface CurrentRouteInfo<Name extends RouteNames> { + name: Name; + parameters: Record<ExtractParameterKey<Routes[Name]>, string|null>; +} + +type UnionCurrentRoute = { + [K in RouteNames]: CurrentRouteInfo<K>; +}[RouteNames]; + +export const currentRoute = signal<UnionCurrentRoute|null>(null); + +function extractCurrentRouteInfo(url: URL): UnionCurrentRoute|null { + // We use hash based client side navigation, to avoid the following issue + // for modern path based client side navigation in our use case: + // * recorder_app_ui.cc needs to have all the paths that it should handle. + // * When serving bundled output via cra.py bundle, many static hosting + // server (like x20) doesn't support path rewrite and doesn't work well + // with client side navigation. + // * The route below needs to handle when the bundled output is hosted on a + // subpath. + // + // TODO(pihsun): Since changing hash won't trigger page refresh, we + // probably can simplify some of the logic in installRouter. + const routeInHash = new URL( + url.hash.slice(1), + // Note that the origin part is not used and we only use the path and + // search, but URL constructor requires a base URL if the first argument + // is just a path. + document.location.origin, + ); + const path = routeInHash.pathname; + const search = new URLSearchParams(routeInHash.search); + + for (const [name, info] of Object.entries(routes)) { + if (path !== info.path) { + continue; + } + const parameters: Record<string, string|null> = {}; + for (const key of info.parameterKeys) { + parameters[key] = search.get(key); + } + // TypeScript can't deduce the type of name and the dependent parameters. + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return {name, parameters} as UnionCurrentRoute; + } + return null; +} + +function updateRoute() { + const url = new URL(window.location.href); + currentRoute.value = extractCurrentRouteInfo(url); +} + +function navigateToImpl(path: string) { + window.history.pushState({}, '', `#${path}`); + updateRoute(); +} + +/** + * Navigates to the given path by name. * * Note that this should only be used for pages under Recorder App, and not * external link. Since we do client side navigation via URL hash (see the * reason in pages/recorder-app.ts), the path is put into URL hash. */ -export function navigateTo(path: string): void { - window.history.pushState({}, '', `#${path}`); - updateRoute(); +export function navigateTo<Name extends RouteNames>( + name: Name, + parameters: Partial<Record<ExtractParameterKey<Routes[Name]>, string>> = {}, +): void { + const {path} = routes[name]; + // TypeScript can't deduce that parameters is a sub-type of Record<string, + // string>. + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const params = new URLSearchParams(parameters as Record<string, string>); + navigateToImpl(`${path}?${params.toString()}`); } /** @@ -54,7 +144,7 @@ e.preventDefault(); if (href !== window.location.href) { - navigateTo(url.pathname); + navigateToImpl(url.pathname); } });
diff --git a/ash/webui/recorder_app_ui/resources/core/test_helper.ts b/ash/webui/recorder_app_ui/resources/core/test_helper.ts index f6ff72f3..396ab845 100644 --- a/ash/webui/recorder_app_ui/resources/core/test_helper.ts +++ b/ash/webui/recorder_app_ui/resources/core/test_helper.ts
@@ -4,9 +4,7 @@ import {RecorderApp} from '../pages/recorder-app.js'; -import { - useRecordingDataManager, -} from './lit/context.js'; +import {usePlatformHandler, useRecordingDataManager} from './lit/context.js'; import {TextToken, Transcription} from './soda/soda.js'; import {navigateTo} from './state/route.js'; import { @@ -54,7 +52,7 @@ * to start the test. */ static goToMainPage(): void { - navigateTo('/'); + navigateTo('index'); } /** @@ -114,6 +112,57 @@ } } + /** + * Installs the model used for transcription. + */ + static installTranscriptionModel(): void { + usePlatformHandler().installSoda(); + } + + /** + * Returns whether the transcription model is installed. + * + * @return Boolean indicating if the transcription model is installed. + */ + static isTranscriptionModelInstalled(): boolean { + const state = usePlatformHandler().sodaState.value; + return state.kind === 'installed'; + } + + /** + * Installs the model used for summarize recordings. + */ + static installSummaryModel(): void { + usePlatformHandler().summaryModelLoader.download(); + } + + /** + * Returns whether the summary model is installed. + * + * @return Boolean indicating if the summary model is installed. + */ + static isSummaryModelInstalled(): boolean { + const state = usePlatformHandler().summaryModelLoader.state.value; + return state.kind === 'installed'; + } + + /** + * Installs the model used for suggest recording titles. + */ + static installTitleSuggestionModel(): void { + usePlatformHandler().titleSuggestionModelLoader.download(); + } + + /** + * Returns whether the title suggestion model is installed. + * + * @return Boolean indicating if the title suggestion model is installed. + */ + static isTitleSuggestionModelInstalled(): boolean { + const state = usePlatformHandler().titleSuggestionModelLoader.state.value; + return state.kind === 'installed'; + } + // UI-related functions. /** * Returns the UI from the given key, throws an error if not exists. @@ -144,7 +193,9 @@ static getNthSuggestedTitle(index: number): Element { return app() .playbackPageForTest.recordingTitleForTest.titleSuggestionForTest - .nthSuggestedTitleForTest(index); + .nthSuggestedTitleForTest( + index, + ); } /**
diff --git a/ash/webui/recorder_app_ui/resources/init.ts b/ash/webui/recorder_app_ui/resources/init.ts index 5cbdc78..fc7fc4a 100644 --- a/ash/webui/recorder_app_ui/resources/init.ts +++ b/ash/webui/recorder_app_ui/resources/init.ts
@@ -4,7 +4,7 @@ import {init} from './core/init.js'; import {RecorderApp} from './pages/recorder-app.js'; -import {PlatformHandler} from './platforms/swa/handler.js'; +import {PlatformHandler} from './platforms/index.js'; // The error for the promise is handled by the global unhandledrejection // handler.
diff --git a/ash/webui/recorder_app_ui/resources/pages/main-page.ts b/ash/webui/recorder_app_ui/resources/pages/main-page.ts index 1240391..29e735c 100644 --- a/ash/webui/recorder_app_ui/resources/pages/main-page.ts +++ b/ash/webui/recorder_app_ui/resources/pages/main-page.ts
@@ -207,7 +207,7 @@ } else { audio.revoke(); } - navigateTo(`/playback?id=${ev.detail}`); + navigateTo('playback', {id: ev.detail}); } private onDeleteRecordingClick(ev: CustomEvent<string>) { @@ -252,14 +252,17 @@ private onClickRecordButton() { // TODO(shik): Should we let the record page read the store value // directly? + // TODO(pihsun): The typed route accepts string only as parameters for now. + // Have some way to integrate with schema.ts so this is not needed? const includeSystemAudio = settings.value.includeSystemAudio.toString(); const micId = assertExists( this.microphoneManager.getSelectedMicId().value, 'There is no selected microphone.', ); - navigateTo( - `/record?includeSystemAudio=${includeSystemAudio}&micId=${micId}`, - ); + navigateTo('record', { + includeSystemAudio, + micId, + }); } private renderStartRecordNudge() {
diff --git a/ash/webui/recorder_app_ui/resources/pages/playback-page.ts b/ash/webui/recorder_app_ui/resources/pages/playback-page.ts index 37e509c..573d185 100644 --- a/ash/webui/recorder_app_ui/resources/pages/playback-page.ts +++ b/ash/webui/recorder_app_ui/resources/pages/playback-page.ts
@@ -533,11 +533,15 @@ } private renderPlayPauseButton() { + const ariaLabel = this.audioPlayer.playing.value ? + i18n.playbackPauseButtonTooltip : + i18n.playbackPlayButtonTooltip; return html`<cra-icon-button id="play-button" shape="circle" @click=${this.onPlayPauseClick} ${ref(this.playPauseButton)} + aria-label=${ariaLabel} > <cra-icon slot="icon" @@ -566,7 +570,7 @@ private deleteRecording() { if (this.recordingId !== null) { this.recordingDataManager.remove(this.recordingId); - navigateTo('/'); + navigateTo('index'); } } @@ -615,6 +619,9 @@ } private renderHeader() { + const transcriptionLabel = this.showTranscription.value ? + i18n.playbackHideTranscriptButtonTooltip : + i18n.playbackShowTranscriptButtonTooltip; const transcriptionToggleButton = this.transcription.value === null ? nothing : html` <cra-icon-button @@ -622,6 +629,7 @@ .selected=${live(this.showTranscription.value)} @click=${this.toggleTranscription} ${ref(this.transcriptionButtonRef)} + aria-label=${transcriptionLabel} > <cra-icon slot="icon" name="notes"></cra-icon> <cra-icon slot="selectedIcon" name="notes"></cra-icon> @@ -632,8 +640,9 @@ <div id="header" class="sheet"> <cra-icon-button buttonstyle="floating" - @click=${() => navigateTo('/')} + @click=${() => navigateTo('index')} ${ref(this.backButton)} + aria-label=${i18n.backToMainButtonTooltip} > <cra-icon slot="icon" name="arrow_back"></cra-icon> </cra-icon-button> @@ -647,6 +656,7 @@ buttonstyle="floating" id="show-menu" @click=${this.toggleMenu} + aria-label=${i18n.playbackMenuButtonTooltip} > <cra-icon slot="icon" name="more_vertical"></cra-icon> </cra-icon-button> @@ -679,6 +689,7 @@ step="0.1" .value=${currentTime} @input=${this.onTimelineInput} + aria-label=${i18n.playbackSeekSliderAriaLabel} ></cros-slider> <div> <span>${currentTimeString}</span> @@ -730,6 +741,8 @@ id="show-speed-menu" @click=${togglePlaybackSpeedMenu} .selected=${live(this.playbackSpeedMenuOpened.value)} + aria-haspopup="true" + aria-label=${i18n.playbackSpeedButtonTooltip} > <cra-icon slot="icon" .name=${iconName}></cra-icon> <cra-icon slot="selectedIcon" .name=${iconName}></cra-icon> @@ -773,6 +786,7 @@ min="0" max="100" @input=${this.onVolumeInput} + aria-label=${i18n.playbackVolumeAriaLabel} ></cros-slider> `; } @@ -793,7 +807,11 @@ private renderVolumeControl(): RenderResult { return html` <div id="inline-slider"> - <cra-icon-button buttonstyle="floating" @click=${this.toggleMuted}> + <cra-icon-button + buttonstyle="floating" + @click=${this.toggleMuted} + aria-label=${i18n.playbackMuteButtonTooltip} + > ${this.renderVolumeIcon()} </cra-icon-button> ${this.renderVolumeSlider()} @@ -802,6 +820,7 @@ <cra-icon-button buttonstyle="floating" @click=${this.showFloatingVolume} + aria-label=${i18n.playbackVolumeAriaLabel} > ${this.renderVolumeIcon()} </cra-icon-button> @@ -836,7 +855,12 @@ <div id="audio-waveform-container" class="sheet"> ${this.renderAudioWaveform()} </div> - <div id="transcription-container" class="sheet"> + <div + id="transcription-container" + class="sheet" + aria-label=${i18n.playbackTranscriptLandmarkAriaLabel} + role="region" + > ${this.renderTranscription()} </div> </div> @@ -850,11 +874,17 @@ <div id="actions"> <div id="volume-controls">${this.renderVolumeControl()}</div> <div id="middle-controls"> - <secondary-button @click=${this.onRewind10Secs}> + <secondary-button + @click=${this.onRewind10Secs} + aria-label=${i18n.playbackBackwardButtonTooltip} + > <cra-icon slot="icon" name="replay_10"></cra-icon> </secondary-button> ${this.renderPlayPauseButton()} - <secondary-button @click=${this.onForward10Secs}> + <secondary-button + @click=${this.onForward10Secs} + aria-label=${i18n.playbackForwardButtonTooltip} + > <cra-icon slot="icon" name="forward_10"></cra-icon> </secondary-button> </div>
diff --git a/ash/webui/recorder_app_ui/resources/pages/record-page.ts b/ash/webui/recorder_app_ui/resources/pages/record-page.ts index c8bc96e..5fddead 100644 --- a/ash/webui/recorder_app_ui/resources/pages/record-page.ts +++ b/ash/webui/recorder_app_ui/resources/pages/record-page.ts
@@ -401,7 +401,7 @@ // Permission denied, maybe user clicked cancel. Return to the main // page in this case. // TODO(pihsun): Better error handling/reporting and ask user to retry. - navigateTo('/'); + navigateTo('index'); } else { console.error(e); } @@ -495,7 +495,7 @@ this.recordingControlQueue.push(async () => { const id = await this.stopRecording(); if (id !== null) { - navigateTo(`/playback?id=${id}`); + navigateTo('playback', {id}); } }); } @@ -579,7 +579,7 @@ private async deleteRecording() { // TODO(pihsun): Make this function sync since it's called as event handler. await this.cancelRecording(); - navigateTo('/'); + navigateTo('index'); } private onToggleMuted() { @@ -595,7 +595,13 @@ return html` <audio-waveform .values=${session.progress.value.powers}> </audio-waveform> - <cra-icon-button shape="circle" @click=${this.onToggleMuted}> + <cra-icon-button + shape="circle" + @click=${this.onToggleMuted} + aria-checked=${this.micMuted.value} + aria-label=${i18n.recordMuteButtonTooltip} + role="switch" + > <cra-icon slot="icon" .name=${this.micMuted.value ? 'mic_mute' : 'mic'} @@ -706,7 +712,7 @@ private async saveAndExitRecording() { await this.stopRecording(); - navigateTo('/'); + navigateTo('index'); } private onSaveClick() { @@ -783,6 +789,8 @@ <cra-icon-button buttonstyle="toggle" @click=${this.toggleTranscriptionShown} + aria-expanded=${this.transcriptionShown.value} + aria-label=${i18n.recordTranscriptButtonTooltip} > <cra-icon slot="icon" name="notes"></cra-icon> <cra-icon slot="selectedIcon" name="notes"></cra-icon> @@ -790,7 +798,11 @@ `; return html` <div id="header" class="sheet"> - <cra-icon-button buttonstyle="floating" @click=${this.onBackClick}> + <cra-icon-button + buttonstyle="floating" + @click=${this.onBackClick} + aria-label=${i18n.backToMainButtonTooltip} + > <cra-icon slot="icon" name="arrow_back"></cra-icon> </cra-icon-button> <span id="title">${this.recordingTitle}</span> @@ -800,6 +812,7 @@ buttonstyle="floating" @click=${this.toggleMenu} id="show-menu" + aria-label=${i18n.recordMenuButtonTooltip} > <cra-icon slot="icon" name="more_vertical"></cra-icon> </cra-icon-button> @@ -832,11 +845,18 @@ <div id="footer" class=${classMap(footerClasses)}> <div id="timer">${this.renderTimer()}</div> <div id="actions"> - <secondary-button @click=${this.onDeleteButtonClick}> + <secondary-button + @click=${this.onDeleteButtonClick} + aria-label=${i18n.recordDeleteButtonTooltip} + > <cra-icon slot="icon" name="delete"></cra-icon> </secondary-button> ${this.renderStopRecordButton()} - <secondary-button id="pause-button" @click=${this.onPauseButtonClick}> + <secondary-button + id="pause-button" + @click=${this.onPauseButtonClick} + aria-label=${i18n.recordPauseButtonTooltip} + > <cra-icon slot="icon" name="pause"></cra-icon> </secondary-button> </div>
diff --git a/ash/webui/recorder_app_ui/resources/pages/recorder-app.ts b/ash/webui/recorder_app_ui/resources/pages/recorder-app.ts index 71d047b..4fbbe0a 100644 --- a/ash/webui/recorder_app_ui/resources/pages/recorder-app.ts +++ b/ash/webui/recorder_app_ui/resources/pages/recorder-app.ts
@@ -23,8 +23,8 @@ import {PlaybackPage} from './playback-page.js'; import {RecordPage} from './record-page.js'; -function getBoolean(search: URLSearchParams, key: string): boolean { - return search.get(key) === 'true'; +function toBoolean(s: string|null): boolean { + return s === 'true'; } /** @@ -66,59 +66,33 @@ return nothing; } - // TODO(shik): Make page routes type-safe, so there is no missing or - // wrongly typed search params when calling navigateTo(). - // - // We use hash based client side navigation, to avoid the following issue - // for modern path based client side navigation in our use case: - // * recorder_app_ui.cc needs to have all the paths that it should handle. - // * When serving bundled output via cra.py bundle, many static hosting - // server (like x20) doesn't support path rewrite and doesn't work well - // with client side navigation. - // * The route below needs to handle when the bundled output is hosted on a - // subpath. - // - // TODO(pihsun): Since changing hash won't trigger page refresh, we - // probably can simplify some of the logic in core/state/route.ts. - const routeInHash = new URL( - currentRoute.value.hash.slice(1), - // Note that the origin part is not used and we only use the path and - // search, but URL constructor requires a base URL if the first argument - // is just a path. - document.location.origin, - ); - const path = routeInHash.pathname; - const search = new URLSearchParams(routeInHash.search); + const route = currentRoute.value; - if (path === '/') { - return html`<main-page ${ref(this.mainPage)}></main-page>`; + switch (route.name) { + case 'index': + return html`<main-page ${ref(this.mainPage)}></main-page>`; + case 'playback': + return html`<playback-page + .recordingId=${route.parameters.id} + ${ref(this.playbackPage)} + > + </playback-page>`; + case 'record': { + const {includeSystemAudio, micId} = route.parameters; + return html`<record-page + .includeSystemAudio=${toBoolean(includeSystemAudio)} + .micId=${micId} + ${ref(this.recordPage)} + > + </record-page>`; + } + case 'dev': + return html`<dev-page></dev-page>`; + case 'test': + return nothing; + default: + return this.render404(); } - if (path === '/playback') { - const id = search.get('id'); - return html`<playback-page - .recordingId=${id} - ${ref(this.playbackPage)} - > - </playback-page>`; - } - if (path === '/record') { - const includeSystemAudio = getBoolean(search, 'includeSystemAudio'); - const micId = search.get('micId'); - return html`<record-page - .includeSystemAudio=${includeSystemAudio} - .micId=${micId} - ${ref(this.recordPage)} - > - </record-page>`; - } - if (path === '/dev') { - return html`<dev-page></dev-page>`; - } - if (path === '/test') { - return ''; - } - - return this.render404(); } }
diff --git a/ash/webui/recorder_app_ui/resources/platforms/dev/handler.ts b/ash/webui/recorder_app_ui/resources/platforms/dev/handler.ts index e75bf26..5f798f3 100644 --- a/ash/webui/recorder_app_ui/resources/platforms/dev/handler.ts +++ b/ash/webui/recorder_app_ui/resources/platforms/dev/handler.ts
@@ -332,6 +332,16 @@ readonly errorView = new ErrorView(); + static override getStringF(id: string, ...args: Array<number|string>): + string { + const label = strings[id]; + if (label === undefined) { + console.error(`Unknown string ${id}`); + return ''; + } + return substituteI18nString(label, ...args); + } + override async init(): Promise<void> { document.body.appendChild(this.errorView); settingsInit(); @@ -383,15 +393,6 @@ return {isDefault: false, isInternal: false}; } - override getStringF(id: string, ...args: Array<number|string>): string { - const label = strings[id]; - if (label === undefined) { - console.error(`Unknown string ${id}`); - return ''; - } - return substituteI18nString(label, ...args); - } - override renderDevUi(): RenderResult { function handleColorModeChange(ev: Event) { devSettings.mutate((s) => {
diff --git a/ash/webui/recorder_app_ui/resources/platforms/index.ts b/ash/webui/recorder_app_ui/resources/platforms/index.ts new file mode 100644 index 0000000..fa29c9d0 --- /dev/null +++ b/ash/webui/recorder_app_ui/resources/platforms/index.ts
@@ -0,0 +1,11 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is replaced in dev.py when in local dev, and should be the only +// place that directly import the PlatformHandler from subdirectory. +// +// Note that most user should import core/platform_handler.ts instead, and this +// should only be directly imported by init.ts, or other files that need to +// call static methods on the class (currently only core/i18n.ts). +export {PlatformHandler} from './swa/handler.js';
diff --git a/ash/webui/recorder_app_ui/resources/platforms/platforms.gni b/ash/webui/recorder_app_ui/resources/platforms/platforms.gni index 3141bc36..d030c80 100644 --- a/ash/webui/recorder_app_ui/resources/platforms/platforms.gni +++ b/ash/webui/recorder_app_ui/resources/platforms/platforms.gni
@@ -11,6 +11,7 @@ "dev/handler.ts", "dev/settings.ts", "dev/strings.ts", + "index.ts", "swa/handler.ts", "swa/on_device_model.ts", "swa/soda_session.ts",
diff --git a/ash/webui/recorder_app_ui/resources/platforms/swa/handler.ts b/ash/webui/recorder_app_ui/resources/platforms/swa/handler.ts index 6715362..c32ce73 100644 --- a/ash/webui/recorder_app_ui/resources/platforms/swa/handler.ts +++ b/ash/webui/recorder_app_ui/resources/platforms/swa/handler.ts
@@ -55,6 +55,11 @@ override canUseSpeakerLabel = signal(false); + static override getStringF(id: string, ...args: Array<number|string>): + string { + return loadTimeData.getStringF(id, ...args); + } + constructor() { super(); this.summaryModelLoader = new SummaryModelLoader(this.remote); @@ -132,10 +137,6 @@ return info ?? {isDefault: false, isInternal: false}; } - override getStringF(id: string, ...args: Array<number|string>): string { - return loadTimeData.getStringF(id, ...args); - } - override renderDevUi(): RenderResult { return nothing; }
diff --git a/ash/webui/recorder_app_ui/resources/scripts/cra/commands/dev.py b/ash/webui/recorder_app_ui/resources/scripts/cra/commands/dev.py index 70b1f9c..5bfa13a1 100644 --- a/ash/webui/recorder_app_ui/resources/scripts/cra/commands/dev.py +++ b/ash/webui/recorder_app_ui/resources/scripts/cra/commands/dev.py
@@ -90,11 +90,11 @@ def _transform_js(self, request_path: _RequestPath, js: str) -> str: return _stub_chrome_url(request_path, js) - def _transform_init_js(self, request_path: _RequestPath, js: str) -> str: + def _transform_platforms_index_js(self, request_path: _RequestPath, + js: str) -> str: # TODO(pihsun): The inline source would still be wrong, have some hacky # way to fix that too. - js = js.replace("'./platforms/swa/handler.js'", - "'./platforms/dev/handler.js'") + js = js.replace("'./swa/handler.js'", "'./dev/handler.js'") return self._transform_js(request_path, js) def _load_grd_strings(self) -> dict[str, str]: @@ -209,13 +209,14 @@ _Route(re.compile(r"static/.*"), self._handle_static_file), # images.js are dynamically generated from images. _Route(_RequestPath("images/images.js"), self._handle_images_js), - # init.js needs special transform to change the platform used. + # platforms/index.js needs special transform to change the platform + # used. _Route( - _RequestPath("init.js"), + _RequestPath("platforms/index.js"), functools.partial( self._handle_static_file, root=self._tsc_root, - transform=self._transform_init_js, + transform=self._transform_platforms_index_js, ), ), # platforms/dev/strings.js is for strings in dev server.
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc index e37fc69..b5e0f05 100644 --- a/base/trace_event/malloc_dump_provider.cc +++ b/base/trace_event/malloc_dump_provider.cc
@@ -415,8 +415,10 @@ } base::trace_event::MemoryAllocatorDump* partitions_dump = nullptr; - base::trace_event::MemoryAllocatorDump* elud_dump = nullptr; - ExtremeLUDStats elud_stats; + base::trace_event::MemoryAllocatorDump* elud_dump_for_small_objects = nullptr; + ExtremeLUDStats elud_stats_for_small_objects; + base::trace_event::MemoryAllocatorDump* elud_dump_for_large_objects = nullptr; + ExtremeLUDStats elud_stats_for_large_objects; #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) partitions_dump = pmd->CreateAllocatorDump("malloc/partitions"); pmd->AddOwnershipEdge(inner_dump->guid(), partitions_dump->guid()); @@ -424,16 +426,25 @@ auto& extreme_lud_get_stats_callback = GetExtremeLUDGetStatsCallback(); if (!extreme_lud_get_stats_callback.is_null()) { // The Extreme LUD is enabled. - elud_dump = pmd->CreateAllocatorDump("malloc/extreme_lud"); - elud_stats = extreme_lud_get_stats_callback.Run(); - ReportPartitionAllocLightweightQuarantineStats(elud_dump, - elud_stats.lq_stats); + elud_dump_for_small_objects = + pmd->CreateAllocatorDump("malloc/extreme_lud/small_objects"); + elud_dump_for_large_objects = + pmd->CreateAllocatorDump("malloc/extreme_lud/large_objects"); + const auto elud_stats_set = extreme_lud_get_stats_callback.Run(); + elud_stats_for_small_objects = elud_stats_set.for_small_objects; + elud_stats_for_large_objects = elud_stats_set.for_large_objects; + ReportPartitionAllocLightweightQuarantineStats( + elud_dump_for_small_objects, elud_stats_for_small_objects.lq_stats); + ReportPartitionAllocLightweightQuarantineStats( + elud_dump_for_large_objects, elud_stats_for_large_objects.lq_stats); } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - ReportPerMinuteStats(syscall_count, cumulative_brp_quarantined_size, - cumulative_brp_quarantined_count, elud_stats, outer_dump, - partitions_dump, elud_dump); + ReportPerMinuteStats( + syscall_count, cumulative_brp_quarantined_size, + cumulative_brp_quarantined_count, elud_stats_for_small_objects, + elud_stats_for_large_objects, outer_dump, partitions_dump, + elud_dump_for_small_objects, elud_dump_for_large_objects); return true; } @@ -442,10 +453,12 @@ uint64_t syscall_count, size_t cumulative_brp_quarantined_bytes, size_t cumulative_brp_quarantined_count, - const ExtremeLUDStats& elud_stats, + const ExtremeLUDStats& elud_stats_for_small_objects, + const ExtremeLUDStats& elud_stats_for_large_objects, MemoryAllocatorDump* malloc_dump, MemoryAllocatorDump* partition_alloc_dump, - MemoryAllocatorDump* elud_dump) { + MemoryAllocatorDump* elud_dump_for_small_objects, + MemoryAllocatorDump* elud_dump_for_large_objects) { #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) uint64_t new_syscalls = syscall_count - last_syscall_count_; size_t new_brp_quarantined_bytes = @@ -470,13 +483,19 @@ MemoryAllocatorDump::kNameObjectCount, brp_quarantined_count_per_minute); } - if (elud_dump) { + + auto report_elud_per_minute_stats = [time_since_last_dump, + seconds_since_last_dump]( + const ExtremeLUDStats& elud_stats, + CumulativeEludStats& + last_cumulative_elud_stats, + MemoryAllocatorDump* elud_dump) { size_t bytes = elud_stats.lq_stats.cumulative_size_in_bytes - - last_cumulative_elud_quarantined_bytes_; + last_cumulative_elud_stats.quarantined_bytes; size_t count = elud_stats.lq_stats.cumulative_count - - last_cumulative_elud_quarantined_count_; + last_cumulative_elud_stats.quarantined_count; size_t miss_count = elud_stats.lq_stats.quarantine_miss_count - - last_cumulative_elud_miss_count_; + last_cumulative_elud_stats.miss_count; elud_dump->AddScalar("bytes_per_minute", MemoryAllocatorDump::kUnitsBytes, 60ull * bytes / seconds_since_last_dump); elud_dump->AddScalar("count_per_minute", @@ -509,12 +528,22 @@ static_cast<uint64_t>(time_since_last_dump.InMilliseconds()) * elud_stats.capacity_in_bytes / bytes); } - last_cumulative_elud_quarantined_bytes_ = + last_cumulative_elud_stats.quarantined_bytes = elud_stats.lq_stats.cumulative_size_in_bytes; - last_cumulative_elud_quarantined_count_ = + last_cumulative_elud_stats.quarantined_count = elud_stats.lq_stats.cumulative_count; - last_cumulative_elud_miss_count_ = + last_cumulative_elud_stats.miss_count = elud_stats.lq_stats.quarantine_miss_count; + }; + if (elud_dump_for_small_objects) { + report_elud_per_minute_stats(elud_stats_for_small_objects, + last_cumulative_elud_stats_for_small_objects_, + elud_dump_for_small_objects); + } + if (elud_dump_for_large_objects) { + report_elud_per_minute_stats(elud_stats_for_large_objects, + last_cumulative_elud_stats_for_large_objects_, + elud_dump_for_large_objects); } last_memory_dump_time_ = base::TimeTicks::Now();
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h index ae3f02a..7b659be1 100644 --- a/base/trace_event/malloc_dump_provider.h +++ b/base/trace_event/malloc_dump_provider.h
@@ -44,8 +44,12 @@ partition_alloc::LightweightQuarantineStats lq_stats{0}; size_t capacity_in_bytes = 0; }; + struct ExtremeLUDStatsSet { + ExtremeLUDStats for_small_objects{}; + ExtremeLUDStats for_large_objects{}; + }; #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - using ExtremeLUDGetStatsCallback = RepeatingCallback<ExtremeLUDStats()>; + using ExtremeLUDGetStatsCallback = RepeatingCallback<ExtremeLUDStatsSet()>; static void SetExtremeLUDGetStatsCallback( ExtremeLUDGetStatsCallback callback); #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) @@ -58,6 +62,12 @@ ProcessMemoryDump* pmd) override; private: + struct CumulativeEludStats { + size_t quarantined_bytes = 0; + size_t quarantined_count = 0; + size_t miss_count = 0; + }; + friend struct DefaultSingletonTraits<MallocDumpProvider>; MallocDumpProvider(); @@ -66,10 +76,12 @@ void ReportPerMinuteStats(uint64_t syscall_count, size_t cumulative_brp_quarantined_bytes, size_t cumulative_brp_quarantined_count, - const ExtremeLUDStats& elud_stats, + const ExtremeLUDStats& elud_stats_for_small_objects, + const ExtremeLUDStats& elud_stats_for_large_objects, MemoryAllocatorDump* malloc_dump, MemoryAllocatorDump* partition_alloc_dump, - MemoryAllocatorDump* elud_dump); + MemoryAllocatorDump* elud_dump_for_small_objects, + MemoryAllocatorDump* elud_dump_for_large_objects); bool emit_metrics_on_memory_dump_ GUARDED_BY(emit_metrics_on_memory_dump_lock_) = true; @@ -86,9 +98,8 @@ uint64_t last_syscall_count_ = 0; size_t last_cumulative_brp_quarantined_bytes_ = 0; size_t last_cumulative_brp_quarantined_count_ = 0; - size_t last_cumulative_elud_quarantined_bytes_ = 0; - size_t last_cumulative_elud_quarantined_count_ = 0; - size_t last_cumulative_elud_miss_count_ = 0; + CumulativeEludStats last_cumulative_elud_stats_for_small_objects_{0}; + CumulativeEludStats last_cumulative_elud_stats_for_large_objects_{0}; #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) };
diff --git a/base/trace_event/memory_infra_background_allowlist.cc b/base/trace_event/memory_infra_background_allowlist.cc index bfd7531..c13899e3 100644 --- a/base/trace_event/memory_infra_background_allowlist.cc +++ b/base/trace_event/memory_infra_background_allowlist.cc
@@ -190,7 +190,9 @@ "malloc/allocated_objects", #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) "malloc/extreme_lud", -#endif + "malloc/extreme_lud/small_objects", + "malloc/extreme_lud/large_objects", +#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) "malloc/metadata_fragmentation_caches", #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) "malloc/partitions",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java index 9eebaa6a..b31ca70e 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
@@ -230,18 +230,19 @@ } float iconAlpha; - int textAppearance; if (item.getSuggestion().applyDeactivatedStyle()) { + // Disabling chipview if deactivated style is set. + chipView.setEnabled(false); iconAlpha = GRAYED_OUT_OPACITY_ALPHA; - textAppearance = R.style.TextAppearance_TextMedium_Disabled; - chipView.setOnClickListener(null); - chipView.setOnLongClickListener(null); + // Restoring the chipview border post disabling it to meet the + // required UI. + chipView.setBorder( + chipView.getResources().getDimensionPixelSize(R.dimen.chip_border_width), + chipView.getContext().getColor(R.color.black_alpha_12)); } else { + chipView.setEnabled(true); iconAlpha = COMPLETE_OPACITY_ALPHA; - textAppearance = R.style.TextAppearance_ChipText; } - chipView.getPrimaryTextView().setTextAppearance(textAppearance); - chipView.getSecondaryTextView().setTextAppearance(textAppearance); Drawable iconDrawable = mSuggestionDrawableFunction.apply(item.getSuggestion()); if (iconDrawable != null) { iconDrawable.setAlpha((int) (255 * iconAlpha));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java index 3e970f5..af66e49c 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
@@ -826,6 +826,7 @@ onView(withText("Virtual Card")).perform(click()); assertFalse(clickRecorded.get()); + onView(withText("Virtual Card")).check(matches(not(isSelected()))); } private static AutofillSuggestion.Builder getDefaultAutofillSuggestionBuilder() {
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 7364aec..e607bcec 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -757,6 +757,18 @@ <message name="IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_PAGE_TITLE" desc="The title of the page in Settings that allows to manage the autofill improved predictions settings." translateable="false"> Autofill prediction improvements </message> + <message name="IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_WHEN_ON_SAVED_INFO" desc="One of the items describing what happens when improved autofill predictions are enabled." translateable="false"> + Chrome asks if you want to use saved info to fill forms + </message> + <message name="IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_WHEN_ON_ADAPTS" desc="One of the items describing what happens when improved autofill predictions are enabled." translateable="false"> + TODO: Describe how autofill adapts to user preferences + </message> + <message name="IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_TO_CONSIDER_INFO_LOCAL" desc="One of the items describing what the user should consider before enabling improved autofill predictions." translateable="false"> + Your info is saved on your device and isn't shared with others + </message> + <message name="IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_TO_CONSIDER_DATA_USAGE" desc="One of the items describing what the user should consider before enabling improved autofill predictions." translateable="false"> + TODO: Describe how data is used + </message> <if expr="is_win or is_macosx"> <message name="IDS_AUTOFILL_MANAGE_PASSKEYS_LABEL" desc="The label on a button that a user can click in order to see and delete passkeys saved on their computer. For consistency, the word 'passkey' is in the glossary with translations already suggested."> @@ -2513,14 +2525,6 @@ <message name="IDS_SETTINGS_SEARCH" desc="Name of the settings page which displays search engine preferences."> Search engine </message> - <message name="IDS_SETTINGS_SEARCH_EXPLANATION" desc="Explanation for the search engine dropdown setting."> - Search engine used in the address bar. - </message> - <if expr="is_chromeos"> - <message name="IDS_SETTINGS_SEARCH_EXPLANATION_PRIMARY_PROFILE" desc="Explanation for the search engine dropdown setting in the primary profile."> - Search engine used in the address bar and the launcher. - </message> - </if> <message name="IDS_SETTINGS_SEARCH_EXPLANATION_ACCESSIBILITY_LABEL" desc="Accessibility label for a 'learn more' link which links to an article about setting a default search engine."> Learn more about default search engines </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION.png.sha1 deleted file mode 100644 index 11fde0b5..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -34bc8bbcf22b3d1705483d33d329fe521a985734 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION_PRIMARY_PROFILE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION_PRIMARY_PROFILE.png.sha1 deleted file mode 100644 index 47034ed8..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SEARCH_EXPLANATION_PRIMARY_PROFILE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -992bff84466375d27932337276cb944aba8310b3 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 7e3a966..a22caca 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4281,6 +4281,7 @@ "//chrome/browser/ui/color:color_headers", "//chrome/browser/ui/commerce", "//chrome/browser/ui/commerce:impl", + "//chrome/browser/ui/content_settings:impl", "//chrome/browser/ui/exclusive_access", "//chrome/browser/ui/lens", "//chrome/browser/ui/page_action:icon_type", @@ -4404,6 +4405,7 @@ "//chrome/browser/ui/views/toolbar", "//chrome/browser/ui/webui/searchbox", "//chrome/browser/ui/webui/top_chrome:impl", + "//chrome/browser/ui/content_settings:impl", "//chrome/browser/ui/commerce:impl", ] @@ -5192,6 +5194,7 @@ "//chrome/browser/ui/ash/wallpaper", "//chrome/browser/ui/ash/web_view", "//chrome/browser/ui/views/borealis", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/add_supervision", "//chrome/browser/ui/webui/ash/app_install", "//chrome/browser/ui/webui/ash/arc_overview_tracing", @@ -5618,6 +5621,7 @@ "//chrome/browser/ui/ash/wallpaper", "//chrome/browser/ui/ash/web_view", "//chrome/browser/ui/views/borealis", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/arc_overview_tracing", "//chrome/browser/ui/webui/ash/arc_power_control", "//chrome/browser/ui/webui/ash/assistant_optin", @@ -7681,6 +7685,7 @@ "//chrome/browser/extensions", "//chrome/browser/extensions:keyed_service_factories", "//chrome/browser/extensions/api", + "//chrome/browser/ui/tabs:tab_strip_model_observer", ] # Any circular includes must depend on the target
diff --git a/chrome/browser/ai/ai_manager_keyed_service_unittest.cc b/chrome/browser/ai/ai_manager_keyed_service_unittest.cc index 38078d7..78050e7 100644 --- a/chrome/browser/ai/ai_manager_keyed_service_unittest.cc +++ b/chrome/browser/ai/ai_manager_keyed_service_unittest.cc
@@ -8,13 +8,11 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/supports_user_data.h" #include "base/test/mock_callback.h" #include "chrome/browser/ai/ai_manager_keyed_service_factory.h" +#include "chrome/browser/ai/ai_test_utils.h" #include "chrome/browser/ai/ai_text_session.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" -#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/keyed_service/core/keyed_service.h" #include "components/optimization_guide/core/mock_optimization_guide_model_executor.h" #include "components/optimization_guide/core/optimization_guide_model_executor.h" @@ -28,15 +26,11 @@ using optimization_guide::MockSession; using optimization_guide::MockSessionWrapper; using testing::_; -using testing::An; using testing::AtMost; using testing::Invoke; using testing::NiceMock; -using testing::Return; namespace { -class MockSupportsUserData : public base::SupportsUserData {}; - const optimization_guide::TokenLimits& GetFakeTokenLimits() { static const optimization_guide::TokenLimits limits{ .max_tokens = 4096, @@ -49,37 +43,10 @@ } // namespace -class AIManagerKeyedServiceTest : public ChromeRenderViewHostTestHarness { - public: - void SetUp() override { - ChromeRenderViewHostTestHarness::SetUp(); - SetUpOptimizationGuide(); - } - - void TearDown() override { - mock_optimization_guide_keyed_service_ = nullptr; - ChromeRenderViewHostTestHarness::TearDown(); - } - +class AIManagerKeyedServiceTest : public AITestUtils::AITestBase { protected: - MockSupportsUserData* mock_host() { return &mock_host_; } - - testing::NiceMock<MockOptimizationGuideKeyedService>* MockService() { - return mock_optimization_guide_keyed_service_; - } - - private: - void SetUpOptimizationGuide() { - mock_optimization_guide_keyed_service_ = - static_cast<NiceMock<MockOptimizationGuideKeyedService>*>( - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating([](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - return std::make_unique< - NiceMock<MockOptimizationGuideKeyedService>>(); - }))); + void SetupMockOptimizationGuideKeyedService() { + AITestUtils::AITestBase::SetupMockOptimizationGuideKeyedService(); ON_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillByDefault( @@ -87,21 +54,22 @@ ON_CALL(session_, GetTokenLimits()).WillByDefault(GetFakeTokenLimits); } - raw_ptr<testing::NiceMock<MockOptimizationGuideKeyedService>> - mock_optimization_guide_keyed_service_; + private: testing::NiceMock<MockSession> session_; - MockSupportsUserData mock_host_; }; // Tests that involve invalid on-device model file paths should not crash when // the associated RFH is destroyed. TEST_F(AIManagerKeyedServiceTest, NoUAFWithInvalidOnDeviceModelPath) { + SetupMockOptimizationGuideKeyedService(); + auto* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitchASCII( optimization_guide::switches::kOnDeviceModelExecutionOverride, "invalid-on-device-model-file-path"); - EXPECT_CALL(*MockService(), CanCreateOnDeviceSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, + CanCreateOnDeviceSession(_, _)) .Times(AtMost(1)) .WillOnce(Invoke([](optimization_guide::ModelBasedCapabilityKey feature, optimization_guide::OnDeviceModelEligibilityReason* @@ -136,6 +104,8 @@ // Tests the `AIUserDataSet`'s behavior of managing the lifetime of // `AITextSession`s. TEST_F(AIManagerKeyedServiceTest, AIContextBoundObjectSet) { + SetupMockOptimizationGuideKeyedService(); + base::MockCallback<blink::mojom::AIManager::CreateTextSessionCallback> callback; base::RunLoop run_loop; @@ -146,14 +116,8 @@ run_loop.Quit(); })); - AIManagerKeyedService* ai_manager = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); - - mojo::Remote<blink::mojom::AIManager> mock_remote; + mojo::Remote<blink::mojom::AIManager> mock_remote = GetAIManagerRemote(); mojo::Remote<blink::mojom::AITextSession> mock_session; - ai_manager->AddReceiver(mock_remote.BindNewPipeAndPassReceiver(), - mock_host()); // Initially the `AIUserDataSet` is empty. base::WeakPtr<AIContextBoundObjectSet> context_bound_objects = AIContextBoundObjectSet::GetFromContext(mock_host())
diff --git a/chrome/browser/ai/ai_rewriter_unittest.cc b/chrome/browser/ai/ai_rewriter_unittest.cc index e44ebe5..a26bf1e2 100644 --- a/chrome/browser/ai/ai_rewriter_unittest.cc +++ b/chrome/browser/ai/ai_rewriter_unittest.cc
@@ -8,11 +8,9 @@ #include "base/run_loop.h" #include "base/test/bind.h" -#include "base/test/mock_callback.h" #include "chrome/browser/ai/ai_manager_keyed_service_factory.h" +#include "chrome/browser/ai/ai_test_utils.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" -#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/optimization_guide/core/mock_optimization_guide_model_executor.h" #include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/optimization_guide/core/optimization_guide_util.h" @@ -22,8 +20,6 @@ #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" using ::testing::_; -using ::testing::AtMost; -using ::testing::NiceMock; namespace { @@ -55,36 +51,10 @@ mojo::Receiver<blink::mojom::AIManagerCreateRewriterClient> receiver_{this}; }; -// TODO(crbug.com/358214322): Move MockResponder to a common utils file. -class MockResponder : public blink::mojom::ModelStreamingResponder { - public: - MockResponder() = default; - ~MockResponder() override = default; - MockResponder(const MockResponder&) = delete; - MockResponder& operator=(const MockResponder&) = delete; - - mojo::PendingRemote<blink::mojom::ModelStreamingResponder> - BindNewPipeAndPassRemote() { - return receiver_.BindNewPipeAndPassRemote(); - } - - MOCK_METHOD(void, - OnResponse, - (blink::mojom::ModelStreamingResponseStatus status, - const std::optional<std::string>& text, - std::optional<uint64_t> current_tokens), - (override)); - - private: - mojo::Receiver<blink::mojom::ModelStreamingResponder> receiver_{this}; -}; - -class MockSupportsUserData : public base::SupportsUserData {}; - optimization_guide::OptimizationGuideModelStreamingExecutionResult -CreateExecutionResult(const std::string_view outpt, bool is_complete) { +CreateExecutionResult(const std::string_view output, bool is_complete) { optimization_guide::proto::ComposeResponse response; - *response.mutable_output() = outpt; + *response.mutable_output() = output; std::string serialized_metadata; response.SerializeToString(&serialized_metadata); optimization_guide::proto::Any any; @@ -155,51 +125,8 @@ } // namespace -class AIRewriterTest : public ChromeRenderViewHostTestHarness { - public: - void SetUp() override { - ChromeRenderViewHostTestHarness::SetUp(); - mock_host_ = std::make_unique<MockSupportsUserData>(); - } - - void TearDown() override { - optimization_guide_keyed_service_ = nullptr; - mock_host_.reset(); - ChromeRenderViewHostTestHarness::TearDown(); - } - +class AIRewriterTest : public AITestUtils::AITestBase { protected: - // Setting up MockOptimizationGuideKeyedService. - void SetupMockOptimizationGuideKeyedService() { - optimization_guide_keyed_service_ = - static_cast<MockOptimizationGuideKeyedService*>( - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating([](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - return std::make_unique< - NiceMock<MockOptimizationGuideKeyedService>>(); - }))); - } - void SetupNullOptimizationGuideKeyedService() { - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating( - [](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { return nullptr; })); - } - - mojo::Remote<blink::mojom::AIManager> GetAIManagerRemote() { - AIManagerKeyedService* ai_manager_keyed_service = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); - mojo::Remote<blink::mojom::AIManager> ai_manager; - ai_manager_keyed_service->AddReceiver( - ai_manager.BindNewPipeAndPassReceiver(), mock_host_.get()); - return ai_manager; - } void RunSimpleRewriteTest( blink::mojom::AIRewriterTone tone, blink::mojom::AIRewriterLength length, @@ -208,13 +135,6 @@ void RunRewriteOptionCombinationFailureTest( blink::mojom::AIRewriterTone tone, blink::mojom::AIRewriterLength length); - - void ResetMockHost() { mock_host_.reset(); } - - raw_ptr<MockOptimizationGuideKeyedService> optimization_guide_keyed_service_; - - private: - std::unique_ptr<MockSupportsUserData> mock_host_; }; void AIRewriterTest::RunSimpleRewriteTest( @@ -223,7 +143,7 @@ base::OnceCallback<void(const google::protobuf::MessageLite& request_metadata)> request_check_callback) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -273,7 +193,7 @@ length)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -342,12 +262,12 @@ TEST_F(AIRewriterTest, CreateRewriterModelNotAvailable) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& config_params) { return nullptr; })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -380,7 +300,7 @@ SetupMockOptimizationGuideKeyedService(); // StartSession must be called twice. - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& @@ -396,7 +316,7 @@ return std::make_unique<optimization_guide::MockSession>(); })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -411,7 +331,7 @@ optimization_guide::OnDeviceModelAvailabilityObserver* availability_observer = nullptr; base::RunLoop run_loop_for_add_observer; - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, AddOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -458,13 +378,13 @@ TEST_F(AIRewriterTest, CreateRewriterAbortAfterConfigNotAvailableForFeature) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& config_params) { return nullptr; })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -480,7 +400,7 @@ nullptr; base::RunLoop run_loop_for_add_observer; base::RunLoop run_loop_for_remove_observer; - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, AddOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -488,7 +408,7 @@ availability_observer = observer; run_loop_for_add_observer.Quit(); })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, RemoveOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -518,7 +438,7 @@ TEST_F(AIRewriterTest, ContextDestroyed) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& @@ -635,7 +555,7 @@ TEST_F(AIRewriterTest, RewriteError) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -688,7 +608,7 @@ blink::mojom::AIRewriterLength::kAsIs)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -709,7 +629,7 @@ TEST_F(AIRewriterTest, RewriteMultipleResponse) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -762,7 +682,7 @@ blink::mojom::AIRewriterLength::kAsIs)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -798,7 +718,7 @@ TEST_F(AIRewriterTest, MultipleRewrite) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -864,7 +784,7 @@ run_loop.Run(); } { - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke( @@ -889,7 +809,7 @@ run_loop.Run(); } { - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke( @@ -921,7 +841,7 @@ base::RunLoop run_loop_for_callback; optimization_guide::OptimizationGuideModelExecutionResultStreamingCallback streaming_callback; - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -971,8 +891,8 @@ blink::mojom::AIRewriterLength::kAsIs)); run_loop.Run(); } - std::unique_ptr<MockResponder> mock_responder = - std::make_unique<MockResponder>(); + std::unique_ptr<AITestUtils::MockModelStreamingResponder> mock_responder = + std::make_unique<AITestUtils::MockModelStreamingResponder>(); rewriter_remote->Rewrite(kInputString, kContextString, mock_responder->BindNewPipeAndPassRemote()); mock_responder.reset(); @@ -993,7 +913,7 @@ base::RunLoop run_loop_for_callback; optimization_guide::OptimizationGuideModelExecutionResultStreamingCallback streaming_callback; - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -1044,7 +964,7 @@ run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop_for_response; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke([&](blink::mojom::ModelStreamingResponseStatus
diff --git a/chrome/browser/ai/ai_summarizer_unittest.cc b/chrome/browser/ai/ai_summarizer_unittest.cc index f1ba7f6..f35cdb8 100644 --- a/chrome/browser/ai/ai_summarizer_unittest.cc +++ b/chrome/browser/ai/ai_summarizer_unittest.cc
@@ -8,9 +8,8 @@ #include "base/test/run_until.h" #include "chrome/browser/ai/ai_manager_keyed_service.h" #include "chrome/browser/ai/ai_manager_keyed_service_factory.h" +#include "chrome/browser/ai/ai_test_utils.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" -#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/optimization_guide/core/mock_optimization_guide_model_executor.h" #include "components/optimization_guide/proto/features/summarize.pb.h" #include "components/optimization_guide/proto/string_value.pb.h" @@ -31,8 +30,6 @@ using optimization_guide::proto::SummarizerOutputLength; using optimization_guide::proto::SummarizerOutputType; -class MockSupportsUserData : public base::SupportsUserData {}; - class MockStreamingResponder : public blink::mojom::ModelStreamingResponder { public: MockStreamingResponder() = default; @@ -72,57 +69,22 @@ base::RunLoop run_loop_; }; -class AISummarizerUnitTest : public ChromeRenderViewHostTestHarness { +class AISummarizerUnitTest : public AITestUtils::AITestBase { public: AISummarizerUnitTest() = default; - void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); } - - void TearDown() override { - mock_optimization_guide_keyed_service_ = nullptr; - ChromeRenderViewHostTestHarness::TearDown(); - } - void SetupMockOptimizationGuideKeyedService() { - mock_optimization_guide_keyed_service_ = - static_cast<NiceMock<MockOptimizationGuideKeyedService>*>( - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating([](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - return std::make_unique< - NiceMock<MockOptimizationGuideKeyedService>>(); - }))); + AITestUtils::AITestBase::SetupMockOptimizationGuideKeyedService(); ON_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillByDefault( [&] { return std::make_unique<MockSessionWrapper>(&session_); }); } - void SetupNullOptimizationGuideKeyedService() { - mock_optimization_guide_keyed_service_ = - static_cast<NiceMock<MockOptimizationGuideKeyedService>*>( - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating([](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - return nullptr; - }))); - } - ~AISummarizerUnitTest() override = default; protected: - MockSupportsUserData* mock_host() { return &mock_host_; } - - raw_ptr<MockOptimizationGuideKeyedService> - mock_optimization_guide_keyed_service_; testing::NiceMock<MockSession> session_; - - private: - MockSupportsUserData mock_host_; }; class MockCreateSummarizerClient @@ -239,17 +201,12 @@ SummarizerOutputLength::SUMMARIZER_OUTPUT_LENGTH_MEDIUM, "Test output")); - AIManagerKeyedService* ai_manager = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); base::WeakPtr<AIContextBoundObjectSet> context_bound_objects = AIContextBoundObjectSet::GetFromContext(mock_host()) ->GetWeakPtrForTesting(); ASSERT_EQ(0u, context_bound_objects->GetSizeForTesting()); - mojo::Remote<blink::mojom::AIManager> mock_remote; - ai_manager->AddReceiver(mock_remote.BindNewPipeAndPassReceiver(), - mock_host()); + mojo::Remote<blink::mojom::AIManager> mock_remote = GetAIManagerRemote(); MockCreateSummarizerClient create_client; mock_remote->CreateSummarizer( create_client.BindNewPipeAndPassRemote(), @@ -281,17 +238,12 @@ // for the response. SetupMockOptimizationGuideKeyedService(); - AIManagerKeyedService* ai_manager = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); base::WeakPtr<AIContextBoundObjectSet> context_bound_objects = AIContextBoundObjectSet::GetFromContext(mock_host()) ->GetWeakPtrForTesting(); ASSERT_EQ(0u, context_bound_objects->GetSizeForTesting()); - mojo::Remote<blink::mojom::AIManager> mock_remote; - ai_manager->AddReceiver(mock_remote.BindNewPipeAndPassReceiver(), - mock_host()); + mojo::Remote<blink::mojom::AIManager> mock_remote = GetAIManagerRemote(); MockCreateSummarizerClient create_client; mock_remote->CreateSummarizer( create_client.BindNewPipeAndPassRemote(), @@ -317,18 +269,12 @@ TEST_F(AISummarizerUnitTest, MultipleSummarizeWithOptions) { SetupMockOptimizationGuideKeyedService(); - AIManagerKeyedService* ai_manager = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); base::WeakPtr<AIContextBoundObjectSet> context_bound_objects = AIContextBoundObjectSet::GetFromContext(mock_host()) ->GetWeakPtrForTesting(); ASSERT_EQ(0u, context_bound_objects->GetSizeForTesting()); - mojo::Remote<blink::mojom::AIManager> mock_remote; - ai_manager->AddReceiver(mock_remote.BindNewPipeAndPassReceiver(), - mock_host()); - + mojo::Remote<blink::mojom::AIManager> mock_remote = GetAIManagerRemote(); EXPECT_CALL(session_, ExecuteModel(testing::_, testing::_)) .WillOnce(CreateModelExecutionMock( "Test input1", "Shared context.\n",
diff --git a/chrome/browser/ai/ai_test_utils.cc b/chrome/browser/ai/ai_test_utils.cc new file mode 100644 index 0000000..827e094 --- /dev/null +++ b/chrome/browser/ai/ai_test_utils.cc
@@ -0,0 +1,73 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ai/ai_test_utils.h" + +#include "chrome/browser/ai/ai_manager_keyed_service.h" +#include "chrome/browser/ai/ai_manager_keyed_service_factory.h" +#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" +#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" + +AITestUtils::MockModelStreamingResponder::MockModelStreamingResponder() = + default; +AITestUtils::MockModelStreamingResponder::~MockModelStreamingResponder() = + default; + +mojo::PendingRemote<blink::mojom::ModelStreamingResponder> +AITestUtils::MockModelStreamingResponder::BindNewPipeAndPassRemote() { + return receiver_.BindNewPipeAndPassRemote(); +} + +AITestUtils::AITestBase::AITestBase() = default; +AITestUtils::AITestBase::~AITestBase() = default; + +void AITestUtils::AITestBase::SetUp() { + ChromeRenderViewHostTestHarness::SetUp(); + mock_host_ = std::make_unique<MockSupportsUserData>(); +} + +void AITestUtils::AITestBase::TearDown() { + mock_optimization_guide_keyed_service_ = nullptr; + mock_host_.reset(); + ChromeRenderViewHostTestHarness::TearDown(); +} + +void AITestUtils::AITestBase::SetupMockOptimizationGuideKeyedService() { + mock_optimization_guide_keyed_service_ = + static_cast<MockOptimizationGuideKeyedService*>( + OptimizationGuideKeyedServiceFactory::GetInstance() + ->SetTestingFactoryAndUse( + profile(), + base::BindRepeating([](content::BrowserContext* context) + -> std::unique_ptr<KeyedService> { + return std::make_unique< + testing::NiceMock<MockOptimizationGuideKeyedService>>(); + }))); +} + +void AITestUtils::AITestBase::SetupNullOptimizationGuideKeyedService() { + OptimizationGuideKeyedServiceFactory::GetInstance()->SetTestingFactoryAndUse( + profile(), base::BindRepeating( + [](content::BrowserContext* context) + -> std::unique_ptr<KeyedService> { return nullptr; })); +} + +mojo::Remote<blink::mojom::AIManager> +AITestUtils::AITestBase::GetAIManagerRemote() { + AIManagerKeyedService* ai_manager_keyed_service = + AIManagerKeyedServiceFactory::GetAIManagerKeyedService( + main_rfh()->GetBrowserContext()); + mojo::Remote<blink::mojom::AIManager> ai_manager; + ai_manager_keyed_service->AddReceiver(ai_manager.BindNewPipeAndPassReceiver(), + mock_host_.get()); + return ai_manager; +} + +void AITestUtils::AITestBase::ResetMockHost() { + mock_host_.reset(); +}
diff --git a/chrome/browser/ai/ai_test_utils.h b/chrome/browser/ai/ai_test_utils.h new file mode 100644 index 0000000..ac51fc3 --- /dev/null +++ b/chrome/browser/ai/ai_test_utils.h
@@ -0,0 +1,69 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AI_AI_TEST_UTILS_H_ +#define CHROME_BROWSER_AI_AI_TEST_UTILS_H_ + +#include "base/supports_user_data.h" +#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/mojom/ai/ai_manager.mojom.h" +#include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" + +class AITestUtils { + public: + class MockSupportsUserData : public base::SupportsUserData {}; + + class MockModelStreamingResponder + : public blink::mojom::ModelStreamingResponder { + public: + MockModelStreamingResponder(); + ~MockModelStreamingResponder() override; + MockModelStreamingResponder(const MockModelStreamingResponder&) = delete; + MockModelStreamingResponder& operator=(const MockModelStreamingResponder&) = + delete; + + mojo::PendingRemote<blink::mojom::ModelStreamingResponder> + BindNewPipeAndPassRemote(); + + MOCK_METHOD(void, + OnResponse, + (blink::mojom::ModelStreamingResponseStatus status, + const std::optional<std::string>& text, + std::optional<uint64_t> current_tokens), + (override)); + + private: + mojo::Receiver<blink::mojom::ModelStreamingResponder> receiver_{this}; + }; + + class AITestBase : public ChromeRenderViewHostTestHarness { + public: + AITestBase(); + ~AITestBase() override; + + void SetUp() override; + void TearDown() override; + + protected: + void SetupMockOptimizationGuideKeyedService(); + void SetupNullOptimizationGuideKeyedService(); + + mojo::Remote<blink::mojom::AIManager> GetAIManagerRemote(); + MockSupportsUserData* mock_host() { return mock_host_.get(); } + void ResetMockHost(); + + raw_ptr<MockOptimizationGuideKeyedService> + mock_optimization_guide_keyed_service_; + + private: + std::unique_ptr<MockSupportsUserData> mock_host_; + }; +}; + +#endif // CHROME_BROWSER_AI_AI_TEST_UTILS_H_
diff --git a/chrome/browser/ai/ai_text_session_unittest.cc b/chrome/browser/ai/ai_text_session_unittest.cc index 0717999..55cca4b 100644 --- a/chrome/browser/ai/ai_text_session_unittest.cc +++ b/chrome/browser/ai/ai_text_session_unittest.cc
@@ -10,9 +10,13 @@ using testing::Test; +namespace { + const uint32_t kTestMaxContextToken = 10u; const uint32_t kTestSystemPromptToken = 5u; +} // namespace + // Tests `AITextSession::Context` creation without system prompt. TEST(AITextSessionTest, CreateContext_WithoutSystemPrompt) { AITextSession::Context context(kTestMaxContextToken, std::nullopt);
diff --git a/chrome/browser/ai/ai_writer_unittest.cc b/chrome/browser/ai/ai_writer_unittest.cc index 986c7ff..7e2390f 100644 --- a/chrome/browser/ai/ai_writer_unittest.cc +++ b/chrome/browser/ai/ai_writer_unittest.cc
@@ -8,11 +8,9 @@ #include "base/run_loop.h" #include "base/test/bind.h" -#include "base/test/mock_callback.h" #include "chrome/browser/ai/ai_manager_keyed_service_factory.h" +#include "chrome/browser/ai/ai_test_utils.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" -#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/optimization_guide/core/mock_optimization_guide_model_executor.h" #include "components/optimization_guide/core/optimization_guide_switches.h" #include "components/optimization_guide/core/optimization_guide_util.h" @@ -22,8 +20,6 @@ #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h" using ::testing::_; -using ::testing::AtMost; -using ::testing::NiceMock; namespace { @@ -55,36 +51,10 @@ mojo::Receiver<blink::mojom::AIManagerCreateWriterClient> receiver_{this}; }; -// TODO(crbug.com/357967382): Move MockResponder to a common utils file. -class MockResponder : public blink::mojom::ModelStreamingResponder { - public: - MockResponder() = default; - ~MockResponder() override = default; - MockResponder(const MockResponder&) = delete; - MockResponder& operator=(const MockResponder&) = delete; - - mojo::PendingRemote<blink::mojom::ModelStreamingResponder> - BindNewPipeAndPassRemote() { - return receiver_.BindNewPipeAndPassRemote(); - } - - MOCK_METHOD(void, - OnResponse, - (blink::mojom::ModelStreamingResponseStatus status, - const std::optional<std::string>& text, - std::optional<uint64_t> current_tokens), - (override)); - - private: - mojo::Receiver<blink::mojom::ModelStreamingResponder> receiver_{this}; -}; - -class MockSupportsUserData : public base::SupportsUserData {}; - optimization_guide::OptimizationGuideModelStreamingExecutionResult -CreateExecutionResult(const std::string_view outpt, bool is_complete) { +CreateExecutionResult(const std::string_view output, bool is_complete) { optimization_guide::proto::ComposeResponse response; - *response.mutable_output() = outpt; + *response.mutable_output() = output; std::string serialized_metadata; response.SerializeToString(&serialized_metadata); optimization_guide::proto::Any any; @@ -128,59 +98,7 @@ } // namespace -class AIWriterTest : public ChromeRenderViewHostTestHarness { - public: - void SetUp() override { - ChromeRenderViewHostTestHarness::SetUp(); - mock_host_ = std::make_unique<MockSupportsUserData>(); - } - - void TearDown() override { - optimization_guide_keyed_service_ = nullptr; - mock_host_.reset(); - ChromeRenderViewHostTestHarness::TearDown(); - } - - protected: - // Setting up MockOptimizationGuideKeyedService. - void SetupMockOptimizationGuideKeyedService() { - optimization_guide_keyed_service_ = - static_cast<MockOptimizationGuideKeyedService*>( - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating([](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { - return std::make_unique< - NiceMock<MockOptimizationGuideKeyedService>>(); - }))); - } - void SetupNullOptimizationGuideKeyedService() { - OptimizationGuideKeyedServiceFactory::GetInstance() - ->SetTestingFactoryAndUse( - profile(), - base::BindRepeating( - [](content::BrowserContext* context) - -> std::unique_ptr<KeyedService> { return nullptr; })); - } - - mojo::Remote<blink::mojom::AIManager> GetAIManagerRemote() { - AIManagerKeyedService* ai_manager_keyed_service = - AIManagerKeyedServiceFactory::GetAIManagerKeyedService( - main_rfh()->GetBrowserContext()); - mojo::Remote<blink::mojom::AIManager> ai_manager; - ai_manager_keyed_service->AddReceiver( - ai_manager.BindNewPipeAndPassReceiver(), mock_host_.get()); - return ai_manager; - } - - void ResetMockHost() { mock_host_.reset(); } - - raw_ptr<MockOptimizationGuideKeyedService> optimization_guide_keyed_service_; - - private: - std::unique_ptr<MockSupportsUserData> mock_host_; -}; +class AIWriterTest : public AITestUtils::AITestBase {}; TEST_F(AIWriterTest, CreateWriterNoService) { SetupNullOptimizationGuideKeyedService(); @@ -203,12 +121,12 @@ TEST_F(AIWriterTest, CreateWriterModelNotAvailable) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& config_params) { return nullptr; })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -239,7 +157,7 @@ SetupMockOptimizationGuideKeyedService(); // StartSession must be called twice. - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& @@ -255,7 +173,7 @@ return std::make_unique<optimization_guide::MockSession>(); })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -270,7 +188,7 @@ optimization_guide::OnDeviceModelAvailabilityObserver* availability_observer = nullptr; base::RunLoop run_loop_for_add_observer; - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, AddOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -315,13 +233,13 @@ TEST_F(AIWriterTest, CreateWriterAbortAfterConfigNotAvailableForFeature) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& config_params) { return nullptr; })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, CanCreateOnDeviceSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -337,7 +255,7 @@ nullptr; base::RunLoop run_loop_for_add_observer; base::RunLoop run_loop_for_remove_observer; - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, AddOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -345,7 +263,7 @@ availability_observer = observer; run_loop_for_add_observer.Quit(); })); - EXPECT_CALL(*optimization_guide_keyed_service_, + EXPECT_CALL(*mock_optimization_guide_keyed_service_, RemoveOnDeviceModelAvailabilityChangeObserver(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, @@ -372,7 +290,7 @@ TEST_F(AIWriterTest, ContextDestroyed) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke( [&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional<optimization_guide::SessionConfigParams>& @@ -410,7 +328,7 @@ TEST_F(AIWriterTest, SimpleWrite) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -458,7 +376,7 @@ blink::mojom::AIWriterCreateOptions::New(kSharedContextString)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -486,7 +404,7 @@ TEST_F(AIWriterTest, WriteError) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -537,7 +455,7 @@ blink::mojom::AIWriterCreateOptions::New(kSharedContextString)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -558,7 +476,7 @@ TEST_F(AIWriterTest, WriteMultipleResponse) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -608,7 +526,7 @@ blink::mojom::AIWriterCreateOptions::New(kSharedContextString)); run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) @@ -644,7 +562,7 @@ TEST_F(AIWriterTest, MultipleWrite) { SetupMockOptimizationGuideKeyedService(); - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -707,7 +625,7 @@ run_loop.Run(); } { - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke( @@ -732,7 +650,7 @@ run_loop.Run(); } { - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke( @@ -764,7 +682,7 @@ base::RunLoop run_loop_for_callback; optimization_guide::OptimizationGuideModelExecutionResultStreamingCallback streaming_callback; - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -811,8 +729,8 @@ blink::mojom::AIWriterCreateOptions::New(kSharedContextString)); run_loop.Run(); } - std::unique_ptr<MockResponder> mock_responder = - std::make_unique<MockResponder>(); + std::unique_ptr<AITestUtils::MockModelStreamingResponder> mock_responder = + std::make_unique<AITestUtils::MockModelStreamingResponder>(); writer_remote->Write(kInputString, kContextString, mock_responder->BindNewPipeAndPassRemote()); mock_responder.reset(); @@ -833,7 +751,7 @@ base::RunLoop run_loop_for_callback; optimization_guide::OptimizationGuideModelExecutionResultStreamingCallback streaming_callback; - EXPECT_CALL(*optimization_guide_keyed_service_, StartSession(_, _)) + EXPECT_CALL(*mock_optimization_guide_keyed_service_, StartSession(_, _)) .WillOnce(testing::Invoke([&](optimization_guide::ModelBasedCapabilityKey feature, const std::optional< @@ -881,7 +799,7 @@ run_loop.Run(); } - MockResponder mock_responder; + AITestUtils::MockModelStreamingResponder mock_responder; base::RunLoop run_loop_for_response; EXPECT_CALL(mock_responder, OnResponse(_, _, _)) .WillOnce(testing::Invoke([&](blink::mojom::ModelStreamingResponseStatus
diff --git a/chrome/browser/app_mode/test/BUILD.gn b/chrome/browser/app_mode/test/BUILD.gn index 9afbb6e..6bf30f4 100644 --- a/chrome/browser/app_mode/test/BUILD.gn +++ b/chrome/browser/app_mode/test/BUILD.gn
@@ -10,13 +10,18 @@ sources = [ "accelerator_helpers.cc", "accelerator_helpers.h", + "fake_origin_test_server_mixin.cc", + "fake_origin_test_server_mixin.h", ] deps = [ "//base", "//chrome/browser/ui", + "//chrome/test:test_support_ui", + "//content/test:test_support", "//testing/gtest", "//ui/base", "//ui/events:event_constants", + "//url", ] }
diff --git a/chrome/browser/app_mode/test/fake_origin_test_server_mixin.cc b/chrome/browser/app_mode/test/fake_origin_test_server_mixin.cc new file mode 100644 index 0000000..84b04bdf --- /dev/null +++ b/chrome/browser/app_mode/test/fake_origin_test_server_mixin.cc
@@ -0,0 +1,107 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/app_mode/test/fake_origin_test_server_mixin.h" + +#include <cstddef> +#include <string> +#include <string_view> +#include <utility> + +#include "base/base_paths.h" +#include "base/check.h" +#include "base/check_deref.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/functional/bind.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/strings/strcat.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/mixin_based_in_process_browser_test.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "services/network/public/cpp/network_switches.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace ash { + +using net::test_server::EmbeddedTestServer; + +namespace { + +EmbeddedTestServer::Type SchemeTypeOf(const GURL& origin) { + CHECK(origin.SchemeIs("http") || origin.SchemeIs("https")); + return origin.SchemeIs("http") ? EmbeddedTestServer::TYPE_HTTP + : EmbeddedTestServer::TYPE_HTTPS; +} + +// Returns "MAP example.com 127.0.0.1:1234", where "example.com" is the host in +// `origin` and "127.0.0.1:1234" is the host and port of `server`. +std::string MapOriginToServer(const GURL& origin, + const EmbeddedTestServer& server) { + return base::StrCat( + {"MAP ", origin.host_piece(), " ", server.host_port_pair().ToString()}); +} + +void LogUrl(const net::test_server::HttpRequest& request) { + LOG(INFO) << "Received request for url '" << request.GetURL() << "'"; +} + +} // namespace + +FakeOriginTestServerMixin::FakeOriginTestServerMixin( + InProcessBrowserTestMixinHost* host, + GURL origin, + base::FilePath::StringPieceType path_to_be_served) + : InProcessBrowserTestMixin(host), + origin_(std::move(origin)), + path_to_be_served_(path_to_be_served), + server_(SchemeTypeOf(origin_)) { + CHECK(origin_.is_valid()); + CHECK(origin_.has_scheme()); + CHECK(origin_.has_host()); + CHECK(!origin_.has_path() || origin_.path_piece() == "/"); + CHECK(!origin_.has_query()); + CHECK(!origin_.has_username()); + CHECK(!origin_.has_password()); + CHECK(!path_to_be_served_.value().starts_with("/")) + << "path_to_be_served_ must be relative to Chrome's src/"; + + // Generate SSL certificates for `origin_` on HTTPS. + if (SchemeTypeOf(origin_) == EmbeddedTestServer::TYPE_HTTPS) { + server_.SetCertHostnames({origin_.host()}); + } +} + +FakeOriginTestServerMixin::~FakeOriginTestServerMixin() = default; + +void FakeOriginTestServerMixin::SetUp() { + auto src_path = base::PathService::CheckedGet(base::DIR_SRC_TEST_DATA_ROOT); + server_.ServeFilesFromDirectory(src_path.Append(path_to_be_served_)); + server_.RegisterRequestMonitor(base::BindRepeating(&LogUrl)); + CHECK(server_.InitializeAndListen()); +} + +void FakeOriginTestServerMixin::SetUpCommandLine( + base::CommandLine* command_line) { + // Set the `kHostResolverRules` switch so Chrome forwards request made to + // `origin_` to the given `server_`. + auto rule = MapOriginToServer(origin_, server_); + command_line->AppendSwitchASCII(network::switches::kHostResolverRules, rule); + LOG(INFO) << "Configured host resolver rule '" << rule << "'"; +} + +void FakeOriginTestServerMixin::SetUpOnMainThread() { + server_handle_ = server_.StartAcceptingConnectionsAndReturnHandle(); +} + +GURL FakeOriginTestServerMixin::GetUrl(std::string_view url_suffix) const { + CHECK(url_suffix.starts_with("/")) + << "URL suffix must start with '/': " << url_suffix; + return origin_.Resolve(url_suffix); +} + +} // namespace ash
diff --git a/chrome/browser/app_mode/test/fake_origin_test_server_mixin.h b/chrome/browser/app_mode/test/fake_origin_test_server_mixin.h new file mode 100644 index 0000000..2d4c482 --- /dev/null +++ b/chrome/browser/app_mode/test/fake_origin_test_server_mixin.h
@@ -0,0 +1,74 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_APP_MODE_TEST_FAKE_ORIGIN_TEST_SERVER_MIXIN_H_ +#define CHROME_BROWSER_APP_MODE_TEST_FAKE_ORIGIN_TEST_SERVER_MIXIN_H_ + +#include <cstddef> +#include <string_view> + +#include "base/check_deref.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "chrome/test/base/mixin_based_in_process_browser_test.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "url/gurl.h" + +namespace ash { + +// This mixin sets up an `EmbeddedTestServer` configured to serve the files in +// Chrome's src/`path_to_be_served` under the given `origin`. +// +// This allows tests to serve content on a "real" origin like +// "http://your.app.com", instead of "http://127.0.0.1:<port>" with a varying +// port number. +// +// Both HTTP and HTTPS `origin` schemes are supported. +class FakeOriginTestServerMixin : public InProcessBrowserTestMixin { + public: + FakeOriginTestServerMixin(InProcessBrowserTestMixinHost* host, + GURL origin, + base::FilePath::StringPieceType path_to_be_served); + FakeOriginTestServerMixin(const FakeOriginTestServerMixin&) = delete; + FakeOriginTestServerMixin operator=(const FakeOriginTestServerMixin&) = + delete; + + ~FakeOriginTestServerMixin() override; + + const GURL& origin() const { return origin_; } + + // Returns the `origin_` URL with `url_suffix` appended to it. For example + // given `url_suffix` is `/path?q=123` the URL would be + // "https://foo.com/path?q=123". + // + // `url_suffix` must start with "/". + GURL GetUrl(std::string_view url_suffix) const; + + net::test_server::EmbeddedTestServer& server() { return server_; } + + const net::test_server::EmbeddedTestServer& server() const { return server_; } + + // InProcessBrowserTestMixin overrides: + void SetUp() override; + void SetUpCommandLine(base::CommandLine* command_line) override; + void SetUpOnMainThread() override; + + private: + // The origin to be served. Must be a URL with scheme and host, optionally + // followed by a port and a trailing slash. + // + // For example, "https://foo.com/" and "http://127.0.0.1:3244" are allowed but + // "https://foo.com/bar" and "http://127.0.0.1:3244?q=123" are not. + GURL origin_; + + // Path to the directory to be served, relative to Chrome's src/ directory. + base::FilePath path_to_be_served_; + + net::test_server::EmbeddedTestServer server_; + net::test_server::EmbeddedTestServerHandle server_handle_; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_APP_MODE_TEST_FAKE_ORIGIN_TEST_SERVER_MIXIN_H_
diff --git a/chrome/browser/apps/app_service/BUILD.gn b/chrome/browser/apps/app_service/BUILD.gn index 912dcdad..55531a0 100644 --- a/chrome/browser/apps/app_service/BUILD.gn +++ b/chrome/browser/apps/app_service/BUILD.gn
@@ -46,6 +46,7 @@ public_deps = [ ":constants", "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", ] deps = [
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 5da4be3d..cb002b7 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -27,8 +27,6 @@ "browser_context_keyed_service_factories.h", "chrome_browser_main_parts_ash.cc", "chrome_browser_main_parts_ash.h", - "http_auth_dialog.cc", - "http_auth_dialog.h", "idle_detector.cc", "idle_detector.h", "system_token_cert_db_initializer.cc", @@ -1064,7 +1062,6 @@ "../metrics/perf/random_selector_unittest.cc", "../policy/default_geolocation_policy_handler_unittest.cc", "../ui/browser_finder_chromeos_unittest.cc", - "../ui/views/select_file_dialog_extension_unittest.cc", "../ui/webui/settings/about_handler_unittest.cc", "proxy_config_service_impl_unittest.cc", "system_token_cert_db_initializer_unittest.cc", @@ -1828,6 +1825,7 @@ "//chrome/browser/ash/usb:unit_tests", "//chrome/browser/ash/video_conference:unit_tests", "//chrome/browser/ash/wallpaper_handlers:unit_tests", + "//chrome/browser/ui/views/select_file_dialog_extension:unit_tests", ] if (is_cfm) {
diff --git a/chrome/browser/ash/arc/fileapi/DEPS b/chrome/browser/ash/arc/fileapi/DEPS index b5b6a0b..94e958a 100644 --- a/chrome/browser/ash/arc/fileapi/DEPS +++ b/chrome/browser/ash/arc/fileapi/DEPS
@@ -32,5 +32,5 @@ # Dependencies outside of //chrome: # For ArcSelectFilesHandler. - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", ]
diff --git a/chrome/browser/ash/arc/fileapi/arc_select_files_handler.cc b/chrome/browser/ash/arc/fileapi/arc_select_files_handler.cc index 868f66f..24561ea3 100644 --- a/chrome/browser/ash/arc/fileapi/arc_select_files_handler.cc +++ b/chrome/browser/ash/arc/fileapi/arc_select_files_handler.cc
@@ -27,7 +27,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" #include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "chrome/common/chrome_isolated_world_ids.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h"
diff --git a/chrome/browser/ash/arc/fileapi/arc_select_files_handler.h b/chrome/browser/ash/arc/fileapi/arc_select_files_handler.h index a8b2338..a296164 100644 --- a/chrome/browser/ash/arc/fileapi/arc_select_files_handler.h +++ b/chrome/browser/ash/arc/fileapi/arc_select_files_handler.h
@@ -12,7 +12,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "content/public/browser/render_frame_host.h" #include "ui/shell_dialogs/select_file_dialog.h"
diff --git a/chrome/browser/ash/arc/intent_helper/BUILD.gn b/chrome/browser/ash/arc/intent_helper/BUILD.gn index 0efa95b4..e0ed2642 100644 --- a/chrome/browser/ash/arc/intent_helper/BUILD.gn +++ b/chrome/browser/ash/arc/intent_helper/BUILD.gn
@@ -18,7 +18,10 @@ "custom_tab_session_impl.h", ] - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//ash",
diff --git a/chrome/browser/ash/boca/on_task/BUILD.gn b/chrome/browser/ash/boca/on_task/BUILD.gn index 5aa76c24..718ca1f 100644 --- a/chrome/browser/ash/boca/on_task/BUILD.gn +++ b/chrome/browser/ash/boca/on_task/BUILD.gn
@@ -16,7 +16,10 @@ "on_task_system_web_app_manager_impl.h", ] - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//ash",
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn index 2344145..80c3d33 100644 --- a/chrome/browser/ash/crosapi/BUILD.gn +++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -453,6 +453,7 @@ "//chrome/browser/ui/ash/wallpaper", "//chrome/browser/ui/aura/accessibility:impl", "//chrome/browser/ui/chromeos/magic_boost", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/cloud_upload", "//chrome/browser/ui/webui/ash/kerberos", "//chrome/browser/ui/webui/ash/parent_access:mojo_bindings",
diff --git a/chrome/browser/ash/crosapi/DEPS b/chrome/browser/ash/crosapi/DEPS index 9b63f1f0..05e5c203 100644 --- a/chrome/browser/ash/crosapi/DEPS +++ b/chrome/browser/ash/crosapi/DEPS
@@ -162,7 +162,7 @@ ], "select_file_ash\.cc": [ # For Chrome OS-specific file manager parameters. - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", ], "test_controller_ash\.cc": [ # For Chrome OS-specific tab scrubbing tests.
diff --git a/chrome/browser/ash/crosapi/select_file_ash.cc b/chrome/browser/ash/crosapi/select_file_ash.cc index 9add51c..d03ec41d 100644 --- a/chrome/browser/ash/crosapi/select_file_ash.cc +++ b/chrome/browser/ash/crosapi/select_file_ash.cc
@@ -14,7 +14,7 @@ #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "chrome/browser/ash/crosapi/window_util.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "chromeos/crosapi/mojom/select_file.mojom-shared.h" #include "chromeos/crosapi/mojom/select_file.mojom.h" #include "ui/shell_dialogs/select_file_dialog.h"
diff --git a/chrome/browser/ash/dbus/vm/BUILD.gn b/chrome/browser/ash/dbus/vm/BUILD.gn index 10f499e..fc70897 100644 --- a/chrome/browser/ash/dbus/vm/BUILD.gn +++ b/chrome/browser/ash/dbus/vm/BUILD.gn
@@ -46,6 +46,7 @@ "//chrome/browser/chromeos", "//chrome/browser/chromeos/policy/dlp", "//chrome/browser/profiles:profile", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/settings/app_management", "//chrome/common", "//chrome/common:constants",
diff --git a/chrome/browser/ash/dbus/vm/DEPS b/chrome/browser/ash/dbus/vm/DEPS index bc10ec5..aea50759 100644 --- a/chrome/browser/ash/dbus/vm/DEPS +++ b/chrome/browser/ash/dbus/vm/DEPS
@@ -36,6 +36,6 @@ specific_include_rules = { "vm_applications_service_provider.cc": [ - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", ], }
diff --git a/chrome/browser/ash/dbus/vm/vm_applications_service_provider.cc b/chrome/browser/ash/dbus/vm/vm_applications_service_provider.cc index 234f0ed..b0c995e9 100644 --- a/chrome/browser/ash/dbus/vm/vm_applications_service_provider.cc +++ b/chrome/browser/ash/dbus/vm/vm_applications_service_provider.cc
@@ -31,7 +31,7 @@ #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h" #include "chromeos/ash/components/dbus/cicerone/cicerone_service.pb.h" #include "chromeos/ash/components/dbus/vm_applications/apps.pb.h"
diff --git a/chrome/browser/ash/extensions/file_manager/DEPS b/chrome/browser/ash/extensions/file_manager/DEPS index 3304515..6905392d 100644 --- a/chrome/browser/ash/extensions/file_manager/DEPS +++ b/chrome/browser/ash/extensions/file_manager/DEPS
@@ -79,6 +79,6 @@ specific_include_rules = { "private_api_dialog.cc" : [ - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", ], }
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_dialog.cc b/chrome/browser/ash/extensions/file_manager/private_api_dialog.cc index b96bec5..015cf75 100644 --- a/chrome/browser/ash/extensions/file_manager/private_api_dialog.cc +++ b/chrome/browser/ash/extensions/file_manager/private_api_dialog.cc
@@ -23,7 +23,7 @@ #include "chrome/browser/ash/file_manager/filesystem_api_util.h" #include "chrome/browser/ash/file_manager/office_file_tasks.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "chrome/common/extensions/api/file_manager_private.h" #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ash/file_manager/BUILD.gn b/chrome/browser/ash/file_manager/BUILD.gn index 3d47c5f..7328098 100644 --- a/chrome/browser/ash/file_manager/BUILD.gn +++ b/chrome/browser/ash/file_manager/BUILD.gn
@@ -464,6 +464,7 @@ "//chrome/browser/ui/ash/cast_config", "//chrome/browser/ui/ash/sharesheet", "//chrome/browser/ui/ash/system_web_apps", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/cloud_upload", "//chrome/browser/ui/webui/ash/office_fallback", "//chrome/browser/web_applications",
diff --git a/chrome/browser/ash/file_manager/DEPS b/chrome/browser/ash/file_manager/DEPS index b244769..0048f14e 100644 --- a/chrome/browser/ash/file_manager/DEPS +++ b/chrome/browser/ash/file_manager/DEPS
@@ -101,6 +101,6 @@ specific_include_rules = { "file_manager_browsertest_base.cc": [ "+chrome/browser/ui/tabs/tab_strip_model.h", - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", ], }
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc index b8ef46b..7e5430f 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -143,7 +143,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/ash/login/BUILD.gn b/chrome/browser/ash/login/BUILD.gn index c6c9fcc..c76c39bb 100644 --- a/chrome/browser/ash/login/BUILD.gn +++ b/chrome/browser/ash/login/BUILD.gn
@@ -186,6 +186,7 @@ "//chromeos/ash/components/dbus/update_engine", "//chromeos/ash/components/dbus/userdataauth", "//chromeos/ash/components/geolocation", + "//chromeos/ash/components/http_auth_dialog", "//chromeos/ash/components/install_attributes", "//chromeos/ash/components/language_packs", "//chromeos/ash/components/login/session", @@ -474,6 +475,7 @@ "//chromeos/ash/components/dbus/userdataauth", "//chromeos/ash/components/dbus/userdataauth:userdataauth_proto", "//chromeos/ash/components/geolocation", + "//chromeos/ash/components/http_auth_dialog", "//chromeos/ash/components/install_attributes:test_support", "//chromeos/ash/components/language_preferences", "//chromeos/ash/components/network:test_support",
diff --git a/chrome/browser/ash/login/DEPS b/chrome/browser/ash/login/DEPS index 4d7c35d3..640582b 100644 --- a/chrome/browser/ash/login/DEPS +++ b/chrome/browser/ash/login/DEPS
@@ -27,7 +27,6 @@ "+chrome/browser/ash/crosapi", "+chrome/browser/ash/customization", "+chrome/browser/ash/drive", - "+chrome/browser/ash/http_auth_dialog.h", "+chrome/browser/ash/input_method", "+chrome/browser/ash/multidevice_setup", "+chrome/browser/ash/net",
diff --git a/chrome/browser/ash/login/app_mode/test/BUILD.gn b/chrome/browser/ash/login/app_mode/test/BUILD.gn index 7ce23c62..ae35c68 100644 --- a/chrome/browser/ash/login/app_mode/test/BUILD.gn +++ b/chrome/browser/ash/login/app_mode/test/BUILD.gn
@@ -196,4 +196,6 @@ "//ui/views", "//url", ] + + data = [ "//chrome/test/data/" ] }
diff --git a/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc b/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc index 90a73965..a596c105 100644 --- a/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc +++ b/chrome/browser/ash/login/app_mode/test/web_kiosk_browsertest.cc
@@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstddef> +#include <memory> #include <optional> +#include <string> +#include <string_view> #include "ash/public/cpp/keyboard/keyboard_config.h" #include "ash/public/cpp/keyboard/keyboard_controller.h" @@ -13,11 +17,11 @@ #include "ash/shell.h" #include "base/auto_reset.h" #include "base/check_deref.h" -#include "base/functional/bind.h" +#include "base/files/file_path.h" #include "base/test/gtest_tags.h" #include "base/test/test_future.h" #include "base/time/time.h" -#include "chrome/browser/ash/app_mode/kiosk_app_types.h" +#include "chrome/browser/app_mode/test/fake_origin_test_server_mixin.h" #include "chrome/browser/ash/app_mode/kiosk_controller.h" #include "chrome/browser/ash/app_mode/kiosk_system_session.h" #include "chrome/browser/ash/app_mode/kiosk_test_helper.h" @@ -30,32 +34,33 @@ #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" #include "chrome/browser/ash/login/ui/login_display_host.h" #include "chrome/browser/ash/ownership/fake_owner_settings_service.h" +#include "chrome/browser/chromeos/app_mode/web_kiosk_app_installer.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/test/test_browser_closed_waiter.h" #include "chrome/browser/ui/webui/ash/login/app_launch_splash_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/error_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h" -#include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/externally_managed_app_manager.h" -#include "chrome/browser/web_applications/mojom/user_display_mode.mojom-shared.h" -#include "chrome/browser/web_applications/web_app_constants.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/pref_names.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chromeos/crosapi/mojom/web_kiosk_service.mojom-shared.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" -#include "components/webapps/browser/install_result_code.h" #include "content/public/test/browser_test.h" -#include "content/public/test/url_loader_interceptor.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/accelerators/accelerator.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_codes_posix.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/native_widget_types.h" +#include "url/gurl.h" namespace ash { @@ -70,44 +75,18 @@ const test::UIPath kNetworkConfigureScreenContinueButton = {"error-message", "continueButton"}; -Profile* LoadKioskProfile(const AccountId& account_id) { - TestFuture<LoadProfileResult> future; - auto handle = - LoadProfile(account_id, KioskAppType::kWebApp, future.GetCallback()); - return future.Take().value_or(nullptr); +Profile& CurrentProfile() { + return CHECK_DEREF(ProfileManager::GetPrimaryUserProfile()); } -// TODO(b/322497609) Replace `URLLoaderInterceptor` with `EmbeddedTestServer`. -content::URLLoaderInterceptor SimplePageInterceptor() { - return content::URLLoaderInterceptor(base::BindRepeating( - [](content::URLLoaderInterceptor::RequestParams* params) { - content::URLLoaderInterceptor::WriteResponse( - "content/test/data/simple_page.html", params->client.get()); - return true; - })); -} - -bool InstallKioskWebAppInProvider(Profile& profile, const GURL& install_url) { - // Serve a real page to avoid installing a placeholder app. - auto url_interceptor = SimplePageInterceptor(); - - TestFuture<bool> success_future; - - auto* provider = web_app::WebAppProvider::GetForLocalAppsUnchecked(&profile); - - web_app::ExternalInstallOptions install_options( - install_url, web_app::mojom::UserDisplayMode::kStandalone, - web_app::ExternalInstallSource::kKiosk); - install_options.install_placeholder = true; - - provider->externally_managed_app_manager().InstallNow( - install_options, - base::BindOnce([](const GURL& install_url, - web_app::ExternallyManagedAppManager::InstallResult - result) { - return webapps::IsSuccess(result.code); - }).Then(success_future.GetCallback())); - return success_future.Wait(); +bool IsWebAppInstalled(Profile& profile, const GURL& install_url) { + auto installer = chromeos::WebKioskAppInstaller(profile, install_url); + TestFuture<crosapi::mojom::WebKioskInstallState, + const std::optional<std::string>&> + future; + installer.GetInstallState(future.GetCallback()); + auto [state, __] = future.Take(); + return crosapi::mojom::WebKioskInstallState::kInstalled == state; } Browser::CreateParams CreateNewBrowserParams(Browser* initial_kiosk_browser, @@ -130,6 +109,18 @@ return new_browser; } +// Disables the Gaia screen offline message. Leaving this enable may interfere +// with checks done in offline Kiosk launch tests, since it influences the +// screens `WizardController` shows. +void DisableGaiaOfflineScreen() { + LoginDisplayHost::default_host() + ->GetOobeUI() + ->GetHandler<GaiaScreenHandler>() + ->set_offline_timeout_for_testing(base::TimeDelta::Max()); +} + +} // namespace + class WebKioskTest : public WebKioskBaseTest { public: WebKioskTest() = default; @@ -137,20 +128,15 @@ WebKioskTest(const WebKioskTest&) = delete; WebKioskTest& operator=(const WebKioskTest&) = delete; - void EnsureAppIsInstalled() { - Profile* profile = LoadKioskProfile(account_id()); - ASSERT_NE(profile, nullptr); - ASSERT_TRUE(InstallKioskWebAppInProvider(*profile, app_install_url())) - << "App was not installed"; - Shell::Get()->session_controller()->RequestSignOut(); + void SetUpOnMainThread() override { + WebKioskBaseTest::SetUpOnMainThread(); + SetAppInstallUrl(server_mixin_.GetUrl("/title3.html")); } void SetBlockAppLaunch(bool block) { - if (block) { - block_app_launch_override_ = KioskTestHelper::BlockAppLaunch(); - } else { - block_app_launch_override_.reset(); - } + block_app_launch_override_ = + block ? std::make_optional(KioskTestHelper::BlockAppLaunch()) + : std::nullopt; } void WaitNetworkConfigureScreenAndContinueWithOnlineState( @@ -177,30 +163,19 @@ } } - void ExpectKeyboardConfig() { - const keyboard::KeyboardConfig config = - KeyboardController::Get()->GetKeyboardConfig(); - - // `auto_capitalize` is not controlled by the policy - // 'VirtualKeyboardFeatures', and its default value remains true. - EXPECT_TRUE(config.auto_capitalize); - - // The other features are controlled by the policy - // 'VirtualKeyboardFeatures', and their default values should be false. - EXPECT_FALSE(config.auto_complete); - EXPECT_FALSE(config.auto_correct); - EXPECT_FALSE(config.handwriting); - EXPECT_FALSE(config.spell_check); - EXPECT_FALSE(config.voice_input); - } - private: std::optional<base::AutoReset<bool>> block_app_launch_override_; + + FakeOriginTestServerMixin server_mixin_{ + &mixin_host_, + /*origin=*/GURL("https://app.foo.com/"), + /*path_to_be_served=*/FILE_PATH_LITERAL("chrome/test/data")}; }; // Runs the kiosk app when the network is always present. IN_PROC_BROWSER_TEST_F(WebKioskTest, RegularFlowOnline) { InitializeRegularOnlineKiosk(); + ASSERT_TRUE(IsWebAppInstalled(CurrentProfile(), app_install_url())); } // Runs the kiosk app when the network is not present in the beginning, but @@ -211,6 +186,7 @@ LaunchApp(); SetOnline(true); KioskSessionInitializedWaiter().Wait(); + ASSERT_TRUE(IsWebAppInstalled(CurrentProfile(), app_install_url())); } // Runs the kiosk app without a network connection, waits till network wait @@ -225,12 +201,13 @@ /*require_network*/ true, /*auto_close*/ true); KioskSessionInitializedWaiter().Wait(); + ASSERT_TRUE(IsWebAppInstalled(CurrentProfile(), app_install_url())); } // Presses a network configure dialog accelerator during app launch which will // interrupt the startup. We expect this dialog not to require network since the -// app have not yet been installed. -IN_PROC_BROWSER_TEST_F(WebKioskTest, LaunchWithConfigureAcceleratorPressed) { +// app has not yet been installed. +IN_PROC_BROWSER_TEST_F(WebKioskTest, NetworkShortcutWorks) { SetOnline(true); PrepareAppLaunch(); LaunchApp(); @@ -247,26 +224,14 @@ KioskSessionInitializedWaiter().Wait(); } -// App Service launcher requires installing web apps to Kiosk profile before -// launching offline. -IN_PROC_BROWSER_TEST_F(WebKioskTest, - PRE_AlreadyInstalledWithConfigureAcceleratorPressed) { - PrepareAppLaunch(); - EnsureAppIsInstalled(); +IN_PROC_BROWSER_TEST_F(WebKioskTest, PRE_NetworkShortcutWorksOffline) { + InitializeRegularOnlineKiosk(); + ASSERT_TRUE(IsWebAppInstalled(CurrentProfile(), app_install_url())); } -// In case when the app was already installed, we should expect to be able to -// configure network without need to be online. -IN_PROC_BROWSER_TEST_F(WebKioskTest, - AlreadyInstalledWithConfigureAcceleratorPressed) { +IN_PROC_BROWSER_TEST_F(WebKioskTest, NetworkShortcutWorksOffline) { SetOnline(false); - // Set the threshold to a max value to disable the offline message screen, - // otherwise it would interfere with app launch. This is needed as this is - // happening on the GaiaScreen in terms of screens of WizardController. - LoginDisplayHost::default_host() - ->GetOobeUI() - ->GetHandler<GaiaScreenHandler>() - ->set_offline_timeout_for_testing(base::TimeDelta::Max()); + DisableGaiaOfflineScreen(); PrepareAppLaunch(); LaunchApp(); @@ -309,7 +274,21 @@ IN_PROC_BROWSER_TEST_F(WebKioskTest, KeyboardConfigPolicy) { InitializeRegularOnlineKiosk(); - ExpectKeyboardConfig(); + + const keyboard::KeyboardConfig config = + KeyboardController::Get()->GetKeyboardConfig(); + + // `auto_capitalize` is not controlled by the policy + // 'VirtualKeyboardFeatures', and its default value remains true. + EXPECT_TRUE(config.auto_capitalize); + + // The other features are controlled by the policy + // 'VirtualKeyboardFeatures', and their default values should be false. + EXPECT_FALSE(config.auto_complete); + EXPECT_FALSE(config.auto_correct); + EXPECT_FALSE(config.handwriting); + EXPECT_FALSE(config.spell_check); + EXPECT_FALSE(config.voice_input); } IN_PROC_BROWSER_TEST_F(WebKioskTest, OpenA11ySettings) { @@ -454,8 +433,8 @@ void SetUpInProcessBrowserTestFixture() override { WebKioskTest::SetUpInProcessBrowserTestFixture(); provider_.SetDefaultReturns( - true /* is_initialization_complete_return */, - true /* is_first_policy_load_complete_return */); + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); @@ -475,8 +454,8 @@ IN_PROC_BROWSER_TEST_P(WebKioskOfflineEnabledTest, PRE_AlreadyInstalledOffline) { - PrepareAppLaunch(); - EnsureAppIsInstalled(); + InitializeRegularOnlineKiosk(); + ASSERT_TRUE(IsWebAppInstalled(CurrentProfile(), app_install_url())); } IN_PROC_BROWSER_TEST_P(WebKioskOfflineEnabledTest, AlreadyInstalledOffline) { @@ -496,6 +475,4 @@ INSTANTIATE_TEST_SUITE_P(All, WebKioskOfflineEnabledTest, ::testing::Bool()); -} // namespace - } // namespace ash
diff --git a/chrome/browser/ash/login/existing_user_controller.h b/chrome/browser/ash/login/existing_user_controller.h index 27b84f2..01d2f27 100644 --- a/chrome/browser/ash/login/existing_user_controller.h +++ b/chrome/browser/ash/login/existing_user_controller.h
@@ -18,11 +18,11 @@ #include "base/scoped_observation.h" #include "base/timer/timer.h" #include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/saml/password_sync_token_checkers_collection.h" #include "chrome/browser/ash/login/screens/encryption_migration_mode.h" #include "chrome/browser/ash/login/session/user_session_manager.h" #include "chrome/browser/ash/login/signin_specifics.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/login/auth/login_performer.h" #include "chromeos/ash/components/login/auth/public/auth_failure.h" #include "chromeos/ash/components/login/auth/public/user_context.h"
diff --git a/chrome/browser/ash/login/proxy_auth_dialog_browsertest.cc b/chrome/browser/ash/login/proxy_auth_dialog_browsertest.cc index afb868561..b6c51e2 100644 --- a/chrome/browser/ash/login/proxy_auth_dialog_browsertest.cc +++ b/chrome/browser/ash/login/proxy_auth_dialog_browsertest.cc
@@ -6,7 +6,6 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/test/run_until.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/login_manager_test.h" #include "chrome/browser/ash/login/test/js_checker.h" #include "chrome/browser/ash/login/test/login_manager_mixin.h" @@ -14,6 +13,7 @@ #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/user_creation_screen_handler.h" #include "chrome/common/chrome_switches.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/ash/login/saml/BUILD.gn b/chrome/browser/ash/login/saml/BUILD.gn index c14e3649..e3a5b96e 100644 --- a/chrome/browser/ash/login/saml/BUILD.gn +++ b/chrome/browser/ash/login/saml/BUILD.gn
@@ -185,6 +185,7 @@ "//chromeos/ash/components/dbus/shill", "//chromeos/ash/components/dbus/userdataauth", "//chromeos/ash/components/dbus/userdataauth:userdataauth_proto", + "//chromeos/ash/components/http_auth_dialog", "//chromeos/ash/components/install_attributes:test_support", "//chromeos/ash/components/login/auth/public:authpublic", "//chromeos/ash/components/network",
diff --git a/chrome/browser/ash/login/saml/DEPS b/chrome/browser/ash/login/saml/DEPS index 9e069f3..e34b500 100644 --- a/chrome/browser/ash/login/saml/DEPS +++ b/chrome/browser/ash/login/saml/DEPS
@@ -15,7 +15,6 @@ # individually. Other dependencies within //chrome are listed on a per- # directory basis. See //tools/chromeos/gen_deps.sh for details. "+chrome/browser/ash/attestation", - "+chrome/browser/ash/http_auth_dialog.h", "+chrome/browser/ash/login", "+chrome/browser/ash/net", "+chrome/browser/ash/policy/affiliation",
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc index aac2f51..2f9a57cc 100644 --- a/chrome/browser/ash/login/saml/saml_browsertest.cc +++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -32,7 +32,6 @@ #include "build/buildflag.h" #include "chrome/browser/ash/attestation/mock_machine_certificate_uploader.h" #include "chrome/browser/ash/attestation/tpm_challenge_key.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/enrollment/enrollment_screen_view.h" #include "chrome/browser/ash/login/lock/screen_locker_tester.h" #include "chrome/browser/ash/login/saml/fake_saml_idp_mixin.h" @@ -84,6 +83,7 @@ #include "chromeos/ash/components/dbus/shill/shill_manager_client.h" #include "chromeos/ash/components/dbus/userdataauth/fake_cryptohome_misc_client.h" #include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/install_attributes/stub_install_attributes.h" #include "chromeos/ash/components/login/auth/public/key.h" #include "chromeos/ash/components/login/auth/public/saml_password_attributes.h"
diff --git a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc index 606a673..c77c835 100644 --- a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc +++ b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
@@ -21,7 +21,6 @@ #include "base/test/bind.h" #include "base/test/run_until.h" #include "build/build_config.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/lock/online_reauth/lock_screen_reauth_manager.h" #include "chrome/browser/ash/login/lock/online_reauth/lock_screen_reauth_manager_factory.h" #include "chrome/browser/ash/login/lock/screen_locker_tester.h" @@ -44,6 +43,7 @@ #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h" #include "chromeos/ash/components/dbus/shill/fake_shill_manager_client.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/network/network_connection_handler.h" #include "chromeos/ash/components/network/network_handler.h" #include "chromeos/ash/components/network/network_handler_test_helper.h"
diff --git a/chrome/browser/ash/login/ui/BUILD.gn b/chrome/browser/ash/login/ui/BUILD.gn index f853b19..7bb119b 100644 --- a/chrome/browser/ash/login/ui/BUILD.gn +++ b/chrome/browser/ash/login/ui/BUILD.gn
@@ -113,6 +113,7 @@ "//chrome/browser/profiles:profile", "//chrome/browser/safe_browsing", "//chrome/browser/themes", + "//chrome/browser/ui/content_settings", "//chrome/browser/ui/views/toolbar", "//chrome/browser/ui/webui/ash/diagnostics_dialog", "//chrome/browser/ui/webui/ash/internet",
diff --git a/chrome/browser/ash/login/webview_login_browsertest.cc b/chrome/browser/ash/login/webview_login_browsertest.cc index 2f07b66..6a1fc96 100644 --- a/chrome/browser/ash/login/webview_login_browsertest.cc +++ b/chrome/browser/ash/login/webview_login_browsertest.cc
@@ -33,7 +33,6 @@ #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/values.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/helper.h" #include "chrome/browser/ash/login/lock/screen_locker_tester.h" #include "chrome/browser/ash/login/login_pref_names.h" @@ -81,6 +80,7 @@ #include "chrome/test/base/fake_gaia_mixin.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/login/auth/public/user_context.h" #include "chromeos/ash/components/network/network_state_test_helper.h" #include "chromeos/ash/components/osauth/public/auth_session_storage.h"
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc index 25d4629..391d08f 100644 --- a/chrome/browser/ash/login/wizard_controller_browsertest.cc +++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -28,7 +28,6 @@ #include "build/build_config.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/base/locale_util.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/demo_mode/demo_mode_test_utils.h" #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/ash/login/enrollment/enrollment_screen.h" @@ -112,6 +111,7 @@ #include "chromeos/ash/components/dbus/shill/fake_shill_manager_client.h" #include "chromeos/ash/components/dbus/system_clock/system_clock_client.h" #include "chromeos/ash/components/geolocation/simple_geolocation_provider.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/install_attributes/stub_install_attributes.h" #include "chromeos/ash/components/network/network_state.h" #include "chromeos/ash/components/network/network_state_handler.h"
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_fetch_support_packet_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_fetch_support_packet_job.cc index 5d90750..70edc77 100644 --- a/chrome/browser/ash/policy/remote_commands/device_command_fetch_support_packet_job.cc +++ b/chrome/browser/ash/policy/remote_commands/device_command_fetch_support_packet_job.cc
@@ -350,13 +350,13 @@ .GetSigninBrowserContext()) : ProfileManager::GetActiveUserProfile(); // Initialize SupportToolHandler with the requested details. - support_tool_handler_ = - GetSupportToolHandler(support_packet_details_.issue_case_id, - // Leave the email address empty since data - // collection is triggered by the admin remotely. - /*email_address=*/std::string(), - support_packet_details_.issue_description, profile, - support_packet_details_.requested_data_collectors); + support_tool_handler_ = GetSupportToolHandler( + support_packet_details_.issue_case_id, + // Leave the email address empty since data + // collection is triggered by the admin remotely. + /*email_address=*/std::string(), + support_packet_details_.issue_description, std::nullopt, profile, + support_packet_details_.requested_data_collectors); // Start data collection. support_tool_handler_->CollectSupportData(
diff --git a/chrome/browser/browser_features.cc b/chrome/browser/browser_features.cc index d6c8894..33462837 100644 --- a/chrome/browser/browser_features.cc +++ b/chrome/browser/browser_features.cc
@@ -110,6 +110,12 @@ &kDevToolsFreestylerDogfood, "aida_model_id", /*default_value=*/""}; const base::FeatureParam<double> kDevToolsFreestylerDogfoodTemperature{ &kDevToolsFreestylerDogfood, "aida_temperature", /*default_value=*/0}; +const base::FeatureParam<DevToolsFreestylerUserTier>::Option devtools_freestyler_user_tier_options[] = { + {DevToolsFreestylerUserTier::kTesters, "TESTERS"}, + {DevToolsFreestylerUserTier::kPublic, "PUBLIC"}}; +const base::FeatureParam<DevToolsFreestylerUserTier> kDevToolsFreestylerDogfoodUserTier{ + &kDevToolsFreestylerDogfood, "user_tier", /*default_value=*/DevToolsFreestylerUserTier::kTesters, + &devtools_freestyler_user_tier_options}; // Whether the DevTools resource explainer assistant is enabled. BASE_FEATURE(kDevToolsExplainThisResourceDogfood,
diff --git a/chrome/browser/browser_features.h b/chrome/browser/browser_features.h index d488d61..c58e314 100644 --- a/chrome/browser/browser_features.h +++ b/chrome/browser/browser_features.h
@@ -41,6 +41,16 @@ extern const base::FeatureParam<std::string> kDevToolsFreestylerDogfoodModelId; extern const base::FeatureParam<double> kDevToolsFreestylerDogfoodTemperature; +enum class DevToolsFreestylerUserTier { + // Users who are internal testers or validators. + // In future, the data from these users will be excluded from training data when logging is enabled. + kTesters, + // Users in the general public. + kPublic +}; + +extern const base::FeatureParam<DevToolsFreestylerUserTier> kDevToolsFreestylerDogfoodUserTier; + BASE_DECLARE_FEATURE(kDevToolsExplainThisResourceDogfood); extern const base::FeatureParam<std::string> kDevToolsExplainThisResourceDogfoodModelId;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 637fdb3..474bbfca 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -461,7 +461,6 @@ #include "chrome/browser/ash/fileapi/external_file_url_loader_factory.h" #include "chrome/browser/ash/fileapi/file_system_backend.h" #include "chrome/browser/ash/fileapi/mtp_file_system_backend_delegate.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/signin/merge_session_navigation_throttle.h" #include "chrome/browser/ash/login/signin/merge_session_throttling_utils.h" #include "chrome/browser/ash/login/signin_partition_manager.h" @@ -481,6 +480,7 @@ #include "chrome/browser/ui/webui/ash/kerberos/kerberos_in_browser_dialog.h" #include "chrome/common/webui_url_constants.h" #include "chromeos/ash/components/browser_context_helper/browser_context_types.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/settings/cros_settings.h" #include "chromeos/ash/services/network_health/public/cpp/network_health_helper.h" #include "components/user_manager/user.h"
diff --git a/chrome/browser/chromeos/policy/dlp/BUILD.gn b/chrome/browser/chromeos/policy/dlp/BUILD.gn index 1dfa87d..ced83a4 100644 --- a/chrome/browser/chromeos/policy/dlp/BUILD.gn +++ b/chrome/browser/chromeos/policy/dlp/BUILD.gn
@@ -70,7 +70,10 @@ ] } - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//base",
diff --git a/chrome/browser/chromeos/tablet_mode/BUILD.gn b/chrome/browser/chromeos/tablet_mode/BUILD.gn index 8dcb7cc..9c33473 100644 --- a/chrome/browser/chromeos/tablet_mode/BUILD.gn +++ b/chrome/browser/chromeos/tablet_mode/BUILD.gn
@@ -17,7 +17,10 @@ "tablet_mode_page_behavior.h", ] - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//base",
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn index 70f09dfa..4d0feef9 100644 --- a/chrome/browser/devtools/BUILD.gn +++ b/chrome/browser/devtools/BUILD.gn
@@ -138,6 +138,7 @@ ] if (!is_android) { + public_deps += [ "//chrome/browser/ui/tabs:tab_strip_model_observer" ] deps += [ "//build:chromeos_buildflags", "//chrome:extra_resources",
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 570f39f..92d118a 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1560,6 +1560,9 @@ "modelId", features::kDevToolsFreestylerDogfoodModelId.Get()); freestyler_dogfood_dict.Set( "temperature", features::kDevToolsFreestylerDogfoodTemperature.Get()); + freestyler_dogfood_dict.Set( + "userTier", features::kDevToolsFreestylerDogfoodUserTier.GetName( + features::kDevToolsFreestylerDogfoodUserTier.Get())); response_dict.Set("devToolsFreestylerDogfood", std::move(freestyler_dogfood_dict));
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 2f858a0..63b176da 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -754,6 +754,7 @@ "//chrome/browser/media/webrtc", "//chrome/browser/resource_coordinator:tab_lifecycle_observer", "//chrome/browser/task_manager", + "//chrome/browser/ui/tabs:tab_strip_model_observer", "//chrome/common", "//chrome/common/extensions/api", "//components/omnibox/browser",
diff --git a/chrome/browser/media/webrtc/BUILD.gn b/chrome/browser/media/webrtc/BUILD.gn index 293042a..fc2cad6 100644 --- a/chrome/browser/media/webrtc/BUILD.gn +++ b/chrome/browser/media/webrtc/BUILD.gn
@@ -189,7 +189,10 @@ "tab_desktop_media_list.cc", "tab_desktop_media_list.h", ] - public_deps += [ "//extensions/buildflags" ] + public_deps += [ + "//chrome/browser/ui/tabs:tab_strip_model_observer", + "//extensions/buildflags", + ] deps += [ "//extensions/browser", "//extensions/browser/kiosk",
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc index ddddc1f..52857ee 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -348,27 +348,58 @@ MetricSize::kTiny, "brp_quarantined_count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - {"malloc/extreme_lud", "Malloc.ExtremeLUD.Count", MetricSize::kTiny, - "count", EmitTo::kSizeInUmaOnly, nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.SizeInBytes", MetricSize::kSmall, + {"malloc/extreme_lud/large_objects", "Malloc.ExtremeLUD.LargeObjects.Count", + MetricSize::kTiny, "count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.SizeInBytes", MetricSize::kSmall, "size_in_bytes", EmitTo::kSizeInUmaOnly, nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.CumulativeCount", - MetricSize::kSmall, "cumulative_count", EmitTo::kSizeInUmaOnly, nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.CumulativeSizeInBytes", - MetricSize::kLarge, "cumulative_size_in_bytes", EmitTo::kSizeInUmaOnly, - nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.QuarantineMissCount", - MetricSize::kTiny, "quarantine_miss_count", EmitTo::kSizeInUmaOnly, - nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.BytesPerMinute", - MetricSize::kSmall, "bytes_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.CountPerMinute", - MetricSize::kTiny, "count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.MissCountPerMinute", - MetricSize::kTiny, "miss_count_per_minute", EmitTo::kSizeInUmaOnly, - nullptr}, - {"malloc/extreme_lud", "Malloc.ExtremeLUD.QuarantinedTime", - MetricSize::kSmall, "quarantined_time", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.CumulativeCount", MetricSize::kSmall, + "cumulative_count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.CumulativeSizeInBytes", MetricSize::kLarge, + "cumulative_size_in_bytes", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.QuarantineMissCount", MetricSize::kTiny, + "quarantine_miss_count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.BytesPerMinute", MetricSize::kSmall, + "bytes_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.CountPerMinute", MetricSize::kTiny, + "count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.MissCountPerMinute", MetricSize::kTiny, + "miss_count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/large_objects", + "Malloc.ExtremeLUD.LargeObjects.QuarantinedTime", MetricSize::kSmall, + "quarantined_time", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", "Malloc.ExtremeLUD.SmallObjects.Count", + MetricSize::kTiny, "count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.SizeInBytes", MetricSize::kSmall, + "size_in_bytes", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.CumulativeCount", MetricSize::kSmall, + "cumulative_count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.CumulativeSizeInBytes", MetricSize::kLarge, + "cumulative_size_in_bytes", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.QuarantineMissCount", MetricSize::kTiny, + "quarantine_miss_count", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.BytesPerMinute", MetricSize::kSmall, + "bytes_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.CountPerMinute", MetricSize::kTiny, + "count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.MissCountPerMinute", MetricSize::kTiny, + "miss_count_per_minute", EmitTo::kSizeInUmaOnly, nullptr}, + {"malloc/extreme_lud/small_objects", + "Malloc.ExtremeLUD.SmallObjects.QuarantinedTime", MetricSize::kSmall, + "quarantined_time", EmitTo::kSizeInUmaOnly, nullptr}, {"malloc/partitions/allocator/scheduler_loop_quarantine", "Malloc.SchedulerLoopQuarantine.Count", MetricSize::kTiny, "count", EmitTo::kSizeInUmaOnly, nullptr},
diff --git a/chrome/browser/page_load_metrics/observers/abandoned_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/abandoned_page_load_metrics_observer_browsertest.cc index f6f3cf27a..db263f6 100644 --- a/chrome/browser/page_load_metrics/observers/abandoned_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/abandoned_page_load_metrics_observer_browsertest.cc
@@ -385,10 +385,8 @@ AbandonReason::kExplicitCancellation, 1); // Check that the abandonment time from navigation start is recorded. - EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix( - GetTimeToAbandonFromNavigationStart(milestone)), - testing::ElementsAre(testing::Pair( - GetTimeToAbandonFromNavigationStart(milestone), 1))); + histogram_tester.ExpectTotalCount( + GetTimeToAbandonFromNavigationStart(milestone), 1); } else { EXPECT_TRUE(histogram_tester .GetTotalCountsForPrefix(
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn index 9b9786f0..fb0b783 100644 --- a/chrome/browser/password_manager/android/BUILD.gn +++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -601,6 +601,7 @@ "//chrome/browser", "//chrome/browser/autofill", "//chrome/browser/keyboard_accessory/test_utils/android", + "//chrome/browser/password_manager/android/access_loss:test_support", "//chrome/browser/password_manager/android/add_username_dialog:android", "//chrome/browser/sync", "//chrome/browser/touch_to_fill/password_manager/password_generation/android:public",
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java index a6ea631..de6fc05 100644 --- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java +++ b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java
@@ -67,7 +67,7 @@ @Rule public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(2) + .setRevision(3) .setBugComponent(Component.UI_BROWSER_PASSWORDS) .build();
diff --git a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetRenderTest.java b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetRenderTest.java index 6ff1b59..d780744d 100644 --- a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetRenderTest.java +++ b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetRenderTest.java
@@ -67,7 +67,7 @@ @Rule public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(0) + .setRevision(1) .setBugComponent(Component.UI_BROWSER_PASSWORDS) .build();
diff --git a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java index cb0d5862..9ad872de 100644 --- a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java +++ b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java
@@ -112,6 +112,11 @@ } @Override + public float getFullHeightRatio() { + return HeightMode.WRAP_CONTENT; + } + + @Override public int getPeekHeight() { return HeightMode.DISABLED; }
diff --git a/chrome/browser/password_manager/android/java/res/layout/password_access_loss_export_dialog_view.xml b/chrome/browser/password_manager/android/java/res/layout/password_access_loss_export_dialog_view.xml index 8c4f4b7..11ac17db 100644 --- a/chrome/browser/password_manager/android/java/res/layout/password_access_loss_export_dialog_view.xml +++ b/chrome/browser/password_manager/android/java/res/layout/password_access_loss_export_dialog_view.xml
@@ -20,7 +20,6 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:ellipsize="end" - android:text="@string/access_loss_export_dialog_title" android:textAppearance="@style/TextAppearance.AlertDialogTitleStyle" /> <TextView android:id="@+id/message"
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogBinder.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogBinder.java index cc58038..2e2c9842 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogBinder.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogBinder.java
@@ -6,8 +6,10 @@ import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.CLOSE_BUTTON_CALLBACK; import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.EXPORT_AND_DELETE_BUTTON_CALLBACK; +import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.TITLE; import android.view.View; +import android.widget.TextView; import org.chromium.chrome.browser.password_manager.R; import org.chromium.ui.modelutil.PropertyKey; @@ -21,7 +23,9 @@ private PasswordAccessLossExportDialogBinder() {} static void bind(PropertyModel model, View dialogView, PropertyKey propertyKey) { - if (propertyKey == EXPORT_AND_DELETE_BUTTON_CALLBACK) { + if (propertyKey == TITLE) { + ((TextView) dialogView.findViewById(R.id.title)).setText(model.get(TITLE)); + } else if (propertyKey == EXPORT_AND_DELETE_BUTTON_CALLBACK) { dialogView .findViewById(R.id.positive_button) .setOnClickListener(v -> model.get(EXPORT_AND_DELETE_BUTTON_CALLBACK).run());
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinator.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinator.java index 67a389d..9ab09d7 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinator.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinator.java
@@ -6,6 +6,7 @@ import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.CLOSE_BUTTON_CALLBACK; import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.EXPORT_AND_DELETE_BUTTON_CALLBACK; +import static org.chromium.chrome.browser.password_manager.settings.PasswordAccessLossExportDialogProperties.TITLE; import android.view.LayoutInflater; import android.view.View; @@ -61,6 +62,7 @@ private void bindDialogView(View dialogView) { PropertyModel model = new PropertyModel.Builder(PasswordAccessLossExportDialogProperties.ALL_KEYS) + .with(TITLE, mMediator.getDialogTitle()) .with( EXPORT_AND_DELETE_BUTTON_CALLBACK, mMediator::handlePositiveButtonClicked)
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinatorTest.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinatorTest.java index cbcc3a6..0ddfab7 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinatorTest.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogCoordinatorTest.java
@@ -26,7 +26,6 @@ import androidx.fragment.app.FragmentActivity; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -72,6 +71,9 @@ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) @Batch(Batch.PER_CLASS) +@EnableFeatures( + ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PASSWORDS_ANDROID_ACCESS_LOSS_WARNING) +@DisableFeatures(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PWD_MIGRATION_WARNING) public class PasswordAccessLossExportDialogCoordinatorTest { private static final Uri TEMP_EXPORT_FILE_URI = Uri.parse("tmp/fake/test/path/file.ext"); private static final Uri SAVED_EXPORT_FILE_URI = Uri.parse("fake/test/path/file.ext"); @@ -92,13 +94,13 @@ @Mock private PasswordAccessLossExportDialogCoordinator.Observer mPasswordsDeletionFinished; private FakePasswordManagerHandler mPasswordManagerHandler; - @Before - public void setUp() { + public void setUp(@PasswordAccessLossWarningType int type) { mJniMocker.mock(PasswordStoreBridgeJni.TEST_HOOKS, mPasswordStoreBridgeJniMock); mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJniMock); mJniMocker.mock(PasswordManagerUtilBridgeJni.TEST_HOOKS, mPasswordManagerUtilBridgeJniMock); when(mProfileProvider.getOriginalProfile()).thenReturn(mProfile); when(mProfile.getOriginalProfile()).thenReturn(mProfile); + setUpAccessLossWarningType(type); mActivity = Robolectric.buildActivity(BrowserUiDummyFragmentActivity.class) @@ -159,7 +161,8 @@ } @Test - public void testExportDialogStrings() { + public void testExportDialogStringsForNewGmsCoreAndMigrationFailed() { + setUp(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED); mCoordinator.showExportDialog(); mActivity.getSupportFragmentManager().executePendingTransactions(); @@ -180,16 +183,35 @@ } @Test - @EnableFeatures( - ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PASSWORDS_ANDROID_ACCESS_LOSS_WARNING) - @DisableFeatures(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PWD_MIGRATION_WARNING) + public void testExportDialogStringsForNoGmsCore() { + setUp(PasswordAccessLossWarningType.NO_GMS_CORE); + mCoordinator.showExportDialog(); + mActivity.getSupportFragmentManager().executePendingTransactions(); + + Resources resources = RuntimeEnvironment.getApplication().getResources(); + Dialog dialog = ShadowDialog.getLatestDialog(); + assertEquals( + resources.getString(R.string.access_loss_export_dialog_title_no_gms), + ((TextView) dialog.findViewById(R.id.title)).getText()); + assertEquals( + resources.getString(R.string.access_loss_export_dialog_message), + ((TextView) dialog.findViewById(R.id.message)).getText()); + assertEquals( + resources.getString(R.string.access_loss_export_dialog_positive_button_text), + ((Button) dialog.findViewById(R.id.positive_button)).getText()); + assertEquals( + resources.getString(R.string.cancel), + ((Button) dialog.findViewById(R.id.negative_button)).getText()); + } + + @Test public void testExportFlow() throws IOException { + setUp(PasswordAccessLossWarningType.NO_GMS_CORE); mCoordinator.showExportDialog(); setUpPasswordManagerHandler(); setUpPasswordStoreBridge(); setUpReauthenticationManager(); setUpContentResolver(); - setUpAccessLossWarningType(PasswordAccessLossWarningType.NO_GMS_CORE); mActivity.getSupportFragmentManager().executePendingTransactions(); Dialog dialog = ShadowDialog.getLatestDialog(); @@ -233,10 +255,8 @@ } @Test - @EnableFeatures( - ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PASSWORDS_ANDROID_ACCESS_LOSS_WARNING) - @DisableFeatures(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PWD_MIGRATION_WARNING) public void testDialogIsDismissedWhenExportFails() { + setUp(PasswordAccessLossWarningType.NO_GMS_CORE); mCoordinator.showExportDialog(); setUpPasswordManagerHandler(); setUpReauthenticationManager(); @@ -263,13 +283,10 @@ } @Test - @EnableFeatures( - ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PASSWORDS_ANDROID_ACCESS_LOSS_WARNING) - @DisableFeatures(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PWD_MIGRATION_WARNING) public void testPasswordsAreNotDeletedIfUseUpmLocalAndSeparateStoresIsOn() { // This test checks the edge case, when the export dialog was displayed, but the migration // succeeded in while it was showing. - setUpAccessLossWarningType(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED); + setUp(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED); when(mPrefService.getInteger(Pref.PASSWORDS_USE_UPM_LOCAL_AND_SEPARATE_STORES)) .thenReturn(/* UseUpmLocalAndSeparateStoresState::kOn */ 2); // Notification that the export flow succeeded should trigger passwords deletion. @@ -282,10 +299,8 @@ } @Test - @EnableFeatures( - ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PASSWORDS_ANDROID_ACCESS_LOSS_WARNING) - @DisableFeatures(ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_LOCAL_PWD_MIGRATION_WARNING) public void testExportDialogNegativeButtonClick() { + setUp(PasswordAccessLossWarningType.NO_GMS_CORE); mCoordinator.showExportDialog(); mActivity.getSupportFragmentManager().executePendingTransactions();
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogMediator.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogMediator.java index 9444bb8..d0ca975 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogMediator.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogMediator.java
@@ -59,6 +59,15 @@ mExportDialogObserver = exportDialogObserver; } + public String getDialogTitle() { + PrefService prefService = UserPrefs.get(mProfile); + if (PasswordManagerHelper.getAccessLossWarningType(prefService) + == PasswordAccessLossWarningType.NO_GMS_CORE) { + return mActivity.getString(R.string.access_loss_export_dialog_title_no_gms); + } + return mActivity.getString(R.string.access_loss_export_dialog_title); + } + public void handlePositiveButtonClicked() { PasswordManagerHandlerProvider.getForProfile(mProfile).addObserver(this); mExportFlow = new ExportFlow();
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogProperties.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogProperties.java index 06ee847..844757eb 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogProperties.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossExportDialogProperties.java
@@ -12,6 +12,9 @@ class PasswordAccessLossExportDialogProperties { private PasswordAccessLossExportDialogProperties() {} + static final PropertyModel.ReadableObjectPropertyKey<String> TITLE = + new ReadableObjectPropertyKey<>("dialog title"); + static final PropertyModel.ReadableObjectPropertyKey<Runnable> EXPORT_AND_DELETE_BUTTON_CALLBACK = new ReadableObjectPropertyKey<>("export and delete button callback"); @@ -19,6 +22,6 @@ new ReadableObjectPropertyKey<>("close button callback"); static final PropertyKey[] ALL_KEYS = { - EXPORT_AND_DELETE_BUTTON_CALLBACK, CLOSE_BUTTON_CALLBACK + TITLE, EXPORT_AND_DELETE_BUTTON_CALLBACK, CLOSE_BUTTON_CALLBACK }; }
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc index 6a30ce6..7ef6b50 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/password_manager/android/save_update_password_message_delegate.h" +#include <memory> #include <optional> #include <utility> @@ -17,6 +18,7 @@ #include "chrome/browser/android/android_theme_resources.h" #include "chrome/browser/android/resource_mapper.h" #include "chrome/browser/flags/android/chrome_feature_list.h" +#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h" #include "chrome/browser/password_manager/android/password_infobar_utils.h" #include "chrome/browser/password_manager/android/password_manager_android_util.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" @@ -27,6 +29,7 @@ #include "chrome/grit/branded_strings.h" #include "chrome/grit/generated_resources.h" #include "components/messages/android/message_dispatcher_bridge.h" +#include "components/password_manager/core/browser/features/password_features.h" #include "components/password_manager/core/browser/password_form.h" #include "components/password_manager/core/browser/password_form_metrics_recorder.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" @@ -70,6 +73,21 @@ } } +void TryToShowAccessLossWarning(content::WebContents* web_contents, + PasswordAccessLossWarningBridge* bridge) { + if (base::FeatureList::IsEnabled( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning)) { + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + PrefService* prefs = profile->GetPrefs(); + if (profile && bridge->ShouldShowAccessLossNoticeSheet(prefs)) { + bridge->MaybeShowAccessLossNoticeSheet( + prefs, web_contents->GetTopLevelNativeWindow(), profile); + } + } +} + } // namespace SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate() @@ -87,7 +105,9 @@ : password_edit_dialog_factory_(std::move(password_edit_dialog_factory)), create_migration_warning_callback_( std::move(create_migration_warning_callback)), - device_lock_bridge_(std::make_unique<DeviceLockBridge>()) {} + device_lock_bridge_(std::make_unique<DeviceLockBridge>()), + access_loss_bridge_( + std::make_unique<PasswordAccessLossWarningBridgeImpl>()) {} SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate( base::PassKey<class SaveUpdatePasswordMessageDelegateTest>, @@ -97,10 +117,12 @@ Profile*, password_manager::metrics_util::PasswordMigrationWarningTriggers)> create_migration_warning_callback, - std::unique_ptr<DeviceLockBridge> device_lock_bridge) + std::unique_ptr<DeviceLockBridge> device_lock_bridge, + std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge) : SaveUpdatePasswordMessageDelegate(password_edit_dialog_factory, create_migration_warning_callback) { device_lock_bridge_ = std::move(device_lock_bridge); + access_loss_bridge_ = std::move(access_loss_bridge); } SaveUpdatePasswordMessageDelegate::~SaveUpdatePasswordMessageDelegate() { @@ -365,6 +387,7 @@ kUpdateGMSCoreMessageDisplayDelay); TryToShowPasswordMigrationWarning(create_migration_warning_callback_, web_contents_); + TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get()); } ClearState(); } @@ -426,6 +449,7 @@ if (dismiss_reason == messages::DismissReason::PRIMARY_ACTION) { TryToShowPasswordMigrationWarning(create_migration_warning_callback_, web_contents_); + TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get()); } ClearState(); } @@ -460,6 +484,7 @@ web_contents_->GetNativeView()->GetWindowAndroid())) { TryToShowPasswordMigrationWarning(create_migration_warning_callback_, web_contents_); + TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get()); ClearState(); } }
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.h b/chrome/browser/password_manager/android/save_update_password_message_delegate.h index e15fc30..a66ba24 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate.h +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
@@ -12,6 +12,7 @@ #include "base/functional/callback_forward.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h" +#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h" #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/passwords/manage_passwords_state.h" @@ -55,7 +56,8 @@ Profile*, password_manager::metrics_util::PasswordMigrationWarningTriggers)> password_migration_warning_bridge_callback, - std::unique_ptr<DeviceLockBridge> device_lock_bridge); + std::unique_ptr<DeviceLockBridge> device_lock_bridge, + std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge); // Displays a "Save password" message for current |web_contents| and // |form_to_save|. @@ -166,6 +168,7 @@ create_migration_warning_callback_; std::unique_ptr<DeviceLockBridge> device_lock_bridge_; + std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge_; void SavePassword(); void SavePasswordAfterDeviceLockUi(bool is_device_lock_set);
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc index d7138ad..e937c074 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/android/android_theme_resources.h" #include "chrome/browser/android/resource_mapper.h" #include "chrome/browser/flags/android/chrome_feature_list.h" +#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h" #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h" @@ -32,6 +33,7 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/browser_ui/device_lock/android/device_lock_bridge.h" #include "components/messages/android/mock_message_dispatcher_bridge.h" +#include "components/password_manager/core/browser/features/password_features.h" #include "components/password_manager/core/browser/mock_password_form_manager_for_ui.h" #include "components/password_manager/core/browser/password_form.h" #include "components/password_manager/core/browser/password_form_metrics_recorder.h" @@ -173,6 +175,7 @@ void DestroyDelegate(); TestDeviceLockBridge* test_bridge(); + MockPasswordAccessLossWarningBridge* mock_access_loss_warning_bridge(); bool is_password_saved(); messages::MessageWrapper* GetMessageWrapper(); @@ -243,6 +246,7 @@ password_manager::metrics_util::PasswordMigrationWarningTriggers)>> mock_password_migration_warning_callback_; raw_ptr<TestDeviceLockBridge> test_bridge_; + raw_ptr<MockPasswordAccessLossWarningBridge> mock_access_loss_warning_bridge_; std::unique_ptr<SaveUpdatePasswordMessageDelegate> delegate_; bool is_password_saved_ = false; MockPasswordManagerClient password_manager_client_; @@ -262,12 +266,16 @@ auto bridge = std::make_unique<TestDeviceLockBridge>(); test_bridge_ = bridge.get(); + auto access_loss_bridge = + std::make_unique<MockPasswordAccessLossWarningBridge>(); + mock_access_loss_warning_bridge_ = access_loss_bridge.get(); delegate_ = std::make_unique<SaveUpdatePasswordMessageDelegate>( base::PassKey<class SaveUpdatePasswordMessageDelegateTest>(), base::BindRepeating( &SaveUpdatePasswordMessageDelegateTest::CreatePasswordEditDialog, base::Unretained(this)), - mock_password_migration_warning_callback_.Get(), std::move(bridge)); + mock_password_migration_warning_callback_.Get(), std::move(bridge), + std::move(access_loss_bridge)); messages::MessageDispatcherBridge::SetInstanceForTesting( &message_dispatcher_bridge_); @@ -415,6 +423,11 @@ return test_bridge_; } +MockPasswordAccessLossWarningBridge* +SaveUpdatePasswordMessageDelegateTest::mock_access_loss_warning_bridge() { + return mock_access_loss_warning_bridge_; +} + bool SaveUpdatePasswordMessageDelegateTest::is_password_saved() { return is_password_saved_; } @@ -623,6 +636,30 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will show when the user +// clicks the "Save" button. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + TriggerAccessLossWarning_OnSaveClicked) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), empty_best_matches()); + EXPECT_CALL(*form_manager, Save()); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false, + /*update_password=*/false); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())); + TriggerActionClick(); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that the message to update GMSCore will show when the user // clicks the "Save" button if the GMSCore version is too low to save account // passwords. @@ -673,6 +710,8 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the local password migration warning will show when the user +// accepts the password edit dialog. TEST_F(SaveUpdatePasswordMessageDelegateTest, TriggerLocalPasswordMigrationWarning_OnSavePasswordDialogAccepted) { base::test::ScopedFeatureList scoped_feature_state; @@ -699,6 +738,38 @@ TriggerDialogDismissedCallback(/*dialog_accepted=*/true); } +// Tests that the password access loss warning will show when the user +// accepts the password edit dialog. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + TriggerAccessLossWarning_OnSavePasswordDialogAccepted) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), empty_best_matches()); + MockPasswordFormManagerForUI* form_manager_pointer = form_manager.get(); + MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog(); + + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false, + /*update_password=*/false); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_dialog, ShowPasswordEditDialog); + TriggerPasswordEditDialog(/*update_password=*/false); + + EXPECT_EQ(nullptr, GetMessageWrapper()); + EXPECT_CALL(*form_manager_pointer, Save()); + TriggerDialogAcceptedCallback(/*username=*/kUsername, + /*password=*/kPassword); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())); + TriggerDialogDismissedCallback(/*dialog_accepted=*/true); +} + // Tests that the local password migration warning will not show when the user // dismisses the save password message. TEST_F(SaveUpdatePasswordMessageDelegateTest, @@ -717,6 +788,30 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will not show when the user +// dismisses the save password message. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + DontTriggerAccessLossWarning_OnSaveMessageDismissed) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), empty_best_matches()); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/false); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + DismissMessage(messages::DismissReason::GESTURE); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that the local password migration warning will show when the user // accepts the update password message in case when there is no confirmation // dialog. @@ -740,6 +835,33 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will show when the user accepts the update +// password message in case when there is no confirmation dialog. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + TriggerAccessLossWarning_OnUpdatePasswordWithSingleForm) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + SetPendingCredentials(kUsername, kPassword); + std::vector<PasswordForm> single_form_best_matches = { + CreatePasswordForm(kUsername, kPassword)}; + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), single_form_best_matches); + EXPECT_CALL(*form_manager, Save()); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/true); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())); + TriggerActionClick(); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that the message to update GMSCore will show when the user accepts the // update password message in case when there is no confirmation // dialog. @@ -820,6 +942,33 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will not show when the user +// dismisses the update password message. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + DontTriggerAccessLossWarning_OnUpdatePasswordMessageDismissed) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + SetPendingCredentials(kUsername, kPassword); + std::vector<PasswordForm> single_form_best_matches = { + CreatePasswordForm(kUsername, kPassword)}; + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), single_form_best_matches); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/true); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + DismissMessage(messages::DismissReason::GESTURE); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that the local password migration warning will show when the user // accepts the update password message and the confirmation dialog. TEST_F(SaveUpdatePasswordMessageDelegateTest, @@ -847,6 +996,41 @@ TriggerDialogDismissedCallback(/*dialog_accepted=*/true); } +// Tests that the access loss warning will show when the user accepts the update +// password message and the confirmation dialog. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + TriggerAccessLossWarning_OnUpdatePasswordDialogAccepted) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + SetPendingCredentials(kUsername, kPassword); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), two_forms_best_matches()); + MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog(); + EXPECT_CALL( + *mock_dialog, + ShowPasswordEditDialog( + ElementsAre(std::u16string(kUsername), std::u16string(kUsername2)), + Eq(kUsername), Eq(kPassword), Eq(kAccountEmail))); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/true); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + TriggerActionClick(); + TriggerDialogAcceptedCallback(/*username=*/kUsername, + /*password=*/kPassword); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())); + TriggerDialogDismissedCallback(/*dialog_accepted=*/true); +} + // Tests that the message to update GMSCore will show when the user accepts the // update password message and the confirmation dialog. TEST_F(SaveUpdatePasswordMessageDelegateTest, @@ -937,6 +1121,39 @@ TriggerDialogDismissedCallback(/*dialog_accepted=*/false); } +// Tests that the local password migration warning will show when the user +// accepts the update password message and cancels the confirmation dialog. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + TriggerAccessLossWarning_OnUpdatePasswordDialogCanceled) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + SetPendingCredentials(kUsername, kPassword); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), two_forms_best_matches()); + MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog(); + EXPECT_CALL( + *mock_dialog, + ShowPasswordEditDialog( + ElementsAre(std::u16string(kUsername), std::u16string(kUsername2)), + Eq(kUsername), Eq(kPassword), Eq(kAccountEmail))); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/true); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + TriggerActionClick(); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())); + TriggerDialogDismissedCallback(/*dialog_accepted=*/false); +} + // Tests that password form is not saved and metrics recorded correctly when the // user dismisses the message. TEST_F(SaveUpdatePasswordMessageDelegateTest, DontSaveOnDismiss) { @@ -999,6 +1216,30 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will not show when the user lets the save +// message time out. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + DontTriggerAccessLossWarning_OnSaveMessageAutodismissTimer) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), empty_best_matches()); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false, + /*update_password=*/false); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + DismissMessage(messages::DismissReason::TIMER); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that the local password migration warning will not show when the user // lets the update message time out. TEST_F( @@ -1017,6 +1258,33 @@ EXPECT_EQ(nullptr, GetMessageWrapper()); } +// Tests that the access loss warning will not show when the user lets the +// update message time out. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + DontTriggerAccessLossWarning_OnUpdateMessageAutodismissTimer) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + SetPendingCredentials(kUsername, kPassword); + std::vector<PasswordForm> single_form_best_matches = { + CreatePasswordForm(kUsername, kPassword)}; + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), single_form_best_matches); + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true, + /*update_password=*/true); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + DismissMessage(messages::DismissReason::TIMER); + EXPECT_EQ(nullptr, GetMessageWrapper()); +} + // Tests that update password message with a single PasswordForm immediately // saves the form on Update button tap and doesn't display confirmation dialog. TEST_F(SaveUpdatePasswordMessageDelegateTest, UpdatePasswordWithSingleForm) { @@ -1162,6 +1430,33 @@ TriggerNeverSaveMenuItem(); } +// Verifies that the access loss warning is not shown after selecting +// "Never for this site" menu option in the Save message. +TEST_F(SaveUpdatePasswordMessageDelegateTest, + DontTriggerAccessLossWarning_OnNeverSave) { + base::test::ScopedFeatureList scoped_feature_state; + scoped_feature_state.InitAndEnableFeature( + password_manager::features:: + kUnifiedPasswordManagerLocalPasswordsAndroidAccessLossWarning); + + auto form_manager = + CreateFormManager(GURL(kDefaultUrl), empty_best_matches()); + MockPasswordFormManagerForUI* form_manager_pointer = form_manager.get(); + + EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false, + /*update_password=*/false); + EXPECT_NE(nullptr, GetMessageWrapper()); + EXPECT_CALL(*mock_access_loss_warning_bridge(), + ShouldShowAccessLossNoticeSheet(profile()->GetPrefs())) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL( + *mock_access_loss_warning_bridge(), + MaybeShowAccessLossNoticeSheet(profile()->GetPrefs(), _, profile())) + .Times(0); + EXPECT_CALL(*form_manager_pointer, Blocklist()); + TriggerNeverSaveMenuItem(); +} + // Verifies that: // 1. Update password dialog is shown after clicking on cog button (secondary // action) in the message.
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc index a2f833a1..2226475e 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.cc
@@ -137,3 +137,7 @@ kSuppressesSearchPrefetchOnSlowNetworkThreshold{ &kSuppressesSearchPrefetchOnSlowNetwork, "slow_network_threshold_for_search_prefetch", base::Milliseconds(208)}; + +BASE_FEATURE(kEnsureSearchPrefetchServiceOnInterceptor, + "EnsureSearchprefetchServiceOnInterceptor", + base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h index 819a160..c822dfa 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h
@@ -97,4 +97,9 @@ extern const base::FeatureParam<base::TimeDelta> kSuppressesSearchPrefetchOnSlowNetworkThreshold; +// If enabled, SearchPrefetchService is ensured on +// `SearchPrefetchURLLoaderInterceptor::MaybeCreateLoaderForRequest`, so that +// navigation can consult the search prefetch cache even during browser startup. +BASE_DECLARE_FEATURE(kEnsureSearchPrefetchServiceOnInterceptor); + #endif // CHROME_BROWSER_PRELOADING_PREFETCH_SEARCH_PREFETCH_FIELD_TRIAL_SETTINGS_H_
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc index 719abbb9..467f8e57 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.cc
@@ -10,6 +10,7 @@ #include <utility> #include "base/functional/callback.h" +#include "chrome/browser/preloading/prefetch/search_prefetch/field_trial_settings.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_url_loader.h" @@ -45,6 +46,13 @@ if (!profile) { return nullptr; } + // If the feature is enabled, ensure SearchPrefetchService so that the + // navigation can consult the search prefetch cache regardless of if + // SearchPrefetchService has been accessed before this line, for example, + // during browser startup. + if (base::FeatureList::IsEnabled(kEnsureSearchPrefetchServiceOnInterceptor)) { + return SearchPrefetchServiceFactory::GetForProfile(profile); + } return SearchPrefetchServiceFactory::GetForProfileIfExists(profile); }
diff --git a/chrome/browser/resources/search_engine_choice/app.css b/chrome/browser/resources/search_engine_choice/app.css index 8aa5be8..f514ab25 100644 --- a/chrome/browser/resources/search_engine_choice/app.css +++ b/chrome/browser/resources/search_engine_choice/app.css
@@ -41,11 +41,20 @@ #actionButton { height: unset; margin: var(--action-button-margins); + margin-inline-start: auto; padding: 6px 16px 6px 12px; pointer-events: all; text-align: center; } +cr-checkbox { + --cr-checkbox-label-color: var(--google-grey-700); + --cr-checkbox-label-padding-start: 8px; + font-size: 0.75rem; + margin: var(--action-button-margins); + pointer-events: all; +} + .content-container { align-items: center; display: flex; @@ -190,7 +199,6 @@ #buttonContainer { bottom: 0; display: flex; - justify-content: flex-end; pointer-events: none; position: fixed; width: 100vw; @@ -241,6 +249,12 @@ width: 100%; } +/* 'hidden' will not work for '<cr-checkbox>'. This change makes the + 'hidden' attribute selector is more specific than the class selector. */ +[hidden]{ + display: none; +} + @media (prefers-color-scheme: dark) { :host { --background-color: var(--md-background-color); @@ -265,6 +279,10 @@ cr-radio-button { --cr-radio-button-unchecked-color: var(--google-grey-100); } + + cr-checkbox { + --cr-checkbox-label-color: var(--google-grey-500); + } } @media screen and (max-width: 780px) {
diff --git a/chrome/browser/resources/search_engine_choice/app.html b/chrome/browser/resources/search_engine_choice/app.html index 4bb5d54..ec458618 100644 --- a/chrome/browser/resources/search_engine_choice/app.html +++ b/chrome/browser/resources/search_engine_choice/app.html
@@ -35,6 +35,9 @@ </cr-radio-group> </div> <div id="buttonContainer"> + <cr-checkbox ?hidden="${!this.showGuestCheckbox_}"> + $i18n{guestCheckboxText} + </cr-checkbox> <cr-button class="action-button" id="actionButton" @click="${this.onActionButtonClicked_}" ?disabled="${this.isActionButtonDisabled_}">
diff --git a/chrome/browser/resources/search_engine_choice/app.ts b/chrome/browser/resources/search_engine_choice/app.ts index e3daddb..70a283d 100644 --- a/chrome/browser/resources/search_engine_choice/app.ts +++ b/chrome/browser/resources/search_engine_choice/app.ts
@@ -5,6 +5,7 @@ import 'chrome://resources/cr_components/localized_link/localized_link.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.js'; import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.js'; import './strings.m.js'; @@ -74,6 +75,8 @@ protected hasUserScrolledToTheBottom_: boolean = false; protected showInfoDialog_: boolean = false; protected actionButtonText_: string = ''; + protected showGuestCheckbox_: boolean = + loadTimeData.getBoolean('showGuestCheckbox'); private resizeObserver_: ResizeObserver|null = null; private pageHandler_: PageHandlerRemote =
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.html b/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.html index 873d525..782c228 100644 --- a/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.html +++ b/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.html
@@ -1,3 +1,42 @@ +<style include="cr-shared-style settings-columned-section"></style> <div> - <!-- TODO(crbug.com/361437117): Add content. --> + <!-- TODO(crbug.com/361437117): Add the toggle. --> +</div> +<div class="settings-columned-section"> + <div class="column"> + <h3 class="description-header">$i18n{columnHeadingWhenOn}</h3> + <ul class="icon-bulleted-list"> + <li> + <cr-icon icon="settings20:edit-square"></cr-icon> + <div class="cr-secondary-text"> + $i18n{autofillPredictionImprovementsWhenOnSavedInfo} + </div> + </li> + <li> + <cr-icon icon="settings20:history"></cr-icon> + <div class="cr-secondary-text"> + $i18n{autofillPredictionImprovementsWhenOnAdapts} + </div> + </li> + </ul> + </div> + <div class="column"> + <h3 class="description-header"> + $i18n{columnHeadingConsider} + </h3> + <ul class="icon-bulleted-list"> + <li> + <cr-icon icon="settings:devices"></cr-icon> + <div class="cr-secondary-text"> + $i18n{autofillPredictionImprovementsToConsiderInfoLocal} + </div> + </li> + <li> + <cr-icon icon="settings20:data"></cr-icon> + <div class="cr-secondary-text"> + $i18n{autofillPredictionImprovementsToConsiderDataUsage} + </div> + </li> + </ul> + </div> </div>
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.ts b/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.ts index 82e365ca..243afa39 100644 --- a/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.ts +++ b/chrome/browser/resources/settings/autofill_page/autofill_prediction_improvements_section.ts
@@ -7,6 +7,11 @@ * the section containing configuration options for prediction improvements. */ +import 'chrome://resources/cr_elements/cr_icon/cr_icon.js'; +import 'chrome://resources/cr_elements/cr_shared_style.css.js'; +import '../icons.html.js'; +import '../settings_columned_section.css.js'; + import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './autofill_prediction_improvements_section.html.js';
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html index 78bbc79..5983554 100644 --- a/chrome/browser/resources/settings/icons.html +++ b/chrome/browser/resources/settings/icons.html
@@ -28,6 +28,7 @@ <g id="delete-forever"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.4999 3.33333V2.5H7.49992V3.33333H3.33325V5H4.16659V15.8333C4.16659 16.75 4.91659 17.5 5.83325 17.5H14.1666C15.0833 17.5 15.8333 16.75 15.8333 15.8333V5H16.6666V3.33333H12.4999ZM14.1666 5V15.8333H5.83325V5H14.1666ZM9.99992 11.5917L7.84158 13.75L6.66658 12.575L8.82492 10.4167L6.66658 8.25833L7.84158 7.08333L9.99992 9.24167L12.1583 7.08333L13.3333 8.25833L11.1749 10.4167L13.3333 12.575L12.1583 13.75L9.99992 11.5917Z"></path></g> <g id="dns"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.6667 2.5H3.33333C2.875 2.5 2.5 2.875 2.5 3.33333V9.16667C2.5 9.625 2.875 10 3.33333 10H16.6667C17.125 10 17.5 9.625 17.5 9.16667V3.33333C17.5 2.875 17.125 2.5 16.6667 2.5ZM7.5 6.25C7.5 6.94036 6.94036 7.5 6.25 7.5C5.55964 7.5 5 6.94036 5 6.25C5 5.55964 5.55964 5 6.25 5C6.94036 5 7.5 5.55964 7.5 6.25ZM7.5 14.5833C7.5 15.2737 6.94036 15.8333 6.25 15.8333C5.55964 15.8333 5 15.2737 5 14.5833C5 13.893 5.55964 13.3333 6.25 13.3333C6.94036 13.3333 7.5 13.893 7.5 14.5833ZM4.16667 8.33333H15.8333V4.16667H4.16667V8.33333ZM16.6667 10.8333H3.33333C2.875 10.8333 2.5 11.2083 2.5 11.6667V17.5C2.5 17.9583 2.875 18.3333 3.33333 18.3333H16.6667C17.125 18.3333 17.5 17.9583 17.5 17.5V11.6667C17.5 11.2083 17.125 10.8333 16.6667 10.8333ZM4.16667 16.6667H15.8333V12.5H4.16667V16.6667Z"></path></g> <g id="download"><path d="M 10 13.292969 L 5.230469 8.519531 L 6.644531 7.144531 L 9.019531 9.519531 L 9.019531 2.792969 L 10.980469 2.792969 L 10.980469 9.519531 L 13.355469 7.144531 L 14.769531 8.519531 Z M 4.769531 17.1875 C 4.226562 17.1875 3.765625 16.996094 3.386719 16.613281 C 3.003906 16.234375 2.8125 15.773438 2.8125 15.230469 L 2.8125 12.25 L 4.769531 12.25 L 4.769531 15.230469 L 15.230469 15.230469 L 15.230469 12.25 L 17.207031 12.25 L 17.207031 15.230469 C 17.207031 15.769531 17.015625 16.234375 16.628906 16.613281 C 16.246094 16.996094 15.777344 17.1875 15.230469 17.1875 Z M 4.769531 17.1875"></path></g> + <g id="edit-square"><path d="M 4.167969 17.5 C 3.707031 17.5 3.316406 17.335938 2.988281 17.011719 C 2.664062 16.683594 2.5 16.292969 2.5 15.832031 L 2.5 4.167969 C 2.5 3.707031 2.664062 3.316406 2.988281 2.988281 C 3.316406 2.664062 3.707031 2.5 4.167969 2.5 L 11.605469 2.5 L 9.9375 4.167969 L 4.167969 4.167969 L 4.167969 15.832031 L 15.832031 15.832031 L 15.832031 10.042969 L 17.5 8.375 L 17.5 15.832031 C 17.5 16.292969 17.335938 16.683594 17.011719 17.011719 C 16.683594 17.335938 16.292969 17.5 15.832031 17.5 Z M 10 10 Z M 7.5 12.5 L 7.5 8.957031 L 15.144531 1.3125 C 15.3125 1.144531 15.5 1.019531 15.707031 0.9375 C 15.917969 0.855469 16.125 0.8125 16.332031 0.8125 C 16.554688 0.8125 16.765625 0.855469 16.96875 0.9375 C 17.171875 1.019531 17.355469 1.144531 17.519531 1.3125 L 18.6875 2.5 C 18.839844 2.667969 18.957031 2.851562 19.042969 3.050781 C 19.125 3.253906 19.167969 3.457031 19.167969 3.667969 C 19.167969 3.875 19.128906 4.078125 19.050781 4.28125 C 18.976562 4.484375 18.855469 4.667969 18.6875 4.832031 L 11.042969 12.5 Z M 17.519531 3.667969 L 16.355469 2.5 Z M 9.167969 10.832031 L 10.332031 10.832031 L 15.167969 6 L 14.582031 5.417969 L 13.980469 4.832031 L 9.167969 9.644531 Z M 14.582031 5.417969 L 13.980469 4.832031 L 14.582031 5.417969 L 15.167969 6 Z M 14.582031 5.417969 "></path></g> <g id="experiment"><path d="M17.2667 14.7583L12.5 8.18332V4.23332H14.1667V2.56665H5.83332V4.23332H7.49998V8.17498L2.61665 14.9166C2.24998 15.425 2.19998 16.0917 2.48332 16.65C2.76665 17.2083 3.34165 17.5583 3.96665 17.5583H16.05C16.9667 17.5583 17.7167 16.8083 17.7167 15.8917C17.7167 15.4583 17.5416 15.0583 17.2667 14.7583Z" fill="#5F6368"></path></g> <g id="my_extensions" viewBox="0 -960 960 960"><path d="M216-135.869q-33.287 0-56.709-23.422-23.422-23.422-23.422-56.709v-172.304q37.609-2 63.218-28.424 25.608-26.424 25.608-63.272t-25.608-63.272q-25.609-26.424-63.218-28.424V-744q0-33.287 23.422-56.709 23.422-23.422 56.709-23.422h161.065q2.631-40.956 31.96-69.315 29.329-28.359 70.75-28.359t70.975 28.199q29.554 28.199 32.185 69.475H744q33.287 0 56.709 23.422 23.422 23.422 23.422 56.709v161.065q40.956 2.631 69.315 31.96 28.359 29.329 28.359 70.75t-28.199 70.975q-28.199 29.554-69.475 32.185V-216q0 33.287-23.422 56.709-23.422 23.422-56.709 23.422H216Zm2.87-83.001h522.26v-522.26H218.87v108.652q42.13 22.63 65.597 63.772 23.468 41.141 23.468 88.706 0 49.01-23.468 90.168Q261-348.674 218.87-327.283v108.413ZM480-480Z"></path></g> <g id="find-in-path"><path d="M12.3333 16.5L13.8333 18H5.5C5.08333 18 4.72917 17.8542 4.4375 17.5625C4.14583 17.2708 4 16.9167 4 16.5V3.5C4 3.08333 4.14583 2.72917 4.4375 2.4375C4.72917 2.14583 5.08333 2 5.5 2H12L16 6V15.9167C16 16.4167 15.9583 16.7917 15.875 17.0417C15.8056 17.2917 15.6944 17.4722 15.5417 17.5833L11.5208 13.5625C11.3125 13.7014 11.0764 13.8056 10.8125 13.875C10.5486 13.9306 10.2778 13.9583 10 13.9583C9.16667 13.9583 8.45833 13.6667 7.875 13.0833C7.29167 12.5 7 11.7917 7 10.9583C7 10.125 7.29167 9.41667 7.875 8.83333C8.45833 8.25 9.16667 7.95833 10 7.95833C10.8333 7.95833 11.5417 8.25 12.125 8.83333C12.7083 9.41667 13 10.125 13 10.9583C13 11.2361 12.9653 11.5139 12.8958 11.7917C12.8264 12.0556 12.7222 12.2917 12.5833 12.5L14.5 14.4167V6.625L11.375 3.5H5.5V16.5H12.3333ZM10 12.4583C10.4167 12.4583 10.7708 12.3125 11.0625 12.0208C11.3542 11.7292 11.5 11.375 11.5 10.9583C11.5 10.5417 11.3542 10.1875 11.0625 9.89583C10.7708 9.60417 10.4167 9.45833 10 9.45833C9.58333 9.45833 9.22917 9.60417 8.9375 9.89583C8.64583 10.1875 8.5 10.5417 8.5 10.9583C8.5 11.375 8.64583 11.7292 8.9375 12.0208C9.22917 12.3125 9.58333 12.4583 10 12.4583Z"></path></g>
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html index e22f37e..32341c8 100644 --- a/chrome/browser/resources/settings/search_page/search_page.html +++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -1,4 +1,4 @@ -<style include="cr-shared-style iron-flex settings-shared md-select"> +<style include="cr-shared-style iron-flex settings-shared"> :host { --favicon-size: 0; } @@ -39,51 +39,10 @@ <div route-path="default"> <!-- Omnibox search engine --> <div class="cr-row first"> - <template is="dom-if" if="[[searchEngineChoiceSettingsUi_]]"> - <div class="default-search-engine flex"> - $i18n{searchPageTitle} - <div class="secondary"> - $i18n{searchEngineChoiceEntryPointSubtitle} - <a href="$i18n{searchExplanationLearnMoreURL}" - aria-label="$i18n{searchExplanationLearnMoreA11yLabel}" - target="_blank"> - $i18n{learnMore} - </a> - </div> - <template is="dom-if" if="[[isDefaultSearchControlledByPolicy_( - prefs.default_search_provider_data.template_url_data)]]"> - <cr-policy-pref-indicator pref="[[ - prefs.default_search_provider_data.template_url_data]]"> - </cr-policy-pref-indicator> - </template> - <div class="cr-row first"> - <site-favicon favicon-url="[[defaultSearchEngine_.iconURL]]" - url="[[defaultSearchEngine_.url]]" - icon-path="[[defaultSearchEngine_.iconPath]]"> - </site-favicon> - <div class="search-engine-name">[[defaultSearchEngine_.name]]</div> - <cr-button id="openDialogButton" - on-click="onOpenDialogButtonClick_" - disabled$="[[isDefaultSearchEngineEnforced_( - prefs.default_search_provider_data.template_url_data)]]"> - $i18n{searchEnginesChange} - </cr-button> - </div> - </div> - <template is="dom-if" if="[[showSearchEngineListDialog_]]" restamp> - <settings-search-engine-list-dialog - search-engines="[[searchEngines_]]" - on-close="onSearchEngineListDialogClose_" - on-search-engine-changed="onDefaultSearchEngineChangedInDialog_"> - </settings-search-engine-list-dialog> - </template> - <cr-toast id="confirmationToast" duration="10000"> - <div>[[confirmationToastLabel_]]</div> - </cr-toast> - </template> - <template is="dom-if" if="[[!searchEngineChoiceSettingsUi_]]"> - <div id="searchExplanation" class="flex cr-padded-text"> - $i18n{searchExplanation} + <div class="default-search-engine flex"> + $i18n{searchPageTitle} + <div class="secondary"> + $i18n{searchEngineChoiceEntryPointSubtitle} <a href="$i18n{searchExplanationLearnMoreURL}" aria-label="$i18n{searchExplanationLearnMoreA11yLabel}" target="_blank"> @@ -96,15 +55,30 @@ prefs.default_search_provider_data.template_url_data]]"> </cr-policy-pref-indicator> </template> - <select class="md-select" on-change="onChange_" - aria-labelledby="searchExplanation" - disabled$="[[isDefaultSearchEngineEnforced_( - prefs.default_search_provider_data.template_url_data)]]"> - <template is="dom-repeat" items="[[searchEngines_]]"> - <option selected="[[item.default]]">[[item.name]]</option> - </template> - </select> + <div class="cr-row first"> + <site-favicon favicon-url="[[defaultSearchEngine_.iconURL]]" + url="[[defaultSearchEngine_.url]]" + icon-path="[[defaultSearchEngine_.iconPath]]"> + </site-favicon> + <div class="search-engine-name">[[defaultSearchEngine_.name]]</div> + <cr-button id="openDialogButton" + on-click="onOpenDialogButtonClick_" + disabled$="[[isDefaultSearchEngineEnforced_( + prefs.default_search_provider_data.template_url_data)]]"> + $i18n{searchEnginesChange} + </cr-button> + </div> + </div> + <template is="dom-if" if="[[showSearchEngineListDialog_]]" restamp> + <settings-search-engine-list-dialog + search-engines="[[searchEngines_]]" + on-close="onSearchEngineListDialogClose_" + on-search-engine-changed="onDefaultSearchEngineChangedInDialog_"> + </settings-search-engine-list-dialog> </template> + <cr-toast id="confirmationToast" duration="10000"> + <div>[[confirmationToastLabel_]]</div> + </cr-toast> </div> <template is="dom-if" if="[[prefs.default_search_provider_data.template_url_data.extensionId]]">
diff --git a/chrome/browser/resources/settings/search_page/search_page.ts b/chrome/browser/resources/settings/search_page/search_page.ts index a46e3355..9348de5 100644 --- a/chrome/browser/resources/settings/search_page/search_page.ts +++ b/chrome/browser/resources/settings/search_page/search_page.ts
@@ -10,7 +10,6 @@ import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; -import 'chrome://resources/cr_elements/md_select.css.js'; import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; import '/shared/settings/controls/extension_controlled_indicator.js'; import '../settings_page/settings_animated_pages.js'; @@ -22,7 +21,6 @@ import type {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; -import {assert} from 'chrome://resources/js/assert.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {BaseMixin} from '../base_mixin.js'; @@ -30,7 +28,7 @@ import {routes} from '../route.js'; import {Router} from '../router.js'; import type {SearchEngine, SearchEnginesBrowserProxy, SearchEnginesInfo} from '../search_engines_page/search_engines_browser_proxy.js'; -import {ChoiceMadeLocation, SearchEnginesBrowserProxyImpl} from '../search_engines_page/search_engines_browser_proxy.js'; +import {SearchEnginesBrowserProxyImpl} from '../search_engines_page/search_engines_browser_proxy.js'; import {getTemplate} from './search_page.html.js'; @@ -55,14 +53,6 @@ */ searchEngines_: Array, - // Whether the `SearchEngineChoiceTrigger` feature is enabled. - searchEngineChoiceSettingsUi_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('searchEngineChoiceSettingsUi'); - }, - }, - // Whether we need to set the icon size to large because they are loaded // in the binary or smaller because we get them from the favicon service. isEeaChoiceCountry_: { @@ -95,7 +85,6 @@ prefs: Object; private searchEngines_: SearchEngine[]; private searchEnginesFilter_: string; - private searchEngineChoiceSettingsUi_: boolean; private showSearchEngineListDialog_: boolean; private defaultSearchEngine_: SearchEngine|null; private focusConfig_: Map<string, string>|null; @@ -126,15 +115,6 @@ this.setFaviconSize_(); } - private onChange_() { - assert(!this.searchEngineChoiceSettingsUi_); - const select = this.shadowRoot!.querySelector('select'); - assert(select); - const searchEngine = this.searchEngines_[select.selectedIndex]; - this.browserProxy_.setDefaultSearchEngine( - searchEngine.modelIndex, ChoiceMadeLocation.SEARCH_SETTINGS); - } - private onDisableExtension_() { this.dispatchEvent(new CustomEvent('refresh-pref', { bubbles: true, @@ -159,7 +139,7 @@ } private computeDefaultSearchEngine_() { - if (!this.searchEngines_.length || !this.searchEngineChoiceSettingsUi_) { + if (!this.searchEngines_.length) { return null; } @@ -167,7 +147,6 @@ } private onOpenDialogButtonClick_() { - assert(this.searchEngineChoiceSettingsUi_); this.showSearchEngineListDialog_ = true; chrome.metricsPrivate.recordUserAction('ChooseDefaultSearchEngine'); } @@ -180,7 +159,6 @@ } private onSearchEngineListDialogClose_() { - assert(this.searchEngineChoiceSettingsUi_); this.showSearchEngineListDialog_ = false; }
diff --git a/chrome/browser/support_tool/support_packet_metadata.cc b/chrome/browser/support_tool/support_packet_metadata.cc index bc41ea341..25704445 100644 --- a/chrome/browser/support_tool/support_packet_metadata.cc +++ b/chrome/browser/support_tool/support_packet_metadata.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/support_tool/support_packet_metadata.h" #include <memory> +#include <optional> #include <set> #include <string> #include <string_view> @@ -88,16 +89,19 @@ } } // namespace -SupportPacketMetadata::SupportPacketMetadata(std::string case_id, - std::string email_address, - std::string issue_description) { +SupportPacketMetadata::SupportPacketMetadata( + std::string case_id, + std::string email_address, + std::string issue_description, + std::optional<std::string> upload_id) { metadata_[kSupportCaseIdKey] = case_id; metadata_[kIssueDescriptionKey] = issue_description; if (!email_address.empty()) { metadata_[kEmailAddressKey] = email_address; pii_[PIIType::kEmail].insert(email_address); } - metadata_[kSupportPacketGUIDKey] = GetGUIDForSupportPacket(); + metadata_[kSupportPacketGUIDKey] = + upload_id.has_value() ? upload_id.value() : GetGUIDForSupportPacket(); SetChromeMetadataFields(); }
diff --git a/chrome/browser/support_tool/support_packet_metadata.h b/chrome/browser/support_tool/support_packet_metadata.h index 4aecca5..d36322ac 100644 --- a/chrome/browser/support_tool/support_packet_metadata.h +++ b/chrome/browser/support_tool/support_packet_metadata.h
@@ -7,6 +7,7 @@ #include <map> #include <memory> +#include <optional> #include <set> #include <string> #include <vector> @@ -26,7 +27,8 @@ // - Support Case ID // - Issue Description // - Email Address (optional) -// - GUID of the support packet +// - GUID of the support packet: This ID matches with the `upload_id` field on +// server. // - List of data collectors // - Chrome details: // - Platform and OS (contains board and channel for ChromeOS) @@ -38,7 +40,8 @@ public: SupportPacketMetadata(std::string case_id, std::string email_address, - std::string issue_description); + std::string issue_description, + std::optional<std::string> upload_id); ~SupportPacketMetadata();
diff --git a/chrome/browser/support_tool/support_tool_handler.cc b/chrome/browser/support_tool/support_tool_handler.cc index 953cbc3..33e02a8 100644 --- a/chrome/browser/support_tool/support_tool_handler.cc +++ b/chrome/browser/support_tool/support_tool_handler.cc
@@ -62,12 +62,14 @@ SupportToolHandler::SupportToolHandler() : SupportToolHandler(/*case_id=*/std::string(), /*email_address=*/std::string(), - /*issue_description=*/std::string()) {} + /*issue_description=*/std::string(), + std::nullopt) {} SupportToolHandler::SupportToolHandler(std::string case_id, std::string email_address, - std::string issue_description) - : metadata_(case_id, email_address, issue_description), + std::string issue_description, + std::optional<std::string> upload_id) + : metadata_(case_id, email_address, issue_description, upload_id), task_runner_for_redaction_tool_( base::ThreadPool::CreateSequencedTaskRunner( {base::TaskPriority::USER_VISIBLE,
diff --git a/chrome/browser/support_tool/support_tool_handler.h b/chrome/browser/support_tool/support_tool_handler.h index 217ebd3..b664d79 100644 --- a/chrome/browser/support_tool/support_tool_handler.h +++ b/chrome/browser/support_tool/support_tool_handler.h
@@ -8,6 +8,7 @@ #include <memory> #include <optional> #include <set> +#include <string> #include <vector> #include "base/files/file_path.h" @@ -77,7 +78,8 @@ SupportToolHandler(); SupportToolHandler(std::string case_id, std::string email_address, - std::string issue_description); + std::string issue_description, + std::optional<std::string> upload_id); ~SupportToolHandler(); // Returns the support case ID.
diff --git a/chrome/browser/support_tool/support_tool_util.cc b/chrome/browser/support_tool/support_tool_util.cc index 92025bf..c0a2990 100644 --- a/chrome/browser/support_tool/support_tool_util.cc +++ b/chrome/browser/support_tool/support_tool_util.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/support_tool/support_tool_util.h" #include <memory> +#include <optional> #include <set> #include <string> #include <vector> @@ -100,11 +101,12 @@ std::string case_id, std::string email_address, std::string issue_description, + std::optional<std::string> upload_id, Profile* profile, std::set<support_tool::DataCollectorType> included_data_collectors) { std::unique_ptr<SupportToolHandler> handler = std::make_unique<SupportToolHandler>(case_id, email_address, - issue_description); + issue_description, upload_id); for (const auto& data_collector_type : included_data_collectors) { switch (data_collector_type) { case support_tool::CHROME_INTERNAL:
diff --git a/chrome/browser/support_tool/support_tool_util.h b/chrome/browser/support_tool/support_tool_util.h index ac08ade0..69e925f 100644 --- a/chrome/browser/support_tool/support_tool_util.h +++ b/chrome/browser/support_tool/support_tool_util.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_UTIL_H_ #define CHROME_BROWSER_SUPPORT_TOOL_SUPPORT_TOOL_UTIL_H_ +#include <optional> #include <set> #include <string> #include <vector> @@ -18,11 +19,13 @@ // Returns SupportToolHandler that is created for collecting logs from the // given information. Adds the corresponding DataCollectors that were listed in -// `included_data_collectors` to the returned SupportToolHandler. +// `included_data_collectors` to the returned SupportToolHandler. Callers can +// attach an optional `upload_id` to attach to the support packet. std::unique_ptr<SupportToolHandler> GetSupportToolHandler( std::string case_id, std::string email_address, std::string issue_description, + std::optional<std::string> upload_id, Profile* profile, std::set<support_tool::DataCollectorType> included_data_collectors);
diff --git a/chrome/browser/support_tool/support_tool_util_browsertest.cc b/chrome/browser/support_tool/support_tool_util_browsertest.cc index 1a5d01f..55673ba 100644 --- a/chrome/browser/support_tool/support_tool_util_browsertest.cc +++ b/chrome/browser/support_tool/support_tool_util_browsertest.cc
@@ -36,6 +36,7 @@ constexpr char kCaseId[] = "case-id"; constexpr char kEmail[] = "test@test.com"; constexpr char kIssueDescription[] = "fake issue description"; +constexpr char kUploadId[] = "testing_id"; class SupportToolUtilTest : public InProcessBrowserTest { public: @@ -101,7 +102,7 @@ GetAllAvailableDataCollectorsOnDevice(); std::unique_ptr<SupportToolHandler> handler = GetSupportToolHandler( - kCaseId, kEmail, kIssueDescription, browser()->profile(), + kCaseId, kEmail, kIssueDescription, kUploadId, browser()->profile(), std::set<support_tool::DataCollectorType>(data_collectors.begin(), data_collectors.end())); EXPECT_EQ(data_collectors.size(), @@ -125,7 +126,7 @@ support_tool::DataCollectorType::SIGN_IN_STATE}; std::unique_ptr<SupportToolHandler> handler = GetSupportToolHandler( - kCaseId, kEmail, kIssueDescription, signin_profile, + kCaseId, kEmail, kIssueDescription, kUploadId, signin_profile, std::set<support_tool::DataCollectorType>(all_data_collectors.begin(), all_data_collectors.end())); EXPECT_EQ(all_data_collectors.size() - excluded_data_collectors.size(), @@ -133,7 +134,7 @@ // Verify that the data collectors are excluded when they're not supported on // login screen. - handler = GetSupportToolHandler(kCaseId, kEmail, kIssueDescription, + handler = GetSupportToolHandler(kCaseId, kEmail, kIssueDescription, kUploadId, signin_profile, excluded_data_collectors); EXPECT_EQ(0U, handler->GetDataCollectorsForTesting().size()); }
diff --git a/chrome/browser/sync/BUILD.gn b/chrome/browser/sync/BUILD.gn index acd37d86..60e4b4b 100644 --- a/chrome/browser/sync/BUILD.gn +++ b/chrome/browser/sync/BUILD.gn
@@ -153,6 +153,7 @@ "sync_ui_util.cc", "sync_ui_util.h", ] + public_deps += [ "//chrome/browser/ui/tabs:tab_strip_model_observer" ] deps += [ "//chrome/browser/themes", "//chrome/browser/web_applications",
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc index 2b459365..e6ff31c 100644 --- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -317,18 +317,18 @@ ScopedWindowMap old_windows; GURL url = embedded_test_server()->GetURL("/sync/simple.html"); ASSERT_TRUE(OpenTab(0, url)); - ASSERT_TRUE(GetLocalWindows(0, &old_windows)); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + EXPECT_TRUE(GetLocalWindows(0, &old_windows)); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); // Get foreign session data from client 0. SyncedSessionVector sessions; - ASSERT_FALSE(GetSessionData(0, &sessions)); - ASSERT_EQ(0U, sessions.size()); + EXPECT_FALSE(GetSessionData(0, &sessions)); + EXPECT_EQ(0U, sessions.size()); // Verify client didn't change. ScopedWindowMap new_windows; ASSERT_TRUE(GetLocalWindows(0, &new_windows)); - ASSERT_TRUE(WindowsMatch(old_windows, new_windows)); + EXPECT_TRUE(WindowsMatch(old_windows, new_windows)); WaitForURLOnServer(url); @@ -336,6 +336,71 @@ UnorderedElementsAre(url.spec())); } +IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, PRE_SessionStartTime) { + const base::Time initial_time = base::Time::Now(); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + + // Add a tab and wait for it to sync. + GURL url = + embedded_test_server()->GetURL("www.host1.com", "/sync/simple.html"); + ASSERT_TRUE(OpenTab(0, url)); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + + WaitForURLOnServer(url); + + // Ensure the session start time was properly populated in the header. + std::vector<sync_pb::SyncEntity> entities = + fake_server_->GetSyncEntitiesByDataType(syncer::SESSIONS); + EXPECT_EQ(entities.size(), 2u); + bool found_header = false; + for (const sync_pb::SyncEntity& entity : entities) { + const sync_pb::SessionSpecifics session = entity.specifics().session(); + if (session.has_header()) { + found_header = true; + EXPECT_TRUE(session.header().has_session_start_time_unix_epoch_millis()); + EXPECT_GE(base::Time::FromMillisecondsSinceUnixEpoch( + session.header().session_start_time_unix_epoch_millis()), + initial_time); + } + } + EXPECT_TRUE(found_header); +} + +IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, SessionStartTime) { + const base::Time initial_time = base::Time::Now(); + ASSERT_TRUE(SetupClients()) << "SetupSync() failed."; + + // Open another tab and wait for it to sync, just to ensure everything's up + // to date. + GURL url = + embedded_test_server()->GetURL("www.host2.com", "/sync/simple.html"); + ASSERT_TRUE(OpenTab(0, url)); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + + WaitForURLOnServer(url); + + // Ensure the session start time in the header was *not* updated. + std::vector<sync_pb::SyncEntity> entities = + fake_server_->GetSyncEntitiesByDataType(syncer::SESSIONS); + EXPECT_EQ(entities.size(), 2u); + bool found_header = false; + for (const sync_pb::SyncEntity& entity : entities) { + const sync_pb::SessionSpecifics session = entity.specifics().session(); + if (session.has_header()) { + found_header = true; + EXPECT_TRUE(session.header().has_session_start_time_unix_epoch_millis()); + // `initial_time` is after the browser restart, so the session start time + // should be before that. + EXPECT_LT(base::Time::FromMillisecondsSinceUnixEpoch( + session.header().session_start_time_unix_epoch_millis()), + initial_time); + } + } + EXPECT_TRUE(found_header); +} + IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NavigateInTab) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; ASSERT_TRUE(CheckInitialState(0));
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 73711ac..a0f1d640d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1108,13 +1108,6 @@ "collected_cookies_infobar_delegate.h", "confirm_bubble_model.cc", "confirm_bubble_model.h", - "content_settings/content_setting_bubble_model.cc", - "content_settings/content_setting_bubble_model.h", - "content_settings/content_setting_bubble_model_delegate.h", - "content_settings/content_setting_image_model.cc", - "content_settings/content_setting_image_model.h", - "content_settings/content_setting_image_model_states.cc", - "content_settings/content_setting_image_model_states.h", "customize_chrome/side_panel_controller.h", "download/download_bubble_contents_view_info.cc", "download/download_bubble_contents_view_info.h", @@ -1479,7 +1472,6 @@ "tabs/saved_tab_groups/tab_group_sync_service_proxy.cc", "tabs/saved_tab_groups/tab_group_sync_service_proxy.h", "tabs/supports_handles.h", - "tabs/tab_change_type.h", "tabs/tab_collection.h", "tabs/tab_collection_storage.cc", "tabs/tab_collection_storage.h", @@ -1513,8 +1505,6 @@ "tabs/tab_strip_model.h", "tabs/tab_strip_model_delegate.cc", "tabs/tab_strip_model_delegate.h", - "tabs/tab_strip_model_observer.cc", - "tabs/tab_strip_model_observer.h", "tabs/tab_strip_model_stats_recorder.cc", "tabs/tab_strip_model_stats_recorder.h", "tabs/tab_strip_prefs.cc", @@ -1997,9 +1987,13 @@ "//chrome/browser/ui/browser_window:impl", "//chrome/browser/ui/color:color_headers", "//chrome/browser/ui/color:mixers", + "//chrome/browser/ui/content_settings", + "//chrome/browser/ui/content_settings:impl", "//chrome/browser/ui/exclusive_access", "//chrome/browser/ui/permission_bubble", "//chrome/browser/ui/tabs", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + "//chrome/browser/ui/tabs:tab_strip_model_observer_impl", "//chrome/browser/ui/toasts:impl", "//chrome/browser/ui/toasts:toasts", "//chrome/browser/ui/toasts/api:toasts", @@ -2123,11 +2117,17 @@ # //c/b/iu/tab_modal_confirm_dialog_delegate.h. "//chrome/browser/ui/apps:impl", "//chrome/browser/ui/browser_window:impl", + "//chrome/browser/ui/content_settings:impl", "//chrome/browser/ui/exclusive_access", "//chrome/browser/ui/toasts:impl", "//chrome/browser/ui/views/toolbar", "//chrome/browser/ui/webui/searchbox", "//chrome/browser/ui/webui/top_chrome:impl", + + # TODO(crbug.com/364501603): remove this as it depends on + # //c/b/ui/tabs/tab_strip_model.h, which is still part of + # //c/b/ui. + "//chrome/browser/ui/tabs:tab_strip_model_observer_impl", ] if (is_mac) { @@ -2216,10 +2216,6 @@ "views/profiles/profile_indicator_icon.h", "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.cc", "views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h", - "views/select_file_dialog_extension.cc", - "views/select_file_dialog_extension.h", - "views/select_file_dialog_extension_factory.cc", - "views/select_file_dialog_extension_factory.h", "webui/app_management/app_management_page_handler_chromeos.cc", "webui/app_management/app_management_page_handler_chromeos.h", "webui/app_management/app_management_shelf_delegate_chromeos.cc", @@ -2566,6 +2562,7 @@ "//chrome/browser/ui/views/bruschetta", "//chrome/browser/ui/views/crostini", "//chrome/browser/ui/views/plugin_vm", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/account_manager", "//chrome/browser/ui/webui/ash/add_supervision", "//chrome/browser/ui/webui/ash/assistant_optin", @@ -3016,6 +3013,7 @@ "//chrome/browser/ui/views/borealis", "//chrome/browser/ui/views/crostini", "//chrome/browser/ui/views/plugin_vm", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chrome/browser/ui/webui/ash/account_manager", "//chrome/browser/ui/webui/ash/add_supervision", "//chrome/browser/ui/webui/ash/assistant_optin", @@ -3704,8 +3702,6 @@ "cocoa/touchbar/web_textfield_touch_bar_controller.mm", "cocoa/window_size_autosaver.h", "cocoa/window_size_autosaver.mm", - "content_settings/media_authorization_wrapper_test.h", - "content_settings/media_authorization_wrapper_test.mm", "fullscreen_util_mac.cc", "fullscreen_util_mac.h", "views/apps/chrome_app_window_client_views_mac.mm", @@ -4166,6 +4162,8 @@ "views/autofill/popup/popup_row_content_view.h", "views/autofill/popup/popup_row_factory_utils.cc", "views/autofill/popup/popup_row_factory_utils.h", + "views/autofill/popup/popup_row_prediction_improvements_feedback_view.cc", + "views/autofill/popup/popup_row_prediction_improvements_feedback_view.h", "views/autofill/popup/popup_row_view.cc", "views/autofill/popup/popup_row_view.h", "views/autofill/popup/popup_row_with_button_view.cc", @@ -6138,10 +6136,7 @@ static_library("test_support") { testonly = true - sources = [ - "content_settings/fake_owner.cc", - "content_settings/fake_owner.h", - ] + sources = [] public_deps = [ ":ui" ] deps = [ @@ -6255,6 +6250,7 @@ "webui/help/test_version_updater.h", ] deps += [ + "//chrome/browser/ui/content_settings:test_support", "//chrome/browser/ui/views/toolbar", "//chrome/test:test_support_ui", "//components/embedder_support:embedder_support",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 32f145c..fdefc32b 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -992,6 +992,9 @@ <message name="IDS_ACCESS_LOSS_EXPORT_DIALOG_TITLE" desc="The title of the modal dialog proposing the user to export their passwords from Chrome and remove them from Chrome's database (to later import them in Google Play Services)."> First, export and delete the passwords from Chrome </message> + <message name="IDS_ACCESS_LOSS_EXPORT_DIALOG_TITLE_NO_GMS" desc="The title of the modal dialog proposing the user to export their passwords from Chrome and remove them from Chrome's database."> + Export and delete the passwords + </message> <message name="IDS_ACCESS_LOSS_EXPORT_DIALOG_MESSAGE" desc="The message of the modal dialog proposing the user to export their passwords from Chrome and remove them from Chrome's database (to later import them in Google Play Services)."> Your passwords will be downloaded as a CSV file. They will be visible to anyone who can access the file, including apps. Exported passwords will be deleted from Chrome. </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_EXPORT_DIALOG_TITLE_NO_GMS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_EXPORT_DIALOG_TITLE_NO_GMS.png.sha1 new file mode 100644 index 0000000..77740f0 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_EXPORT_DIALOG_TITLE_NO_GMS.png.sha1
@@ -0,0 +1 @@ +911688edab135d23dfe674edfd7480e370c369ce \ No newline at end of file
diff --git a/chrome/browser/ui/ash/back_gesture/BUILD.gn b/chrome/browser/ui/ash/back_gesture/BUILD.gn index 122777bf..b003107 100644 --- a/chrome/browser/ui/ash/back_gesture/BUILD.gn +++ b/chrome/browser/ui/ash/back_gesture/BUILD.gn
@@ -16,6 +16,7 @@ "//ash/public/cpp", "//base", "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", "//content/public/browser", "//ui/aura", ]
diff --git a/chrome/browser/ui/ash/main_extra_parts/BUILD.gn b/chrome/browser/ui/ash/main_extra_parts/BUILD.gn index 02a7455..7addcb7 100644 --- a/chrome/browser/ui/ash/main_extra_parts/BUILD.gn +++ b/chrome/browser/ui/ash/main_extra_parts/BUILD.gn
@@ -73,6 +73,7 @@ "//chrome/browser/ui/ash/web_view", "//chrome/browser/ui/ash/wm", "//chrome/browser/ui/chromeos/read_write_cards:read_write_cards_manager", + "//chrome/browser/ui/views/select_file_dialog_extension", "//chromeos/ash/components/boca", "//chromeos/ash/components/dbus", "//chromeos/ash/components/dbus/resourced",
diff --git a/chrome/browser/ui/ash/main_extra_parts/DEPS b/chrome/browser/ui/ash/main_extra_parts/DEPS index c2d7acc1..13cbf01f 100644 --- a/chrome/browser/ui/ash/main_extra_parts/DEPS +++ b/chrome/browser/ui/ash/main_extra_parts/DEPS
@@ -61,8 +61,8 @@ "+chrome/browser/ui/ash/wallpaper", "+chrome/browser/ui/ash/web_view", "+chrome/browser/ui/chromeos/read_write_cards", - "+chrome/browser/ui/views/select_file_dialog_extension_factory.h", - "+chrome/browser/ui/views/select_file_dialog_extension.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h", + "+chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h", "+chrome/browser/ui/views/tabs", "+chrome/common", ]
diff --git a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc index 50b7406..e458f56e 100644 --- a/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc +++ b/chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.cc
@@ -86,8 +86,8 @@ #include "chrome/browser/ui/ash/web_view/ash_web_view_factory_impl.h" #include "chrome/browser/ui/ash/wm/tab_cluster_ui_client.h" #include "chrome/browser/ui/chromeos/read_write_cards/read_write_cards_manager_impl.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" -#include "chrome/browser/ui/views/select_file_dialog_extension_factory.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h" #include "chrome/browser/ui/views/tabs/tab_scrubber_chromeos.h" #include "chromeos/ash/components/boca/boca_role_util.h" #include "chromeos/ash/components/dbus/dbus_thread_manager.h"
diff --git a/chrome/browser/ui/ash/shelf/BUILD.gn b/chrome/browser/ui/ash/shelf/BUILD.gn index 692a784..872b0c7 100644 --- a/chrome/browser/ui/ash/shelf/BUILD.gn +++ b/chrome/browser/ui/ash/shelf/BUILD.gn
@@ -79,7 +79,10 @@ "standalone_browser_extension_app_shelf_item_controller.h", ] - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//ash",
diff --git a/chrome/browser/ui/ash/wm/BUILD.gn b/chrome/browser/ui/ash/wm/BUILD.gn index da93d3e..2701115 100644 --- a/chrome/browser/ui/ash/wm/BUILD.gn +++ b/chrome/browser/ui/ash/wm/BUILD.gn
@@ -12,7 +12,10 @@ "tab_cluster_ui_client.h", ] - public_deps = [ "//chrome/browser:browser_public_dependencies" ] + public_deps = [ + "//chrome/browser:browser_public_dependencies", + "//chrome/browser/ui/tabs:tab_strip_model_observer", + ] deps = [ "//ash/public/cpp",
diff --git a/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc index 3c23f56..ace987a 100644 --- a/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc +++ b/chrome/browser/ui/autofill/autofill_suggestion_controller_utils.cc
@@ -93,6 +93,7 @@ case SuggestionType::kMixedFormMessage: case SuggestionType::kPasswordEntry: case SuggestionType::kPasswordFieldByFieldFilling: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kSeparator: case SuggestionType::kTitle: case SuggestionType::kVirtualCreditCardEntry:
diff --git a/chrome/browser/ui/content_settings/BUILD.gn b/chrome/browser/ui/content_settings/BUILD.gn new file mode 100644 index 0000000..c097f9a --- /dev/null +++ b/chrome/browser/ui/content_settings/BUILD.gn
@@ -0,0 +1,134 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_win || is_mac || is_linux || is_chromeos) + +source_set("content_settings") { + sources = [] + deps = [] + + if (!is_android) { + sources += [ + "content_setting_bubble_model.h", + "content_setting_bubble_model_delegate.h", + "content_setting_image_model.h", + "content_setting_image_model_states.h", + ] + } + + public_deps = [ + "//base", + "//chrome/app/vector_icons:vector_icons", + "//chrome/browser/ui/blocked_content", + "//components/content_settings/browser", + "//components/content_settings/core/common", + "//components/custom_handlers", + "//services/device/public/cpp/geolocation:buildflags", + ] +} + +source_set("impl") { + sources = [] + + if (!is_android) { + sources += [ + "content_setting_bubble_model.cc", + "content_setting_image_model.cc", + "content_setting_image_model_states.cc", + ] + } + + public_deps = [ "//chrome/browser:browser_public_dependencies" ] + + deps = [ + ":content_settings", + "//chrome/app:generated_resources", + "//chrome/app/theme:theme_resources", + "//chrome/browser:browser_process", + "//chrome/browser/media/webrtc", + "//chrome/browser/permissions", + "//chrome/browser/profiles:profile", + "//chrome/browser/ui:ui_features", + "//chrome/browser/web_applications", + "//chrome/browser/web_applications", + "//chrome/common:non_code_constants", + "//components/content_settings/core/browser", + "//components/content_settings/core/browser:cookie_settings", + "//components/infobars/content:content", + "//components/no_state_prefetch/browser", + "//components/subresource_filter/content/browser", + "//components/subresource_filter/core/browser", + "//services/device/public/cpp:device_features", + ] +} + +source_set("browser_tests") { + testonly = true + sources = [] + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + if (!is_android) { + sources += [ + "content_setting_bubble_model_browsertest.cc", + "content_setting_image_model_browsertest.cc", + "framebust_block_browsertest.cc", + ] + } + + deps = [ + ":content_settings", + ":test_support", + "//chrome/browser:browser_process", + "//chrome/browser/profiles:profile", + "//chrome/test:test_support", + "//components/content_settings/core/test:test_support", + "//components/subresource_filter/core/browser:browser", + ] +} + +source_set("test_support") { + testonly = true + sources = [ + "fake_owner.cc", + "fake_owner.h", + ] + + deps = [ ":content_settings" ] +} + +source_set("unit_tests") { + testonly = true + sources = [] + deps = [] + + if (!is_android) { + sources += [ + "content_setting_bubble_model_unittest.cc", + "content_setting_image_model_unittest.cc", + ] + } + + if (is_mac) { + sources += [ + "content_setting_media_image_model_unittest.mm", + "media_authorization_wrapper_test.h", + "media_authorization_wrapper_test.mm", + ] + deps += [ "//chrome/browser/permissions/system" ] + } + + deps += [ + ":content_settings", + ":test_support", + "//chrome/browser/permissions", + "//chrome/browser/permissions:unit_tests", + "//chrome/browser/ui:ui_features", + "//chrome/browser/web_applications:web_applications_test_support", + "//chrome/test:test_support", + "//components/custom_handlers:test_support", + "//components/infobars/content:content", + "//components/no_state_prefetch/browser", + "//services/data_decoder/public/cpp:test_support", + ] +}
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn index b92c52c8..f6af5f72 100644 --- a/chrome/browser/ui/tabs/BUILD.gn +++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -23,3 +23,33 @@ source_set("tab_enums") { sources = [ "tab_enums.h" ] } + +# This is pulled out in a standalone target as its include is spread +# all around //chrome/browser and it was part of //chrome/browser/ui:ui. +# As a result, it created quite a few of circular dependencies when +# directories in //c/b and //c/b/ui began to be modularized. +# TODO(crbug.com/364501603): modularize all the rest. +if (!is_android) { + source_set("tab_strip_model_observer") { + sources = [ + "tab_change_type.h", + "tab_strip_model_observer.h", + ] + public_deps = [ + "//base", + "//components/sessions:session_id", + "//components/tab_groups", + "//ui/base", + ] + } + + source_set("tab_strip_model_observer_impl") { + sources = [ "tab_strip_model_observer.cc" ] + public_deps = [ "//chrome/browser:browser_public_dependencies" ] + deps = [ + ":tab_strip_model_observer", + "//base", + "//content/public/browser", + ] + } +}
diff --git a/chrome/browser/ui/views/OWNERS b/chrome/browser/ui/views/OWNERS index 58aed401e..eb6b5693 100644 --- a/chrome/browser/ui/views/OWNERS +++ b/chrome/browser/ui/views/OWNERS
@@ -28,6 +28,4 @@ per-file intent_picker_*test*=file://chrome/browser/apps/intent_helper/OWNERS -per-file select_file_dialog_extension*=file://ui/file_manager/OWNERS - per-file incognito_clear_browsing_data_dialog*=file://chrome/browser/incognito/OWNERS
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc index a19e4d7..0d7bbc5 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_row_factory_utils.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/ui/views/autofill/popup/popup_base_view.h" #include "chrome/browser/ui/views/autofill/popup/popup_cell_utils.h" #include "chrome/browser/ui/views/autofill/popup/popup_row_content_view.h" +#include "chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h" #include "chrome/browser/ui/views/autofill/popup/popup_row_view.h" #include "chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.h" #include "chrome/browser/ui/views/autofill/popup/popup_view_utils.h" @@ -636,6 +637,18 @@ PopupRowWithButtonView::ButtonBehavior::kShowOnHoverOrSelect); } +// Creates the row for the `SuggestionType::kPredictionImprovementsFeedback` +// suggestion. +std::unique_ptr<PopupRowPredictionImprovementsFeedbackView> +CreatePredictionImprovementsFeedbackRow( + base::WeakPtr<AutofillPopupController> controller, + PopupRowView::AccessibilitySelectionDelegate& a11y_selection_delegate, + PopupRowView::SelectionDelegate& selection_delegate, + int line_number) { + return std::make_unique<PopupRowPredictionImprovementsFeedbackView>( + a11y_selection_delegate, selection_delegate, controller, line_number); +} + } // namespace std::unique_ptr<PopupRowView> CreatePopupRowView( @@ -656,6 +669,11 @@ controller, a11y_selection_delegate, selection_delegate, line_number); } + if (type == SuggestionType::kPredictionImprovementsFeedback) { + return CreatePredictionImprovementsFeedbackRow( + controller, a11y_selection_delegate, selection_delegate, line_number); + } + if (IsFooterSuggestionType(type)) { return std::make_unique<PopupRowView>( a11y_selection_delegate, selection_delegate, controller, line_number,
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.cc new file mode 100644 index 0000000..108b517 --- /dev/null +++ b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.cc
@@ -0,0 +1,151 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h" + +#include <memory> + +#include "base/functional/bind.h" +#include "base/i18n/rtl.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#include "chrome/browser/ui/views/autofill/popup/popup_cell_utils.h" +#include "chrome/browser/ui/views/autofill/popup/popup_row_content_view.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "components/autofill/core/browser/ui/suggestion_button_action.h" +#include "components/vector_icons/vector_icons.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/controls/button/button_controller.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/image_button_factory.h" +#include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/box_layout_view.h" +#include "ui/views/view.h" + +namespace autofill { + +namespace { + +// The size of the icons used in the buttons. +constexpr int kIconSize = 20; + +// The button radius used to paint the background. +constexpr int kButtonRadius = 12; + +// Creates the suggestion container view with its `text`. +std::unique_ptr<PopupRowContentView> CreateFeedbackContentView( + const std::u16string& text) { + auto feedback_container = std::make_unique<PopupRowContentView>(); + auto* layout = + feedback_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, + popup_cell_utils::GetMarginsForContentCell())); + layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + feedback_container->AddChildView(views::Builder<views::Label>() + .SetText(text) + .SetMultiLine(true) + .SetHorizontalAlignment(gfx::ALIGN_LEFT) + .Build()); + layout->SetFlexForView(feedback_container->children()[0], 1); + layout->set_between_child_spacing( + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_LABEL_HORIZONTAL_LIST)); + + return feedback_container; +} + +void SetHoverStyleImageButton(views::ImageButton* button, bool hover) { + views::InkDrop::Get(button->ink_drop_view())->GetInkDrop()->SetHovered(hover); +} + +std::unique_ptr<views::ImageButton> CreateFeedbackButton( + const gfx::VectorIcon& icon, + base::RepeatingClosure button_action) { + CHECK(icon.name == vector_icons::kThumbUpIcon.name || + icon.name == vector_icons::kThumbDownIcon.name); + + std::unique_ptr<views::ImageButton> button = + views::CreateVectorImageButtonWithNativeTheme(button_action, icon, + kIconSize); + const bool is_thumbs_up = icon.name == vector_icons::kThumbUpIcon.name; + // TODO(b/362468426): Make these strings come from a finch config. + const std::u16string tooltip = + is_thumbs_up ? u"thumbs up tooltip" : u"thumbs down tooltip"; + const std::u16string accessible_name = is_thumbs_up + ? u"thumbs up accessible name" + : u"thumbs down accessible name"; + + views::InstallFixedSizeCircleHighlightPathGenerator(button.get(), + kButtonRadius); + button->SetPreferredSize(gfx::Size(kButtonRadius * 2, kButtonRadius * 2)); + button->SetTooltipText(tooltip); + button->GetViewAccessibility().SetRole(ax::mojom::Role::kMenuItem); + button->GetViewAccessibility().SetName(accessible_name); + button->SetLayoutManager(std::make_unique<views::BoxLayout>()); + button->GetViewAccessibility().SetIsIgnored(true); + return button; +} + +} // namespace + +PopupRowPredictionImprovementsFeedbackView:: + PopupRowPredictionImprovementsFeedbackView( + AccessibilitySelectionDelegate& a11y_selection_delegate, + SelectionDelegate& selection_delegate, + base::WeakPtr<AutofillPopupController> controller, + int line_number) + : PopupRowView( + a11y_selection_delegate, + selection_delegate, + controller, + line_number, + /*content_view=*/ + CreateFeedbackContentView( + controller->GetSuggestionAt(line_number).main_text.value)) { + // Create the feedback buttons. + auto* buttons_wrapper = + GetContentView().AddChildView(std::make_unique<views::BoxLayoutView>()); + buttons_wrapper->SetBetweenChildSpacing( + ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_LABEL_HORIZONTAL_LIST)); + thumbs_up_button_ = buttons_wrapper->AddChildView(CreateFeedbackButton( + vector_icons::kThumbUpIcon, + base::BindRepeating( + &AutofillPopupController::PerformButtonActionForSuggestion, + controller, line_number, + PredictionImprovementsButtonActions::kThumbsUpClicked))); + thumbs_down_button_ = buttons_wrapper->AddChildView(CreateFeedbackButton( + vector_icons::kThumbDownIcon, + base::BindRepeating( + &AutofillPopupController::PerformButtonActionForSuggestion, + controller, line_number, + PredictionImprovementsButtonActions::kThumbsDownClicked))); + + auto* content_layout = + static_cast<views::BoxLayout*>(GetContentView().GetLayoutManager()); + content_layout->SetFlexForView(buttons_wrapper, 0); +} + +PopupRowPredictionImprovementsFeedbackView:: + ~PopupRowPredictionImprovementsFeedbackView() = default; + +void PopupRowPredictionImprovementsFeedbackView::SetSelectedCell( + std::optional<CellType> cell) { + autofill::PopupRowView::SetSelectedCell(cell); + if (cell != CellType::kContent) { + // When the row is not selected, no button should have a hover style. + SetHoverStyleImageButton(thumbs_up_button_, /*hover=*/false); + SetHoverStyleImageButton(thumbs_down_button_, /*hover=*/false); + } +} + +BEGIN_METADATA(PopupRowPredictionImprovementsFeedbackView) +END_METADATA + +} // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h new file mode 100644 index 0000000..7b07003 --- /dev/null +++ b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h
@@ -0,0 +1,56 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_POPUP_POPUP_ROW_PREDICTION_IMPROVEMENTS_FEEDBACK_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_POPUP_POPUP_ROW_PREDICTION_IMPROVEMENTS_FEEDBACK_VIEW_H_ + +#include <memory> +#include <optional> +#include <string> + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/views/autofill/popup/popup_row_view.h" +#include "ui/base/metadata/metadata_header_macros.h" + +namespace views { +class ImageButton; +} // namespace views + +namespace autofill { + +class AutofillPopupController; + +// A class for prediction improvements suggestions feedback. +class PopupRowPredictionImprovementsFeedbackView : public PopupRowView { + METADATA_HEADER(PopupRowPredictionImprovementsFeedbackView, PopupRowView) + + public: + PopupRowPredictionImprovementsFeedbackView( + AccessibilitySelectionDelegate& a11y_selection_delegate, + SelectionDelegate& selection_delegate, + base::WeakPtr<AutofillPopupController> controller, + int line_number); + + PopupRowPredictionImprovementsFeedbackView( + const PopupRowPredictionImprovementsFeedbackView&) = delete; + PopupRowPredictionImprovementsFeedbackView& operator=( + const PopupRowPredictionImprovementsFeedbackView&) = delete; + ~PopupRowPredictionImprovementsFeedbackView() override; + + views::ImageButton* GetThumbsUpButtonForTest() { return thumbs_up_button_; } + views::ImageButton* GetThumbsDownButtonForTest() { + return thumbs_down_button_; + } + + // PopupRowView: + void SetSelectedCell(std::optional<CellType> cell) override; + + private: + raw_ptr<views::ImageButton> thumbs_up_button_ = nullptr; + raw_ptr<views::ImageButton> thumbs_down_button_ = nullptr; +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_POPUP_POPUP_ROW_PREDICTION_IMPROVEMENTS_FEEDBACK_VIEW_H_
diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view_unittest.cc new file mode 100644 index 0000000..a7caa708 --- /dev/null +++ b/chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view_unittest.cc
@@ -0,0 +1,125 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view.h" + +#include <memory> +#include <utility> + +#include "base/functional/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/test/mock_callback.h" +#include "chrome/browser/ui/autofill/mock_autofill_popup_controller.h" +#include "chrome/browser/ui/views/autofill/popup/mock_accessibility_selection_delegate.h" +#include "chrome/browser/ui/views/autofill/popup/mock_selection_delegate.h" +#include "chrome/browser/ui/views/autofill/popup/popup_row_content_view.h" +#include "chrome/test/views/chrome_views_test_base.h" +#include "components/autofill/core/browser/ui/suggestion.h" +#include "components/autofill/core/browser/ui/suggestion_type.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/test/event_generator.h" +#include "ui/gfx/geometry/point.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_utils.h" + +namespace autofill { + +using ::testing::NiceMock; +using ::testing::VariantWith; + +class PopupRowPredictionImprovementsFeedbackViewTest + : public ChromeViewsTestBase { + public: + // views::ViewsTestBase: + void SetUp() override { + ChromeViewsTestBase::SetUp(); + widget_ = CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET); + generator_ = std::make_unique<ui::test::EventGenerator>( + GetRootWindow(widget_.get())); + controller_.set_suggestions( + {Suggestion(u"Improved predictions", + SuggestionType::kPredictionImprovementsFeedback)}); + } + + void ShowView( + std::unique_ptr<PopupRowPredictionImprovementsFeedbackView> view) { + view_ = widget_->SetContentsView(std::move(view)); + widget_->Show(); + } + + void TearDown() override { + view_ = nullptr; + generator_.reset(); + widget_.reset(); + ChromeViewsTestBase::TearDown(); + } + + void CreateFeedbackRowAndGetButtons() { + auto row = std::make_unique<PopupRowPredictionImprovementsFeedbackView>( + a11y_selection_delegate(), selection_delegate(), + controller_.GetWeakPtr(), /*line_number=*/0); + ShowView(std::move(row)); + } + + protected: + MockAutofillPopupController& controller() { return controller_; } + MockAccessibilitySelectionDelegate& a11y_selection_delegate() { + return mock_a11y_selection_delegate_; + } + MockSelectionDelegate& selection_delegate() { + return mock_selection_delegate_; + } + ui::test::EventGenerator& generator() { return *generator_; } + PopupRowPredictionImprovementsFeedbackView& view() { return *view_; } + views::Widget& widget() { return *widget_; } + + private: + NiceMock<MockAccessibilitySelectionDelegate> mock_a11y_selection_delegate_; + NiceMock<MockAutofillPopupController> controller_; + std::unique_ptr<views::Widget> widget_; + std::unique_ptr<ui::test::EventGenerator> generator_; + NiceMock<MockSelectionDelegate> mock_selection_delegate_; + raw_ptr<PopupRowPredictionImprovementsFeedbackView> view_ = nullptr; +}; + +TEST_F(PopupRowPredictionImprovementsFeedbackViewTest, + ThumbsUpButtonClickTriggersCallback) { + CreateFeedbackRowAndGetButtons(); + + view().SetSelectedCell(PopupRowView::CellType::kContent); + + // Assert thumbs up button callback is run when clicked. + EXPECT_CALL(controller(), + PerformButtonActionForSuggestion( + /*line_numer=*/0, + VariantWith<PredictionImprovementsButtonActions>( + PredictionImprovementsButtonActions::kThumbsUpClicked))); + // In test env we have to manually set the bounds when a view becomes visible. + generator().MoveMouseTo( + view().GetThumbsUpButtonForTest()->GetBoundsInScreen().CenterPoint()); + generator().ClickLeftButton(); +} + +TEST_F(PopupRowPredictionImprovementsFeedbackViewTest, + ThumbsDownButtonClickTriggersCallback) { + CreateFeedbackRowAndGetButtons(); + + view().SetSelectedCell(PopupRowView::CellType::kContent); + + // Assert thumbs down button callback is run when clicked. + EXPECT_CALL( + controller(), + PerformButtonActionForSuggestion( + /*line_numer=*/0, + VariantWith<PredictionImprovementsButtonActions>( + PredictionImprovementsButtonActions::kThumbsDownClicked))); + generator().MoveMouseTo( + view().GetThumbsDownButtonForTest()->GetBoundsInScreen().CenterPoint()); + generator().ClickLeftButton(); +} + +} // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc index 4dc0c1b..3b16bc11 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_utils.cc
@@ -494,6 +494,7 @@ case SuggestionType::kPasswordAccountStorageOptInAndGenerate: case SuggestionType::kPasswordAccountStorageReSignin: case SuggestionType::kPasswordFieldByFieldFilling: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kScanCreditCard: case SuggestionType::kSeePromoCodeDetails: case SuggestionType::kSeparator:
diff --git a/chrome/browser/ui/views/select_file_dialog_extension/BUILD.gn b/chrome/browser/ui/views/select_file_dialog_extension/BUILD.gn new file mode 100644 index 0000000..c614d9f --- /dev/null +++ b/chrome/browser/ui/views/select_file_dialog_extension/BUILD.gn
@@ -0,0 +1,73 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") + +assert(is_chromeos_ash) + +static_library("select_file_dialog_extension") { + sources = [ + "select_file_dialog_extension.cc", + "select_file_dialog_extension.h", + "select_file_dialog_extension_factory.cc", + "select_file_dialog_extension_factory.h", + ] + + public_deps = [ "//chrome/browser:browser_public_dependencies" ] + + deps = [ + "//chrome/browser/apps/platform_apps", + "//chrome/browser/ash/arc/fileapi", + "//chrome/browser/ash/extensions/file_manager", + "//chrome/browser/ash/file_manager", + "//chrome/browser/ash/login/ui", + "//chrome/browser/ash/policy/dlp", + "//chrome/browser/ash/profiles", + "//chrome/browser/chromeos/policy/dlp", + "//chrome/browser/extensions", + "//chrome/browser/ui/webui/ash/system_web_dialog", + "//ui/chromeos/styles:cros_tokens_color_mappings_generator", + ] + + allow_circular_includes_from = [ + "//chrome/browser/ash/file_manager", + "//chrome/browser/ash/arc/fileapi", + "//chrome/browser/ash/extensions/file_manager", + ] +} + +source_set("browser_tests") { + testonly = true + + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + sources = [ "select_file_dialog_extension_browsertest.cc" ] + + deps = [ + ":select_file_dialog_extension", + "//chrome/browser/ash/file_manager:test_support", + "//chrome/browser/ash/policy/dlp", + "//chrome/browser/chromeos/policy/dlp", + "//chrome/browser/chromeos/policy/dlp/test:test_support", + "//chrome/browser/ui", + "//chrome/browser/ui:browser_navigator_params_headers", + "//chrome/browser/ui/ash/keyboard", + "//chrome/common:constants", + "//chrome/test:test_support", + "//chrome/test:test_support_ui", + ] +} + +source_set("unit_tests") { + testonly = true + + sources = [ "select_file_dialog_extension_unittest.cc" ] + + deps = [ + ":select_file_dialog_extension", + "//base", + "//testing/gtest", + "//ui/shell_dialogs", + ] +}
diff --git a/chrome/browser/ui/views/select_file_dialog_extension/OWNERS b/chrome/browser/ui/views/select_file_dialog_extension/OWNERS new file mode 100644 index 0000000..31b8eee --- /dev/null +++ b/chrome/browser/ui/views/select_file_dialog_extension/OWNERS
@@ -0,0 +1 @@ +file://ui/file_manager/OWNERS \ No newline at end of file
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.cc similarity index 99% rename from chrome/browser/ui/views/select_file_dialog_extension.cc rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.cc index a6befc69..8872579 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include <map> #include <memory>
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.h b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h similarity index 96% rename from chrome/browser/ui/views/select_file_dialog_extension.h rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h index d26e1db9..b31f070 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension.h +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_H_ -#define CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_H_ +#define CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_H_ #include <memory> #include <optional> @@ -203,4 +203,4 @@ base::WeakPtrFactory<SelectFileDialogExtension> weak_factory_{this}; }; -#endif // CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_H_ +#endif // CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_H_
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_browsertest.cc similarity index 99% rename from chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_browsertest.cc index 93be5dfe..a36cd3b73 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_browsertest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include <memory>
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_factory.cc b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.cc similarity index 74% rename from chrome/browser/ui/views/select_file_dialog_extension_factory.cc rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.cc index 87b7ea1..76adafc7 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_factory.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/select_file_dialog_extension_factory.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h" -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include "ui/shell_dialogs/select_file_policy.h" SelectFileDialogExtensionFactory::SelectFileDialogExtensionFactory() {
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_factory.h b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h similarity index 78% rename from chrome/browser/ui/views/select_file_dialog_extension_factory.h rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h index bc401999..07adf9d 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_factory.h +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_factory.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_ -#define CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_ +#define CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_ #include "ui/shell_dialogs/select_file_dialog.h" #include "ui/shell_dialogs/select_file_dialog_factory.h" @@ -26,4 +26,4 @@ std::unique_ptr<ui::SelectFilePolicy> policy) override; }; -#endif // CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_ +#endif // CHROME_BROWSER_UI_VIEWS_SELECT_FILE_DIALOG_EXTENSION_SELECT_FILE_DIALOG_EXTENSION_FACTORY_H_
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_unittest.cc similarity index 97% rename from chrome/browser/ui/views/select_file_dialog_extension_unittest.cc rename to chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_unittest.cc index 54eff7a8..85a49d95 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_unittest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/select_file_dialog_extension.h" +#include "chrome/browser/ui/views/select_file_dialog_extension/select_file_dialog_extension.h" #include <memory>
diff --git a/chrome/browser/ui/views/toolbar/BUILD.gn b/chrome/browser/ui/views/toolbar/BUILD.gn index aa1d655..dae4920 100644 --- a/chrome/browser/ui/views/toolbar/BUILD.gn +++ b/chrome/browser/ui/views/toolbar/BUILD.gn
@@ -116,6 +116,7 @@ "//chrome/browser/ui/browser_window", "//chrome/browser/ui/color:mixers", "//chrome/browser/ui/tabs:tab_enums", + "//chrome/browser/ui/tabs:tab_strip_model_observer", "//chrome/browser/ui/views/side_panel:side_panel_enums", "//chrome/common:buildflags", "//chrome/common:chrome_features",
diff --git a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn index 08f9399..8d99b84 100644 --- a/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn +++ b/chrome/browser/ui/webui/ash/lock_screen_reauth/BUILD.gn
@@ -35,6 +35,7 @@ "//chrome/browser/profiles:profile", "//chrome/browser/ui/webui/ash/system_web_dialog", "//chrome/common", + "//chromeos/ash/components/http_auth_dialog", "//chromeos/ash/components/login/auth/public:authpublic", "//chromeos/ash/components/network", "//chromeos/services/network_config/public/mojom",
diff --git a/chrome/browser/ui/webui/ash/lock_screen_reauth/DEPS b/chrome/browser/ui/webui/ash/lock_screen_reauth/DEPS index d67c876..969b6955 100644 --- a/chrome/browser/ui/webui/ash/lock_screen_reauth/DEPS +++ b/chrome/browser/ui/webui/ash/lock_screen_reauth/DEPS
@@ -10,7 +10,6 @@ # Existing dependencies within //chrome. There is an active effort to # refactor //chrome/browser/ui/ash to break these dependencies; see b/332804822. # Whenever possible, avoid adding new //chrome dependencies to this list. - "+chrome/browser/ash/http_auth_dialog.h", "+chrome/browser/ash/login", "+chrome/browser/ash/login/lock/online_reauth", "+chrome/browser/ash/login/ui",
diff --git a/chrome/browser/ui/webui/ash/lock_screen_reauth/lock_screen_reauth_dialogs.h b/chrome/browser/ui/webui/ash/lock_screen_reauth/lock_screen_reauth_dialogs.h index 9287af4a..f782720 100644 --- a/chrome/browser/ui/webui/ash/lock_screen_reauth/lock_screen_reauth_dialogs.h +++ b/chrome/browser/ui/webui/ash/lock_screen_reauth/lock_screen_reauth_dialogs.h
@@ -8,12 +8,12 @@ #include "base/memory/raw_ptr.h" #include "base/observer_list.h" #include "base/scoped_observation.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" #include "chrome/browser/ui/webui/ash/lock_screen_reauth/base_lock_dialog.h" #include "chrome/browser/ui/webui/ash/login/network_state_informer.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/network_state_handler_observer.h" #include "components/web_modal/web_contents_modal_dialog_host.h"
diff --git a/chrome/browser/ui/webui/ash/login/BUILD.gn b/chrome/browser/ui/webui/ash/login/BUILD.gn index ba0f945..2fdec38 100644 --- a/chrome/browser/ui/webui/ash/login/BUILD.gn +++ b/chrome/browser/ui/webui/ash/login/BUILD.gn
@@ -202,6 +202,7 @@ "//chrome/browser/ui/webui/ash/login/mojom", "//chrome/common", "//chromeos/ash/components/dbus/os_install", + "//chromeos/ash/components/http_auth_dialog", "//chromeos/ash/components/login/auth", "//chromeos/ash/components/login/auth/public:authpublic", "//chromeos/ash/components/login/auth/public:challenge_response_key",
diff --git a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h index 5ef3ecb..a61e195 100644 --- a/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/ash/login/gaia_screen_handler.h
@@ -12,7 +12,6 @@ #include "base/command_line.h" #include "base/memory/weak_ptr.h" #include "base/values.h" -#include "chrome/browser/ash/http_auth_dialog.h" #include "chrome/browser/ash/login/login_client_cert_usage_observer.h" #include "chrome/browser/ash/login/screens/error_screen.h" #include "chrome/browser/ash/login/screens/network_error.h" @@ -22,6 +21,7 @@ #include "chrome/browser/ui/webui/ash/login/base_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/network_state_informer.h" #include "chrome/browser/ui/webui/ash/login/online_login_utils.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include "chromeos/components/security_token_pin/constants.h" #include "components/user_manager/user_type.h" #include "mojo/public/cpp/bindings/receiver.h"
diff --git a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc index 7e5b83f..d92938b8 100644 --- a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc +++ b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui.h" #include "base/check_deref.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/json/json_writer.h" @@ -29,6 +30,7 @@ #include "chrome/grit/signin_resources.h" #include "components/search_engines/search_engine_choice/search_engine_choice_service.h" #include "components/search_engines/search_engine_choice/search_engine_choice_utils.h" +#include "components/search_engines/search_engines_switches.h" #include "components/search_engines/template_url.h" #include "components/signin/public/base/signin_switches.h" #include "components/strings/grit/components_branded_strings.h" @@ -106,6 +108,8 @@ IDS_SHORT_PRODUCT_LOGO_ALT_TEXT); source->AddLocalizedString("moreButtonText", IDS_SEARCH_ENGINE_CHOICE_MORE_BUTTON); + source->AddLocalizedString("guestCheckboxText", + IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX); source->AddResourcePath("images/left_illustration.svg", IDR_SIGNIN_IMAGES_SHARED_LEFT_BANNER_SVG); source->AddResourcePath("images/left_illustration_dark.svg", @@ -120,6 +124,10 @@ source->AddResourcePath("signin_vars.css.js", IDR_SIGNIN_SIGNIN_VARS_CSS_JS); source->AddString("choiceList", GetChoiceListJSON(profile_.get())); + source->AddBoolean("showGuestCheckbox", + base::FeatureList::IsEnabled( + switches::kSearchEngineChoiceGuestExperience) && + profile_->IsGuestSession()); webui::SetupWebUIDataSource( source,
diff --git a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc index 906cd70c..1036237 100644 --- a/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc +++ b/chrome/browser/ui/webui/search_engine_choice/search_engine_choice_ui_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engine_choice/search_engine_choice_dialog_service.h" @@ -22,8 +23,10 @@ #include "chrome/browser/ui/test/test_browser_dialog.h" #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/mixin_based_in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/search_engines/prepopulated_engines.h" +#include "components/search_engines/search_engines_switches.h" #include "components/search_engines/template_url_data.h" #include "components/search_engines/template_url_prepopulate_data.h" #include "components/search_engines/template_url_service.h" @@ -113,6 +116,7 @@ bool first_snippet_text_larger = false; bool display_info_dialog = false; bool wait_for_banners_displayed = true; + bool is_guest_session = false; gfx::Size dialog_dimensions = gfx::Size(988, 900); }; @@ -148,6 +152,10 @@ {.test_suffix = "InfoDialogDarkTheme", .use_dark_theme = true, .display_info_dialog = true}, + {.test_suffix = "Guest", .is_guest_session = true}, + {.test_suffix = "GuestRtl", + .use_right_to_left_language = true, + .is_guest_session = true}, #endif // We enable the test on platforms other than Windows with the smallest // height due to a small maximum window height set by the operating system. @@ -244,11 +252,29 @@ /*force_chrome_build=*/true)), pixel_test_mixin_(&mixin_host_, GetParam().use_dark_theme, - GetParam().use_right_to_left_language) { - } + GetParam().use_right_to_left_language) {} ~SearchEngineChoiceUIPixelTest() override = default; + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + + if (GetParam().is_guest_session) { + ui_test_utils::BrowserChangeObserver browser_added_observer( + nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); + + CreateGuestBrowser(); + Browser* new_browser = browser_added_observer.Wait(); + ASSERT_TRUE(new_browser); + ASSERT_NE(new_browser, browser()); + ASSERT_TRUE(new_browser->profile()->IsGuestSession()); + + CloseBrowserSynchronously(browser()); + SelectFirstBrowser(); + ASSERT_EQ(new_browser, browser()); + } + } + void SetUpInProcessBrowserTestFixture() override { InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); create_services_subscription_ = @@ -330,6 +356,8 @@ private: base::AutoReset<bool> scoped_chrome_build_override_; + base::test::ScopedFeatureList feature_list_{ + switches::kSearchEngineChoiceGuestExperience}; PixelTestConfigurationMixin pixel_test_mixin_; base::CallbackListSubscription create_services_subscription_; };
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index e257291..12c79fc 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1263,7 +1263,16 @@ {"experimentalAdvancedFeature3Sublabel", IDS_SETTINGS_EXPERIMENTAL_ADVANCED_FEATURE3_SUBLABEL}, {"autofillPredictionImprovementsPageTitle", - IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_PAGE_TITLE}}; + IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_PAGE_TITLE}, + {"autofillPredictionImprovementsWhenOnSavedInfo", + IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_WHEN_ON_SAVED_INFO}, + {"autofillPredictionImprovementsWhenOnAdapts", + IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_WHEN_ON_ADAPTS}, + {"autofillPredictionImprovementsToConsiderInfoLocal", + IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_TO_CONSIDER_INFO_LOCAL}, + {"autofillPredictionImprovementsToConsiderDataUsage", + IDS_SETTINGS_AUTOFILL_PREDICTION_IMPROVEMENTS_TO_CONSIDER_DATA_USAGE}, + }; GURL google_password_manager_url = GetGooglePasswordManagerURL( password_manager::ManagePasswordsReferrer::kChromeSettings); @@ -2335,13 +2344,7 @@ html_source->AddString("searchNoResultsHelp", help_text); } -void AddSearchStrings(content::WebUIDataSource* html_source, - Profile* profile -#if BUILDFLAG(IS_CHROMEOS) - , - bool for_primary_profile -#endif // BUILDFLAG(IS_CHROMEOS) -) { +void AddSearchStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"searchEnginesManageSiteSearch", IDS_SETTINGS_SEARCH_MANAGE_SEARCH_ENGINES_AND_SITE_SEARCH}, @@ -2359,20 +2362,6 @@ IDS_SEARCH_ENGINE_CHOICE_SETTINGS_CONFIRMATION_TOAST_LABEL}, }; html_source->AddLocalizedStrings(kLocalizedStrings); - -#if BUILDFLAG(IS_CHROMEOS) - if (for_primary_profile) { - html_source->AddLocalizedString( - "searchExplanation", IDS_SETTINGS_SEARCH_EXPLANATION_PRIMARY_PROFILE); - } else { - html_source->AddLocalizedString("searchExplanation", - IDS_SETTINGS_SEARCH_EXPLANATION); - } -#else // !BUILDFLAG(IS_CHROMEOS) - html_source->AddLocalizedString("searchExplanation", - IDS_SETTINGS_SEARCH_EXPLANATION); -#endif // BUILDFLAG(IS_CHROMEOS) - html_source->AddString("searchExplanationLearnMoreURL", chrome::kOmniboxLearnMoreURL); @@ -3740,16 +3729,7 @@ AddResetStrings(html_source, profile); AddSearchEnginesStrings(html_source); AddSearchInSettingsStrings(html_source); -#if BUILDFLAG(IS_CHROMEOS) -#if BUILDFLAG(IS_CHROMEOS_LACROS) - const bool for_primary_profile = profile->IsMainProfile(); -#else // !BUILDFLAG(IS_CHROMEOS_LACROS) - const bool for_primary_profile = true; -#endif // BUILDFLAG(IS_CHROMEOS_LACROS) - AddSearchStrings(html_source, profile, for_primary_profile); -#else // !BUILDFLAG(IS_CHROMEOS) AddSearchStrings(html_source, profile); -#endif // BUILDFLAG(IS_CHROMEOS) AddSiteSettingsStrings(html_source, profile); AddSiteDataPageStrings(html_source, profile); AddStorageAccessStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index d83da86..7d24453 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -335,12 +335,6 @@ ->FetchPriceEmailPref(); } - const bool is_search_engine_choice_settings_ui = - search_engines::IsChoiceScreenFlagEnabled( - search_engines::ChoicePromo::kAny); - html_source->AddBoolean("searchEngineChoiceSettingsUi", - is_search_engine_choice_settings_ui); - search_engines::SearchEngineChoiceService* search_engine_choice_dialog_service = search_engines::SearchEngineChoiceServiceFactory::GetForProfile(
diff --git a/chrome/browser/ui/webui/support_tool/support_tool_ui.cc b/chrome/browser/ui/webui/support_tool/support_tool_ui.cc index 41c62f6..bebb9529 100644 --- a/chrome/browser/ui/webui/support_tool/support_tool_ui.cc +++ b/chrome/browser/ui/webui/support_tool/support_tool_ui.cc
@@ -346,7 +346,7 @@ GetSupportToolHandler(*issue_details->FindString("caseId"), *issue_details->FindString("emailAddress"), *issue_details->FindString("issueDescription"), - Profile::FromWebUI(web_ui()), + std::nullopt, Profile::FromWebUI(web_ui()), GetIncludedDataCollectorTypes(data_collectors)); this->handler_->CollectSupportData( base::BindOnce(&SupportToolMessageHandler::OnDataCollectionDone,
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index d7dc55c..278c7153 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1725494338-97a3e8780aae7607733234a55f4c36d7c2cd41a5-37f9fd474bd2ba9eb70b2fae98bbe8765bc48ee0.profdata +chrome-android32-main-1725515931-064d218edb5b34ff83dfdf113a31bfd308798105-9debac12cff4b150983771fec461b4646033227e.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 7223390c..814d779 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1725501481-6314aa751e4f039c00a2ebeb9ee74fd19638f75d-6babf55a02eba105e8db6f7b2bb5041abcd90549.profdata +chrome-android64-main-1725521087-7de73b8b09c70607f755c8440a9d10911284aaa4-fdc627bc2bf16f02c4d65e1382f6cdfcbffb5b34.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 1e2a284d..35b9e2e 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1725501481-23af0b65050161958354a0c572c5bc70f3bac880-6babf55a02eba105e8db6f7b2bb5041abcd90549.profdata +chrome-mac-arm-main-1725521087-7732993becd5f01a0464e7c4c4dc5d6a0231c692-fdc627bc2bf16f02c4d65e1382f6cdfcbffb5b34.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index a7e15bb..129282d 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1725494338-3a5f5a737255b675e45312dac88ed24b9eb6b742-37f9fd474bd2ba9eb70b2fae98bbe8765bc48ee0.profdata +chrome-mac-main-1725515931-b880c36a9a6bd9bf18d4b43497f462721209b407-9debac12cff4b150983771fec461b4646033227e.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 4b1f8b9..34f3989 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1725494338-2147b2aee0e6b854ce48e4c84e51cf63e6a8e0a0-37f9fd474bd2ba9eb70b2fae98bbe8765bc48ee0.profdata +chrome-win32-main-1725515931-c4e755804586b8518d055a1bd68e96c101695d18-9debac12cff4b150983771fec461b4646033227e.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 1ee64d8d..36523173 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1725494338-fc84ba578e4d0faa15290a7f33bd56aac98ffc47-37f9fd474bd2ba9eb70b2fae98bbe8765bc48ee0.profdata +chrome-win64-main-1725515931-592bb2362d466fc77f0a60a2dcaeb7f85e0a696b-9debac12cff4b150983771fec461b4646033227e.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 1d1d2d8..bf7417fe 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1973,6 +1973,8 @@ "//chrome/browser/ui/bluetooth", "//chrome/browser/ui/browser_window", "//chrome/browser/ui/color:color_headers", + "//chrome/browser/ui/content_settings", + "//chrome/browser/ui/content_settings:browser_tests", "//chrome/browser/ui/exclusive_access", "//chrome/browser/ui/find_bar:browser_tests", "//chrome/browser/ui/omnibox", @@ -3044,9 +3046,6 @@ "../browser/ui/browser_navigator_iwa_browsertest.cc", "../browser/ui/browser_tab_strip_model_delegate_browsertest.cc", "../browser/ui/browser_tabrestore_browsertest.cc", - "../browser/ui/content_settings/content_setting_bubble_model_browsertest.cc", - "../browser/ui/content_settings/content_setting_image_model_browsertest.cc", - "../browser/ui/content_settings/framebust_block_browsertest.cc", "../browser/ui/exclusive_access/exclusive_access_manager_browsertest.cc", "../browser/ui/exclusive_access/fullscreen_controller_browsertest.cc", "../browser/ui/exclusive_access/pointer_lock_controller_browsertest.cc", @@ -4617,10 +4616,7 @@ ] } if (is_chromeos_ash) { - sources += [ - "../browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc", - "../browser/ui/views/select_file_dialog_extension_browsertest.cc", - ] + sources += [ "../browser/ui/views/frame/system_web_app_non_client_frame_view_browsertest.cc" ] deps += [ "//chromeos/ash/services/multidevice_setup/public/cpp:prefs" ] } else { sources += [ "../browser/ui/views/profiles/profile_customization_bubble_view_browsertest.cc" ] @@ -4980,6 +4976,7 @@ "//chrome/browser/ui/views/editor_menu:views", "//chrome/browser/ui/views/mahi", "//chrome/browser/ui/views/plugin_vm:browser_tests", + "//chrome/browser/ui/views/select_file_dialog_extension:browser_tests", "//chrome/browser/ui/webui/ash:browser_tests", "//chrome/browser/ui/webui/ash/add_supervision", "//chrome/browser/ui/webui/ash/add_supervision:mojo_bindings", @@ -6033,6 +6030,8 @@ "../browser/ai/ai_manager_keyed_service_unittest.cc", "../browser/ai/ai_rewriter_unittest.cc", "../browser/ai/ai_summarizer_unittest.cc", + "../browser/ai/ai_test_utils.cc", + "../browser/ai/ai_test_utils.h", "../browser/ai/ai_text_session_unittest.cc", "../browser/ai/ai_writer_unittest.cc", "../browser/apps/icon_standardizer_unittest.cc", @@ -7261,7 +7260,6 @@ "../browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm", "../browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm", "../browser/ui/cocoa/window_size_autosaver_unittest.mm", - "../browser/ui/content_settings/content_setting_media_image_model_unittest.mm", "../browser/upgrade_detector/directory_monitor_unittest.cc", "../utility/importer/safari_importer_unittest.mm", ] @@ -7828,8 +7826,6 @@ "../browser/ui/color/chrome_color_provider_utils_unittest.cc", "../browser/ui/color/material_new_tab_page_color_mixer_unittest.cc", "../browser/ui/color/new_tab_page_color_mixer_unittest.cc", - "../browser/ui/content_settings/content_setting_bubble_model_unittest.cc", - "../browser/ui/content_settings/content_setting_image_model_unittest.cc", "../browser/ui/exclusive_access/exclusive_access_bubble_unittest.cc", "../browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc", "../browser/ui/extensions/controlled_home_bubble_delegate_unittest.cc", @@ -8280,6 +8276,8 @@ "//chrome/browser/ui/color:color_headers", "//chrome/browser/ui/color:mixers", "//chrome/browser/ui/commerce:unit_tests", + "//chrome/browser/ui/content_settings", + "//chrome/browser/ui/content_settings:unit_tests", "//chrome/browser/ui/cookie_controls:unit_tests", "//chrome/browser/ui/exclusive_access", "//chrome/browser/ui/lens:unit_tests", @@ -10087,6 +10085,7 @@ "../browser/ui/views/autofill/popup/popup_cell_utils_unittest.cc", "../browser/ui/views/autofill/popup/popup_row_content_view_unittest.cc", "../browser/ui/views/autofill/popup/popup_row_factory_utils_unittest.cc", + "../browser/ui/views/autofill/popup/popup_row_prediction_improvements_feedback_view_unittest.cc", "../browser/ui/views/autofill/popup/popup_row_view_unittest.cc", "../browser/ui/views/autofill/popup/popup_row_with_button_view_unittest.cc", "../browser/ui/views/autofill/popup/popup_search_bar_view_unittest.cc",
diff --git a/chrome/test/data/webui/settings/search_page_test.ts b/chrome/test/data/webui/settings/search_page_test.ts index 744b3842..bb058ccc 100644 --- a/chrome/test/data/webui/settings/search_page_test.ts +++ b/chrome/test/data/webui/settings/search_page_test.ts
@@ -8,7 +8,7 @@ import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import type {SettingsSearchEngineListDialogElement, SearchEnginesInfo, SettingsSearchPageElement} from 'chrome://settings/settings.js'; -import {SearchEnginesBrowserProxyImpl, loadTimeData} from 'chrome://settings/settings.js'; +import {SearchEnginesBrowserProxyImpl} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertNotReached, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; @@ -35,114 +35,9 @@ suite('SearchPageTests', function() { let page: SettingsSearchPageElement; let browserProxy: TestSearchEnginesBrowserProxy; - - setup(function() { - loadTimeData.overrideValues({searchEngineChoiceSettingsUi: false}); - browserProxy = new TestSearchEnginesBrowserProxy(); - browserProxy.setSearchEnginesInfo(generateSearchEngineInfo()); - SearchEnginesBrowserProxyImpl.setInstance(browserProxy); - document.body.innerHTML = window.trustedTypes!.emptyHTML; - page = document.createElement('settings-search-page'); - page.prefs = { - default_search_provider_data: { - template_url_data: {}, - }, - }; - document.body.appendChild(page); - return flushTasks(); - }); - - teardown(function() { - page.remove(); - }); - - // Tests that the page is querying and displaying search engine info on - // startup. - test('Initialization', async function() { - const selectElement = page.shadowRoot!.querySelector('select')!; - - await browserProxy.whenCalled('getSearchEnginesList'); - - flush(); - assertEquals(0, selectElement.selectedIndex); - - // Simulate a user initiated change of the default search engine. - selectElement.selectedIndex = 1; - selectElement.dispatchEvent(new CustomEvent('change')); - await browserProxy.whenCalled('setDefaultSearchEngine'); - - assertEquals(1, selectElement.selectedIndex); - - // Simulate a change that happened in a different tab. - const searchEnginesInfo = generateSearchEngineInfo(); - searchEnginesInfo.defaults[0]!.default = false; - searchEnginesInfo.defaults[1]!.default = false; - searchEnginesInfo.defaults[2]!.default = true; - - browserProxy.resetResolver('setDefaultSearchEngine'); - webUIListenerCallback('search-engines-changed', searchEnginesInfo); - flush(); - assertEquals(2, selectElement.selectedIndex); - - browserProxy.whenCalled('setDefaultSearchEngine').then(function() { - // Since the change happened in a different tab, there should be - // no new call to |setDefaultSearchEngine|. - assertNotReached('Should not call setDefaultSearchEngine again'); - }); - }); - - test('ControlledByExtension', async function() { - await browserProxy.whenCalled('getSearchEnginesList'); - - const selectElement = page.shadowRoot!.querySelector('select')!; - assertFalse(selectElement.disabled); - assertFalse( - !!page.shadowRoot!.querySelector('extension-controlled-indicator')); - - page.set('prefs.default_search_provider_data.template_url_data', { - controlledBy: chrome.settingsPrivate.ControlledBy.EXTENSION, - controlledByName: 'fake extension name', - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - extensionId: 'fake extension id', - extensionCanBeDisabled: true, - value: {}, - }); - flush(); - - assertTrue(selectElement.disabled); - assertTrue( - !!page.shadowRoot!.querySelector('extension-controlled-indicator')); - assertFalse(!!page.shadowRoot!.querySelector('cr-policy-pref-indicator')); - }); - - test('ControlledByPolicy', async function() { - await browserProxy.whenCalled('getSearchEnginesList'); - const selectElement = page.shadowRoot!.querySelector('select')!; - assertFalse(selectElement.disabled); - assertFalse( - !!page.shadowRoot!.querySelector('extension-controlled-indicator')); - - page.set('prefs.default_search_provider_data.template_url_data', { - controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY, - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - value: {}, - }); - flush(); - - assertTrue(selectElement.disabled); - assertFalse( - !!page.shadowRoot!.querySelector('extension-controlled-indicator')); - assertTrue(!!page.shadowRoot!.querySelector('cr-policy-pref-indicator')); - }); -}); - -suite('SearchPageTestsWithSearchEngineChoiceUiEnabled', function() { - let page: SettingsSearchPageElement; - let browserProxy: TestSearchEnginesBrowserProxy; let metrics: MetricsTracker; setup(function() { - loadTimeData.overrideValues({searchEngineChoiceSettingsUi: true}); metrics = fakeMetricsPrivate(); browserProxy = new TestSearchEnginesBrowserProxy(); browserProxy.setSearchEnginesInfo(generateSearchEngineInfo());
diff --git a/chromeos/ash/components/emoji/emoji_search.cc b/chromeos/ash/components/emoji/emoji_search.cc index a45518d4..7a4e67b 100644 --- a/chromeos/ash/components/emoji/emoji_search.cc +++ b/chromeos/ash/components/emoji/emoji_search.cc
@@ -39,28 +39,18 @@ constexpr std::string_view kDefaultLanguageCode = "en"; // Map from keyword -> sum of position weightings -std::map<std::string, double, std::less<>> CombineSearchTerms( +std::map<std::u16string, double, std::less<>> CombineSearchTerms( base::span<const std::string> long_search_terms) { - std::map<std::string, std::vector<int>, std::less<>> position_map; + std::map<std::u16string, double, std::less<>> ret; for (const std::string& long_string : long_search_terms) { std::vector<std::string_view> words = base::SplitStringPieceUsingSubstr( long_string, " ", base::WhitespaceHandling::TRIM_WHITESPACE, base::SplitResult::SPLIT_WANT_NONEMPTY); for (size_t i = 0; i < words.size(); ++i) { - position_map[base::UTF16ToUTF8( - base::i18n::ToLower(base::UTF8ToUTF16(words[i])))] - .push_back(i); + ret[base::i18n::ToLower(base::UTF8ToUTF16(words[i]))] += 1.0 / (1.0 + i); } } - std::map<std::string, double, std::less<>> ret; - for (auto& map_entry : position_map) { - double weight = 0; - for (int p : map_entry.second) { - weight += 1.0 / (1.0 + p); - } - ret[map_entry.first] = weight; - } return ret; } @@ -68,7 +58,7 @@ // position in keyword / name. void AddDataFromFileToMap( const int file_id_in_resources, - std::map<std::string, std::vector<EmojiSearchEntry>, std::less<>>& map) { + std::map<std::u16string, std::vector<EmojiSearchEntry>, std::less<>>& map) { std::string json_string = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( file_id_in_resources); @@ -150,14 +140,14 @@ } std::map<std::string_view, double> GetResultsFromMap( - const std::map<std::string, std::vector<EmojiSearchEntry>, std::less<>>& + const std::map<std::u16string, std::vector<EmojiSearchEntry>, std::less<>>& map, base::span<const std::u16string_view> lowercase_words) { std::map<std::string_view, double> scored_emoji; for (const std::u16string_view lowercase_word : lowercase_words) { std::map<std::string_view, double> word_scored_emoji; - std::string lower_bound = base::UTF16ToUTF8(lowercase_word); - std::string upper_bound = lower_bound; + std::u16string_view lower_bound = lowercase_word; + std::u16string upper_bound = std::u16string(lowercase_word); // will break if someone searches for some very specific char, but // should be fine. upper_bound.back() = upper_bound.back() + 1; @@ -409,12 +399,15 @@ void EmojiSearch::LoadLanguage(std::string_view language_code) { std::optional<EmojiLanguageCode> lang = GetLanguageCode(language_code); - if (!lang.has_value() || language_data_.contains(*lang)) { + if (!lang.has_value()) { return; } - language_data_.emplace(*lang, EmojiLanguageData()); - EmojiLanguageData& new_data = language_data_.at(*lang); + auto [it, inserted] = language_data_.emplace(*lang, EmojiLanguageData()); + if (!inserted) { + return; + } + EmojiLanguageData& new_data = it->second; if (std::optional<EmojiLanguageResourceIds> resource_ids = GetLanguageResourceIds(*lang);
diff --git a/chromeos/ash/components/emoji/emoji_search.h b/chromeos/ash/components/emoji/emoji_search.h index d511fe0..b814249 100644 --- a/chromeos/ash/components/emoji/emoji_search.h +++ b/chromeos/ash/components/emoji/emoji_search.h
@@ -38,7 +38,7 @@ }; using EmojiEntryMap = - std::map<std::string, std::vector<EmojiSearchEntry>, std::less<>>; + std::map<std::u16string, std::vector<EmojiSearchEntry>, std::less<>>; enum class EmojiLanguageCode { kDa, // Danish
diff --git a/chromeos/ash/components/http_auth_dialog/BUILD.gn b/chromeos/ash/components/http_auth_dialog/BUILD.gn new file mode 100644 index 0000000..ac76574 --- /dev/null +++ b/chromeos/ash/components/http_auth_dialog/BUILD.gn
@@ -0,0 +1,32 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") + +assert(is_chromeos_ash, + "Non-Chrome-OS builds must not depend on //chromeos/ash") + +component("http_auth_dialog") { + defines = [ "IS_CHROMEOS_ASH_COMPONENTS_HTTP_AUTH_DIALOG_IMPL" ] + + sources = [ + "http_auth_dialog.cc", + "http_auth_dialog.h", + ] + + public_deps = [ + "//base", + "//content/public/browser", + "//ui/views", + ] + + deps = [ + "//components/constrained_window", + "//components/strings:components_strings_grit", + "//components/url_formatter", + "//components/web_modal", + "//services/network/public/cpp", + "//ui/base", + ] +}
diff --git a/chromeos/ash/components/http_auth_dialog/DEPS b/chromeos/ash/components/http_auth_dialog/DEPS new file mode 100644 index 0000000..81fd9589 --- /dev/null +++ b/chromeos/ash/components/http_auth_dialog/DEPS
@@ -0,0 +1,9 @@ +include_rules = [ + "+components/constrained_window/constrained_window_views.h", + "+components/strings/grit/components_strings.h", + "+components/url_formatter/elide_url.h", + "+components/web_modal/web_contents_modal_dialog_manager.h", + "+content/public/browser", + "+ui/base", + "+ui/views", +]
diff --git a/chrome/browser/ash/http_auth_dialog.cc b/chromeos/ash/components/http_auth_dialog/http_auth_dialog.cc similarity index 99% rename from chrome/browser/ash/http_auth_dialog.cc rename to chromeos/ash/components/http_auth_dialog/http_auth_dialog.cc index e2996a4..47dcf0e 100644 --- a/chrome/browser/ash/http_auth_dialog.cc +++ b/chromeos/ash/components/http_auth_dialog/http_auth_dialog.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ash/http_auth_dialog.h" +#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h" #include <vector>
diff --git a/chrome/browser/ash/http_auth_dialog.h b/chromeos/ash/components/http_auth_dialog/http_auth_dialog.h similarity index 93% rename from chrome/browser/ash/http_auth_dialog.h rename to chromeos/ash/components/http_auth_dialog/http_auth_dialog.h index 10282e56..2a511bc 100644 --- a/chrome/browser/ash/http_auth_dialog.h +++ b/chromeos/ash/components/http_auth_dialog/http_auth_dialog.h
@@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ -#define CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ +#ifndef CHROMEOS_ASH_COMPONENTS_HTTP_AUTH_DIALOG_HTTP_AUTH_DIALOG_H_ +#define CHROMEOS_ASH_COMPONENTS_HTTP_AUTH_DIALOG_HTTP_AUTH_DIALOG_H_ +#include "base/component_export.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "content/public/browser/login_delegate.h" @@ -25,7 +26,8 @@ // expect fine grained control over the dialog that is shown. This class // provides a mechanism to do so. -class HttpAuthDialog : public content::LoginDelegate { +class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_HTTP_AUTH_DIALOG) + HttpAuthDialog : public content::LoginDelegate { public: // There are two ways for this class to be deleted. // (1) The //content layer can decide the class is no longer necessary, in @@ -151,4 +153,4 @@ } // namespace ash -#endif // CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ +#endif // CHROMEOS_ASH_COMPONENTS_HTTP_AUTH_DIALOG_HTTP_AUTH_DIALOG_H_
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt index ff59a13..dc7f4b3 100644 --- a/chromeos/profiles/bigcore.afdo.newest.txt +++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-bigcore-130-6668.0-1725243046-benchmark-130.0.6697.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-130-6668.0-1725243046-benchmark-130.0.6698.0-r1-redacted.afdo.xz
diff --git a/chromeos/recorder_strings.grdp b/chromeos/recorder_strings.grdp index 1d550c0..411b9a6 100644 --- a/chromeos/recorder_strings.grdp +++ b/chromeos/recorder_strings.grdp
@@ -5,6 +5,12 @@ <message desc="Name of the Recorder App." name="IDS_RECORDER_APP_NAME"> Recorder </message> + <message desc="Tooltip of the button to navigate back to main page." meaning="Go back to main page." name="IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP"> + Back + </message> + <message desc="Tooltip of the button to close the dialog." meaning="Close the dialog." name="IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP"> + Close + </message> <message desc="Label of the menu item to choose webm as audio format in the export dialog." name="IDS_RECORDER_EXPORT_DIALOG_AUDIO_FORMAT_WEBM_OPTION"> WEBM </message> @@ -26,6 +32,12 @@ <message desc="Header of the export transcription section in the export dialog." name="IDS_RECORDER_EXPORT_DIALOG_TRANSCRIPTION_HEADER"> Export transcript </message> + <message desc="Tooltip of the button to send negative feedback for the output from generative AI features." name="IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP"> + Bad suggestion + </message> + <message desc="Tooltip of the button to send positive feedback for the output from generative AI features." name="IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP"> + Good suggestion + </message> <message desc="Disclaimer under generative AI features." name="IDS_RECORDER_GEN_AI_DISCLAIMER_TEXT"> Generative AI is experimental and content may be inaccurate, misleading, or offensive. </message> @@ -120,9 +132,21 @@ <message desc="Button to go next in the welcome step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_WELCOME_NEXT_BUTTON"> Next </message> + <message desc="Tooltip of the button to rewind the recording playback 10 seconds." name="IDS_RECORDER_PLAYBACK_BACKWARD_BUTTON_TOOLTIP"> + Backward 10 seconds + </message> <message desc="Accessibility label of the landmark for the playback controls section in the playback page." name="IDS_RECORDER_PLAYBACK_CONTROLS_LANDMARK_ARIA_LABEL"> Playback controls </message> + <message desc="Tooltip of the button to forward the recording playback 10 seconds." name="IDS_RECORDER_PLAYBACK_FORWARD_BUTTON_TOOLTIP"> + Forward 10 seconds + </message> + <message desc="Tooltip of the button to hide the recording transcript in playback page." name="IDS_RECORDER_PLAYBACK_HIDE_TRANSCRIPT_BUTTON_TOOLTIP"> + Hide transcript + </message> + <message desc="Tooltip of the button to open the menu item listing playback options." name="IDS_RECORDER_PLAYBACK_MENU_BUTTON_TOOLTIP"> + More options + </message> <message desc="Label of the menu item to delete the recording in playback page." name="IDS_RECORDER_PLAYBACK_MENU_DELETE_OPTION"> Delete </message> @@ -132,9 +156,33 @@ <message desc="Label of the menu item to show recording details in playback page." name="IDS_RECORDER_PLAYBACK_MENU_SHOW_DETAIL_OPTION"> More details </message> + <message desc="Tooltip of the button to toggle mute on and off for the playback." meaning="Toggle mute for recording playback." name="IDS_RECORDER_PLAYBACK_MUTE_BUTTON_TOOLTIP"> + Toggle mute + </message> + <message desc="Tooltip of the button to pause the recording playback." meaning="Pause the audio recording playback." name="IDS_RECORDER_PLAYBACK_PAUSE_BUTTON_TOOLTIP"> + Pause + </message> + <message desc="Tooltip of the button to play the recording playback." meaning="Play the audio recording playback." name="IDS_RECORDER_PLAYBACK_PLAY_BUTTON_TOOLTIP"> + Play + </message> + <message desc="Accessibility label for the seek slider in playback page." name="IDS_RECORDER_PLAYBACK_SEEK_SLIDER_ARIA_LABEL"> + Seek + </message> + <message desc="Tooltip of the button to show the recording transcript in playback page." name="IDS_RECORDER_PLAYBACK_SHOW_TRANSCRIPT_BUTTON_TOOLTIP"> + Show transcript + </message> + <message desc="Tooltip of the button to open the menu item listing playback speed." name="IDS_RECORDER_PLAYBACK_SPEED_BUTTON_TOOLTIP"> + Playback speed + </message> <message desc="Label of the menu item to set playback speed to normal (1.0)." name="IDS_RECORDER_PLAYBACK_SPEED_NORMAL_OPTION"> Normal </message> + <message desc="Accessibility label of the landmark for recording transcript in playback page." meaning="Transcript of the audio recording." name="IDS_RECORDER_PLAYBACK_TRANSCRIPT_LANDMARK_ARIA_LABEL"> + Transcript + </message> + <message desc="Accessibility label of the volume slider for the playback." meaning="Set the playback volume." name="IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL"> + Volume + </message> <message desc="Tooltip of the button to open more record options." name="IDS_RECORDER_RECORDING_ITEM_OPTIONS_BUTTON_TOOLTIP"> More options </message> @@ -171,6 +219,9 @@ <message desc="Header of the group of recordings recorded this yesterday." name="IDS_RECORDER_RECORDING_LIST_YESTERDAY_HEADER"> Yesterday </message> + <message desc="Tooltip of the button to delete the ongoing recording." name="IDS_RECORDER_RECORD_DELETE_BUTTON_TOOLTIP"> + Delete + </message> <message desc="Button to cancel deleting recording in the delete recording dialog." name="IDS_RECORDER_RECORD_DELETE_DIALOG_CANCEL_BUTTON"> Cancel </message> @@ -216,12 +267,21 @@ <message desc="Label of the recording title on the recording info dialog." name="IDS_RECORDER_RECORD_INFO_DIALOG_TITLE_LABEL"> Name </message> + <message desc="Tooltip of the button to open the menu item listing recording options." name="IDS_RECORDER_RECORD_MENU_BUTTON_TOOLTIP"> + More options + </message> <message desc="Label of the menu item to delete the ongoing recording." name="IDS_RECORDER_RECORD_MENU_DELETE_OPTION"> Delete </message> <message desc="Label of the menu item to toggle whether transcription is enabled while recording." name="IDS_RECORDER_RECORD_MENU_TOGGLE_TRANSCRIPTION_OPTION"> Create transcript </message> + <message desc="Tooltip of the button to toggle mute on microphone on and off while recording." name="IDS_RECORDER_RECORD_MUTE_BUTTON_TOOLTIP"> + Toggle mute on microphone + </message> + <message desc="Tooltip of the button to pause the ongoing recording." meaning="Pause the ongoing audio recording session." name="IDS_RECORDER_RECORD_PAUSE_BUTTON_TOOLTIP"> + Pause + </message> <message desc="Button to stop audio recording." meaning="Finish an audio recording session." name="IDS_RECORDER_RECORD_STOP_BUTTON"> Stop recording </message> @@ -243,6 +303,9 @@ <message desc="Header when transcription is off in the transcription view while recording." name="IDS_RECORDER_RECORD_TRANSCRIPTION_OFF_HEADER"> Transcript is off </message> + <message desc="Tooltip of the button to show or hide the live transcription of the recording." name="IDS_RECORDER_RECORD_TRANSCRIPT_BUTTON_TOOLTIP"> + Transcript + </message> <message desc="Header of the settings." name="IDS_RECORDER_SETTINGS_HEADER"> Recorder settings </message> @@ -321,6 +384,9 @@ <message desc="Tooltip of the record title renaming text input." name="IDS_RECORDER_TITLE_RENAME_TOOLTIP"> Rename </message> + <message desc="Tooltip of the button to suggest the recording title." name="IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP"> + Create name using Google AI + </message> <message desc="Header of title suggestion." name="IDS_RECORDER_TITLE_SUGGESTION_HEADER"> A few options: </message>
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..bb16bf7 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_BACK_TO_MAIN_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +f8c5497b6b14392c7a727443a71ec77c2d13b881 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..8d87fbb --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_CLOSE_DIALOG_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +b24353fe266a92770175793f69fa221facc7efb1 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..79be0e3 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +5ad54ee46a0ed319cd4c949c31877e8795f7a00c \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..a83b366 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +1bc7480d28a48fbeeaa8c69646df91fbad59fdaf \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_BACKWARD_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_BACKWARD_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..5ff340f --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_BACKWARD_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +fe8aa88d6c40d7f519bb24f7622ab82027793f62 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_FORWARD_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_FORWARD_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..971908f --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_FORWARD_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +1d81dbc9dbb4e9bc710f280e281f879e56f15c8b \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_HIDE_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_HIDE_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..401e384 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_HIDE_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +d4759141b7d581b1ea4b21b8e3e7f81659e4492d \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MENU_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MENU_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..d5c37f2a --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MENU_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +f48d647ae7ef229bb1ccedd46a43bafa68d7ea48 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MUTE_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MUTE_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..2512a237 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_MUTE_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +756fffa33b7adcdb645801d4cac5ca477054cd46 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PAUSE_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PAUSE_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..36798fe --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PAUSE_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +d07b919f0bb0eb49ae500ed159c7d1f6b7e0fba9 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PLAY_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PLAY_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..8208ce81 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_PLAY_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +54c7711914e0f14f5a588e704788cffa5caf0431 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SEEK_SLIDER_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SEEK_SLIDER_ARIA_LABEL.png.sha1 new file mode 100644 index 0000000..a7dcbad --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SEEK_SLIDER_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@ +f16577e774502dd3b665e7151772d9fd78148aa3 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SHOW_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SHOW_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..93a50d9 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SHOW_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +68872cb24916087cd39c080c4228babc2d0e9fa3 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SPEED_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SPEED_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..f277676 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_SPEED_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +95798e2118f593c41eb8a682fca928ee9914c8d7 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_TRANSCRIPT_LANDMARK_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_TRANSCRIPT_LANDMARK_ARIA_LABEL.png.sha1 new file mode 100644 index 0000000..45d4a80 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_TRANSCRIPT_LANDMARK_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@ +cc67395b98a84587e5bbdcc62c526c3f1ee80ad6 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL.png.sha1 new file mode 100644 index 0000000..e2c539f3 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_PLAYBACK_VOLUME_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@ +7df5fd5ef6ebde663bab5f0f1f8a04d661c64e6c \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_DELETE_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_DELETE_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..1d67c7d --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_DELETE_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +971a0ccea412cf3fb76dbaf68272b6eb3c6c1ac1 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MENU_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MENU_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..a008c6e --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MENU_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +808e35de7081f12fc36cb241ff402cc220394f87 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MUTE_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MUTE_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..bd560092 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_MUTE_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +627b0c815536f5e18c4941edd83014be6f5383f6 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_PAUSE_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_PAUSE_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..a1ba1708c --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_PAUSE_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +a018dfdc8574bbdf94f6874e56d05555f20409d2 \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..9271966 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_RECORD_TRANSCRIPT_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +b1eb0271bf21276543542fda64f8e45f99a952ef \ No newline at end of file
diff --git a/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP.png.sha1 b/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP.png.sha1 new file mode 100644 index 0000000..acf4766 --- /dev/null +++ b/chromeos/recorder_strings_grdp/IDS_RECORDER_TITLE_SUGGESTION_BUTTON_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +3478a6851c4ac65e36bc56bb6442c5ba91aaf3dc \ No newline at end of file
diff --git a/clank b/clank index 58ce7a7d..6d00498 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 58ce7a7d34a0a9c1ea7730c874094b0ca039f4eb +Subproject commit 6d0049883faa7e13155ac288d96597b4bb7a5477
diff --git a/components/arc/common/intent_helper/activity_icon_loader_unittest.cc b/components/arc/common/intent_helper/activity_icon_loader_unittest.cc index 7a254261..e37339d 100644 --- a/components/arc/common/intent_helper/activity_icon_loader_unittest.cc +++ b/components/arc/common/intent_helper/activity_icon_loader_unittest.cc
@@ -224,8 +224,9 @@ ActivityIconLoader::ActivityName("p2", "a2"))); EXPECT_EQ(1U, activity_to_icons->count( ActivityIconLoader::ActivityName("p3", "a3"))); - if (!on_icon_ready_callback_.is_null()) + if (!on_icon_ready_callback_.is_null()) { std::move(on_icon_ready_callback_).Run(); + } } void WaitForIconReady() {
diff --git a/components/arc/common/intent_helper/link_handler_model.cc b/components/arc/common/intent_helper/link_handler_model.cc index 3e5e4aff..04652b3 100644 --- a/components/arc/common/intent_helper/link_handler_model.cc +++ b/components/arc/common/intent_helper/link_handler_model.cc
@@ -168,15 +168,17 @@ const ArcIconCacheDelegate::ActivityName activity( handlers_[i].package_name, handlers_[i].activity_name); const auto it = icons_.find(activity); - if (it != icons_.end()) + if (it != icons_.end()) { icon = it->second.icon16; + } // Use the handler's index as an ID. LinkHandlerInfo handler = {base::UTF8ToUTF16(handlers_[i].name), icon, static_cast<uint32_t>(i)}; handlers.push_back(handler); } - for (auto& observer : observer_list_) + for (auto& observer : observer_list_) { observer.ModelChanged(handlers); + } } // static
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index eefca70..d71e858b 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -64,7 +64,6 @@ #include "ui/accessibility/platform/ax_platform.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/geometry/rect.h" -#include "ui/suggestion_button_action.h" namespace autofill { @@ -229,6 +228,7 @@ case SuggestionType::kPasswordAccountStorageOptInAndGenerate: case SuggestionType::kPasswordAccountStorageReSignin: case SuggestionType::kPasswordEntry: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kScanCreditCard: case SuggestionType::kSeePromoCodeDetails: case SuggestionType::kTitle: @@ -360,19 +360,30 @@ base::OnceCallback<void(std::vector<Suggestion>, AutofillSuggestionTriggerSource)> AutofillExternalDelegate::CreateUpdateSuggestionsCallback() { + using SessionId = AutofillClient::SuggestionUiSessionId; + const std::optional<SessionId> session_id = + manager_->client().GetSessionIdForCurrentAutofillSuggestions(); + if (!session_id) { + return base::DoNothing(); + } return base::BindOnce( - [](base::WeakPtr<AutofillExternalDelegate> self, + [](base::WeakPtr<AutofillExternalDelegate> self, SessionId session_id, std::vector<Suggestion> suggestions, AutofillSuggestionTriggerSource trigger_source) { if (!self) { return; } + if (self->manager_->client() + .GetSessionIdForCurrentAutofillSuggestions() + .value_or(SessionId()) != session_id) { + return; + } self->AttemptToDisplayAutofillSuggestions( std::move(suggestions), /*suggestion_ranking_context=*/std::nullopt, trigger_source, /*is_update=*/true); }, - GetWeakPtr()); + GetWeakPtr(), *session_id); } SuggestionType @@ -650,6 +661,7 @@ case SuggestionType::kWebauthnSignInWithAnotherDevice: case SuggestionType::kPasswordFieldByFieldFilling: case SuggestionType::kFillPassword: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kViewPasswordDetails: NOTREACHED(); // Should be handled elsewhere. } @@ -813,6 +825,7 @@ case SuggestionType::kWebauthnSignInWithAnotherDevice: case SuggestionType::kPasswordFieldByFieldFilling: case SuggestionType::kFillPassword: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kViewPasswordDetails: case SuggestionType::kPredictionImprovementsLoadingState: NOTREACHED(); // Should be handled elsewhere. @@ -942,6 +955,7 @@ case SuggestionType::kDevtoolsTestAddressEntry: case SuggestionType::kDevtoolsTestAddressByCountry: case SuggestionType::kPasswordFieldByFieldFilling: + case SuggestionType::kPredictionImprovementsFeedback: case SuggestionType::kFillPassword: case SuggestionType::kViewPasswordDetails: case SuggestionType::kRetrievePredictionImprovements:
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index 024d89f7..97e13173 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -163,10 +163,10 @@ bool is_update); // Returns a callback that, when run, attempts to update the currently shown - // suggestions. The callback is safe to call even if `this` is no longer - // alive. - // TODO(crbug.com/362445807): Take SuggestionUiSessionId into account once it - // is implemented. + // suggestions. If the `SuggestionUiSessionId` of the currently showing UI + // surface has changed between when this callback is created and when it is + // run, running it is a no-op. The callback is also safe to call even if + // `this` is no longer alive. base::OnceCallback<void(std::vector<Suggestion>, AutofillSuggestionTriggerSource)> CreateUpdateSuggestionsCallback();
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc index 3fab25b5..c02e8df8 100644 --- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -2221,6 +2221,8 @@ OnSuggestionsReturned(queried_field().global_id(), suggestions); ON_CALL(client(), GetAutofillSuggestions) .WillByDefault(Return(base::span<const Suggestion>(suggestions))); + client().set_suggestion_ui_session_id( + AutofillClient::SuggestionUiSessionId(123)); { InSequence s; @@ -2244,6 +2246,46 @@ suggestions[0], SuggestionButtonAction()); } +// Tests that running the update callback is a no-op if the session id of the +// suggestions UI has changed since the update callback was requested. +TEST_F(AutofillExternalDelegateUnitTest, + PlusAddressExtraButtonActionUiSessionIdChanged) { + IssueOnQuery(); + + const std::u16string plus_address = u"test+plus@test.example"; + std::vector<Suggestion> suggestions; + suggestions.emplace_back(u"Some other suggestion"); + suggestions.emplace_back(/*main_text=*/u"Create plus address", + SuggestionType::kCreateNewPlusAddressInline); + suggestions.back().payload = Suggestion::PlusAddressPayload(plus_address); + OnSuggestionsReturned(queried_field().global_id(), suggestions); + ON_CALL(client(), GetAutofillSuggestions) + .WillByDefault(Return(base::span<const Suggestion>(suggestions))); + + base::OnceCallback<void(std::vector<Suggestion>, + AutofillSuggestionTriggerSource)> + update_callback; + + EXPECT_CALL(client(), UpdateAutofillSuggestions).Times(0); + EXPECT_CALL(plus_address_delegate(), + OnClickedRefreshInlineSuggestion( + _, base::span<const Suggestion>(suggestions), + /*current_suggestion_index=*/1, _)) + .WillOnce(MoveArg<3>(&update_callback)); + + client().set_suggestion_ui_session_id( + AutofillClient::SuggestionUiSessionId(3)); + external_delegate().DidPerformButtonActionForSuggestion( + suggestions[1], SuggestionButtonAction()); + ASSERT_TRUE(update_callback); + + // Now simulate that the popup has a new session id. + client().set_suggestion_ui_session_id( + AutofillClient::SuggestionUiSessionId(4)); + std::move(update_callback) + .Run(suggestions, AutofillSuggestionTriggerSource::kUnspecified); +} + // Tests that running the update callback is safe even after AED has been // destroyed. TEST_F(AutofillExternalDelegateUnitTest,
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 6c7823e..412ff81 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -344,6 +344,7 @@ case SuggestionType::kRetrievePredictionImprovements: case SuggestionType::kPredictionImprovementsLoadingState: case SuggestionType::kFillPredictionImprovements: + case SuggestionType::kPredictionImprovementsFeedback: NOTREACHED_IN_MIGRATION(); } NOTREACHED_IN_MIGRATION(); @@ -572,6 +573,7 @@ case SuggestionType::kRetrievePredictionImprovements: case SuggestionType::kPredictionImprovementsLoadingState: case SuggestionType::kFillPredictionImprovements: + case SuggestionType::kPredictionImprovementsFeedback: NOTREACHED(); } NOTREACHED();
diff --git a/components/autofill/core/browser/data_model/credit_card.h b/components/autofill/core/browser/data_model/credit_card.h index 90936fb..537e66a7 100644 --- a/components/autofill/core/browser/data_model/credit_card.h +++ b/components/autofill/core/browser/data_model/credit_card.h
@@ -473,6 +473,11 @@ void clear_cvc() { cvc_.clear(); } void set_cvc(const std::u16string& cvc) { cvc_ = cvc; } + base::Time cvc_modification_date() const { return cvc_modification_date_; } + void set_cvc_modification_date(base::Time date) { + cvc_modification_date_ = date; + } + private: friend class CreditCardTestApi; @@ -600,6 +605,10 @@ // The card verification code of the card. May be empty. std::u16string cvc_; + + // CVCs can be updated independently of the card and track their modification + // date independently. The timestamp `is_null()` for cards without CVC. + base::Time cvc_modification_date_; }; // So we can compare CreditCards with EXPECT_EQ().
diff --git a/components/autofill/core/browser/filling_product.cc b/components/autofill/core/browser/filling_product.cc index 0c179be..5c425c6 100644 --- a/components/autofill/core/browser/filling_product.cc +++ b/components/autofill/core/browser/filling_product.cc
@@ -95,6 +95,8 @@ case SuggestionType::kFillExistingPlusAddress: case SuggestionType::kManagePlusAddress: return FillingProduct::kPlusAddresses; + case SuggestionType::kPredictionImprovementsFeedback: + return FillingProduct::kPredictionImprovements; case SuggestionType::kSeePromoCodeDetails: case SuggestionType::kTitle: case SuggestionType::kSeparator:
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index 3caeec7..735948d 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h
@@ -276,6 +276,11 @@ FillingProduct main_filling_product, AutofillSuggestionTriggerSource trigger_source) override {} + std::optional<AutofillClient::SuggestionUiSessionId> + GetSessionIdForCurrentAutofillSuggestions() const override { + return suggestion_ui_session_id_; + } + void HideAutofillSuggestions(SuggestionHidingReason reason) override { popup_hidden_reason_ = reason; is_showing_popup_ = false; @@ -452,6 +457,11 @@ plus_address_delegate_ = std::move(plus_address_delegate); } + void set_suggestion_ui_session_id( + std::optional<AutofillClient::SuggestionUiSessionId> session_id) { + suggestion_ui_session_id_ = session_id; + } + GURL form_origin() { return form_origin_; } ukm::TestUkmRecorder* GetTestUkmRecorder() { return &test_ukm_recorder_; } @@ -535,6 +545,9 @@ // constructor. GURL last_committed_primary_main_frame_url_{"https://example.test"}; + std::optional<AutofillClient::SuggestionUiSessionId> + suggestion_ui_session_id_; + LogRouter log_router_; struct LogToTerminal { explicit LogToTerminal(LogRouter& log_router) {
diff --git a/components/autofill/core/browser/ui/suggestion_type.cc b/components/autofill/core/browser/ui/suggestion_type.cc index 4f0b8c0..7352e20 100644 --- a/components/autofill/core/browser/ui/suggestion_type.cc +++ b/components/autofill/core/browser/ui/suggestion_type.cc
@@ -122,6 +122,8 @@ return "kPredictionImprovementsLoadingState"; case SuggestionType::kFillPredictionImprovements: return "kFillPredictionImprovements"; + case SuggestionType::kPredictionImprovementsFeedback: + return "kPredictionImprovementsFeedback"; } NOTREACHED(); }
diff --git a/components/autofill/core/browser/ui/suggestion_type.h b/components/autofill/core/browser/ui/suggestion_type.h index 0fa59c1..a08e892 100644 --- a/components/autofill/core/browser/ui/suggestion_type.h +++ b/components/autofill/core/browser/ui/suggestion_type.h
@@ -131,7 +131,11 @@ // Fill prediction improvements. kFillPredictionImprovements = 55, - kMaxValue = kFillPredictionImprovements + // Suggestion that provides users the possibility to give feedback about + // predictions improvements. + kPredictionImprovementsFeedback = 56, + + kMaxValue = kPredictionImprovementsFeedback }; std::string_view SuggestionTypeToStringView(SuggestionType type);
diff --git a/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc b/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc index 60d0010d..5bdd947 100644 --- a/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc +++ b/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc
@@ -421,6 +421,8 @@ if (cvc_statement) { credit_card->set_cvc( DecryptU16StringFromColumn(cvc_statement.value(), 0, encryptor)); + credit_card->set_cvc_modification_date( + base::Time::FromTimeT(cvc_statement->get().ColumnInt64(1))); } return credit_card; } @@ -854,8 +856,8 @@ // Get cvc from local_stored_cvc table. sql::Statement cvc_statement; - SelectBuilder(db(), cvc_statement, kLocalStoredCvcTable, {kValueEncrypted}, - "WHERE guid = ?"); + SelectBuilder(db(), cvc_statement, kLocalStoredCvcTable, + {kValueEncrypted, kLastUpdatedTimestamp}, "WHERE guid = ?"); cvc_statement.BindString(0, guid); bool has_cvc = cvc_statement.Step(); @@ -897,9 +899,9 @@ bool PaymentsAutofillTable::GetServerCreditCards( std::vector<std::unique_ptr<CreditCard>>& credit_cards) const { credit_cards.clear(); - auto instrument_to_cvc = base::MakeFlatMap<int64_t, std::u16string>( - GetAllServerCvcs(), {}, [](const auto& server_cvc) { - return std::make_pair(server_cvc->instrument_id, server_cvc->cvc); + auto instrument_to_cvc = base::MakeFlatMap<int64_t, ServerCvc>( + GetAllServerCvcs(), {}, [](const std::unique_ptr<ServerCvc>& server_cvc) { + return std::make_pair(server_cvc->instrument_id, *server_cvc); }); sql::Statement s; @@ -955,7 +957,9 @@ // Add CVC to the the `card` if the CVC storage flag is enabled. if (base::FeatureList::IsEnabled( features::kAutofillEnableCvcStorageAndFilling)) { - card->set_cvc(instrument_to_cvc[card->instrument_id()]); + const ServerCvc& cvc = instrument_to_cvc[card->instrument_id()]; + card->set_cvc(cvc.cvc); + card->set_cvc_modification_date(cvc.last_updated_timestamp); } credit_cards.push_back(std::move(card)); }
diff --git a/components/autofill/core/browser/webdata/payments/payments_autofill_table.h b/components/autofill/core/browser/webdata/payments/payments_autofill_table.h index 262b15b4..ca29e0f 100644 --- a/components/autofill/core/browser/webdata/payments/payments_autofill_table.h +++ b/components/autofill/core/browser/webdata/payments/payments_autofill_table.h
@@ -42,11 +42,11 @@ struct ServerCvc { bool operator==(const ServerCvc&) const = default; // A server generated id to identify the corresponding credit card. - const int64_t instrument_id; + int64_t instrument_id; // CVC value of the card. - const std::u16string cvc; + std::u16string cvc; // The timestamp of the most recent update to the data entry. - const base::Time last_updated_timestamp; + base::Time last_updated_timestamp; }; // This class manages the various payments Autofill tables within the SQLite
diff --git a/components/autofill/core/browser/webdata/payments/payments_autofill_table_unittest.cc b/components/autofill/core/browser/webdata/payments/payments_autofill_table_unittest.cc index 1bd110ac..b8a6cf8 100644 --- a/components/autofill/core/browser/webdata/payments/payments_autofill_table_unittest.cc +++ b/components/autofill/core/browser/webdata/payments/payments_autofill_table_unittest.cc
@@ -343,6 +343,9 @@ // Get the credit card, cvc should match. std::unique_ptr<CreditCard> db_card = table_->GetCreditCard(card.guid()); EXPECT_EQ(card.cvc(), db_card->cvc()); + // Some precision is lost when converting to time_t and back. + EXPECT_EQ(arbitrary_time.ToTimeT(), + db_card->cvc_modification_date().ToTimeT()); // Verify last_updated_timestamp in local_stored_cvc table is set correctly. EXPECT_EQ(GetDateModified("local_stored_cvc", "last_updated_timestamp", @@ -375,6 +378,8 @@ db_card = table_->GetCreditCard(card.guid()); // CVC should be updated to new CVC. EXPECT_EQ(u"234", db_card->cvc()); + EXPECT_EQ(much_later_time.ToTimeT(), + db_card->cvc_modification_date().ToTimeT()); // local_stored_cvc table timestamp should be updated. EXPECT_EQ(GetDateModified("local_stored_cvc", "last_updated_timestamp", card.guid()), @@ -861,14 +866,9 @@ TEST_F(PaymentsAutofillTableTest, SetGetServerCards) { for (bool is_cvc_storage_flag_enabled : {true, false}) { - base::test::ScopedFeatureList features; - if (is_cvc_storage_flag_enabled) { - features.InitAndEnableFeature( - features::kAutofillEnableCvcStorageAndFilling); - } else { - features.InitAndDisableFeature( - features::kAutofillEnableCvcStorageAndFilling); - } + base::test::ScopedFeatureList feature; + feature.InitWithFeatureState(features::kAutofillEnableCvcStorageAndFilling, + is_cvc_storage_flag_enabled); std::vector<CreditCard> inputs; inputs.emplace_back(CreditCard::RecordType::kMaskedServerCard, "a123"); @@ -905,6 +905,8 @@ inputs[1].set_product_terms_url(GURL("https://www.example_term.com")); inputs[1].set_cvc(u"111"); + // The CVC modification dates are set to `now` during insertion. + const time_t now = base::Time::Now().ToTimeT(); test::SetServerCreditCards(table_.get(), inputs); std::vector<std::unique_ptr<CreditCard>> outputs; @@ -929,7 +931,9 @@ // clear the same from the input entries to allow the comparison between // input and output. EXPECT_TRUE(outputs[0]->cvc().empty()); + EXPECT_TRUE(outputs[0]->cvc_modification_date().is_null()); EXPECT_TRUE(outputs[1]->cvc().empty()); + EXPECT_TRUE(outputs[1]->cvc_modification_date().is_null()); inputs[0].clear_cvc(); inputs[1].clear_cvc(); @@ -969,7 +973,9 @@ if (is_cvc_storage_flag_enabled) { EXPECT_EQ(inputs[0].cvc(), outputs[0]->cvc()); + EXPECT_EQ(now, outputs[0]->cvc_modification_date().ToTimeT()); EXPECT_EQ(inputs[1].cvc(), outputs[1]->cvc()); + EXPECT_EQ(now, outputs[1]->cvc_modification_date().ToTimeT()); } } }
diff --git a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.cc b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.cc index a1d6746..9e42df0 100644 --- a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.cc +++ b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.cc
@@ -52,14 +52,17 @@ // A raw pointer to the LightweightQuarantineBranch as the fast path to the // object. This bypasses the access check and indirect access due to the // following std::optional and base::NoDestructor. -LightweightQuarantineBranch* lightweight_quarantine_branch; +LightweightQuarantineBranch* lightweight_quarantine_branch_for_small_objects; +LightweightQuarantineBranch* lightweight_quarantine_branch_for_large_objects; // The memory storage for the quarantine root and branch to make them alive for // the process lifetime. std::optional reserves the memory space without // constructing the objects and allows to construct them lazily. std::optional<LightweightQuarantineRoot> lightweight_quarantine_root_storage; std::optional<base::NoDestructor<LightweightQuarantineBranch>> - lightweight_quarantine_branch_storage; + lightweight_quarantine_branch_storage_for_small_objects; +std::optional<base::NoDestructor<LightweightQuarantineBranch>> + lightweight_quarantine_branch_storage_for_large_objects; // Sets up all we need and returns true, or returns false. // @@ -103,17 +106,28 @@ static bool init_once = [&]() -> bool { partition_alloc::PartitionRoot* partition_root = allocator_shim::internal::PartitionAllocMalloc::Allocator(); - - LightweightQuarantineBranchConfig quarantine_config = { - .lock_required = true, - .branch_capacity_in_bytes = init_options.quarantine_capacity_in_bytes, - }; lightweight_quarantine_partition_root = partition_root; lightweight_quarantine_root_storage.emplace(*partition_root); - lightweight_quarantine_branch_storage.emplace( - lightweight_quarantine_root_storage->CreateBranch(quarantine_config)); - lightweight_quarantine_branch = - lightweight_quarantine_branch_storage.value().get(); + + lightweight_quarantine_branch_storage_for_small_objects.emplace( + lightweight_quarantine_root_storage->CreateBranch( + LightweightQuarantineBranchConfig{ + .lock_required = true, + .branch_capacity_in_bytes = + init_options.quarantine_capacity_for_small_objects_in_bytes, + })); + lightweight_quarantine_branch_for_small_objects = + lightweight_quarantine_branch_storage_for_small_objects.value().get(); + + lightweight_quarantine_branch_storage_for_large_objects.emplace( + lightweight_quarantine_root_storage->CreateBranch( + LightweightQuarantineBranchConfig{ + .lock_required = true, + .branch_capacity_in_bytes = + init_options.quarantine_capacity_for_large_objects_in_bytes, + })); + lightweight_quarantine_branch_for_large_objects = + lightweight_quarantine_branch_storage_for_large_objects.value().get(); is_quarantine_initialized.store(true, std::memory_order_release); @@ -170,8 +184,13 @@ ExtremeLightweightDetectorUtil::Zap(object, usable_size); uintptr_t slot_start = root->ObjectToSlotStart(object); - lightweight_quarantine_branch->Quarantine(object, slot_span, slot_start, - usable_size); + if (usable_size <= init_options.object_size_threshold_in_bytes) [[likely]] { + lightweight_quarantine_branch_for_small_objects->Quarantine( + object, slot_span, slot_start, usable_size); + } else { + lightweight_quarantine_branch_for_large_objects->Quarantine( + object, slot_span, slot_start, usable_size); + } return true; } @@ -227,16 +246,26 @@ nullptr // next }; -[[maybe_unused]] base::trace_event::MallocDumpProvider::ExtremeLUDStats +[[maybe_unused]] base::trace_event::MallocDumpProvider::ExtremeLUDStatsSet GetStats() { - if (!lightweight_quarantine_branch) { // Not yet initialized. - return {}; + if (!lightweight_quarantine_branch_for_small_objects || + !lightweight_quarantine_branch_for_large_objects) { + return {}; // Not yet initialized. } - base::trace_event::MallocDumpProvider::ExtremeLUDStats stats{ - .capacity_in_bytes = lightweight_quarantine_branch->GetCapacityInBytes()}; - lightweight_quarantine_branch->GetRoot().AccumulateStats(stats.lq_stats); - return stats; + base::trace_event::MallocDumpProvider::ExtremeLUDStatsSet elud_stats_set; + + elud_stats_set.for_small_objects.capacity_in_bytes = + lightweight_quarantine_branch_for_small_objects->GetCapacityInBytes(); + lightweight_quarantine_branch_for_small_objects->GetRoot().AccumulateStats( + elud_stats_set.for_small_objects.lq_stats); + + elud_stats_set.for_large_objects.capacity_in_bytes = + lightweight_quarantine_branch_for_large_objects->GetCapacityInBytes(); + lightweight_quarantine_branch_for_large_objects->GetRoot().AccumulateStats( + elud_stats_set.for_large_objects.lq_stats); + + return elud_stats_set; } } // namespace @@ -258,10 +287,17 @@ } partition_alloc::internal::LightweightQuarantineBranch& -GetEludQuarantineBranchForTesting() { +GetEludQuarantineBranchForSmallObjectsForTesting() { CHECK(TryInit()); - return *lightweight_quarantine_branch; + return *lightweight_quarantine_branch_for_small_objects; +} + +partition_alloc::internal::LightweightQuarantineBranch& +GetEludQuarantineBranchForLargeObjectsForTesting() { + CHECK(TryInit()); + + return *lightweight_quarantine_branch_for_large_objects; } } // namespace gwp_asan::internal
diff --git a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.h b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.h index 20c7d351..7f97c67 100644 --- a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.h +++ b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.h
@@ -14,7 +14,9 @@ struct GWP_ASAN_EXPORT ExtremeLightweightDetectorOptions { size_t sampling_frequency; - size_t quarantine_capacity_in_bytes; + size_t quarantine_capacity_for_small_objects_in_bytes; + size_t quarantine_capacity_for_large_objects_in_bytes; + size_t object_size_threshold_in_bytes; }; GWP_ASAN_EXPORT void InstallExtremeLightweightDetectorHooks( @@ -22,7 +24,9 @@ // Elud = Extreme Lightweight UAF Detector GWP_ASAN_EXPORT partition_alloc::internal::LightweightQuarantineBranch& -GetEludQuarantineBranchForTesting(); +GetEludQuarantineBranchForSmallObjectsForTesting(); +GWP_ASAN_EXPORT partition_alloc::internal::LightweightQuarantineBranch& +GetEludQuarantineBranchForLargeObjectsForTesting(); } // namespace gwp_asan::internal
diff --git a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims_unittest.cc b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims_unittest.cc index 69132c7..703eb7b 100644 --- a/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims_unittest.cc +++ b/components/gwp_asan/client/extreme_lightweight_detector_malloc_shims_unittest.cc
@@ -18,7 +18,9 @@ namespace { constexpr size_t kSamplingFrequency = 10; -constexpr size_t kQuarantineCapacityInBytes = 4096; +constexpr size_t kQuarantineCapacityForSmallObjectsInBytes = 4096; +constexpr size_t kQuarantineCapacityForLargeObjectsInBytes = 4096; +constexpr size_t kObjectSizeThresholdInBytes = 256; // Number of loop iterations required to definitely hit a sampled allocation. constexpr size_t kLoopIterations = kSamplingFrequency * 10; @@ -42,7 +44,11 @@ allocator_shim::UseSmallSingleSlotSpans(true)); InstallExtremeLightweightDetectorHooks( {.sampling_frequency = kSamplingFrequency, - .quarantine_capacity_in_bytes = kQuarantineCapacityInBytes}); + .quarantine_capacity_for_small_objects_in_bytes = + kQuarantineCapacityForSmallObjectsInBytes, + .quarantine_capacity_for_large_objects_in_bytes = + kQuarantineCapacityForLargeObjectsInBytes, + .object_size_threshold_in_bytes = kObjectSizeThresholdInBytes}); } protected: @@ -58,31 +64,57 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP( Basic, ExtremeLightweightDetectorMallocShimsTest::MultiprocessTestSetup) { - auto& quarantine_branch = GetEludQuarantineBranchForTesting(); + auto& small_quarantine = GetEludQuarantineBranchForSmallObjectsForTesting(); + auto& large_quarantine = GetEludQuarantineBranchForLargeObjectsForTesting(); - struct TestObject { + struct SmallObject { + using TypeTag = SmallObject*; char c[42]; }; - TestObject* ptr = nullptr; - for (size_t i = 0; i < kLoopIterations; ++i) { - // macOS defers the actual deallocation when `free` is called (i.e. `free` - // returns immediately without actually deallocating the memory pointed to - // by the given pointer). It's not easy to predict when `Quarantine` is - // called. However, `operator delete` doesn't defer the deallocation. It - // calls `malloc_zone_free` in sync (As of Jan 2024). So, new/delete is - // used instead of malloc/free here. - ptr = new TestObject(); - delete ptr; - if (quarantine_branch.IsQuarantinedForTesting(ptr)) { - break; + CHECK_LT(sizeof(SmallObject), kObjectSizeThresholdInBytes); + + struct LargeObject { + using TypeTag = LargeObject*; + char c[1234]; + }; + CHECK_GT(sizeof(LargeObject), kObjectSizeThresholdInBytes); + + auto try_to_quarantine = + []<typename ObjectType>( + partition_alloc::internal::LightweightQuarantineBranch& + quarantine_branch, + ObjectType* unused_type_tag) -> ObjectType* { + for (size_t i = 0; i < kLoopIterations; ++i) { + // macOS defers the actual deallocation when `free` is called (i.e. `free` + // returns immediately without actually deallocating the memory pointed to + // by the given pointer). It's not easy to predict when `Quarantine` is + // called. However, `operator delete` doesn't defer the deallocation. It + // calls `malloc_zone_free` in sync (As of Jan 2024). So, new/delete is + // used instead of malloc/free here. + ObjectType* ptr = new ObjectType(); + delete ptr; + if (quarantine_branch.IsQuarantinedForTesting(ptr)) { + return ptr; + } } - } + return nullptr; + }; - const bool result = quarantine_branch.IsQuarantinedForTesting(ptr); - EXPECT_TRUE(result); - quarantine_branch.Purge(); + SmallObject* small_object = + try_to_quarantine(small_quarantine, SmallObject::TypeTag()); + EXPECT_TRUE(small_object); + EXPECT_TRUE(small_quarantine.IsQuarantinedForTesting(small_object)); + EXPECT_FALSE(large_quarantine.IsQuarantinedForTesting(small_object)); + small_quarantine.Purge(); - return result ? kSuccess : kFailure; + LargeObject* large_object = + try_to_quarantine(large_quarantine, LargeObject::TypeTag()); + EXPECT_TRUE(large_object); + EXPECT_FALSE(small_quarantine.IsQuarantinedForTesting(large_object)); + EXPECT_TRUE(large_quarantine.IsQuarantinedForTesting(large_object)); + large_quarantine.Purge(); + + return ::testing::Test::HasFailure() ? kFailure : kSuccess; } TEST_F(ExtremeLightweightDetectorMallocShimsTest, Basic) {
diff --git a/components/gwp_asan/client/gwp_asan.cc b/components/gwp_asan/client/gwp_asan.cc index 99901fce..78296051 100644 --- a/components/gwp_asan/client/gwp_asan.cc +++ b/components/gwp_asan/client/gwp_asan.cc
@@ -571,12 +571,24 @@ [[maybe_unused]] static bool init_once = [&]() -> bool { size_t sampling_frequency = static_cast<size_t>( internal::kExtremeLightweightUAFDetectorSamplingFrequency.Get()); - size_t quarantine_capacity_in_bytes = static_cast<size_t>( - internal::kExtremeLightweightUAFDetectorQuarantineCapacityInBytes + size_t quarantine_capacity_for_small_objects_in_bytes = static_cast<size_t>( + internal:: + kExtremeLightweightUAFDetectorQuarantineCapacityForSmallObjectsInBytes + .Get()); + size_t quarantine_capacity_for_large_objects_in_bytes = static_cast<size_t>( + internal:: + kExtremeLightweightUAFDetectorQuarantineCapacityForLargeObjectsInBytes + .Get()); + size_t object_size_threshold_in_bytes = static_cast<size_t>( + internal::kExtremeLightweightUAFDetectorObjectSizeThresholdInBytes .Get()); internal::InstallExtremeLightweightDetectorHooks( {.sampling_frequency = sampling_frequency, - .quarantine_capacity_in_bytes = quarantine_capacity_in_bytes}); + .quarantine_capacity_for_small_objects_in_bytes = + quarantine_capacity_for_small_objects_in_bytes, + .quarantine_capacity_for_large_objects_in_bytes = + quarantine_capacity_for_large_objects_in_bytes, + .object_size_threshold_in_bytes = object_size_threshold_in_bytes}); return true; }(); #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/components/gwp_asan/client/gwp_asan_features.cc b/components/gwp_asan/client/gwp_asan_features.cc index cebea167..af6e4bf 100644 --- a/components/gwp_asan/client/gwp_asan_features.cc +++ b/components/gwp_asan/client/gwp_asan_features.cc
@@ -27,9 +27,21 @@ &kExtremeLightweightUAFDetector, "sampling_frequency", 1000}; // Quarantine once per 1000 calls to `free`. const base::FeatureParam<int> - kExtremeLightweightUAFDetectorQuarantineCapacityInBytes{ - &kExtremeLightweightUAFDetector, "quarantine_capacity_in_bytes", - 256 * 1024}; + kExtremeLightweightUAFDetectorQuarantineCapacityForSmallObjectsInBytes{ + &kExtremeLightweightUAFDetector, + "quarantine_capacity_for_small_objects_in_bytes", + 1 * 1024 * 1024 - 100 * 1024}; // 900 KiB for small objects. +const base::FeatureParam<int> + kExtremeLightweightUAFDetectorQuarantineCapacityForLargeObjectsInBytes{ + &kExtremeLightweightUAFDetector, + "quarantine_capacity_for_large_objects_in_bytes", + 100 * 1024}; // 100 KiB for large objects. +// Small objects: size <= 1 KiB +// Large objects: size > 1 KiB +const base::FeatureParam<int> + kExtremeLightweightUAFDetectorObjectSizeThresholdInBytes{ + &kExtremeLightweightUAFDetector, "object_size_threshold_in_bytes", + 1 * 1024}; constexpr base::FeatureParam<ExtremeLightweightUAFDetectorTargetProcesses>:: Option kExtremeLightweightUAFDetectorTargetProcessesOptions[] = { {ExtremeLightweightUAFDetectorTargetProcesses::kAllProcesses, "all"},
diff --git a/components/gwp_asan/client/gwp_asan_features.h b/components/gwp_asan/client/gwp_asan_features.h index fb366aee..efa849f 100644 --- a/components/gwp_asan/client/gwp_asan_features.h +++ b/components/gwp_asan/client/gwp_asan_features.h
@@ -18,7 +18,11 @@ GWP_ASAN_EXPORT extern const base::FeatureParam<int> kExtremeLightweightUAFDetectorSamplingFrequency; GWP_ASAN_EXPORT extern const base::FeatureParam<int> - kExtremeLightweightUAFDetectorQuarantineCapacityInBytes; + kExtremeLightweightUAFDetectorQuarantineCapacityForSmallObjectsInBytes; +GWP_ASAN_EXPORT extern const base::FeatureParam<int> + kExtremeLightweightUAFDetectorQuarantineCapacityForLargeObjectsInBytes; +GWP_ASAN_EXPORT extern const base::FeatureParam<int> + kExtremeLightweightUAFDetectorObjectSizeThresholdInBytes; enum class ExtremeLightweightUAFDetectorTargetProcesses { kAllProcesses, kBrowserProcessOnly,
diff --git a/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc index 18f7d24..d8c441ce 100644 --- a/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc +++ b/components/page_load_metrics/browser/observers/abandoned_page_load_metrics_observer.cc
@@ -321,8 +321,7 @@ std::string AbandonedPageLoadMetricsObserver:: GetTimeToAbandonFromNavigationStartWithoutPrefixSuffix( NavigationMilestone milestone) { - return std::string(internal::kAbandonedPageLoadMetricsHistogramPrefix) + - internal::kTimeToAbandonFromNavigationStart + + return internal::kTimeToAbandonFromNavigationStart + NavigationMilestoneToString(milestone); }
diff --git a/components/page_load_metrics/browser/page_load_metrics_forward_observer.cc b/components/page_load_metrics/browser/page_load_metrics_forward_observer.cc index c0cbfe4..d881723 100644 --- a/components/page_load_metrics/browser/page_load_metrics_forward_observer.cc +++ b/components/page_load_metrics/browser/page_load_metrics_forward_observer.cc
@@ -28,7 +28,10 @@ const PageLoadMetricsObserverDelegate& PageLoadMetricsForwardObserver::GetDelegate() const { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); const PageLoadMetricsObserverDelegate* null_value = nullptr; return *null_value; } @@ -48,7 +51,10 @@ content::NavigationHandle* navigation_handle, const GURL& currently_committed_url, bool started_in_foreground) { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); return STOP_OBSERVING; } @@ -56,7 +62,10 @@ PageLoadMetricsForwardObserver::OnFencedFramesStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); return STOP_OBSERVING; } @@ -64,7 +73,10 @@ PageLoadMetricsForwardObserver::OnPrerenderStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); return STOP_OBSERVING; } @@ -72,7 +84,10 @@ PageLoadMetricsForwardObserver::OnPreviewStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); return STOP_OBSERVING; } @@ -199,7 +214,10 @@ void PageLoadMetricsForwardObserver::OnUserInput( const blink::WebInputEvent& event, const mojom::PageLoadTiming& timing) { - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); } // Following events should be ignored as they are controlled at @@ -237,21 +255,30 @@ OnFirstPaintAfterBackForwardCacheRestoreInPage( const mojom::BackForwardCacheTiming& timing, size_t index) { - NOTREACHED_IN_MIGRATION() << "Not supported."; + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED() << "Not supported."; } void PageLoadMetricsForwardObserver:: OnFirstInputAfterBackForwardCacheRestoreInPage( const mojom::BackForwardCacheTiming& timing, size_t index) { - NOTREACHED_IN_MIGRATION() << "Not supported."; + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED() << "Not supported."; } void PageLoadMetricsForwardObserver:: OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage( const mojom::BackForwardCacheTiming& timing, size_t index) { - NOTREACHED_IN_MIGRATION() << "Not supported."; + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED() << "Not supported."; } void PageLoadMetricsForwardObserver::OnFirstMeaningfulPaintInMainFrameDocument( @@ -284,7 +311,10 @@ // See also MetricsWebContentsObserver::SetUpSharedMemoryForSmoothness and // the relevant TODO. Currently, information from OOPIFs and FencedFrames are // not handled. - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); } // PageLoadTracker already aggregates inter-pages data and processes it via @@ -423,7 +453,10 @@ void PageLoadMetricsForwardObserver::OnPrefetchLikely() { // This event is delivered only for the primary page. - NOTREACHED_IN_MIGRATION(); + // TODO(crbug.com/40895492): Investigate whether this should truly be + // unreachable. Note that all NOTREACHED()s were made non-fatal in this file, + // they are not all necessarily hit. + DUMP_WILL_BE_NOTREACHED(); } void PageLoadMetricsForwardObserver::DidActivatePrerenderedPage(
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc index 9a70f49..a38d5ab8 100644 --- a/components/plugins/renderer/webview_plugin.cc +++ b/components/plugins/renderer/webview_plugin.cc
@@ -91,7 +91,7 @@ if (!response_.IsNull()) { plugin->DidReceiveResponse(response_); for (auto it = data_.begin(); it != data_.end(); ++it) { - plugin->DidReceiveData(it->c_str(), it->length()); + plugin->DidReceiveData(*it); } } // We need to transfer the |focused_| to new plugin after it loaded. @@ -247,8 +247,8 @@ response_ = response; } -void WebViewPlugin::DidReceiveData(const char* data, size_t data_length) { - data_.push_back(std::string(data, data_length)); +void WebViewPlugin::DidReceiveData(base::span<const char> data) { + data_.push_back(std::string(data.data(), data.size())); } void WebViewPlugin::DidFinishLoading() {
diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h index 420c4b2..68ff19c 100644 --- a/components/plugins/renderer/webview_plugin.h +++ b/components/plugins/renderer/webview_plugin.h
@@ -115,7 +115,7 @@ ui::Cursor* cursor) override; void DidReceiveResponse(const blink::WebURLResponse& response) override; - void DidReceiveData(const char* data, size_t data_length) override; + void DidReceiveData(base::span<const char> data) override; void DidFinishLoading() override; void DidFailLoading(const blink::WebURLError& error) override;
diff --git a/components/plus_addresses/plus_address_parsing_utils.cc b/components/plus_addresses/plus_address_parsing_utils.cc index ec3fc39..bb16d55 100644 --- a/components/plus_addresses/plus_address_parsing_utils.cc +++ b/components/plus_addresses/plus_address_parsing_utils.cc
@@ -16,7 +16,6 @@ #include "components/plus_addresses/plus_address_types.h" #include "components/plus_addresses/webdata/plus_address_webdata_service.h" #include "services/data_decoder/public/cpp/data_decoder.h" -#include "url/origin.h" namespace plus_addresses { @@ -68,13 +67,9 @@ !is_confirmed.has_value()) { return std::nullopt; } - GURL url = GURL(facet_str); affiliations::FacetURI facet = affiliations::FacetURI::FromPotentiallyInvalidSpec(facet_str); - // An exception is made for `http` domains as these are considered invalid by - // the `FacetURI` class. - if (!facet.is_valid() && - (!url.is_valid() || !url.SchemeIs(url::kHttpScheme))) { + if (!facet.is_valid()) { return std::nullopt; } return PlusProfile(std::move(profile_id), std::move(facet),
diff --git a/components/policy/resources/templates/policy_definitions/ContentSettings/DefaultGeolocationSetting.yaml b/components/policy/resources/templates/policy_definitions/ContentSettings/DefaultGeolocationSetting.yaml index f5bad75..14f4288b 100644 --- a/components/policy/resources/templates/policy_definitions/ContentSettings/DefaultGeolocationSetting.yaml +++ b/components/policy/resources/templates/policy_definitions/ContentSettings/DefaultGeolocationSetting.yaml
@@ -1,6 +1,6 @@ arc_support: (Warning! Soon this dependency will be dropped, please start using <ph name="GLS_POLICY_NAME">GoogleLocationServicesEnabled</ph> instead) If this policy is set to <ph name="BLOCK_GEOLOCATION_SETTING">BlockGeolocation</ph>, - Android apps cannot access location information. If you set this policy to any other - value or leave it unset, the user is asked to consent when an Android app wants + <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph> system services and Android apps cannot access location information. If you set this policy to any other + value or leave it unset, the user is asked to allow when an Android app wants to access location information. caption: Default geolocation setting default: null
diff --git a/components/search_engine_choice_strings.grdp b/components/search_engine_choice_strings.grdp index 426d4c4b..afa46de4 100644 --- a/components/search_engine_choice_strings.grdp +++ b/components/search_engine_choice_strings.grdp
@@ -138,4 +138,8 @@ <message name="IDS_SEARCH_ENGINE_CHOICE_LIST_A11Y_LABEL" desc="Accessibility label for the list of search engines. This list is on a screen that prompts the user to select the search engine that they want to use by default. (A search engine provides answers to search queries; this is different from a browser, which displays web pages. A search engine powers many experiences within a browser.) This screen appears when the user opens Chrome after updating or installing the app. The headline for this screen is 'Choose your search engine'."> Search engines </message> + + <message name="IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX" desc="This label is displayed on a checkbox. When selected, Chrome will remember the chosen search engine and apply it to all future Guest profiles. If your language requires an object noun for the verb, you can phrase it as 'Use this choice for all guests'; however, please try to keep this string concise, because the rest of the screen provides a lot of obvious context. A terse tone is acceptable."> + Use for all guests + </message> </grit-part>
diff --git a/components/search_engine_choice_strings_grdp/IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX.png.sha1 b/components/search_engine_choice_strings_grdp/IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX.png.sha1 new file mode 100644 index 0000000..8bbcb78 --- /dev/null +++ b/components/search_engine_choice_strings_grdp/IDS_SEARCH_ENGINE_CHOICE_GUEST_SESSION_CHECKBOX.png.sha1
@@ -0,0 +1 @@ +ded9e13f0f49aca39f809ba3be16737f2f9b2e3a \ No newline at end of file
diff --git a/components/search_engines/search_engines_switches.cc b/components/search_engines/search_engines_switches.cc index 0eea1922..a937c37f 100644 --- a/components/search_engines/search_engines_switches.cc +++ b/components/search_engines/search_engines_switches.cc
@@ -35,6 +35,12 @@ const char kForceSearchEngineChoiceScreen[] = "force-search-engine-choice-screen"; +// Enables the new guest mode experience for the search engine choice dialog. +COMPONENT_EXPORT(SEARCH_ENGINES_SWITCHES) +BASE_FEATURE(kSearchEngineChoiceGuestExperience, + "SearchEngineChoiceGuestExperience", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables the search engine choice screen. Feature parameters below can // affect the actual triggering logic. // The default feature state is split by platform to ease potential merges
diff --git a/components/search_engines/search_engines_switches.h b/components/search_engines/search_engines_switches.h index e60140c9..9b6bbf0 100644 --- a/components/search_engines/search_engines_switches.h +++ b/components/search_engines/search_engines_switches.h
@@ -39,6 +39,9 @@ extern const char kForceSearchEngineChoiceScreen[]; COMPONENT_EXPORT(SEARCH_ENGINES_SWITCHES) +BASE_DECLARE_FEATURE(kSearchEngineChoiceGuestExperience); + +COMPONENT_EXPORT(SEARCH_ENGINES_SWITCHES) BASE_DECLARE_FEATURE(kSearchEngineChoiceTrigger); #if BUILDFLAG(IS_ANDROID)
diff --git a/components/supervised_user/core/browser/proto_fetcher.cc b/components/supervised_user/core/browser/proto_fetcher.cc index 4a1f7cd..c32534a7 100644 --- a/components/supervised_user/core/browser/proto_fetcher.cc +++ b/components/supervised_user/core/browser/proto_fetcher.cc
@@ -145,15 +145,6 @@ } // namespace -base::TimeDelta Stopwatch::Lap() { - base::TimeDelta lap = lap_timer_.Elapsed(); - lap_timer_ = base::ElapsedTimer(); - return lap; -} -base::TimeDelta Stopwatch::Elapsed() const { - return elapsed_timer_.Elapsed(); -} - Metrics::Metrics(std::string_view basename) : basename_(basename) {} /* static */ std::optional<Metrics> Metrics::FromConfig( const FetcherConfig& config) { @@ -170,26 +161,12 @@ void Metrics::RecordLatency() const { base::UmaHistogramTimes(GetFullHistogramName(MetricType::kLatency), - stopwatch_.Elapsed()); -} - -void Metrics::RecordAccessTokenLatency( - GoogleServiceAuthError::State auth_error_state) { - base::UmaHistogramTimes( - GetFullHistogramName(MetricType::kAccessTokenLatency, auth_error_state), - stopwatch_.Lap()); -} - -void Metrics::RecordApiLatency( - ProtoFetcherStatus::HttpStatusOrNetErrorType http_status_or_net_error) { - base::UmaHistogramTimes( - GetFullHistogramName(MetricType::kApiLatency, http_status_or_net_error), - stopwatch_.Lap()); + elapsed_timer_.Elapsed()); } void Metrics::RecordStatusLatency(const ProtoFetcherStatus& status) const { base::UmaHistogramTimes(GetFullHistogramName(MetricType::kLatency, status), - stopwatch_.Elapsed()); + elapsed_timer_.Elapsed()); } void Metrics::RecordAuthError(const GoogleServiceAuthError& auth_error) const { @@ -214,10 +191,6 @@ return "Latency"; case MetricType::kHttpStatusOrNetError: return "HttpStatusOrNetError"; - case MetricType::kAccessTokenLatency: - return "AccessTokenLatency"; - case MetricType::kApiLatency: - return "ApiLatency"; case MetricType::kAuthError: return "AuthError"; case MetricType::kRetryCount: @@ -365,10 +338,6 @@ } } - if (IsMetricsRecordingEnabled()) { - metrics_->RecordAccessTokenLatency(GoogleServiceAuthError::State::NONE); - } - simple_url_loader_ = InitializeSimpleUrlLoader(base::OptionalFromExpected(access_token), config_, args_, channel_, GetRequestPayload()); @@ -389,10 +358,6 @@ return; } - if (IsMetricsRecordingEnabled()) { - metrics_->RecordApiLatency( - ProtoFetcherStatus::HttpStatusOrNetErrorType(net::HTTP_OK)); - } OnResponse(std::move(response_body)); }
diff --git a/components/supervised_user/core/browser/proto_fetcher.h b/components/supervised_user/core/browser/proto_fetcher.h index 0825da0..7b201cc9 100644 --- a/components/supervised_user/core/browser/proto_fetcher.h +++ b/components/supervised_user/core/browser/proto_fetcher.h
@@ -64,22 +64,6 @@ // // The static configuration should be placed in the fetcher_config.h module. -// A stopwatch with two functions: -// * measure total elapsed time, -// * measure lap time (with automatic resetting after each lap). -// The stopwatch is created started. -class Stopwatch { - public: - // Time since start of last lap. Resets the lap timer. - base::TimeDelta Lap(); - // Time since start of last lap. - base::TimeDelta Elapsed() const; - - private: - base::ElapsedTimer elapsed_timer_; - base::ElapsedTimer lap_timer_; -}; - // Encapsulates metric functionalities. class Metrics { public: @@ -88,8 +72,6 @@ kLatency, kHttpStatusOrNetError, kRetryCount, - kAccessTokenLatency, - kApiLatency, kAuthError, }; @@ -142,7 +124,7 @@ static std::string ToMetricEnumLabel(const ProtoFetcherStatus& status); std::string_view basename_; - Stopwatch stopwatch_; + base::ElapsedTimer elapsed_timer_; }; // Metrics for retrying fetchers, which are aggregating individual
diff --git a/components/supervised_user/core/browser/proto_fetcher_unittest.cc b/components/supervised_user/core/browser/proto_fetcher_unittest.cc index 68ac1e7..031cdcd 100644 --- a/components/supervised_user/core/browser/proto_fetcher_unittest.cc +++ b/components/supervised_user/core/browser/proto_fetcher_unittest.cc
@@ -484,13 +484,6 @@ base::StrCat({*GetConfig().histogram_basename, ".Latency"}), /*expected_count(grew by)*/ 1); histogram_tester.ExpectTotalCount( - base::StrCat( - {*GetConfig().histogram_basename, ".NONE.AccessTokenLatency"}), - /*expected_count(grew by)*/ 1); - histogram_tester.ExpectTotalCount( - base::StrCat({*GetConfig().histogram_basename, ".HTTP_OK.ApiLatency"}), - /*expected_count(grew by)*/ 1); - histogram_tester.ExpectTotalCount( base::StrCat({*GetConfig().histogram_basename, ".NoError.Latency"}), /*expected_count(grew by)*/ 1); @@ -574,16 +567,6 @@ base::StrCat({*GetConfig().histogram_basename, ".NoError.Latency"}), /*expected_count(grew by)*/ 1); - // System made it through access token phase three times. - histogram_tester.ExpectTotalCount( - base::StrCat( - {*GetConfig().histogram_basename, ".NONE.AccessTokenLatency"}), - /*expected_count(grew by)*/ 3); - // Only one successful api call. - histogram_tester.ExpectTotalCount( - base::StrCat({*GetConfig().histogram_basename, ".HTTP_OK.ApiLatency"}), - /*expected_count(grew by)*/ 1); - histogram_tester.ExpectTotalCount( base::StrCat( {*GetConfig().histogram_basename, ".HttpStatusOrNetError.Latency"}), @@ -665,16 +648,6 @@ base::StrCat({*GetConfig().histogram_basename, ".ParseError.Latency"}), /*expected_count(grew by)*/ 1); - // System made it through access token phase two times. - histogram_tester.ExpectTotalCount( - base::StrCat( - {*GetConfig().histogram_basename, ".NONE.AccessTokenLatency"}), - /*expected_count(grew by)*/ 2); - // Only one successful api call (parse error is a successful api call). - histogram_tester.ExpectTotalCount( - base::StrCat({*GetConfig().histogram_basename, ".HTTP_OK.ApiLatency"}), - /*expected_count(grew by)*/ 1); - histogram_tester.ExpectTotalCount( base::StrCat( {*GetConfig().histogram_basename, ".HttpStatusOrNetError.Latency"}), @@ -745,16 +718,6 @@ {*GetConfig().histogram_basename, ".HttpStatusOrNetError.Latency"}), /*expected_count(grew by)*/ 2); - // System made it through access token phase two times. - histogram_tester.ExpectTotalCount( - base::StrCat( - {*GetConfig().histogram_basename, ".NONE.AccessTokenLatency"}), - /*expected_count(grew by)*/ 3); - // Server only responds with error. - histogram_tester.ExpectTotalCount( - base::StrCat({*GetConfig().histogram_basename, ".HTTP_OK.ApiLatency"}), - /*expected_count(grew by)*/ 0); - EXPECT_THAT( histogram_tester.GetAllSamples( base::StrCat({*GetConfig().histogram_basename, ".Status"})),
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h index 8fb2589f..a47cc74 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h
@@ -1287,6 +1287,7 @@ } VISIT_PROTO_FIELDS(const sync_pb::SessionHeader& proto) { + VISIT(session_start_time_unix_epoch_millis); VISIT_REP(window); VISIT(client_name); VISIT_ENUM(device_type);
diff --git a/components/sync/protocol/session_specifics.proto b/components/sync/protocol/session_specifics.proto index 2d46485..ec5f5b6 100644 --- a/components/sync/protocol/session_specifics.proto +++ b/components/sync/protocol/session_specifics.proto
@@ -31,6 +31,10 @@ // Properties of session sync objects. message SessionHeader { + // The timestamp when this session was started, i.e. when the user signed in + // or turned on the sessions data type. Introduced in M130, and not populated + // for sessions created/started before that milestone. + optional int64 session_start_time_unix_epoch_millis = 6; // Each session is composed of windows. repeated SessionWindow window = 2; // A non-unique but human-readable name to describe this client.
diff --git a/components/sync_sessions/local_session_event_handler_impl.cc b/components/sync_sessions/local_session_event_handler_impl.cc index a9d56e8..b9795b9 100644 --- a/components/sync_sessions/local_session_event_handler_impl.cc +++ b/components/sync_sessions/local_session_event_handler_impl.cc
@@ -113,7 +113,8 @@ LocalSessionEventHandlerImpl::LocalSessionEventHandlerImpl( Delegate* delegate, SyncSessionsClient* sessions_client, - SyncedSessionTracker* session_tracker) + SyncedSessionTracker* session_tracker, + bool is_new_session) : delegate_(delegate), sessions_client_(sessions_client), session_tracker_(session_tracker) { @@ -124,6 +125,10 @@ current_session_tag_ = session_tracker_->GetLocalSessionTag(); DCHECK(!current_session_tag_.empty()); + if (is_new_session) { + session_tracker_->SetLocalSessionStartTime(base::Time::Now()); + } + if (!IsSessionRestoreInProgress(sessions_client)) { OnSessionRestoreComplete(); }
diff --git a/components/sync_sessions/local_session_event_handler_impl.h b/components/sync_sessions/local_session_event_handler_impl.h index 15ed85f..f39fedc 100644 --- a/components/sync_sessions/local_session_event_handler_impl.h +++ b/components/sync_sessions/local_session_event_handler_impl.h
@@ -61,7 +61,8 @@ // changes). LocalSessionEventHandlerImpl(Delegate* delegate, SyncSessionsClient* sessions_client, - SyncedSessionTracker* session_tracker); + SyncedSessionTracker* session_tracker, + bool is_new_session); LocalSessionEventHandlerImpl(const LocalSessionEventHandlerImpl&) = delete; LocalSessionEventHandlerImpl& operator=(const LocalSessionEventHandlerImpl&) =
diff --git a/components/sync_sessions/local_session_event_handler_impl_unittest.cc b/components/sync_sessions/local_session_event_handler_impl_unittest.cc index 2a3e1d8..d4de86b 100644 --- a/components/sync_sessions/local_session_event_handler_impl_unittest.cc +++ b/components/sync_sessions/local_session_event_handler_impl_unittest.cc
@@ -126,7 +126,8 @@ void InitHandler() { handler_ = std::make_unique<LocalSessionEventHandlerImpl>( - &mock_delegate_, &mock_sync_sessions_client_, &session_tracker_); + &mock_delegate_, &mock_sync_sessions_client_, &session_tracker_, + /*is_new_session=*/true); window_getter_.router()->StartRoutingTo(handler_.get()); }
diff --git a/components/sync_sessions/session_sync_bridge.cc b/components/sync_sessions/session_sync_bridge.cc index ac99a1c..b071aac4 100644 --- a/components/sync_sessions/session_sync_bridge.cc +++ b/components/sync_sessions/session_sync_bridge.cc
@@ -143,13 +143,15 @@ DCHECK(!syncing_); DCHECK(change_processor()->IsTrackingMetadata()); - StartLocalSessionEventHandler(); + store_->mutable_tracker()->SetLocalSessionStartTime(base::Time::Now()); + + StartLocalSessionEventHandler(/*is_new_session=*/true); return ApplyIncrementalSyncChanges(std::move(metadata_change_list), std::move(entity_data)); } -void SessionSyncBridge::StartLocalSessionEventHandler() { +void SessionSyncBridge::StartLocalSessionEventHandler(bool is_new_session) { // We should be ready to propagate local state to sync. DCHECK(change_processor()->IsTrackingMetadata()); DCHECK(!syncing_); @@ -161,7 +163,8 @@ // store. syncing_->local_session_event_handler = std::make_unique<LocalSessionEventHandlerImpl>( - /*delegate=*/this, sessions_client_, store_->mutable_tracker()); + /*delegate=*/this, sessions_client_, store_->mutable_tracker(), + is_new_session); syncing_->open_tabs_ui_delegate = std::make_unique<OpenTabsUIDelegateImpl>( sessions_client_, store_->tracker(), @@ -364,7 +367,7 @@ // If initial sync was already done, MergeFullSyncData() will never be // called so we need to start syncing local changes. if (change_processor()->IsTrackingMetadata()) { - StartLocalSessionEventHandler(); + StartLocalSessionEventHandler(/*is_new_session=*/false); } return; } @@ -396,7 +399,7 @@ // If initial sync was already done, MergeFullSyncData() will never be called // so we need to start syncing local changes. if (change_processor()->IsTrackingMetadata()) { - StartLocalSessionEventHandler(); + StartLocalSessionEventHandler(/*is_new_session=*/false); } }
diff --git a/components/sync_sessions/session_sync_bridge.h b/components/sync_sessions/session_sync_bridge.h index 4b8f851..ec1b279 100644 --- a/components/sync_sessions/session_sync_bridge.h +++ b/components/sync_sessions/session_sync_bridge.h
@@ -85,7 +85,7 @@ const std::optional<syncer::ModelError>& error, std::unique_ptr<SessionStore> store, std::unique_ptr<syncer::MetadataBatch> metadata_batch); - void StartLocalSessionEventHandler(); + void StartLocalSessionEventHandler(bool is_new_session); void DeleteForeignSessionFromUI(const std::string& tag); void DoGarbageCollection(SessionStore::WriteBatch* write_batch); std::unique_ptr<SessionStore::WriteBatch> CreateSessionStoreWriteBatch();
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc index e1f6ed3..689e427 100644 --- a/components/sync_sessions/session_sync_bridge_unittest.cc +++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/bind.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "components/prefs/testing_pref_service.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/engine/commit_and_get_updates_types.h" @@ -126,12 +127,13 @@ return data; } -syncer::CommitResponseData CreateSuccessResponse( - const std::string& client_tag) { +syncer::CommitResponseData CreateSuccessResponse(const std::string& client_tag, + int sequence_number = 1) { syncer::CommitResponseData response; response.client_tag_hash = syncer::ClientTagHash::FromUnhashed(syncer::SESSIONS, client_tag); - response.sequence_number = 1; + response.sequence_number = sequence_number; + response.response_version = sequence_number; return response; } @@ -214,14 +216,10 @@ request.cache_guid = kLocalCacheGuid; request.authenticated_account_id = CoreAccountId::FromGaiaId(kAccountId); - base::RunLoop loop; - real_processor_->OnSyncStarting( - request, - base::BindLambdaForTesting( - [&loop](std::unique_ptr<syncer::DataTypeActivationResponse>) { - loop.Quit(); - })); - loop.Run(); + base::test::TestFuture<std::unique_ptr<syncer::DataTypeActivationResponse>> + sync_starting_cb; + real_processor_->OnSyncStarting(request, sync_starting_cb.GetCallback()); + ASSERT_TRUE(sync_starting_cb.Wait()); // ClientTagBasedDataTypeProcessor requires connecting before other // interactions with the worker happen. @@ -376,6 +374,41 @@ EXPECT_THAT(GetAllData(), SizeIs(1)); } +TEST_F(SessionSyncBridgeTest, ShouldPopulateSessionStartTimeOnFirstSync) { + // Store the initial time, in order to later verify that the session start + // time is >= this time. Round down to the nearest millisecond, since the + // session start time only uses millisecond granularity. + const base::Time initial_time = base::Time::FromMillisecondsSinceUnixEpoch( + base::Time::Now().InMillisecondsSinceUnixEpoch()); + + InitializeBridge(); + + EXPECT_CALL(mock_processor(), ModelReadyToSync(IsEmptyMetadataBatch())); + StartSyncing(); + + const std::string header_storage_key = + SessionStore::GetHeaderStorageKey(kLocalCacheGuid); + + // The session start time should have been populated. + const base::Time session_start_time = + base::Time::FromMillisecondsSinceUnixEpoch( + GetAllData()[header_storage_key] + ->specifics.session() + .header() + .session_start_time_unix_epoch_millis()); + EXPECT_GE(session_start_time, initial_time); + + // A browser restart should not change the session start time. + ShutdownBridge(); + InitializeBridge(); + StartSyncing(); + EXPECT_THAT(GetAllData(), + UnorderedElementsAre( + Pair(header_storage_key, + EntityDataHasSpecifics(MatchesHeader( + kLocalCacheGuid, session_start_time, _, _))))); +} + // Tests that local windows and tabs that exist at the time the bridge is // started (e.g. after a Chrome restart) are properly exposed via the bridge's // GetDataForCommit() and GetAllData() methods, as well as notified via Put().
diff --git a/components/sync_sessions/synced_session.cc b/components/sync_sessions/synced_session.cc index 2dbbbfd..7180670 100644 --- a/components/sync_sessions/synced_session.cc +++ b/components/sync_sessions/synced_session.cc
@@ -223,6 +223,14 @@ return session_name_; } +void SyncedSession::SetStartTime(base::Time start_time) { + start_time_ = start_time; +} + +std::optional<base::Time> SyncedSession::GetStartTime() const { + return start_time_; +} + void SyncedSession::SetModifiedTime(const base::Time& modified_time) { modified_time_ = modified_time; } @@ -248,6 +256,10 @@ sync_pb::SessionWindow* w = header.add_window(); w->CopyFrom(window->ToSessionWindowProto()); } + if (start_time_) { + header.set_session_start_time_unix_epoch_millis( + start_time_->InMillisecondsSinceUnixEpoch()); + } header.set_client_name(session_name_); header.set_device_type(device_type); header.set_device_form_factor(ToDeviceFormFactorProto(device_form_factor));
diff --git a/components/sync_sessions/synced_session.h b/components/sync_sessions/synced_session.h index 0e3a6a06..983a079e 100644 --- a/components/sync_sessions/synced_session.h +++ b/components/sync_sessions/synced_session.h
@@ -86,15 +86,18 @@ ~SyncedSession(); void SetSessionTag(const std::string& session_tag); - const std::string& GetSessionTag() const; void SetSessionName(const std::string& session_name); - const std::string& GetSessionName() const; - void SetModifiedTime(const base::Time& modified_time); + // The timestamp when this session was started, i.e. when the user signed in + // or turned on the sessions data type. Only populated for sessions started in + // M130 or later. + void SetStartTime(base::Time start_time); + std::optional<base::Time> GetStartTime() const; + void SetModifiedTime(const base::Time& modified_time); const base::Time& GetModifiedTime() const; // Map of windows that make up this session. @@ -117,6 +120,11 @@ // User-visible name std::string session_name_; + // The timestamp when this session was started, i.e. when the user signed in + // or turned on the sessions data type. Only populated for sessions started in + // M130 or later. + std::optional<base::Time> start_time_; + // Last time this session was modified remotely. This is the max of the header // and all children tab mtimes. base::Time modified_time_;
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc index 4ed357f..2898f94 100644 --- a/components/sync_sessions/synced_session_tracker.cc +++ b/components/sync_sessions/synced_session_tracker.cc
@@ -129,6 +129,10 @@ if (header_specifics.has_client_name()) { synced_session->SetSessionName(header_specifics.client_name()); } + if (header_specifics.has_session_start_time_unix_epoch_millis()) { + synced_session->SetStartTime(base::Time::FromMillisecondsSinceUnixEpoch( + header_specifics.session_start_time_unix_epoch_millis())); + } syncer::DeviceInfo::FormFactor device_form_factor = syncer::ToDeviceInfoFormFactor(header_specifics.device_form_factor()); @@ -187,6 +191,15 @@ local_session->SetDeviceTypeAndFormFactor(local_device_type, local_device_form_factor); local_session->SetSessionTag(local_session_tag); + // Note: Do *not* call `SetStartTime()` here! `InitLocalSession()` gets called + // on every browser startup (if sessions sync is enabled), but the session + // start time should only be set when the session is initially created. +} + +void SyncedSessionTracker::SetLocalSessionStartTime( + base::Time local_session_start_time) { + SyncedSession* local_session = GetSession(local_session_tag_); + local_session->SetStartTime(local_session_start_time); } const std::string& SyncedSessionTracker::GetLocalSessionTag() const {
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h index 1171464..998b92a 100644 --- a/components/sync_sessions/synced_session_tracker.h +++ b/components/sync_sessions/synced_session_tracker.h
@@ -176,6 +176,11 @@ sync_pb::SyncEnums_DeviceType local_device_type, syncer::DeviceInfo::FormFactor local_device_form_factor); + // Populate the start-time of the local session. This should be called once, + // when syncing of sessions gets enabled (and then never again, unless syncing + // of sessions gets disabled and enabled again). + void SetLocalSessionStartTime(base::Time local_session_start_time); + // Gets the session tag previously set with InitLocalSession(). const std::string& GetLocalSessionTag() const;
diff --git a/components/sync_sessions/synced_session_tracker_unittest.cc b/components/sync_sessions/synced_session_tracker_unittest.cc index 1bf9d6cc..a734cc3a 100644 --- a/components/sync_sessions/synced_session_tracker_unittest.cc +++ b/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -18,6 +18,7 @@ using testing::AssertionResult; using testing::AssertionSuccess; using testing::ElementsAre; +using testing::Eq; using testing::IsEmpty; using testing::IsNull; using testing::Ne; @@ -31,6 +32,9 @@ const char kValidUrl[] = "http://www.example.com"; const char kSessionName[] = "sessionname"; +// Monday, September 2, 2024 13:31:31 GMT+2. +const base::Time kSessionStartTime = + base::Time::FromSecondsSinceUnixEpoch(1725283891); const sync_pb::SyncEnums::DeviceType kDeviceType = sync_pb::SyncEnums_DeviceType_TYPE_PHONE; const syncer::DeviceInfo::FormFactor kFormFactor = @@ -816,11 +820,15 @@ TEST_F(SyncedSessionTrackerTest, UpdateTrackerWithHeader) { sync_pb::SessionSpecifics header; header.set_session_tag(kTag); + header.mutable_header()->set_session_start_time_unix_epoch_millis( + kSessionStartTime.InMillisecondsSinceUnixEpoch()); header.mutable_header()->add_window()->set_window_id(kWindow1.id()); header.mutable_header()->mutable_window(0)->add_tab(kTab1.id()); header.mutable_header()->mutable_window(0)->add_tab(kTab2.id()); UpdateTrackerWithSpecifics(header, base::Time::Now(), &tracker_); + EXPECT_THAT(tracker_.LookupSession(kTag)->GetStartTime(), + Eq(kSessionStartTime)); EXPECT_THAT( tracker_.LookupSession(kTag), MatchesSyncedSession(kTag, {{kWindow1.id(), {kTab1.id(), kTab2.id()}}})); @@ -994,6 +1002,7 @@ TEST_F(SyncedSessionTrackerTest, SerializeTrackerToSpecifics) { tracker_.InitLocalSession(kTag, kSessionName, kDeviceType, kFormFactor); + tracker_.SetLocalSessionStartTime(kSessionStartTime); tracker_.PutWindowInSession(kTag, kWindow1); tracker_.GetSession(kTag)->windows[kWindow1]->window_type = sync_pb::SyncEnums_BrowserType_TYPE_TABBED; @@ -1011,9 +1020,10 @@ base::MockCallback<base::RepeatingCallback<void( const std::string& session_name, sync_pb::SessionSpecifics* specifics)>> callback; - EXPECT_CALL(callback, Run(kSessionName, - Pointee(MatchesHeader(kTag, {kWindow1.id()}, - {kTab1.id(), kTab2.id()})))); + EXPECT_CALL(callback, + Run(kSessionName, Pointee(MatchesHeader( + kTag, kSessionStartTime, {kWindow1.id()}, + {kTab1.id(), kTab2.id()})))); EXPECT_CALL(callback, Run(kSessionName, Pointee(MatchesTab(kTag, kWindow1.id(), kTab1.id(), kTabNode1, /*urls=*/_)))); @@ -1029,9 +1039,10 @@ EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&callback)); // Serialize the header only. - EXPECT_CALL(callback, Run(kSessionName, - Pointee(MatchesHeader(kTag, {kWindow1.id()}, - {kTab1.id(), kTab2.id()})))); + EXPECT_CALL(callback, + Run(kSessionName, Pointee(MatchesHeader( + kTag, kSessionStartTime, {kWindow1.id()}, + {kTab1.id(), kTab2.id()})))); SerializePartialTrackerToSpecifics( tracker_, {{kTag, {TabNodePool::kInvalidTabNodeID}}}, callback.Get()); EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&callback));
diff --git a/components/sync_sessions/test_matchers.cc b/components/sync_sessions/test_matchers.cc index 8dd0352..4e54f86 100644 --- a/components/sync_sessions/test_matchers.cc +++ b/components/sync_sessions/test_matchers.cc
@@ -12,8 +12,10 @@ namespace sync_sessions { namespace { +using testing::_; using testing::ContainerEq; using testing::ElementsAreArray; +using testing::Eq; using testing::Matcher; using testing::MatcherInterface; using testing::MatchResultListener; @@ -23,9 +25,13 @@ : public MatcherInterface<const sync_pb::SessionSpecifics&> { public: MatchesHeaderMatcher(Matcher<std::string> session_tag, + Matcher<base::Time> session_start_time, Matcher<std::vector<int>> window_ids, Matcher<std::vector<int>> tab_ids) - : session_tag_(session_tag), window_ids_(window_ids), tab_ids_(tab_ids) {} + : session_tag_(session_tag), + session_start_time_(session_start_time), + window_ids_(window_ids), + tab_ids_(tab_ids) {} bool MatchAndExplain(const sync_pb::SessionSpecifics& actual, MatchResultListener* listener) const override { @@ -42,6 +48,13 @@ << actual.session_tag(); return false; } + base::Time actual_start_time = base::Time::FromMillisecondsSinceUnixEpoch( + actual.header().session_start_time_unix_epoch_millis()); + if (!session_start_time_.MatchAndExplain(actual_start_time, listener)) { + *listener << " which contains an unexpected start time: " + << actual_start_time; + return false; + } std::vector<int> actual_window_ids; std::vector<int> actual_tab_ids; for (const auto& window : actual.header().window()) { @@ -72,6 +85,7 @@ private: Matcher<std::string> session_tag_; + Matcher<base::Time> session_start_time_; Matcher<std::vector<int>> window_ids_; Matcher<std::vector<int>> tab_ids_; }; @@ -199,12 +213,29 @@ } // namespace +testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( + testing::Matcher<std::string> session_tag, + testing::Matcher<base::Time> session_start_time, + testing::Matcher<std::vector<int>> window_ids, + testing::Matcher<std::vector<int>> tab_ids) { + return testing::MakeMatcher(new MatchesHeaderMatcher( + session_tag, session_start_time, window_ids, tab_ids)); +} + Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( Matcher<std::string> session_tag, Matcher<std::vector<int>> window_ids, Matcher<std::vector<int>> tab_ids) { - return testing::MakeMatcher( - new MatchesHeaderMatcher(session_tag, window_ids, tab_ids)); + return MatchesHeader(session_tag, _, window_ids, tab_ids); +} + +testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( + testing::Matcher<std::string> session_tag, + base::Time session_start_time, + const std::vector<int>& window_ids, + const std::vector<int>& tab_ids) { + return MatchesHeader(session_tag, Eq(session_start_time), + ElementsAreArray(window_ids), ElementsAreArray(tab_ids)); } Matcher<const sync_pb::SessionSpecifics&> MatchesHeader(
diff --git a/components/sync_sessions/test_matchers.h b/components/sync_sessions/test_matchers.h index c7aa3fe..8b5e595 100644 --- a/components/sync_sessions/test_matchers.h +++ b/components/sync_sessions/test_matchers.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/time/time.h" #include "components/sync/protocol/session_specifics.pb.h" #include "testing/gmock/include/gmock/gmock.h" @@ -18,10 +19,21 @@ testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( testing::Matcher<std::string> session_tag, + testing::Matcher<base::Time> session_start_time, testing::Matcher<std::vector<int>> window_ids, testing::Matcher<std::vector<int>> tab_ids); -// Convenience overload. +testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( + testing::Matcher<std::string> session_tag, + testing::Matcher<std::vector<int>> window_ids, + testing::Matcher<std::vector<int>> tab_ids); + +// Convenience overloads. +testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( + testing::Matcher<std::string> session_tag, + base::Time session_start_time, + const std::vector<int>& window_ids, + const std::vector<int>& tab_ids); testing::Matcher<const sync_pb::SessionSpecifics&> MatchesHeader( testing::Matcher<std::string> session_tag, const std::vector<int>& window_ids,
diff --git a/components/user_annotations/user_annotations_database.cc b/components/user_annotations/user_annotations_database.cc index 962d463..b381206 100644 --- a/components/user_annotations/user_annotations_database.cc +++ b/components/user_annotations/user_annotations_database.cc
@@ -161,4 +161,19 @@ return entries; } +bool UserAnnotationsDatabase::RemoveEntry(EntryID entry_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + sql::Statement delete_statement(db_.GetCachedStatement( + SQL_FROM_HERE, "DELETE FROM entries WHERE entry_id=?")); + delete_statement.BindInt64(0, entry_id); + return delete_statement.Run(); +} + +bool UserAnnotationsDatabase::RemoveAllEntries() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + sql::Statement delete_statement( + db_.GetCachedStatement(SQL_FROM_HERE, "DELETE FROM entries")); + return delete_statement.Run(); +} + } // namespace user_annotations
diff --git a/components/user_annotations/user_annotations_database.h b/components/user_annotations/user_annotations_database.h index 431079498..1474349 100644 --- a/components/user_annotations/user_annotations_database.h +++ b/components/user_annotations/user_annotations_database.h
@@ -39,11 +39,21 @@ // Returns all the annotations from database. UserAnnotationsEntryRetrievalResult RetrieveAllEntries(); + // Remove the user annotation entry with `entry_id` and returns whether the + // operation completed successfully. Returns true even when no entry is found. + bool RemoveEntry(EntryID entry_id); + + // Removes all the user annotation entries and returns whether the + // operation completed successfully. Returns true even when there are no + // entries to delete. + bool RemoveAllEntries(); + private: sql::InitStatus InitInternal(const base::FilePath& storage_dir); // The underlying SQL database. - sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_); + sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_) = + sql::Database(sql::DatabaseOptions{}); os_crypt_async::Encryptor encryptor_ GUARDED_BY_CONTEXT(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
diff --git a/components/user_annotations/user_annotations_database_unittest.cc b/components/user_annotations/user_annotations_database_unittest.cc index 8094ec9..37f7190 100644 --- a/components/user_annotations/user_annotations_database_unittest.cc +++ b/components/user_annotations/user_annotations_database_unittest.cc
@@ -91,4 +91,29 @@ UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1]))); } +TEST_F(UserAnnotationsDatabaseTest, RemoveEntry) { + std::vector<UserAnnotationsEntry> entries; + entries.push_back(CreateUserAnnotationsEntry(1, "foo", "foo_value")); + entries.push_back(CreateUserAnnotationsEntry(2, "bar", "bar_value")); + EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess, + database_->UpdateEntries(entries)); + + auto db_entries = *database_->RetrieveAllEntries(); + EXPECT_EQ(2U, db_entries.size()); + EXPECT_TRUE(database_->RemoveEntry(db_entries[0].entry_id())); + EXPECT_TRUE(database_->RemoveEntry(db_entries[1].entry_id())); + EXPECT_TRUE(database_->RetrieveAllEntries()->empty()); +} + +TEST_F(UserAnnotationsDatabaseTest, RemoveAllEntries) { + std::vector<UserAnnotationsEntry> entries; + entries.push_back(CreateUserAnnotationsEntry(1, "foo", "foo_value")); + entries.push_back(CreateUserAnnotationsEntry(2, "bar", "bar_value")); + EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess, + database_->UpdateEntries(entries)); + EXPECT_TRUE(database_->RemoveAllEntries()); + EXPECT_TRUE(database_->RemoveAllEntries()); + EXPECT_TRUE(database_->RetrieveAllEntries()->empty()); +} + } // namespace user_annotations
diff --git a/components/user_annotations/user_annotations_service.cc b/components/user_annotations/user_annotations_service.cc index 55bd02d..1d453dcc 100644 --- a/components/user_annotations/user_annotations_service.cc +++ b/components/user_annotations/user_annotations_service.cc
@@ -4,6 +4,8 @@ #include "components/user_annotations/user_annotations_service.h" +#include "base/callback_list.h" +#include "base/functional/callback.h" #include "base/metrics/histogram_functions.h" #include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" @@ -42,6 +44,15 @@ std::move(callback).Run(user_annotations.value()); } +void RecordRemoveEntryResult(UserAnnotationsExecutionResult result) { + base::UmaHistogramEnumeration("UserAnnotations.RemoveEntry.Result", result); +} + +void RecordRemoveAllEntriesResult(UserAnnotationsExecutionResult result) { + base::UmaHistogramEnumeration("UserAnnotations.RemoveAllEntries.Result", + result); +} + } // namespace UserAnnotationsService::UserAnnotationsService( @@ -159,14 +170,69 @@ } for (const auto& entry : maybe_response->entries()) { + EntryID entry_id = ++entry_id_counter_; optimization_guide::proto::UserAnnotationsEntry entry_proto; + entry_proto.set_entry_id(entry_id); entry_proto.set_key(entry.key()); entry_proto.set_value(entry.value()); - entries_.push_back({.entry_id = ++entry_id_counter_, - .entry_proto = std::move(entry_proto)}); + entries_.push_back( + {.entry_id = entry_id, .entry_proto = std::move(entry_proto)}); } RecordUserAnnotationsFormSubmissionResult( UserAnnotationsExecutionResult::kSuccess); } +void UserAnnotationsService::RemoveEntry(EntryID entry_id, + base::OnceClosure callback) { + if (!ShouldPersistUserAnnotations()) { + std::erase_if(entries_, [entry_id](Entry entry) { + return entry.entry_id == entry_id; + }); + RecordRemoveEntryResult(UserAnnotationsExecutionResult::kSuccess); + std::move(callback).Run(); + return; + } + if (!user_annotations_database_) { + RecordRemoveEntryResult( + UserAnnotationsExecutionResult::kCryptNotInitialized); + std::move(callback).Run(); + return; + } + user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::RemoveEntry) + .WithArgs(entry_id) + .Then(base::BindOnce( + [](base::OnceClosure callback, bool result) { + RecordRemoveEntryResult( + result ? UserAnnotationsExecutionResult::kSuccess + : UserAnnotationsExecutionResult::kSqlError); + std::move(callback).Run(); + }, + std::move(callback))); +} + +void UserAnnotationsService::RemoveAllEntries(base::OnceClosure callback) { + if (!ShouldPersistUserAnnotations()) { + entries_.clear(); + RecordRemoveAllEntriesResult(UserAnnotationsExecutionResult::kSuccess); + std::move(callback).Run(); + return; + } + if (!user_annotations_database_) { + RecordRemoveAllEntriesResult( + UserAnnotationsExecutionResult::kCryptNotInitialized); + std::move(callback).Run(); + return; + } + user_annotations_database_ + .AsyncCall(&UserAnnotationsDatabase::RemoveAllEntries) + .Then(base::BindOnce( + [](base::OnceClosure callback, bool result) { + RecordRemoveAllEntriesResult( + result ? UserAnnotationsExecutionResult::kSuccess + : UserAnnotationsExecutionResult::kSqlError); + std::move(callback).Run(); + }, + std::move(callback))); +} + } // namespace user_annotations
diff --git a/components/user_annotations/user_annotations_service.h b/components/user_annotations/user_annotations_service.h index 05edbda..d0bd680 100644 --- a/components/user_annotations/user_annotations_service.h +++ b/components/user_annotations/user_annotations_service.h
@@ -7,7 +7,7 @@ #include "base/callback_list.h" #include "base/files/file_path.h" -#include "base/functional/callback.h" +#include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/sequence_bound.h" @@ -54,6 +54,14 @@ virtual void RetrieveAllEntries( base::OnceCallback<void(UserAnnotationsEntries)> callback); + // Remove the user annotation entry with `entry_id` and calls `callback` upon + // completion. + void RemoveEntry(EntryID entry_id, base::OnceClosure callback); + + // Removes all the user annotation entries` and calls `callback` upon + // completion. + void RemoveAllEntries(base::OnceClosure callback); + // KeyedService: void Shutdown() override;
diff --git a/components/user_annotations/user_annotations_service_unittest.cc b/components/user_annotations/user_annotations_service_unittest.cc index 2143f10..43e0dd6 100644 --- a/components/user_annotations/user_annotations_service_unittest.cc +++ b/components/user_annotations/user_annotations_service_unittest.cc
@@ -34,6 +34,7 @@ public testing::WithParamInterface<bool> { public: void SetUp() override { + InitializeFeatureList(); CHECK(temp_dir_.CreateUniqueTempDir()); os_crypt_ = os_crypt_async::GetTestOSCryptAsyncForTesting( /*is_sync_for_unittests=*/true); @@ -76,6 +77,41 @@ EXPECT_TRUE(entries.empty()); } +struct FormsAnnotationsTestRequest { + optimization_guide::proto::Any forms_annotations_response; + optimization_guide::proto::AXTreeUpdate ax_tree; + autofill::FormData form_data; +}; + +// Returns sample annotations for tests. +FormsAnnotationsTestRequest CreateSampleFormsAnnotationsTestRequest() { + optimization_guide::proto::FormsAnnotationsResponse response; + optimization_guide::proto::UserAnnotationsEntry* entry1 = + response.add_entries(); + entry1->set_key("label"); + entry1->set_value("whatever"); + optimization_guide::proto::UserAnnotationsEntry* entry2 = + response.add_entries(); + entry2->set_key("nolabel"); + entry2->set_value("value"); + optimization_guide::proto::Any forms_annotations_response; + forms_annotations_response.set_type_url(response.GetTypeName()); + response.SerializeToString(forms_annotations_response.mutable_value()); + + autofill::FormFieldData form_field_data; + form_field_data.set_label(u"label"); + form_field_data.set_value(u"whatever"); + autofill::FormFieldData form_field_data2; + form_field_data2.set_name(u"nolabel"); + form_field_data2.set_value(u"value"); + autofill::FormData form_data; + form_data.set_fields({form_field_data, form_field_data2}); + optimization_guide::proto::AXTreeUpdate ax_tree; + ax_tree.mutable_tree_data()->set_title("title"); + + return {forms_annotations_response, ax_tree, form_data}; +} + TEST_P(UserAnnotationsServiceTest, RetrieveAllEntriesWithInsert) { { base::HistogramTester histogram_tester; @@ -105,18 +141,7 @@ field_proto2->set_form_control_type( optimization_guide::proto::FORM_CONTROL_TYPE_INPUT_TEXT); - optimization_guide::proto::FormsAnnotationsResponse response; - optimization_guide::proto::UserAnnotationsEntry* entry1 = - response.add_entries(); - entry1->set_key("label"); - entry1->set_value("whatever"); - optimization_guide::proto::UserAnnotationsEntry* entry2 = - response.add_entries(); - entry2->set_key("nolabel"); - entry2->set_value("value"); - optimization_guide::proto::Any any; - any.set_type_url(response.GetTypeName()); - response.SerializeToString(any.mutable_value()); + auto test_request = CreateSampleFormsAnnotationsTestRequest(); EXPECT_CALL( *model_executor(), ExecuteModel( @@ -124,19 +149,10 @@ EqualsProto(expected_request), An<optimization_guide:: OptimizationGuideModelExecutionResultCallback>())) - .WillOnce(base::test::RunOnceCallback<2>(any, /*log_entry=*/nullptr)); + .WillOnce(base::test::RunOnceCallback<2>( + test_request.forms_annotations_response, /*log_entry=*/nullptr)); - autofill::FormFieldData form_field_data; - form_field_data.set_label(u"label"); - form_field_data.set_value(u"whatever"); - autofill::FormFieldData form_field_data2; - form_field_data2.set_name(u"nolabel"); - form_field_data2.set_value(u"value"); - autofill::FormData form_data; - form_data.set_fields({form_field_data, form_field_data2}); - optimization_guide::proto::AXTreeUpdate ax_tree; - ax_tree.mutable_tree_data()->set_title("title"); - service()->AddFormSubmission(ax_tree, form_data); + service()->AddFormSubmission(test_request.ax_tree, test_request.form_data); base::test::TestFuture<UserAnnotationsEntries> test_future; service()->RetrieveAllEntries(test_future.GetCallback()); @@ -191,7 +207,7 @@ } } -TEST_F(UserAnnotationsServiceTest, ExecuteFailed) { +TEST_P(UserAnnotationsServiceTest, ExecuteFailed) { base::HistogramTester histogram_tester; EXPECT_CALL( @@ -223,7 +239,7 @@ 0); } -TEST_F(UserAnnotationsServiceTest, UnexpectedResponseType) { +TEST_P(UserAnnotationsServiceTest, UnexpectedResponseType) { base::HistogramTester histogram_tester; optimization_guide::proto::Any any; @@ -250,6 +266,79 @@ 0); } +TEST_P(UserAnnotationsServiceTest, RemoveEntry) { + base::HistogramTester histogram_tester; + auto test_request = CreateSampleFormsAnnotationsTestRequest(); + EXPECT_CALL( + *model_executor(), + ExecuteModel( + optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, + An<optimization_guide:: + OptimizationGuideModelExecutionResultCallback>())) + .WillOnce(base::test::RunOnceCallback<2>( + test_request.forms_annotations_response, /*log_entry=*/nullptr)); + + service()->AddFormSubmission(test_request.ax_tree, test_request.form_data); + + base::test::TestFuture< + std::vector<optimization_guide::proto::UserAnnotationsEntry>> + test_future_retrieve; + service()->RetrieveAllEntries(test_future_retrieve.GetCallback()); + auto entries = test_future_retrieve.Take(); + EXPECT_EQ(2u, entries.size()); + + base::test::TestFuture<void> test_future_remove_entry; + service()->RemoveEntry(entries[0].entry_id(), + test_future_remove_entry.GetCallback()); + EXPECT_TRUE(test_future_remove_entry.Wait()); + test_future_remove_entry.Clear(); + service()->RetrieveAllEntries(test_future_retrieve.GetCallback()); + EXPECT_TRUE(test_future_retrieve.Wait()); + EXPECT_EQ(1u, test_future_retrieve.Take().size()); + histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result", + UserAnnotationsExecutionResult::kSuccess, + 1); + + service()->RemoveEntry(entries[1].entry_id(), + test_future_remove_entry.GetCallback()); + EXPECT_TRUE(test_future_remove_entry.Wait()); + histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result", + UserAnnotationsExecutionResult::kSuccess, + 2); + service()->RetrieveAllEntries(test_future_retrieve.GetCallback()); + EXPECT_TRUE(test_future_retrieve.Take().empty()); +} + +TEST_P(UserAnnotationsServiceTest, RemoveAllEntries) { + base::HistogramTester histogram_tester; + auto test_request = CreateSampleFormsAnnotationsTestRequest(); + EXPECT_CALL( + *model_executor(), + ExecuteModel( + optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, + An<optimization_guide:: + OptimizationGuideModelExecutionResultCallback>())) + .WillOnce(base::test::RunOnceCallback<2>( + test_request.forms_annotations_response, /*log_entry=*/nullptr)); + + service()->AddFormSubmission(test_request.ax_tree, test_request.form_data); + + base::test::TestFuture< + std::vector<optimization_guide::proto::UserAnnotationsEntry>> + test_future_retrieve; + service()->RetrieveAllEntries(test_future_retrieve.GetCallback()); + EXPECT_EQ(2u, test_future_retrieve.Take().size()); + + base::test::TestFuture<void> test_future_remove_entry; + service()->RemoveAllEntries(test_future_remove_entry.GetCallback()); + EXPECT_TRUE(test_future_remove_entry.Wait()); + histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveAllEntries.Result", + UserAnnotationsExecutionResult::kSuccess, + 1); + service()->RetrieveAllEntries(test_future_retrieve.GetCallback()); + EXPECT_TRUE(test_future_retrieve.Take().empty()); +} + INSTANTIATE_TEST_SUITE_P(All, UserAnnotationsServiceTest, ::testing::Bool()); class UserAnnotationsServiceReplaceAnnotationsTest @@ -273,36 +362,17 @@ TEST_P(UserAnnotationsServiceReplaceAnnotationsTest, RetrieveAllEntriesWithInsertShouldReplace) { { - optimization_guide::proto::FormsAnnotationsResponse response; - optimization_guide::proto::UserAnnotationsEntry* entry1 = - response.add_entries(); - entry1->set_key("label"); - entry1->set_value("whatever"); - optimization_guide::proto::UserAnnotationsEntry* entry2 = - response.add_entries(); - entry2->set_key("nolabel"); - entry2->set_value("value"); - optimization_guide::proto::Any any; - any.set_type_url(response.GetTypeName()); - response.SerializeToString(any.mutable_value()); + auto test_request = CreateSampleFormsAnnotationsTestRequest(); EXPECT_CALL( *model_executor(), ExecuteModel( optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, An<optimization_guide:: OptimizationGuideModelExecutionResultCallback>())) - .WillOnce(base::test::RunOnceCallback<2>(any, /*log_entry=*/nullptr)); + .WillOnce(base::test::RunOnceCallback<2>( + test_request.forms_annotations_response, /*log_entry=*/nullptr)); - autofill::FormFieldData form_field_data; - form_field_data.set_label(u"label"); - form_field_data.set_value(u"whatever"); - autofill::FormFieldData form_field_data2; - form_field_data2.set_name(u"nolabel"); - form_field_data2.set_value(u"value"); - autofill::FormData form_data; - form_data.set_fields({form_field_data, form_field_data2}); - optimization_guide::proto::AXTreeUpdate ax_tree; - service()->AddFormSubmission(ax_tree, form_data); + service()->AddFormSubmission(test_request.ax_tree, test_request.form_data); base::test::TestFuture<UserAnnotationsEntries> test_future; service()->RetrieveAllEntries(test_future.GetCallback());
diff --git a/components/viz/service/display_embedder/skia_output_device_dawn.cc b/components/viz/service/display_embedder/skia_output_device_dawn.cc index 3e6976c..8c6f5def 100644 --- a/components/viz/service/display_embedder/skia_output_device_dawn.cc +++ b/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -108,7 +108,11 @@ std::make_unique<gl::VSyncProviderWin>(window_handle_to_draw_to); // Create the wgpu::Surface from our HWND. +#ifdef WGPU_BREAKING_CHANGE_DROP_DESCRIPTOR + wgpu::SurfaceSourceWindowsHWND hwnd_desc; +#else wgpu::SurfaceDescriptorFromWindowsHWND hwnd_desc; +#endif hwnd_desc.hwnd = window_handle_to_draw_to; hwnd_desc.hinstance = GetModuleHandle(nullptr); @@ -126,7 +130,11 @@ auto& scoped_java_surface = absl::get<gl::ScopedJavaSurface>(surface_variant); android_native_window_ = gl::ScopedANativeWindow(scoped_java_surface); +#ifdef WGPU_BREAKING_CHANGE_DROP_DESCRIPTOR + wgpu::SurfaceSourceAndroidNativeWindow android_native_window_desc; +#else wgpu::SurfaceDescriptorFromAndroidNativeWindow android_native_window_desc; +#endif android_native_window_desc.window = android_native_window_.a_native_window(); surface_desc.nextInChain = &android_native_window_desc; #endif
diff --git a/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc b/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc index ea6cd83..c03acb11 100644 --- a/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc +++ b/content/browser/file_system_access/file_system_access_clipboard_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -15,6 +16,7 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "third_party/blink/public/common/features_generated.h" #include "ui/base/clipboard/clipboard_buffer.h" #include "ui/base/clipboard/file_info.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -27,6 +29,11 @@ class FileSystemAccessClipboardBrowserTest : public ContentBrowserTest { public: + FileSystemAccessClipboardBrowserTest() { + scoped_features_.InitAndEnableFeature( + blink::features::kFileSystemAccessLocal); + } + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(embedded_test_server()->Start()); @@ -58,6 +65,7 @@ protected: base::ScopedTempDir temp_dir_; + base::test::ScopedFeatureList scoped_features_; }; IN_PROC_BROWSER_TEST_F(FileSystemAccessClipboardBrowserTest, File) {
diff --git a/content/browser/file_system_access/file_system_access_drag_drop_browsertest.cc b/content/browser/file_system_access/file_system_access_drag_drop_browsertest.cc index aab3dd99..f15df5a2 100644 --- a/content/browser/file_system_access/file_system_access_drag_drop_browsertest.cc +++ b/content/browser/file_system_access/file_system_access_drag_drop_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/test/scoped_feature_list.h" #include "content/browser/file_system_access/file_system_access_manager_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/common/content_switches.h" @@ -16,6 +17,7 @@ #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "third_party/blink/public/common/features_generated.h" #include "ui/base/clipboard/file_info.h" #include "ui/gfx/geometry/point_f.h" @@ -26,6 +28,11 @@ class FileSystemAccessDragDropBrowserTest : public ContentBrowserTest { public: + FileSystemAccessDragDropBrowserTest() { + scoped_features_.InitAndEnableFeature( + blink::features::kFileSystemAccessLocal); + } + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(embedded_test_server()->Start()); @@ -68,6 +75,9 @@ protected: base::ScopedTempDir temp_dir_; + + private: + base::test::ScopedFeatureList scoped_features_; }; IN_PROC_BROWSER_TEST_F(FileSystemAccessDragDropBrowserTest, DropFile) {
diff --git a/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc b/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc index a2fcf5f..e39a28f 100644 --- a/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc +++ b/content/browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc
@@ -15,11 +15,17 @@ #include "content/public/test/file_system_chooser_test_helpers.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features_generated.h" namespace content { class FileSystemAccessFileHandleImplBrowserTest : public ContentBrowserTest { public: + FileSystemAccessFileHandleImplBrowserTest() { + scoped_features_.InitAndEnableFeature( + blink::features::kFileSystemAccessLocal); + } + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(embedded_test_server()->Start()); @@ -80,6 +86,9 @@ protected: base::ScopedTempDir temp_dir_; GURL test_url_; + + private: + base::test::ScopedFeatureList scoped_features_; }; // TODO(crbug.com/40888337): Make this a WPT once crbug.com/1114920 is fixed.
diff --git a/content/browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc b/content/browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc index ac404b1..1246e8d 100644 --- a/content/browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc +++ b/content/browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/services/quarantine/test_support.h" @@ -24,6 +25,7 @@ #include "content/public/test/file_system_chooser_test_helpers.h" #include "content/shell/browser/shell.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "third_party/blink/public/common/features_generated.h" #include "ui/shell_dialogs/select_file_dialog.h" #include "ui/shell_dialogs/select_file_dialog_factory.h" #include "ui/shell_dialogs/select_file_policy.h" @@ -38,6 +40,11 @@ // FileSystemAccessFileWriterImpl. class FileSystemAccessFileWriterBrowserTest : public ContentBrowserTest { public: + FileSystemAccessFileWriterBrowserTest() { + scoped_features_.InitAndEnableFeature( + blink::features::kFileSystemAccessLocal); + } + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); @@ -112,6 +119,9 @@ protected: base::ScopedTempDir temp_dir_; GURL test_url_; + + private: + base::test::ScopedFeatureList scoped_features_; }; IN_PROC_BROWSER_TEST_F(FileSystemAccessFileWriterBrowserTest,
diff --git a/content/browser/file_system_access/file_system_chooser_browsertest.cc b/content/browser/file_system_access/file_system_chooser_browsertest.cc index ab525bf..bf80c7f 100644 --- a/content/browser/file_system_access/file_system_chooser_browsertest.cc +++ b/content/browser/file_system_access/file_system_chooser_browsertest.cc
@@ -57,6 +57,11 @@ // APIs. class FileSystemChooserBrowserTest : public ContentBrowserTest { public: + FileSystemChooserBrowserTest() { + scoped_features_.InitAndEnableFeature( + blink::features::kFileSystemAccessLocal); + } + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); #if BUILDFLAG(IS_WIN) @@ -123,6 +128,9 @@ base::ScopedTempDir temp_dir_; // Must persist through TearDown(). SelectFileDialogParams dialog_params_; + + private: + base::test::ScopedFeatureList scoped_features_; }; IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, CancelDialog) {
diff --git a/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc b/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc index 303f0b4..f908fcee 100644 --- a/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc +++ b/content/browser/renderer_host/back_forward_cache_can_store_document_result.cc
@@ -517,7 +517,7 @@ case Reason::kNetworkRequestDatapipeDrainedAsBytesConsumer: return "outstanding-network-request"; case Reason::kBroadcastChannelOnMessage: - return "broadcast-channel-on-message"; + return "broadcastchannel-message"; case Reason::kCacheControlNoStore: case Reason::kCacheControlNoStoreCookieModified: case Reason::kCacheControlNoStoreHTTPOnlyCookieModified:
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc index b96a095..3aff27c9 100644 --- a/content/browser/webui/web_ui_url_loader_factory.cc +++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -78,7 +78,7 @@ return; } - if (replacements) { + if (replacements && !replacements->empty()) { // We won't know the the final output size ahead of time, so we have to // use an intermediate string. auto input = base::as_string_view(*bytes);
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc index e3703a2..3ad61009 100644 --- a/content/renderer/pepper/pepper_webplugin_impl.cc +++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -236,7 +236,7 @@ instance_->HandleDocumentLoad(response); } -void PepperWebPluginImpl::DidReceiveData(const char* data, size_t data_length) { +void PepperWebPluginImpl::DidReceiveData(base::span<const char> data) { // Re-entrancy may cause JS to try to execute script on the plugin before it // is fully initialized. See: crbug.com/715747. if (!instance_) @@ -244,7 +244,7 @@ blink::WebAssociatedURLLoaderClient* document_loader = instance_->document_loader(); if (document_loader) - document_loader->DidReceiveData(data, data_length); + document_loader->DidReceiveData(data.data(), data.size()); } void PepperWebPluginImpl::DidFinishLoading() {
diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h index 0e4ac0f..d65c135b 100644 --- a/content/renderer/pepper/pepper_webplugin_impl.h +++ b/content/renderer/pepper/pepper_webplugin_impl.h
@@ -55,7 +55,7 @@ const blink::WebCoalescedInputEvent& event, ui::Cursor* cursor) override; void DidReceiveResponse(const blink::WebURLResponse& response) override; - void DidReceiveData(const char* data, size_t data_length) override; + void DidReceiveData(base::span<const char> data) override; void DidFinishLoading() override; void DidFailLoading(const blink::WebURLError&) override; bool HasSelection() const override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 41fc6a5..944a438d 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1449,8 +1449,13 @@ "../browser/file_system/file_system_url_drag_drop_browsertest.cc", "../browser/file_system/file_system_url_loader_factory_browsertest.cc", "../browser/file_system/fileapi_browsertest.cc", + "../browser/file_system_access/file_system_access_clipboard_browsertest.cc", + "../browser/file_system_access/file_system_access_drag_drop_browsertest.cc", + "../browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc", "../browser/file_system_access/file_system_access_file_modification_host_impl_browsertest.cc", + "../browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc", "../browser/file_system_access/file_system_access_observer_browsertest.cc", + "../browser/file_system_access/file_system_chooser_browsertest.cc", "../browser/find_request_manager_browsertest.cc", "../browser/first_party_sets/first_party_sets_handler_impl_browsertest.cc", "../browser/first_party_sets/test/first_party_sets_initialization_browsertest.cc", @@ -1869,6 +1874,7 @@ "//ui/accessibility:test_support", "//ui/base:test_support", "//ui/base/clipboard", + "//ui/base/clipboard:clipboard_test_support", "//ui/base/cursor", "//ui/base/ime", "//ui/base/ime/init", @@ -2136,11 +2142,6 @@ "../browser/direct_sockets/direct_sockets_open_browsertest.cc", "../browser/direct_sockets/direct_sockets_tcp_browsertest.cc", "../browser/direct_sockets/direct_sockets_udp_browsertest.cc", - "../browser/file_system_access/file_system_access_clipboard_browsertest.cc", - "../browser/file_system_access/file_system_access_drag_drop_browsertest.cc", - "../browser/file_system_access/file_system_access_file_handle_impl_browsertest.cc", - "../browser/file_system_access/file_system_access_file_writer_impl_browsertest.cc", - "../browser/file_system_access/file_system_chooser_browsertest.cc", "../browser/font_preferences_browsertest.cc", "../browser/renderer_host/clipboard_host_impl_browsertest.cc", "../browser/serial/serial_browsertest.cc", @@ -2154,7 +2155,6 @@ "//components/soda:utils", "//content/public/browser:proto", "//media/mojo/mojom:web_speech_recognition", - "//ui/base/clipboard:clipboard_test_support", ] if (enable_compute_pressure) {
diff --git a/content/web_test/renderer/test_plugin.h b/content/web_test/renderer/test_plugin.h index d5a07797..4da2eda3 100644 --- a/content/web_test/renderer/test_plugin.h +++ b/content/web_test/renderer/test_plugin.h
@@ -105,7 +105,7 @@ const gfx::PointF& position, const gfx::PointF& screen_position) override; void DidReceiveResponse(const blink::WebURLResponse& response) override {} - void DidReceiveData(const char* data, size_t data_length) override {} + void DidReceiveData(base::span<const char> data) override {} void DidFinishLoading() override {} void DidFailLoading(const blink::WebURLError& error) override {} v8::Local<v8::Object> V8ScriptableObject(v8::Isolate*) override;
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc index 75aecd51..1d47c93d 100644 --- a/device/bluetooth/chromeos/bluetooth_utils.cc +++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -286,13 +286,17 @@ } #if BUILDFLAG(IS_CHROMEOS_ASH) -bool IsPolyDevice(const device::BluetoothDevice* device) { +bool IsNonPhonePolyDevice(const device::BluetoothDevice* device) { // OUI portions of Bluetooth addresses for devices manufactured by Poly. See - // https://standards-oui.ieee.org/. - constexpr auto kPolyOuis = base::MakeFixedFlatSet<std::string_view>( - {"64:16:7F", "48:25:67", "00:04:F2"}); + // https://standards-oui.ieee.org/. This also includes acquisitions by Poly, + // namely ViaVideo and PictureTel. + // Actually there are still others belonging in this category, but they are + // truly phones, e.g. Voyant and Spectralink, so we omit those here. + constexpr auto kNonPhonePolyOuis = base::MakeFixedFlatSet<std::string_view>( + {"64:16:7F", "48:25:67", "00:04:F2", "00:E0:DB", "00:10:1A"}); - return base::Contains(kPolyOuis, device->GetOuiPortionOfBluetoothAddress()); + return base::Contains(kNonPhonePolyOuis, + device->GetOuiPortionOfBluetoothAddress()); } #endif @@ -402,7 +406,7 @@ // Never filter out Poly devices; this requires a special case since these // devices often identify themselves as phones, which are disallowed below. // See b/228118615. - if (IsPolyDevice(device)) { + if (IsNonPhonePolyDevice(device)) { return false; } #endif
diff --git a/docs/website b/docs/website index bb84951..098e573 160000 --- a/docs/website +++ b/docs/website
@@ -1 +1 @@ -Subproject commit bb849512794519eb3e1c6d1b4386ecbccb7d9076 +Subproject commit 098e573ad7d9decf03efa002eb1b4ee0d474e7a2
diff --git a/gpu/command_buffer/service/shared_image/dawn_image_representation_unittest_common.cc b/gpu/command_buffer/service/shared_image/dawn_image_representation_unittest_common.cc index 3d6e5977..dcae407 100644 --- a/gpu/command_buffer/service/shared_image/dawn_image_representation_unittest_common.cc +++ b/gpu/command_buffer/service/shared_image/dawn_image_representation_unittest_common.cc
@@ -35,7 +35,11 @@ wgpu::ShaderModule CreateShaderModule(const wgpu::Device& device, const char* source) { +#ifdef WGPU_BREAKING_CHANGE_DROP_DESCRIPTOR + wgpu::ShaderSourceWGSL wgsl_desc; +#else wgpu::ShaderModuleWGSLDescriptor wgsl_desc; +#endif wgsl_desc.code = source; wgpu::ShaderModuleDescriptor descriptor; descriptor.nextInChain = &wgsl_desc;
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc index 3de6117..280aa50 100644 --- a/gpu/command_buffer/tests/webgpu_test.cc +++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -408,7 +408,11 @@ wgpu::Device device = GetNewDevice(); // Make a invalid ShaderModuleDescriptor because it contains SPIR-V. +#ifdef WGPU_BREAKING_CHANGE_DROP_DESCRIPTOR + wgpu::ShaderSourceSPIRV spirvDesc; +#else wgpu::ShaderModuleSPIRVDescriptor spirvDesc; +#endif spirvDesc.codeSize = 0; spirvDesc.code = nullptr;
diff --git a/infra/config/generated/builders/try/linux-full-remote-rel/properties.json b/infra/config/generated/builders/try/linux-full-remote-rel/properties.json index b668a1f..e3031dc6 100644 --- a/infra/config/generated/builders/try/linux-full-remote-rel/properties.json +++ b/infra/config/generated/builders/try/linux-full-remote-rel/properties.json
@@ -180,6 +180,7 @@ "enable_cloud_profiler": true, "enable_cloud_trace": true, "experiments": [], + "output_local_strategy": "minimum", "project": "rbe-chromium-untrusted", "remote_jobs": -1 },
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star index 747d86e..6f1de842 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -352,6 +352,7 @@ compilator = "linux-full-remote-rel-compilator", contact_team_email = "chrome-build-team@google.com", siso_configs = ["builder", "remote-library-link", "remote-exec-link"], + siso_output_local_strategy = "minimum", tryjob = try_.job( experiment_percentage = 10, ),
diff --git a/ios/chrome/app/background_refresh/background_refresh_app_agent.mm b/ios/chrome/app/background_refresh/background_refresh_app_agent.mm index 6fc7690a..665ea53 100644 --- a/ios/chrome/app/background_refresh/background_refresh_app_agent.mm +++ b/ios/chrome/app/background_refresh/background_refresh_app_agent.mm
@@ -40,6 +40,11 @@ NSString* appStateBackgroundCountDuringBackgroundRefreshKey = @"debug_app_state_background_count_during_background_refresh"; +// Debug NSUserDefaults key used to collect debug data. +// Number of times systemTriggeredRefreshForTask was run with no due tasks. +NSString* appStateDueCountDuringBackgroundRefreshKey = + @"debug_app_state_no_due_count_during_background_refresh"; + } // namespace @interface BGTaskScheduler (cheating) @@ -154,12 +159,25 @@ ProceduralBlock completion = ^{ [task setTaskCompletedWithSuccess:YES]; }; + + // YES if there is at least one due task. + BOOL hasDueTasks = NO; for (AppRefreshProvider* provider in self.providers) { // Only execute due tasks. if ([provider isDue]) { + hasDueTasks = YES; [provider handleRefreshWithCompletion:completion]; } } + + // TODO(crbug.com/354918794): Remove this code once not needed anymore. + if (!hasDueTasks) { + [defaults + setInteger:[defaults integerForKey: + appStateDueCountDuringBackgroundRefreshKey] + + 1 + forKey:appStateDueCountDuringBackgroundRefreshKey]; + } } // Request that app refresh runs no sooner than `delay` seconds from now.
diff --git a/ios/chrome/app/background_refresh/test_refresher.mm b/ios/chrome/app/background_refresh/test_refresher.mm index 5d49736a..fd0e86a2 100644 --- a/ios/chrome/app/background_refresh/test_refresher.mm +++ b/ios/chrome/app/background_refresh/test_refresher.mm
@@ -31,7 +31,8 @@ // TODO(crbug.com/354918403): If this provider is used outside of canary, it // *must* post the logging task (which reads from AppState) to the main // thread! - InitStageDuringBackgroundRefreshActions stage; + InitStageDuringBackgroundRefreshActions stage = + InitStageDuringBackgroundRefreshActions::kUnknown; switch (_appState.initStage) { case InitStageStart: stage = InitStageDuringBackgroundRefreshActions::kInitStageStart;
diff --git a/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm b/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm index f7ff6722..825690e7 100644 --- a/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm +++ b/ios/chrome/browser/profile/model/profile_manager_ios_impl.mm
@@ -488,7 +488,7 @@ ios::AccountReconcilorFactory::GetForBrowserState(profile); // Initialization needs to happen after the browser context is available // because UnifiedConsentService's dependencies needs the URL context getter. - UnifiedConsentServiceFactory::GetForBrowserState(profile); + UnifiedConsentServiceFactory::GetForProfile(profile); // Initialization needs to happen after the profile is available because // IOSChromeMetricsServiceAccessor requires profile to be registered in the
diff --git a/ios/chrome/browser/ui/authentication/signout_action_sheet/BUILD.gn b/ios/chrome/browser/ui/authentication/signout_action_sheet/BUILD.gn index 311e7f1..2e19469 100644 --- a/ios/chrome/browser/ui/authentication/signout_action_sheet/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/signout_action_sheet/BUILD.gn
@@ -17,6 +17,7 @@ "//components/sync/base:features", "//components/sync/service", "//ios/chrome/app/strings", + "//ios/chrome/browser/ntp/ui_bundled:feature_flags", "//ios/chrome/browser/shared/model/browser", "//ios/chrome/browser/shared/model/profile", "//ios/chrome/browser/shared/public/commands",
diff --git a/ios/chrome/browser/ui/authentication/signout_action_sheet/signout_action_sheet_coordinator.mm b/ios/chrome/browser/ui/authentication/signout_action_sheet/signout_action_sheet_coordinator.mm index 1788f54..bfe8ba8 100644 --- a/ios/chrome/browser/ui/authentication/signout_action_sheet/signout_action_sheet_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signout_action_sheet/signout_action_sheet_coordinator.mm
@@ -18,6 +18,7 @@ #import "components/strings/grit/components_strings.h" #import "components/sync/service/sync_service.h" #import "components/sync/service/sync_user_settings.h" +#import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h" #import "ios/chrome/browser/shared/model/browser/browser.h" #import "ios/chrome/browser/shared/model/profile/profile_ios.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" @@ -435,6 +436,9 @@ } case SignedInUserStateWithManagedAccountAndMigratedFromSyncing: case SignedInUserStateWithManagedAccountAndSyncing: { + if (base::FeatureList::IsEnabled(kIdentityDiscAccountMenu)) { + self.actionSheetCoordinator.alertStyle = UIAlertControllerStyleAlert; + } NSString* const clearFromDeviceTitle = l10n_util::GetNSString(IDS_IOS_SIGNOUT_DIALOG_CLEAR_DATA_BUTTON); [self.actionSheetCoordinator
diff --git a/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_view.mm b/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_view.mm index 247c99a..def3b05 100644 --- a/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_view.mm +++ b/ios/chrome/browser/ui/content_suggestions/tab_resumption/tab_resumption_view.mm
@@ -477,7 +477,8 @@ _reasonLabel = [[UILabel alloc] init]; _reasonLabel.translatesAutoresizingMaskIntoConstraints = NO; _reasonLabel.adjustsFontForContentSizeCategory = YES; - _reasonLabel.textColor = [UIColor colorNamed:kTextSecondaryColor]; + _reasonLabel.textColor = + [UIColor colorNamed:kTextLightTertiaryDarkPrimaryColor]; [_reasonLabel setText:_item.reason]; UIFont* font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; @@ -487,7 +488,7 @@ _reasonLabelContainer.translatesAutoresizingMaskIntoConstraints = NO; [_reasonLabelContainer addSubview:_reasonLabel]; _reasonLabelContainer.backgroundColor = - [UIColor colorNamed:kSecondaryBackgroundColor]; + [UIColor colorNamed:kTertiaryBackgroundColor]; _leadingLabelConstraint = [_reasonLabel.leadingAnchor constraintEqualToAnchor:_reasonLabelContainer.leadingAnchor];
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm index 266e39f..429ca11 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -553,8 +553,9 @@ [item setObject:base::SysUTF16ToNSString(text) forKey:UTTypePlainText.identifier]; - if (write_url) + if (write_url && url.is_valid()) { [item setObject:net::NSURLWithGURL(url) forKey:UTTypeURL.identifier]; + } StoreItemInPasteboard(item);
diff --git a/ios/chrome/browser/unified_consent/model/BUILD.gn b/ios/chrome/browser/unified_consent/model/BUILD.gn index c71fee9d..e4f1a9163 100644 --- a/ios/chrome/browser/unified_consent/model/BUILD.gn +++ b/ios/chrome/browser/unified_consent/model/BUILD.gn
@@ -9,13 +9,13 @@ ] deps = [ "//components/browser_sync", - "//components/keyed_service/ios", "//components/metrics", "//components/sync", "//components/sync_preferences", "//components/unified_consent", "//ios/chrome/browser/shared/model/prefs:pref_names", "//ios/chrome/browser/shared/model/profile", + "//ios/chrome/browser/shared/model/profile:profile_keyed_service_factory", "//ios/chrome/browser/signin/model", "//ios/chrome/browser/sync/model", ]
diff --git a/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.h b/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.h index a74b1dd..540381f6 100644 --- a/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.h +++ b/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.h
@@ -6,27 +6,23 @@ #define IOS_CHROME_BROWSER_UNIFIED_CONSENT_MODEL_UNIFIED_CONSENT_SERVICE_FACTORY_H_ #import "base/no_destructor.h" -#import "components/keyed_service/ios/browser_state_keyed_service_factory.h" #import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h" +#import "ios/chrome/browser/shared/model/profile/profile_keyed_service_factory_ios.h" namespace unified_consent { class UnifiedConsentService; } -class UnifiedConsentServiceFactory : public BrowserStateKeyedServiceFactory { +class UnifiedConsentServiceFactory : public ProfileKeyedServiceFactoryIOS { public: - static unified_consent::UnifiedConsentService* GetForBrowserState( - ChromeBrowserState* browser_state); + static unified_consent::UnifiedConsentService* GetForProfile( + ProfileIOS* profile); - static unified_consent::UnifiedConsentService* GetForBrowserStateIfExists( - ChromeBrowserState* browser_state); + static unified_consent::UnifiedConsentService* GetForProfileIfExists( + ProfileIOS* profile); static UnifiedConsentServiceFactory* GetInstance(); - UnifiedConsentServiceFactory(const UnifiedConsentServiceFactory&) = delete; - UnifiedConsentServiceFactory& operator=(const UnifiedConsentServiceFactory&) = - delete; - private: friend class base::NoDestructor<UnifiedConsentServiceFactory>;
diff --git a/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.mm b/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.mm index 8f7abbac..676ab9d 100644 --- a/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.mm +++ b/ios/chrome/browser/unified_consent/model/unified_consent_service_factory.mm
@@ -8,7 +8,6 @@ #import <vector> #import "base/no_destructor.h" -#import "components/keyed_service/ios/browser_state_dependency_manager.h" #import "components/sync/service/sync_service.h" #import "components/sync_preferences/pref_service_syncable.h" #import "components/unified_consent/unified_consent_metrics.h" @@ -19,9 +18,7 @@ #import "ios/chrome/browser/sync/model/sync_service_factory.h" UnifiedConsentServiceFactory::UnifiedConsentServiceFactory() - : BrowserStateKeyedServiceFactory( - "UnifiedConsentService", - BrowserStateDependencyManager::GetInstance()) { + : ProfileKeyedServiceFactoryIOS("UnifiedConsentService") { DependsOn(IdentityManagerFactory::GetInstance()); DependsOn(SyncServiceFactory::GetInstance()); } @@ -30,18 +27,18 @@ // static unified_consent::UnifiedConsentService* -UnifiedConsentServiceFactory::GetForBrowserState( - ChromeBrowserState* browser_state) { - return static_cast<unified_consent::UnifiedConsentService*>( - GetInstance()->GetServiceForBrowserState(browser_state, true)); +UnifiedConsentServiceFactory::GetForProfile(ProfileIOS* profile) { + return GetInstance() + ->GetServiceForProfileAs<unified_consent::UnifiedConsentService>( + profile, /*create=*/true); } // static unified_consent::UnifiedConsentService* -UnifiedConsentServiceFactory::GetForBrowserStateIfExists( - ChromeBrowserState* browser_state) { - return static_cast<unified_consent::UnifiedConsentService*>( - GetInstance()->GetServiceForBrowserState(browser_state, false)); +UnifiedConsentServiceFactory::GetForProfileIfExists(ProfileIOS* profile) { + return GetInstance() + ->GetServiceForProfileAs<unified_consent::UnifiedConsentService>( + profile, /*create=*/false); } // static @@ -53,15 +50,14 @@ std::unique_ptr<KeyedService> UnifiedConsentServiceFactory::BuildServiceInstanceFor( web::BrowserState* context) const { - ChromeBrowserState* browser_state = - ChromeBrowserState::FromBrowserState(context); + ProfileIOS* profile = ProfileIOS::FromBrowserState(context); sync_preferences::PrefServiceSyncable* user_pref_service = - browser_state->GetSyncablePrefs(); + profile->GetSyncablePrefs(); signin::IdentityManager* identity_manager = - IdentityManagerFactory::GetForBrowserState(browser_state); + IdentityManagerFactory::GetForBrowserState(profile); syncer::SyncService* sync_service = - SyncServiceFactory::GetForBrowserState(browser_state); + SyncServiceFactory::GetForBrowserState(profile); // Record settings for pre- and post-UnifiedConsent users. unified_consent::metrics::RecordSettingsHistogram(user_pref_service);
diff --git a/ios/chrome/common/ui/colors/resources/Assets.xcassets/text_light_tertiary_dark_primary_color.colorset/Contents.json b/ios/chrome/common/ui/colors/resources/Assets.xcassets/text_light_tertiary_dark_primary_color.colorset/Contents.json new file mode 100644 index 0000000..95c15c88 --- /dev/null +++ b/ios/chrome/common/ui/colors/resources/Assets.xcassets/text_light_tertiary_dark_primary_color.colorset/Contents.json
@@ -0,0 +1,38 @@ +{ + "info": { + "version": 1, + "author": "xcode" + }, + "colors": [ + { + "idiom": "universal", + "color": { + "color-space": "display-p3", + "components": { + "alpha": "0.6", + "red": "0x3C", + "green": "0x3C", + "blue": "0x43" + } + } + }, + { + "idiom": "universal", + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "display-p3", + "components": { + "alpha" : "1.000", + "red" : "0xFF", + "green" : "0xFF", + "blue" : "0xFF" + } + } + } + ] +}
diff --git a/ios/chrome/common/ui/colors/resources/BUILD.gn b/ios/chrome/common/ui/colors/resources/BUILD.gn index 5137839..95ec92f1 100644 --- a/ios/chrome/common/ui/colors/resources/BUILD.gn +++ b/ios/chrome/common/ui/colors/resources/BUILD.gn
@@ -88,6 +88,7 @@ "Assets.xcassets/tab_strip_new_tab_button_color.colorset/Contents.json", "Assets.xcassets/table_view_row_highlight_color.colorset/Contents.json", "Assets.xcassets/tertiary_background_color.colorset/Contents.json", + "Assets.xcassets/text_light_tertiary_dark_primary_color.colorset/Contents.json", "Assets.xcassets/text_primary_color.colorset/Contents.json", "Assets.xcassets/text_quaternary_color.colorset/Contents.json", "Assets.xcassets/text_secondary_color.colorset/Contents.json",
diff --git a/ios/chrome/common/ui/colors/semantic_color_names.h b/ios/chrome/common/ui/colors/semantic_color_names.h index 4c48912..2a8d2af 100644 --- a/ios/chrome/common/ui/colors/semantic_color_names.h +++ b/ios/chrome/common/ui/colors/semantic_color_names.h
@@ -48,6 +48,7 @@ extern NSString* const kInvertedTextSecondaryColor; extern NSString* const kTextTertiaryColor; extern NSString* const kTextQuaternaryColor; +extern NSString* const kTextLightTertiaryDarkPrimaryColor; extern NSString* const kTextfieldBackgroundColor; extern NSString* const kTextfieldFocusedBackgroundColor; extern NSString* const kTextfieldHighlightBackgroundColor;
diff --git a/ios/chrome/common/ui/colors/semantic_color_names.mm b/ios/chrome/common/ui/colors/semantic_color_names.mm index 9be305b..bfb6cb9 100644 --- a/ios/chrome/common/ui/colors/semantic_color_names.mm +++ b/ios/chrome/common/ui/colors/semantic_color_names.mm
@@ -30,6 +30,8 @@ NSString* const kTextPrimaryColor = @"text_primary_color"; NSString* const kInvertedTextPrimaryColor = @"inverted_text_primary_color"; NSString* const kTextSecondaryColor = @"text_secondary_color"; +NSString* const kTextLightTertiaryDarkPrimaryColor = + @"text_light_tertiary_dark_primary_color"; NSString* const kInvertedTextSecondaryColor = @"inverted_text_secondary_color"; NSString* const kTextTertiaryColor = @"text_tertiary_color"; NSString* const kTextQuaternaryColor = @"text_quaternary_color";
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm index 51267f6..9b98abb 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm +++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -1386,7 +1386,7 @@ #pragma mark - Unified Consent utilities + (void)setURLKeyedAnonymizedDataCollectionEnabled:(BOOL)enabled { - UnifiedConsentServiceFactory::GetForBrowserState( + UnifiedConsentServiceFactory::GetForProfile( chrome_test_util::GetOriginalBrowserState()) ->SetUrlKeyedAnonymizedDataCollectionEnabled(enabled); }
diff --git a/ios_internal b/ios_internal index 04d3d91..ef95707 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 04d3d919e6e9c04f692abbab2c1b817075bf7d49 +Subproject commit ef95707679427db9a0d94d329299e6222658b4b6
diff --git a/mojo/public/tools/fuzzers/mojolpm_generator.py b/mojo/public/tools/fuzzers/mojolpm_generator.py index 9b32e8e..3056cfc9 100755 --- a/mojo/public/tools/fuzzers/mojolpm_generator.py +++ b/mojo/public/tools/fuzzers/mojolpm_generator.py
@@ -170,7 +170,7 @@ if self.type == MojoLPMActionType.NEW_ACTION: assert self.camel_case_namespace ns = self.camel_case_namespace - return f"{ns}{snake_to_camel_case(self.identifier)}{self.type.value}" + return f"{ns}{snake_to_camel_case(self.identifier)}" if not self.namespace: return f"mojolpm.{self.type.value}" return f"mojolpm.{self.namespace}.{self.type.value}" @@ -270,6 +270,26 @@ } +def _GetProtoId(name): + # We reserve ids [0,15] + # Protobuf implementation reserves [19000,19999] + # Max proto id is 2^29-1 + # 32-bit fnv-1a + fnv = 2166136261 + for c in name: + fnv = fnv ^ ord(c) + fnv = (fnv * 16777619) & 0xffffffff + # xor-fold to 29-bits + fnv = (fnv >> 29) ^ (fnv & 0x1fffffff) + # now use a modulo to reduce to [0,2^29-1 - 1016] + fnv = fnv % 536869895 + # now we move out the disallowed ranges + fnv = fnv + 15 + if fnv >= 19000: + fnv += 1000 + return fnv + + def camel_to_snake_case(name: str) -> str: """Camel case to snake case conversion. @@ -448,6 +468,7 @@ self._environment = jinja2.Environment(loader=jinja2.FileSystemLoader( os.path.join(os.path.dirname(os.path.abspath(__file__)), "mojolpm_generator_templates/"))) + self._environment.globals['proto_id'] = _GetProtoId self.template = self._environment.get_template(template_filename)
diff --git a/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.h.tmpl b/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.h.tmpl index e929d5c5..e0e3caf7 100644 --- a/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.h.tmpl +++ b/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.h.tmpl
@@ -52,18 +52,22 @@ {% endfor %} {% endfor %} private: -{% for action in actions_list %} - void HandleRemote{{loop.index}}(const {{proto_namespace}}::Remote{{loop.index}}&, - base::OnceClosure); +{% for actions in actions_list %} +{%- set root_action = actions|selectattr("is_new_action")|first %} + void HandleRemote{{root_action['cpp_name']}}(const {{proto_namespace}}::Remote{{root_action['cpp_name']}}&, + base::OnceClosure); {% endfor %} -{% for action in actions_list %} - void HandleRemoteAction{{loop.index}}(const {{proto_namespace}}::RemoteAction{{loop.index}}&, +{% for actions in actions_list %} +{%- set root_action = actions|selectattr("is_new_action")|first %} +{% set current_action = "RemoteAction" + root_action['cpp_name']|string %} + void Handle{{current_action}}(const {{proto_namespace}}::{{current_action}}&, base::OnceClosure); {% endfor %} }; {% for actions in actions_list %} -{% set current_action = "RemoteAction" + loop.index|string %} +{%- set root_action = actions|selectattr("is_new_action")|first %} +{% set current_action = "RemoteAction" + root_action['cpp_name']|string %} void {{classname}}::Handle{{current_action}}(const {{proto_namespace}}::{{current_action}}& action, base::OnceClosure done_closure) { {% set all_switch_actions = actions -%} @@ -93,17 +97,25 @@ {% for actions in actions_list %} -void {{classname}}::HandleRemote{{loop.index}}(const {{proto_namespace}}::Remote{{loop.index}}& action, +{%- set root_action = actions|selectattr("is_new_action")|first %} +void {{classname}}::HandleRemote{{root_action['cpp_name']}}(const {{proto_namespace}}::Remote{{root_action['cpp_name']}}& action, base::OnceClosure done_closure) { {% if ensure_remote %} {% for action in actions|selectattr("is_new_action") %} HandleNew{{action['cpp_name']}}Action(action.{{action['mojo_name']}}().id(), base::DoNothing()); {% endfor %} -{% set all_switch_actions = actions|rejectattr("is_new_action")|list -%} {% endif %} - for (const auto& sub_action : action.remote_{{loop.index}}()) { - HandleRemoteAction{{loop.index}}(sub_action, base::DoNothing()); + if (action.action_{{root_action['mojo_name']}}_size() != 0) { + for (const uint32_t index : action.sequence_indexes()) { + if (action.sequences_size() == 0) break; + const auto& sequence = action.sequences(index % action.sequences_size()); + for (const uint32_t action_index : sequence.action_indexes()) { + const auto& remote_action = + action.action_{{root_action['mojo_name']}}(action_index % action.action_{{root_action['mojo_name']}}_size()); + HandleRemoteAction{{root_action['cpp_name']}}(remote_action, base::DoNothing()); + } + } } GetFuzzerTaskRunner()->PostTask(FROM_HERE, std::move(done_closure)); } @@ -123,9 +135,10 @@ case ProtoAction::kRunThreadAction: HandleRunThreadAction(action.run_thread_action().id(), std::move(done_closure)); return; -{% for action in actions_list %} - case ProtoAction::kAction{{loop.index}}: - HandleRemote{{loop.index}}(action.action_{{loop.index}}(), std::move(done_closure)); +{% for action_set in actions_list %} +{%- set action = action_set|selectattr("is_new_action")|first %} + case ProtoAction::{{action['case_name']}}: + HandleRemote{{action['cpp_name']}}(action.{{action['mojo_name']}}(), std::move(done_closure)); return; {% endfor %} case ProtoAction::ACTION_NOT_SET:
diff --git a/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.proto.tmpl b/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.proto.tmpl index f9505ce..c346a96 100644 --- a/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.proto.tmpl +++ b/mojo/public/tools/fuzzers/mojolpm_generator_templates/mojolpm_generator.proto.tmpl
@@ -11,26 +11,27 @@ } {% for new_message in new_messages %} -message {{new_message}} { +message {{new_message}}NewAction { required uint32 id = 1; } {% endfor %} {% for actions in actions_list %} -message RemoteAction{{loop.index}} { -{% set new_actions = [] -%} +{%- set root_action = actions|selectattr("is_new_action")|first %} +message RemoteAction{{root_action['proto_type']}} { {% if ensure_remote %} {% set oneof_actions = actions|rejectattr("is_new_action")|list -%} {% else %} {% set oneof_actions = actions -%} {% endif %} -{% for action in new_actions %} - required {{action['proto_type']}} {{action['proto_identifier']}} = {{loop.index}}; -{% endfor %} {% if oneof_actions|length > 0 %} oneof action { {% for action in oneof_actions %} - {{action['proto_type']}} {{action['proto_identifier']}} = {{loop.index + 1}}; +{%- if action['is_new_action'] %} + {{action['proto_type']}}NewAction {{action['proto_identifier']}} = {{proto_id(action['proto_identifier'])}}; +{% else %} + {{action['proto_type']}} {{action['proto_identifier']}} = {{proto_id(action['proto_identifier'])}}; +{% endif -%} {% endfor %} } {% endif %} @@ -38,13 +39,16 @@ {% endfor %} {% for actions in actions_list %} -message Remote{{loop.index}} { +{%- set root_action = actions|selectattr("is_new_action")|first %} +message Remote{{root_action['proto_type']}} { + repeated RemoteAction{{root_action['proto_type']}} action_{{root_action['proto_identifier']}} = 1; + repeated Sequence sequences = 2; + repeated uint32 sequence_indexes = 3 [packed = true]; {% if ensure_remote %} {% for action in actions|selectattr("is_new_action") %} - required {{action['proto_type']}} {{action['proto_identifier']}} = {{loop.index}}; + required {{action['proto_type']}}NewAction {{action['proto_identifier']}} = {{proto_id(action['proto_identifier'])}}; {% endfor %} {% endif %} - repeated RemoteAction{{loop.index}} remote_{{loop.index}} = {{loop.index + 1}}; } {% endfor %} @@ -53,7 +57,8 @@ oneof action { RunThreadAction run_thread_action = 1; {% for action_set in actions_list %} - Remote{{loop.index}} action_{{loop.index}} = {{loop.index + 1}}; +{%- set root_action = action_set|selectattr("is_new_action")|first %} + Remote{{root_action['proto_type']}} {{root_action['proto_identifier']}} = {{proto_id(root_action['proto_type'])}}; {% endfor %} } }
diff --git a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc index d3e6bad..6bc6827c 100644 --- a/net/dns/host_resolver_manager_service_endpoint_request_impl.cc +++ b/net/dns/host_resolver_manager_service_endpoint_request_impl.cc
@@ -95,12 +95,12 @@ return finalized_result_->endpoints; } - if (job_) { - CHECK(job_.value()->dns_task_results_manager()); + if (job_ && job_.value()->dns_task_results_manager()) { return job_.value()->dns_task_results_manager()->GetCurrentEndpoints(); } - NOTREACHED(); + static const base::NoDestructor<std::vector<ServiceEndpoint>> kEmptyEndpoints; + return *kEmptyEndpoints.get(); } const std::set<std::string>& @@ -111,13 +111,13 @@ return finalized_result_->dns_aliases; } - if (job_) { - CHECK(job_.value()->dns_task_results_manager()); + if (job_ && job_.value()->dns_task_results_manager()) { // TODO(crbug.com/41493696): Call dns_alias_utility::FixUpDnsAliases(). return job_.value()->dns_task_results_manager()->GetAliases(); } - NOTREACHED(); + static const base::NoDestructor<std::set<std::string>> kEmptyDnsAliases; + return *kEmptyDnsAliases.get(); } bool HostResolverManager::ServiceEndpointRequestImpl::EndpointsCryptoReady() {
diff --git a/net/dns/host_resolver_service_endpoint_request_unittest.cc b/net/dns/host_resolver_service_endpoint_request_unittest.cc index 6cfbc8e..17ecde2 100644 --- a/net/dns/host_resolver_service_endpoint_request_unittest.cc +++ b/net/dns/host_resolver_service_endpoint_request_unittest.cc
@@ -135,6 +135,12 @@ run_loop.Run(); } + void WaitForOnUpdated() { + base::RunLoop run_loop; + SetOnUpdatedCallback(run_loop.QuitClosure()); + run_loop.Run(); + } + ServiceEndpointRequest* request() const { return request_.get(); } std::optional<int> finished_result() const { return finished_result_; } @@ -342,6 +348,25 @@ IsError(ERR_DNS_TIMED_OUT)); } +// Tests that a request returns valid endpoints and DNS aliases after DnsTasks +// are aborted. +TEST_F(HostResolverServiceEndpointRequestTest, KillDnsTask) { + UseIpv4DelayedDnsRules("4slow_ok"); + + proc_->SignalMultiple(1u); + Requester requester = CreateRequester("https://4slow_ok"); + int rv = requester.Start(); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + requester.WaitForOnUpdated(); + + // Simulate the case when the preference or policy has disabled the insecure + // DNS client causing AbortInsecureDnsTasks. + resolver_->SetInsecureDnsClientEnabled( + /*enabled=*/false, /*additional_dns_types_enabled=*/false); + ASSERT_TRUE(requester.request()->GetEndpointResults().empty()); + ASSERT_TRUE(requester.request()->GetDnsAliasResults().empty()); +} + TEST_F(HostResolverServiceEndpointRequestTest, Ok) { UseNonDelayedDnsRules("ok");
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc index f1d886c7..75654ea 100644 --- a/pdf/pdf_view_web_plugin.cc +++ b/pdf/pdf_view_web_plugin.cc
@@ -612,7 +612,7 @@ void PdfViewWebPlugin::DidReceiveResponse( const blink::WebURLResponse& response) {} -void PdfViewWebPlugin::DidReceiveData(const char* data, size_t data_length) {} +void PdfViewWebPlugin::DidReceiveData(base::span<const char> data) {} void PdfViewWebPlugin::DidFinishLoading() {}
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h index df3590e..91185378 100644 --- a/pdf/pdf_view_web_plugin.h +++ b/pdf/pdf_view_web_plugin.h
@@ -263,7 +263,7 @@ const blink::WebCoalescedInputEvent& event, ui::Cursor* cursor) override; void DidReceiveResponse(const blink::WebURLResponse& response) override; - void DidReceiveData(const char* data, size_t data_length) override; + void DidReceiveData(base::span<const char> data) override; void DidFinishLoading() override; void DidFailLoading(const blink::WebURLError& error) override; bool SupportsPaginatedPrint() override;
diff --git a/services/network/resource_scheduler/resource_scheduler.cc b/services/network/resource_scheduler/resource_scheduler.cc index 2cdeeaf..8f56291 100644 --- a/services/network/resource_scheduler/resource_scheduler.cc +++ b/services/network/resource_scheduler/resource_scheduler.cc
@@ -25,7 +25,6 @@ #include "base/time/tick_clock.h" #include "base/trace_event/trace_event.h" #include "base/unguessable_token.h" -#include "components/miracle_parameter/common/public/miracle_parameter.h" #include "net/base/isolation_info.h" #include "net/base/load_flags.h" #include "net/base/request_priority.h" @@ -99,39 +98,15 @@ return (reinterpret_cast<uint64_t>(scheduler) << 32) | sNextId++; } -BASE_FEATURE(kMaxNumDelayableRequestsPerHostPerClientFeature, - "MaxNumDelayableRequestsPerHostPerClientFeature", - base::FEATURE_ENABLED_BY_DEFAULT); - -BASE_FEATURE(kDelayablePriorityThresholdFeature, - "DelayablePriorityThresholdFeature", - base::FEATURE_ENABLED_BY_DEFAULT); - -constexpr base::FeatureParam<net::RequestPriority>::Option - kRequestPriorities[] = { - {net::LOWEST, "lowest"}, - {net::LOW, "low"}, - {net::MEDIUM, "medium"}, - {net::HIGHEST, "highest"}, -}; - } // namespace // The maximum number of requests to allow be in-flight at any point in time per // host. This limit does not apply to hosts that support request prioritization // when |delay_requests_on_multiplexed_connections| is true. -MIRACLE_PARAMETER_FOR_INT(GetMaxNumDelayableRequestsPerHostPerClient, - kMaxNumDelayableRequestsPerHostPerClientFeature, - "MaxNumDelayableRequestsPerHostPerClient", - 6) +static const size_t kMaxNumDelayableRequestsPerHostPerClient = 6; // The priority level below which resources are considered to be delayable. -MIRACLE_PARAMETER_FOR_ENUM(GetDelayablePriorityThreshold, - kDelayablePriorityThresholdFeature, - "DelayablePriorityThreshold", - net::MEDIUM, - net::RequestPriority, - kRequestPriorities) +static const net::RequestPriority kDelayablePriorityThreshold = net::MEDIUM; // Returns the duration after which the timer to dispatch queued requests should // fire. @@ -809,9 +784,7 @@ if (base::Contains(in_flight_requests_, request)) attributes |= kAttributeInFlight; - const net::RequestPriority kPriorityThreshold = - GetDelayablePriorityThreshold(); - if (request->url_request()->priority() < kPriorityThreshold) { + if (request->url_request()->priority() < kDelayablePriorityThreshold) { if (params_for_network_quality_ .delay_requests_on_multiplexed_connections) { // Resources below the delayable priority threshold that are considered @@ -857,14 +830,12 @@ return false; } - const size_t kMaxSameHostCount = - GetMaxNumDelayableRequestsPerHostPerClient(); size_t same_host_count = 0; for (const ScheduledResourceRequestImpl* in_flight_request : in_flight_requests_) { if (active_request_host == in_flight_request->scheme_host_port()) { same_host_count++; - if (same_host_count >= kMaxSameHostCount) { + if (same_host_count >= kMaxNumDelayableRequestsPerHostPerClient) { return true; } }
diff --git a/third_party/angle b/third_party/angle index 621bba6..34201e0 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 621bba6cc6a80cf910157c157beb21796e62e7d8 +Subproject commit 34201e0d441070446108a655d9ad0b32c4c7d88a
diff --git a/third_party/bidimapper/README.chromium b/third_party/bidimapper/README.chromium index a221bc5..3934c4b 100644 --- a/third_party/bidimapper/README.chromium +++ b/third_party/bidimapper/README.chromium
@@ -1,10 +1,10 @@ Name: Implementation of WebDriver BiDi standard Short Name: chromium-bidi -URL: https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.4.tgz -Version: 0.6.4 -Date: 2024-08-05 -Revision: 54dab6c913ef15cd1a12594e97d716ca3f7ca9e6 -SHA-512: a0bece1b2306539dbdcc03dc5ae7131461499cfb68191c8d0556fb18ae388843c336b1ab094b4b0af8dc7625152a6de777ce59b1d96e93e1c958cd957c1ba904 +URL: https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.7.0.tgz +Version: 0.7.0 +Date: 2024-09-05 +Revision: 46546defe5111fe4a33ebc947e0c684202e86222 +SHA-512: 13d55192a5beaaeadb187bff8cd10ee7e31f20a2f53508b8dfd3e732c5a146fb6ace63457e4ff371082cab24d0b837b01def74277e2af8b94ae30d7554132029 License: Apache 2.0 License File: LICENSE Shipped: yes @@ -32,7 +32,7 @@ The upstream is maintained by the Chromium developers. All the changes must be done there. -The source code of the current revision can be found at the following url: https://github.com/GoogleChromeLabs/chromium-bidi/archive/54dab6c913ef15cd1a12594e97d716ca3f7ca9e6.zip +The source code of the current revision can be found at the following url: https://github.com/GoogleChromeLabs/chromium-bidi/archive/46546defe5111fe4a33ebc947e0c684202e86222.zip -------------------- DEPENDENCY DIVIDER -------------------- @@ -47,17 +47,6 @@ -------------------- DEPENDENCY DIVIDER -------------------- -Name: urlpattern-polyfill -URL: https://github.com/kenchris/urlpattern-polyfill -Version: 10.0.0 -License: MIT -Revision: 039357b28b68e3d68f59d7c6af0138cd25a91914 -Security Critical: no -Shipped: yes -License File: licenses/LICENSE.urlpattern_polyfill - --------------------- DEPENDENCY DIVIDER -------------------- - Name: zod URL: https://zod.dev Version: 3.23.8
diff --git a/third_party/bidimapper/licenses/LICENSE.urlpattern_polyfill b/third_party/bidimapper/licenses/LICENSE.urlpattern_polyfill deleted file mode 100644 index 6e95fa3c..0000000 --- a/third_party/bidimapper/licenses/LICENSE.urlpattern_polyfill +++ /dev/null
@@ -1,19 +0,0 @@ -Copyright 2020 Intel Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.
diff --git a/third_party/bidimapper/mapper.js b/third_party/bidimapper/mapper.js index 866819b..ead596e7 100644 --- a/third_party/bidimapper/mapper.js +++ b/third_party/bidimapper/mapper.js
@@ -2358,6 +2358,12 @@ break; case "pen" /* Input.PointerType.Pen */: if (source.pressed.size !== 0) { + // Empty `source.pressed.size` means the pen is not detected by digitizer. + // Dispatch a mouse event for the pen only if either: + // 1. the pen is hovering over the digitizer (0); + // 2. the pen is in contact with the digitizer (1); + // 3. the pen has at least one button pressed (2, 4, etc). + // https://www.w3.org/TR/pointerevents/#the-buttons-property // TODO: Implement width and height when available. await this.#context.cdpTarget.cdpClient.sendCommand('Input.dispatchMouseEvent', { type: 'mouseMoved', @@ -2372,7 +2378,7 @@ tiltX, tiltY, twist, - force: pressure, + force: pressure ?? 0.5, }); } break; @@ -2708,6 +2714,7 @@ return; }; function getCdpButton(button) { + // https://www.w3.org/TR/pointerevents/#the-button-property switch (button) { case 0: return 'left'; @@ -2725,7 +2732,7 @@ } function getTilt(action) { // https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle - const altitudeAngle = action.altitudeAngle ?? 0; + const altitudeAngle = action.altitudeAngle ?? Math.PI / 2; const azimuthAngle = action.azimuthAngle ?? 0; let tiltXRadians = 0; let tiltYRadians = 0; @@ -3004,11 +3011,9 @@ const InputStateManager_js_1 = InputStateManager$1; class InputProcessor { #browsingContextStorage; - #realmStorage; #inputStateManager = new InputStateManager_js_1.InputStateManager(); - constructor(browsingContextStorage, realmStorage) { + constructor(browsingContextStorage) { this.#browsingContextStorage = browsingContextStorage; - this.#realmStorage = realmStorage; } async performActions(params) { const context = this.#browsingContextStorage.getContext(params.context); @@ -3175,6 +3180,33 @@ var NetworkProcessor$1 = {}; + var UrlPatternBrowser = {}; + + /** + * Copyright 2024 Google LLC. + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + Object.defineProperty(UrlPatternBrowser, "__esModule", { value: true }); + UrlPatternBrowser.URLPattern = void 0; + const URLPattern = globalThis + .URLPattern; + UrlPatternBrowser.URLPattern = URLPattern; + if (!URLPattern) { + throw new Error('Unable to find URLPattern'); + } + /** * Copyright 2023 Google LLC. * Copyright (c) Microsoft Corporation. @@ -3194,6 +3226,7 @@ Object.defineProperty(NetworkProcessor$1, "__esModule", { value: true }); NetworkProcessor$1.NetworkProcessor = void 0; const protocol_js_1$i = protocol; + const UrlPattern_js_1$1 = UrlPatternBrowser; /** Dispatches Network domain commands. */ class NetworkProcessor { #browsingContextStorage; @@ -3420,7 +3453,7 @@ throw new protocol_js_1$i.InvalidArgumentException(`URL pattern must specify a port`); } try { - new URLPattern(urlPattern); + new UrlPattern_js_1$1.URLPattern(urlPattern); } catch (error) { throw new protocol_js_1$i.InvalidArgumentException(`${error}`); @@ -3967,15 +4000,42 @@ const protocol_js_1$f = protocol; const PreloadScript_js_1 = PreloadScript$1; class ScriptProcessor { + #eventManager; #browsingContextStorage; #realmStorage; #preloadScriptStorage; #logger; - constructor(browsingContextStorage, realmStorage, preloadScriptStorage, logger) { + constructor(eventManager, browsingContextStorage, realmStorage, preloadScriptStorage, logger) { this.#browsingContextStorage = browsingContextStorage; this.#realmStorage = realmStorage; this.#preloadScriptStorage = preloadScriptStorage; this.#logger = logger; + this.#eventManager = eventManager; + this.#eventManager.addSubscribeHook(protocol_js_1$f.ChromiumBidi.Script.EventNames.RealmCreated, this.#onRealmCreatedSubscribeHook.bind(this)); + } + #onRealmCreatedSubscribeHook(contextId) { + const context = this.#browsingContextStorage.getContext(contextId); + const contextsToReport = [ + context, + ...this.#browsingContextStorage.getContext(contextId).allChildren, + ]; + const realms = new Set(); + for (const reportContext of contextsToReport) { + const realmsForContext = this.#realmStorage.findRealms({ + browsingContextId: reportContext.id, + }); + for (const realm of realmsForContext) { + realms.add(realm); + } + } + for (const realm of realms) { + this.#eventManager.registerEvent({ + type: 'event', + method: protocol_js_1$f.ChromiumBidi.Script.EventNames.RealmCreated, + params: realm.realmInfo, + }, context.id); + } + return Promise.resolve(); } async addPreloadScript(params) { const contexts = this.#browsingContextStorage.verifyTopLevelContextsList(params.contexts); @@ -4192,45 +4252,6 @@ return Buffer.from(base64Str, 'base64').toString('ascii'); } - var UrlPattern = {}; - - var M=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Re=Object.getOwnPropertyNames;var Ee=Object.prototype.hasOwnProperty;var Oe=(e,t)=>{for(var r in t)M(e,r,{get:t[r],enumerable:!0});},ke=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Re(t))!Ee.call(e,a)&&a!==r&&M(e,a,{get:()=>t[a],enumerable:!(n=Pe(t,a))||n.enumerable});return e};var Te=e=>ke(M({},"__esModule",{value:!0}),e);var Ne={};Oe(Ne,{URLPattern:()=>Y});var urlpattern=Te(Ne);var R=class{type=3;name="";prefix="";value="";suffix="";modifier=3;constructor(t,r,n,a,c,l){this.type=t,this.name=r,this.prefix=n,this.value=a,this.suffix=c,this.modifier=l;}hasCustomName(){return this.name!==""&&typeof this.name!="number"}},Ae=/[$_\p{ID_Start}]/u,ye=/[$_\u200C\u200D\p{ID_Continue}]/u,v=".*";function we(e,t){return (/^[\x00-\x7F]*$/).test(e)}function D(e,t=!1){let r=[],n=0;for(;n<e.length;){let a=e[n],c=function(l){if(!t)throw new TypeError(l);r.push({type:"INVALID_CHAR",index:n,value:e[n++]});};if(a==="*"){r.push({type:"ASTERISK",index:n,value:e[n++]});continue}if(a==="+"||a==="?"){r.push({type:"OTHER_MODIFIER",index:n,value:e[n++]});continue}if(a==="\\"){r.push({type:"ESCAPED_CHAR",index:n++,value:e[n++]});continue}if(a==="{"){r.push({type:"OPEN",index:n,value:e[n++]});continue}if(a==="}"){r.push({type:"CLOSE",index:n,value:e[n++]});continue}if(a===":"){let l="",s=n+1;for(;s<e.length;){let i=e.substr(s,1);if(s===n+1&&Ae.test(i)||s!==n+1&&ye.test(i)){l+=e[s++];continue}break}if(!l){c(`Missing parameter name at ${n}`);continue}r.push({type:"NAME",index:n,value:l}),n=s;continue}if(a==="("){let l=1,s="",i=n+1,o=!1;if(e[i]==="?"){c(`Pattern cannot start with "?" at ${i}`);continue}for(;i<e.length;){if(!we(e[i])){c(`Invalid character '${e[i]}' at ${i}.`),o=!0;break}if(e[i]==="\\"){s+=e[i++]+e[i++];continue}if(e[i]===")"){if(l--,l===0){i++;break}}else if(e[i]==="("&&(l++,e[i+1]!=="?")){c(`Capturing groups are not allowed at ${i}`),o=!0;break}s+=e[i++];}if(o)continue;if(l){c(`Unbalanced pattern at ${n}`);continue}if(!s){c(`Missing pattern at ${n}`);continue}r.push({type:"REGEX",index:n,value:s}),n=i;continue}r.push({type:"CHAR",index:n,value:e[n++]});}return r.push({type:"END",index:n,value:""}),r}function F(e,t={}){let r=D(e);t.delimiter??="/#?",t.prefixes??="./";let n=`[^${S(t.delimiter)}]+?`,a=[],c=0,l=0,i=new Set,o=h=>{if(l<r.length&&r[l].type===h)return r[l++].value},f=()=>o("OTHER_MODIFIER")??o("ASTERISK"),d=h=>{let u=o(h);if(u!==void 0)return u;let{type:p,index:A}=r[l];throw new TypeError(`Unexpected ${p} at ${A}, expected ${h}`)},T=()=>{let h="",u;for(;u=o("CHAR")??o("ESCAPED_CHAR");)h+=u;return h},xe=h=>h,L=t.encodePart||xe,I="",U=h=>{I+=h;},$=()=>{I.length&&(a.push(new R(3,"","",L(I),"",3)),I="");},X=(h,u,p,A,Z)=>{let g=3;switch(Z){case"?":g=1;break;case"*":g=0;break;case"+":g=2;break}if(!u&&!p&&g===3){U(h);return}if($(),!u&&!p){if(!h)return;a.push(new R(3,"","",L(h),"",g));return}let m;p?p==="*"?m=v:m=p:m=n;let O=2;m===n?(O=1,m=""):m===v&&(O=0,m="");let P;if(u?P=u:p&&(P=c++),i.has(P))throw new TypeError(`Duplicate name '${P}'.`);i.add(P),a.push(new R(O,P,L(h),m,L(A),g));};for(;l<r.length;){let h=o("CHAR"),u=o("NAME"),p=o("REGEX");if(!u&&!p&&(p=o("ASTERISK")),u||p){let g=h??"";t.prefixes.indexOf(g)===-1&&(U(g),g=""),$();let m=f();X(g,u,p,"",m);continue}let A=h??o("ESCAPED_CHAR");if(A){U(A);continue}if(o("OPEN")){let g=T(),m=o("NAME"),O=o("REGEX");!m&&!O&&(O=o("ASTERISK"));let P=T();d("CLOSE");let be=f();X(g,m,O,P,be);continue}$(),d("END");}return a}function S(e){return e.replace(/([.+*?^${}()[\]|/\\])/g,"\\$1")}function B(e){return e&&e.ignoreCase?"ui":"u"}function q(e,t,r){return W(F(e,r),t,r)}function k(e){switch(e){case 0:return "*";case 1:return "?";case 2:return "+";case 3:return ""}}function W(e,t,r={}){r.delimiter??="/#?",r.prefixes??="./",r.sensitive??=!1,r.strict??=!1,r.end??=!0,r.start??=!0,r.endsWith="";let n=r.start?"^":"";for(let s of e){if(s.type===3){s.modifier===3?n+=S(s.value):n+=`(?:${S(s.value)})${k(s.modifier)}`;continue}t&&t.push(s.name);let i=`[^${S(r.delimiter)}]+?`,o=s.value;if(s.type===1?o=i:s.type===0&&(o=v),!s.prefix.length&&!s.suffix.length){s.modifier===3||s.modifier===1?n+=`(${o})${k(s.modifier)}`:n+=`((?:${o})${k(s.modifier)})`;continue}if(s.modifier===3||s.modifier===1){n+=`(?:${S(s.prefix)}(${o})${S(s.suffix)})`,n+=k(s.modifier);continue}n+=`(?:${S(s.prefix)}`,n+=`((?:${o})(?:`,n+=S(s.suffix),n+=S(s.prefix),n+=`(?:${o}))*)${S(s.suffix)})`,s.modifier===0&&(n+="?");}let a=`[${S(r.endsWith)}]|$`,c=`[${S(r.delimiter)}]`;if(r.end)return r.strict||(n+=`${c}?`),r.endsWith.length?n+=`(?=${a})`:n+="$",new RegExp(n,B(r));r.strict||(n+=`(?:${c}(?=${a}))?`);let l=!1;if(e.length){let s=e[e.length-1];s.type===3&&s.modifier===3&&(l=r.delimiter.indexOf(s)>-1);}return l||(n+=`(?=${c}|${a})`),new RegExp(n,B(r))}var x={delimiter:"",prefixes:"",sensitive:!0,strict:!0},J={delimiter:".",prefixes:"",sensitive:!0,strict:!0},Q={delimiter:"/",prefixes:"/",sensitive:!0,strict:!0};function ee(e,t){return e.length?e[0]==="/"?!0:!t||e.length<2?!1:(e[0]=="\\"||e[0]=="{")&&e[1]=="/":!1}function te(e,t){return e.startsWith(t)?e.substring(t.length,e.length):e}function Ce(e,t){return e.endsWith(t)?e.substr(0,e.length-t.length):e}function _(e){return !e||e.length<2?!1:e[0]==="["||(e[0]==="\\"||e[0]==="{")&&e[1]==="["}var re=["ftp","file","http","https","ws","wss"];function N(e){if(!e)return !0;for(let t of re)if(e.test(t))return !0;return !1}function ne(e,t){if(e=te(e,"#"),t||e==="")return e;let r=new URL("https://example.com");return r.hash=e,r.hash?r.hash.substring(1,r.hash.length):""}function se(e,t){if(e=te(e,"?"),t||e==="")return e;let r=new URL("https://example.com");return r.search=e,r.search?r.search.substring(1,r.search.length):""}function ie(e,t){return t||e===""?e:_(e)?K(e):j(e)}function ae(e,t){if(t||e==="")return e;let r=new URL("https://example.com");return r.password=e,r.password}function oe(e,t){if(t||e==="")return e;let r=new URL("https://example.com");return r.username=e,r.username}function ce(e,t,r){if(r||e==="")return e;if(t&&!re.includes(t))return new URL(`${t}:${e}`).pathname;let n=e[0]=="/";return e=new URL(n?e:"/-"+e,"https://example.com").pathname,n||(e=e.substring(2,e.length)),e}function le(e,t,r){return z(t)===e&&(e=""),r||e===""?e:G(e)}function fe(e,t){return e=Ce(e,":"),t||e===""?e:y(e)}function z(e){switch(e){case"ws":case"http":return "80";case"wws":case"https":return "443";case"ftp":return "21";default:return ""}}function y(e){if(e==="")return e;if(/^[-+.A-Za-z0-9]*$/.test(e))return e.toLowerCase();throw new TypeError(`Invalid protocol '${e}'.`)}function he(e){if(e==="")return e;let t=new URL("https://example.com");return t.username=e,t.username}function ue(e){if(e==="")return e;let t=new URL("https://example.com");return t.password=e,t.password}function j(e){if(e==="")return e;if(/[\t\n\r #%/:<>?@[\]^\\|]/g.test(e))throw new TypeError(`Invalid hostname '${e}'`);let t=new URL("https://example.com");return t.hostname=e,t.hostname}function K(e){if(e==="")return e;if(/[^0-9a-fA-F[\]:]/g.test(e))throw new TypeError(`Invalid IPv6 hostname '${e}'`);return e.toLowerCase()}function G(e){if(e===""||/^[0-9]*$/.test(e)&&parseInt(e)<=65535)return e;throw new TypeError(`Invalid port '${e}'.`)}function de(e){if(e==="")return e;let t=new URL("https://example.com");return t.pathname=e[0]!=="/"?"/-"+e:e,e[0]!=="/"?t.pathname.substring(2,t.pathname.length):t.pathname}function pe(e){return e===""?e:new URL(`data:${e}`).pathname}function ge(e){if(e==="")return e;let t=new URL("https://example.com");return t.search=e,t.search.substring(1,t.search.length)}function me(e){if(e==="")return e;let t=new URL("https://example.com");return t.hash=e,t.hash.substring(1,t.hash.length)}var H=class{#i;#n=[];#t={};#e=0;#s=1;#l=0;#o=0;#d=0;#p=0;#g=!1;constructor(t){this.#i=t;}get result(){return this.#t}parse(){for(this.#n=D(this.#i,!0);this.#e<this.#n.length;this.#e+=this.#s){if(this.#s=1,this.#n[this.#e].type==="END"){if(this.#o===0){this.#b(),this.#f()?this.#r(9,1):this.#h()?this.#r(8,1):this.#r(7,0);continue}else if(this.#o===2){this.#u(5);continue}this.#r(10,0);break}if(this.#d>0)if(this.#A())this.#d-=1;else continue;if(this.#T()){this.#d+=1;continue}switch(this.#o){case 0:this.#P()&&this.#u(1);break;case 1:if(this.#P()){this.#C();let t=7,r=1;this.#E()?(t=2,r=3):this.#g&&(t=2),this.#r(t,r);}break;case 2:this.#S()?this.#u(3):(this.#x()||this.#h()||this.#f())&&this.#u(5);break;case 3:this.#O()?this.#r(4,1):this.#S()&&this.#r(5,1);break;case 4:this.#S()&&this.#r(5,1);break;case 5:this.#y()?this.#p+=1:this.#w()&&(this.#p-=1),this.#k()&&!this.#p?this.#r(6,1):this.#x()?this.#r(7,0):this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 6:this.#x()?this.#r(7,0):this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 7:this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 8:this.#f()&&this.#r(9,1);break;}}this.#t.hostname!==void 0&&this.#t.port===void 0&&(this.#t.port="");}#r(t,r){switch(this.#o){case 0:break;case 1:this.#t.protocol=this.#c();break;case 2:break;case 3:this.#t.username=this.#c();break;case 4:this.#t.password=this.#c();break;case 5:this.#t.hostname=this.#c();break;case 6:this.#t.port=this.#c();break;case 7:this.#t.pathname=this.#c();break;case 8:this.#t.search=this.#c();break;case 9:this.#t.hash=this.#c();break;}this.#o!==0&&t!==10&&([1,2,3,4].includes(this.#o)&&[6,7,8,9].includes(t)&&(this.#t.hostname??=""),[1,2,3,4,5,6].includes(this.#o)&&[8,9].includes(t)&&(this.#t.pathname??=this.#g?"/":""),[1,2,3,4,5,6,7].includes(this.#o)&&t===9&&(this.#t.search??="")),this.#R(t,r);}#R(t,r){this.#o=t,this.#l=this.#e+r,this.#e+=r,this.#s=0;}#b(){this.#e=this.#l,this.#s=0;}#u(t){this.#b(),this.#o=t;}#m(t){return t<0&&(t=this.#n.length-t),t<this.#n.length?this.#n[t]:this.#n[this.#n.length-1]}#a(t,r){let n=this.#m(t);return n.value===r&&(n.type==="CHAR"||n.type==="ESCAPED_CHAR"||n.type==="INVALID_CHAR")}#P(){return this.#a(this.#e,":")}#E(){return this.#a(this.#e+1,"/")&&this.#a(this.#e+2,"/")}#S(){return this.#a(this.#e,"@")}#O(){return this.#a(this.#e,":")}#k(){return this.#a(this.#e,":")}#x(){return this.#a(this.#e,"/")}#h(){if(this.#a(this.#e,"?"))return !0;if(this.#n[this.#e].value!=="?")return !1;let t=this.#m(this.#e-1);return t.type!=="NAME"&&t.type!=="REGEX"&&t.type!=="CLOSE"&&t.type!=="ASTERISK"}#f(){return this.#a(this.#e,"#")}#T(){return this.#n[this.#e].type=="OPEN"}#A(){return this.#n[this.#e].type=="CLOSE"}#y(){return this.#a(this.#e,"[")}#w(){return this.#a(this.#e,"]")}#c(){let t=this.#n[this.#e],r=this.#m(this.#l).index;return this.#i.substring(r,t.index)}#C(){let t={};Object.assign(t,x),t.encodePart=y;let r=q(this.#c(),void 0,t);this.#g=N(r);}};var V=["protocol","username","password","hostname","port","pathname","search","hash"],E="*";function Se(e,t){if(typeof e!="string")throw new TypeError("parameter 1 is not of type 'string'.");let r=new URL(e,t);return {protocol:r.protocol.substring(0,r.protocol.length-1),username:r.username,password:r.password,hostname:r.hostname,port:r.port,pathname:r.pathname,search:r.search!==""?r.search.substring(1,r.search.length):void 0,hash:r.hash!==""?r.hash.substring(1,r.hash.length):void 0}}function b(e,t){return t?C(e):e}function w(e,t,r){let n;if(typeof t.baseURL=="string")try{n=new URL(t.baseURL),t.protocol===void 0&&(e.protocol=b(n.protocol.substring(0,n.protocol.length-1),r)),!r&&t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.username===void 0&&(e.username=b(n.username,r)),!r&&t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.username===void 0&&t.password===void 0&&(e.password=b(n.password,r)),t.protocol===void 0&&t.hostname===void 0&&(e.hostname=b(n.hostname,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&(e.port=b(n.port,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&(e.pathname=b(n.pathname,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&t.search===void 0&&(e.search=b(n.search.substring(1,n.search.length),r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&t.search===void 0&&t.hash===void 0&&(e.hash=b(n.hash.substring(1,n.hash.length),r));}catch{throw new TypeError(`invalid baseURL '${t.baseURL}'.`)}if(typeof t.protocol=="string"&&(e.protocol=fe(t.protocol,r)),typeof t.username=="string"&&(e.username=oe(t.username,r)),typeof t.password=="string"&&(e.password=ae(t.password,r)),typeof t.hostname=="string"&&(e.hostname=ie(t.hostname,r)),typeof t.port=="string"&&(e.port=le(t.port,e.protocol,r)),typeof t.pathname=="string"){if(e.pathname=t.pathname,n&&!ee(e.pathname,r)){let a=n.pathname.lastIndexOf("/");a>=0&&(e.pathname=b(n.pathname.substring(0,a+1),r)+e.pathname);}e.pathname=ce(e.pathname,e.protocol,r);}return typeof t.search=="string"&&(e.search=se(t.search,r)),typeof t.hash=="string"&&(e.hash=ne(t.hash,r)),e}function C(e){return e.replace(/([+*?:{}()\\])/g,"\\$1")}function Le(e){return e.replace(/([.+*?^${}()[\]|/\\])/g,"\\$1")}function Ie(e,t){t.delimiter??="/#?",t.prefixes??="./",t.sensitive??=!1,t.strict??=!1,t.end??=!0,t.start??=!0,t.endsWith="";let r=".*",n=`[^${Le(t.delimiter)}]+?`,a=/[$_\u200C\u200D\p{ID_Continue}]/u,c="";for(let l=0;l<e.length;++l){let s=e[l];if(s.type===3){if(s.modifier===3){c+=C(s.value);continue}c+=`{${C(s.value)}}${k(s.modifier)}`;continue}let i=s.hasCustomName(),o=!!s.suffix.length||!!s.prefix.length&&(s.prefix.length!==1||!t.prefixes.includes(s.prefix)),f=l>0?e[l-1]:null,d=l<e.length-1?e[l+1]:null;if(!o&&i&&s.type===1&&s.modifier===3&&d&&!d.prefix.length&&!d.suffix.length)if(d.type===3){let T=d.value.length>0?d.value[0]:"";o=a.test(T);}else o=!d.hasCustomName();if(!o&&!s.prefix.length&&f&&f.type===3){let T=f.value[f.value.length-1];o=t.prefixes.includes(T);}o&&(c+="{"),c+=C(s.prefix),i&&(c+=`:${s.name}`),s.type===2?c+=`(${s.value})`:s.type===1?i||(c+=`(${n})`):s.type===0&&(!i&&(!f||f.type===3||f.modifier!==3||o||s.prefix!=="")?c+="*":c+=`(${r})`),s.type===1&&i&&s.suffix.length&&a.test(s.suffix[0])&&(c+="\\"),c+=C(s.suffix),o&&(c+="}"),s.modifier!==3&&(c+=k(s.modifier));}return c}var Y=class{#i;#n={};#t={};#e={};#s={};#l=!1;constructor(t={},r,n){try{let a;if(typeof r=="string"?a=r:n=r,typeof t=="string"){let i=new H(t);if(i.parse(),t=i.result,a===void 0&&typeof t.protocol!="string")throw new TypeError("A base URL must be provided for a relative constructor string.");t.baseURL=a;}else {if(!t||typeof t!="object")throw new TypeError("parameter 1 is not of type 'string' and cannot convert to dictionary.");if(a)throw new TypeError("parameter 1 is not of type 'string'.")}typeof n>"u"&&(n={ignoreCase:!1});let c={ignoreCase:n.ignoreCase===!0},l={pathname:E,protocol:E,username:E,password:E,hostname:E,port:E,search:E,hash:E};this.#i=w(l,t,!0),z(this.#i.protocol)===this.#i.port&&(this.#i.port="");let s;for(s of V){if(!(s in this.#i))continue;let i={},o=this.#i[s];switch(this.#t[s]=[],s){case"protocol":Object.assign(i,x),i.encodePart=y;break;case"username":Object.assign(i,x),i.encodePart=he;break;case"password":Object.assign(i,x),i.encodePart=ue;break;case"hostname":Object.assign(i,J),_(o)?i.encodePart=K:i.encodePart=j;break;case"port":Object.assign(i,x),i.encodePart=G;break;case"pathname":N(this.#n.protocol)?(Object.assign(i,Q,c),i.encodePart=de):(Object.assign(i,x,c),i.encodePart=pe);break;case"search":Object.assign(i,x,c),i.encodePart=ge;break;case"hash":Object.assign(i,x,c),i.encodePart=me;break}try{this.#s[s]=F(o,i),this.#n[s]=W(this.#s[s],this.#t[s],i),this.#e[s]=Ie(this.#s[s],i),this.#l=this.#l||this.#s[s].some(f=>f.type===2);}catch{throw new TypeError(`invalid ${s} pattern '${this.#i[s]}'.`)}}}catch(a){throw new TypeError(`Failed to construct 'URLPattern': ${a.message}`)}}test(t={},r){let n={pathname:"",protocol:"",username:"",password:"",hostname:"",port:"",search:"",hash:""};if(typeof t!="string"&&r)throw new TypeError("parameter 1 is not of type 'string'.");if(typeof t>"u")return !1;try{typeof t=="object"?n=w(n,t,!1):n=w(n,Se(t,r),!1);}catch{return !1}let a;for(a of V)if(!this.#n[a].exec(n[a]))return !1;return !0}exec(t={},r){let n={pathname:"",protocol:"",username:"",password:"",hostname:"",port:"",search:"",hash:""};if(typeof t!="string"&&r)throw new TypeError("parameter 1 is not of type 'string'.");if(typeof t>"u")return;try{typeof t=="object"?n=w(n,t,!1):n=w(n,Se(t,r),!1);}catch{return null}let a={};r?a.inputs=[t,r]:a.inputs=[t];let c;for(c of V){let l=this.#n[c].exec(n[c]);if(!l)return null;let s={};for(let[i,o]of this.#t[c].entries())if(typeof o=="string"||typeof o=="number"){let f=l[i+1];s[o]=f;}a[c]={input:n[c]??"",groups:s};}return a}static compareComponent(t,r,n){let a=(i,o)=>{for(let f of ["type","modifier","prefix","value","suffix"]){if(i[f]<o[f])return -1;if(i[f]===o[f])continue;return 1}return 0},c=new R(3,"","","","",3),l=new R(0,"","","","",3),s=(i,o)=>{let f=0;for(;f<Math.min(i.length,o.length);++f){let d=a(i[f],o[f]);if(d)return d}return i.length===o.length?0:a(i[f]??c,o[f]??c)};return !r.#e[t]&&!n.#e[t]?0:r.#e[t]&&!n.#e[t]?s(r.#s[t],[l]):!r.#e[t]&&n.#e[t]?s([l],n.#s[t]):s(r.#s[t],n.#s[t])}get protocol(){return this.#e.protocol}get username(){return this.#e.username}get password(){return this.#e.password}get hostname(){return this.#e.hostname}get port(){return this.#e.port}get pathname(){return this.#e.pathname}get search(){return this.#e.search}get hash(){return this.#e.hash}get hasRegExpGroups(){return this.#l}}; - - const { URLPattern: URLPattern$2 } = urlpattern; - - var urlpatternPolyfill = { URLPattern: URLPattern$2 }; - - if (!globalThis.URLPattern) { - globalThis.URLPattern = URLPattern$2; - } - - Object.defineProperty(UrlPattern, "__esModule", { value: true }); - UrlPattern.URLPattern = void 0; - /** - * Copyright 2023 Google LLC. - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - const urlpattern_polyfill_1 = urlpatternPolyfill; - // XXX: Switch to native URLPattern when available. - // https://github.com/nodejs/node/issues/40844 - let URLPattern$1 = urlpattern_polyfill_1.URLPattern; - UrlPattern.URLPattern = URLPattern$1; - if ('URLPattern' in globalThis) { - UrlPattern.URLPattern = URLPattern$1 = globalThis.URLPattern; - } - /* * Copyright 2023 Google LLC. * Copyright (c) Microsoft Corporation. @@ -4267,7 +4288,7 @@ NetworkUtils.getTiming = getTiming; const ErrorResponse_js_1 = ErrorResponse; const Base64_js_1 = Base64; - const UrlPattern_js_1 = UrlPattern; + const UrlPattern_js_1 = UrlPatternBrowser; function computeHeadersSize(headers) { const requestHeaders = headers.reduce((acc, header) => { return `${acc}${header.name}: ${header.value.value}\r\n`; @@ -4828,10 +4849,10 @@ this.#browserProcessor = new BrowserProcessor_js_1.BrowserProcessor(browserCdpClient); this.#browsingContextProcessor = new BrowsingContextProcessor_js_1.BrowsingContextProcessor(browserCdpClient, browsingContextStorage, eventManager); this.#cdpProcessor = new CdpProcessor_js_1.CdpProcessor(browsingContextStorage, realmStorage, cdpConnection, browserCdpClient); - this.#inputProcessor = new InputProcessor_js_1.InputProcessor(browsingContextStorage, realmStorage); + this.#inputProcessor = new InputProcessor_js_1.InputProcessor(browsingContextStorage); this.#networkProcessor = new NetworkProcessor_js_1.NetworkProcessor(browsingContextStorage, networkStorage); this.#permissionsProcessor = new PermissionsProcessor_js_1.PermissionsProcessor(browserCdpClient); - this.#scriptProcessor = new ScriptProcessor_js_1.ScriptProcessor(browsingContextStorage, realmStorage, preloadScriptStorage, logger); + this.#scriptProcessor = new ScriptProcessor_js_1.ScriptProcessor(eventManager, browsingContextStorage, realmStorage, preloadScriptStorage, logger); this.#sessionProcessor = new SessionProcessor_js_1.SessionProcessor(eventManager, browserCdpClient, initConnection); this.#storageProcessor = new StorageProcessor_js_1.StorageProcessor(browserCdpClient, browsingContextStorage, logger); // keep-sorted end @@ -5263,6 +5284,7 @@ * target's `globalThis`. */ async serializeCdpObject(cdpRemoteObject, resultOwnership) { + // TODO: if the object is a primitive, return it directly without CDP roundtrip. const argument = Realm.#cdpRemoteObjectToCallArgument(cdpRemoteObject); const cdpValue = await this.cdpClient.sendCommand('Runtime.callFunctionOn', { functionDeclaration: String((remoteObject) => remoteObject), @@ -5854,10 +5876,21 @@ #previousViewport = { width: 0, height: 0 }; // The URL of the navigation that is currently in progress. A workaround of the CDP // lacking URL for the pending navigation events, e.g. `Page.frameStartedLoading`. - // Set on `Page.navigate`, `Page.reload` commands and on deprecated CDP event - // `Page.frameScheduledNavigation`. + // Set on `Page.navigate`, `Page.reload` commands, on `Page.frameRequestedNavigation` or + // on a deprecated `Page.frameScheduledNavigation` event. The latest is required as the + // `Page.frameRequestedNavigation` event is not emitted for same-document navigations. #pendingNavigationUrl; - #virtualNavigationId = (0, uuid_1.uuidv4)(); + // Navigation ID is required, as CDP `loaderId` cannot be mapped 1:1 to all the + // navigations (e.g. same document navigations). Updated after each navigation, + // including same-document ones. + #navigationId = (0, uuid_1.uuidv4)(); + // When a new navigation is started via `BrowsingContext.navigate` with `wait` set to + // `None`, the command result should have `navigation` value, but mapper does not have + // it yet. This value will be set to `navigationId` after next . + #pendingNavigationId; + // Set if there is a pending navigation initiated by `BrowsingContext.navigate` command. + // The promise is resolved when the navigation is finished or rejected when canceled. + #pendingCommandNavigation; #originalOpener; // Set when the user prompt is opened. Required to provide the type in closing event. #lastUserPromptType; @@ -5915,30 +5948,28 @@ get navigableId() { return this.#loaderId; } - /** - * Virtual navigation ID. Required, as CDP `loaderId` cannot be mapped 1:1 to all the - * navigations (e.g. same document navigations). Updated after each navigation, - * including same-document ones. - */ - get virtualNavigationId() { - return this.#virtualNavigationId; + get navigationId() { + return this.#navigationId; } - dispose() { + dispose(emitContextDestroyed) { + this.#pendingCommandNavigation?.reject(new protocol_js_1$9.UnknownErrorException('navigation canceled by context disposal')); this.#deleteAllChildren(); this.#realmStorage.deleteRealms({ browsingContextId: this.id, }); - // Remove context from the parent. + // Delete context from the parent. if (!this.isTopLevelContext()) { this.parent.#children.delete(this.id); } // Fail all ongoing navigations. this.#failLifecycleIfNotFinished(); - this.#eventManager.registerEvent({ - type: 'event', - method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.ContextDestroyed, - params: this.serializeToBidiValue(), - }, this.id); + if (emitContextDestroyed) { + this.#eventManager.registerEvent({ + type: 'event', + method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.ContextDestroyed, + params: this.serializeToBidiValue(), + }, this.id); + } this.#browsingContextStorage.deleteContextById(this.id); } /** Returns the ID of this context. */ @@ -5998,8 +6029,8 @@ addChild(childId) { this.#children.add(childId); } - #deleteAllChildren() { - this.directChildren.map((child) => child.dispose()); + #deleteAllChildren(emitContextDestroyed = false) { + this.directChildren.map((child) => child.dispose(emitContextDestroyed)); } get cdpTarget() { return this.#cdpTarget; @@ -6072,7 +6103,7 @@ this.#pendingNavigationUrl = undefined; // At the point the page is initialized, all the nested iframes from the // previous page are detached and realms are destroyed. - // Remove children from context. + // Delete children from context. this.#deleteAllChildren(); }); this.#cdpTarget.cdpClient.on('Page.navigatedWithinDocument', (params) => { @@ -6088,7 +6119,7 @@ method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.FragmentNavigated, params: { context: this.id, - navigation: this.#virtualNavigationId, + navigation: this.#navigationId, timestamp, url: this.#url, }, @@ -6098,14 +6129,16 @@ if (this.id !== params.frameId) { return; } - // Generate a new virtual navigation id. - this.#virtualNavigationId = (0, uuid_1.uuidv4)(); + // Use `pendingNavigationId` if navigation initiated by BiDi + // `BrowsingContext.navigate` or generate a new navigation id. + this.#navigationId = this.#pendingNavigationId ?? (0, uuid_1.uuidv4)(); + this.#pendingNavigationId = undefined; this.#eventManager.registerEvent({ type: 'event', method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.NavigationStarted, params: { context: this.id, - navigation: this.#virtualNavigationId, + navigation: this.#navigationId, timestamp: BrowsingContextImpl.getTimestamp(), // The URL of the navigation that is currently in progress. Although the URL // is not yet known in case of user-initiated navigations, it is possible to @@ -6122,6 +6155,14 @@ } this.#pendingNavigationUrl = params.url; }); + this.#cdpTarget.cdpClient.on('Page.frameRequestedNavigation', (params) => { + if (this.id !== params.frameId) { + return; + } + // If there is a pending navigation, reject it. + this.#pendingCommandNavigation?.reject(new protocol_js_1$9.UnknownErrorException(`navigation canceled, as new navigation is requested by ${params.reason}`)); + this.#pendingNavigationUrl = params.url; + }); this.#cdpTarget.cdpClient.on('Page.lifecycleEvent', (params) => { if (this.id !== params.frameId) { return; @@ -6152,7 +6193,7 @@ method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.DomContentLoaded, params: { context: this.id, - navigation: this.#virtualNavigationId, + navigation: this.#navigationId, timestamp, url: this.#url, }, @@ -6165,7 +6206,7 @@ method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.Load, params: { context: this.id, - navigation: this.#virtualNavigationId, + navigation: this.#navigationId, timestamp, url: this.#url, }, @@ -6318,8 +6359,8 @@ } } #documentChanged(loaderId) { - // Same document navigation. if (loaderId === undefined || this.#loaderId === loaderId) { + // Same document navigation. Document didn't change. if (this.#navigation.withinDocument.isFinished) { this.#navigation.withinDocument = new Deferred_js_1$2.Deferred(); } @@ -6328,8 +6369,11 @@ } return; } + // Document changed. this.#resetLifecycleIfFinished(); this.#loaderId = loaderId; + // Delete all child iframes and notify about top level destruction. + this.#deleteAllChildren(true); } #resetLifecycleIfFinished() { if (this.#lifecycle.DOMContentLoaded.isFinished) { @@ -6360,61 +6404,83 @@ catch { throw new protocol_js_1$9.InvalidArgumentException(`Invalid URL: ${url}`); } + this.#pendingCommandNavigation?.reject(new protocol_js_1$9.UnknownErrorException('navigation canceled by concurrent navigation')); await this.targetUnblockedOrThrow(); // Set the pending navigation URL to provide it in `browsingContext.navigationStarted` // event. // TODO: detect navigation start not from CDP. Check if // `Page.frameRequestedNavigation` can be used for this purpose. this.#pendingNavigationUrl = url; - // TODO: handle loading errors. - const cdpNavigateResult = await this.#cdpTarget.cdpClient.sendCommand('Page.navigate', { - url, - frameId: this.id, - }); - if (cdpNavigateResult.errorText) { - // If navigation failed, no pending navigation is left. - this.#pendingNavigationUrl = undefined; - this.#eventManager.registerEvent({ - type: 'event', - method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.NavigationFailed, - params: { - context: this.id, - navigation: this.#virtualNavigationId, - timestamp: BrowsingContextImpl.getTimestamp(), - url, - }, - }, this.id); - throw new protocol_js_1$9.UnknownErrorException(cdpNavigateResult.errorText); + const navigationId = (0, uuid_1.uuidv4)(); + this.#pendingNavigationId = navigationId; + this.#pendingCommandNavigation = new Deferred_js_1$2.Deferred(); + // Navigate and wait for the result. If the navigation fails, the error event is + // emitted and the promise is rejected. + const cdpNavigatePromise = (async () => { + const cdpNavigateResult = await this.#cdpTarget.cdpClient.sendCommand('Page.navigate', { + url, + frameId: this.id, + }); + if (cdpNavigateResult.errorText) { + // If navigation failed, no pending navigation is left. + this.#pendingNavigationUrl = undefined; + this.#eventManager.registerEvent({ + type: 'event', + method: protocol_js_1$9.ChromiumBidi.BrowsingContext.EventNames.NavigationFailed, + params: { + context: this.id, + navigation: navigationId, + timestamp: BrowsingContextImpl.getTimestamp(), + url, + }, + }, this.id); + throw new protocol_js_1$9.UnknownErrorException(cdpNavigateResult.errorText); + } + this.#documentChanged(cdpNavigateResult.loaderId); + return cdpNavigateResult; + })(); + if (wait === "none" /* BrowsingContext.ReadinessState.None */) { + // Do not wait for the result of the navigation promise. + this.#pendingCommandNavigation.resolve(); + this.#pendingCommandNavigation = undefined; + return { + navigation: navigationId, + url, + }; } - this.#documentChanged(cdpNavigateResult.loaderId); - switch (wait) { - case "none" /* BrowsingContext.ReadinessState.None */: - break; - case "interactive" /* BrowsingContext.ReadinessState.Interactive */: - // No `loaderId` means same-document navigation. - if (cdpNavigateResult.loaderId === undefined) { - await this.#navigation.withinDocument; - } - else { - await this.#lifecycle.DOMContentLoaded; - } - break; - case "complete" /* BrowsingContext.ReadinessState.Complete */: - // No `loaderId` means same-document navigation. - if (cdpNavigateResult.loaderId === undefined) { - await this.#navigation.withinDocument; - } - else { - await this.#lifecycle.load; - } - break; - } + const cdpNavigateResult = await cdpNavigatePromise; + // Wait for either the navigation is finished or canceled by another navigation. + await Promise.race([ + // No `loaderId` means same-document navigation. + this.#waitNavigation(wait, cdpNavigateResult.loaderId === undefined), + // Throw an error if the navigation is canceled. + this.#pendingCommandNavigation, + ]); + this.#pendingCommandNavigation.resolve(); + this.#pendingCommandNavigation = undefined; return { - navigation: this.#virtualNavigationId, + navigation: navigationId, // Url can change due to redirect get the latest one. - url: wait === "none" /* BrowsingContext.ReadinessState.None */ ? url : this.#url, + url: this.#url, }; } + async #waitNavigation(wait, withinDocument) { + if (withinDocument) { + await this.#navigation.withinDocument; + return; + } + switch (wait) { + case "none" /* BrowsingContext.ReadinessState.None */: + return; + case "interactive" /* BrowsingContext.ReadinessState.Interactive */: + await this.#lifecycle.DOMContentLoaded; + return; + case "complete" /* BrowsingContext.ReadinessState.Complete */: + await this.#lifecycle.load; + return; + } + } + // TODO: support concurrent navigations analogous to `navigate`. async reload(ignoreCache, wait) { await this.targetUnblockedOrThrow(); this.#resetLifecycleIfFinished(); @@ -6432,7 +6498,7 @@ break; } return { - navigation: this.#virtualNavigationId, + navigation: this.#navigationId, url: this.url, }; } @@ -6705,7 +6771,7 @@ } return [...element.querySelectorAll(cssSelector)]; }; - startNodes = startNodes.length > 0 ? startNodes : [document.body]; + startNodes = startNodes.length > 0 ? startNodes : [document]; const returnedNodes = startNodes .map((startNode) => // TODO: stop search early if `maxNodeCount` is reached. @@ -6738,7 +6804,7 @@ } return returnedNodes; }; - startNodes = startNodes.length > 0 ? startNodes : [document.body]; + startNodes = startNodes.length > 0 ? startNodes : [document]; const returnedNodes = startNodes .map((startNode) => // TODO: stop search early if `maxNodeCount` is reached. @@ -6916,7 +6982,10 @@ collect(childNodes, selector); } } - startNodes = startNodes.length > 0 ? startNodes : [document.body]; + startNodes = + startNodes.length > 0 + ? startNodes + : Array.from(document.documentElement.children).filter((c) => c instanceof HTMLElement); collect(startNodes, { role, name, @@ -7375,6 +7444,43 @@ logManager.#initializeEntryAddedEventListener(); return logManager; } + /** + * Heuristic serialization of CDP remote object. If possible, return the BiDi value + * without deep serialization. + */ + async #heuristicSerializeArg(arg, realm) { + switch (arg.type) { + // TODO: Implement regexp, array, object, map and set heuristics base on + // preview. + case 'undefined': + return { type: 'undefined' }; + case 'boolean': + return { type: 'boolean', value: arg.value }; + case 'string': + return { type: 'string', value: arg.value }; + case 'number': + // The value can be either a number or a string like `Infinity` or `-0`. + return { type: 'number', value: arg.unserializableValue ?? arg.value }; + case 'bigint': + if (arg.unserializableValue !== undefined && + arg.unserializableValue[arg.unserializableValue.length - 1] === 'n') { + return { + type: arg.type, + value: arg.unserializableValue.slice(0, -1), + }; + } + // Unexpected bigint value, fall back to CDP deep serialization. + break; + case 'object': + if (arg.subtype === 'null') { + return { type: 'null' }; + } + // Fall back to CDP deep serialization. + break; + } + // Fall back to CDP deep serialization. + return await realm.serializeCdpObject(arg, "none" /* Script.ResultOwnership.None */); + } #initializeEntryAddedEventListener() { this.#cdpTarget.cdpClient.on('Runtime.consoleAPICalled', (params) => { // Try to find realm by `cdpSessionId` and `executionContextId`, @@ -7388,12 +7494,7 @@ this.#logger?.(log_js_1$8.LogType.cdp, params); return; } - const argsPromise = realm === undefined - ? Promise.resolve(params.args) - : // Properly serialize arguments if possible. - Promise.all(params.args.map((arg) => { - return realm.serializeCdpObject(arg, "none" /* Script.ResultOwnership.None */); - })); + const argsPromise = Promise.all(params.args.map((arg) => this.#heuristicSerializeArg(arg, realm))); for (const browsingContext of realm.associatedBrowsingContexts) { this.#eventManager.registerPromiseEvent(argsPromise.then((args) => ({ kind: 'success', @@ -7756,6 +7857,7 @@ }); cdpClient.on('Page.frameAttached', this.#handleFrameAttachedEvent.bind(this)); cdpClient.on('Page.frameDetached', this.#handleFrameDetachedEvent.bind(this)); + cdpClient.on('Page.frameSubtreeWillBeDetached', this.#handleFrameSubtreeWillBeDetached.bind(this)); } #handleFrameAttachedEvent(params) { const parentBrowsingContext = this.#browsingContextStorage.findContext(params.parentFrameId); @@ -7771,7 +7873,10 @@ if (params.reason === 'swap') { return; } - this.#browsingContextStorage.findContext(params.frameId)?.dispose(); + this.#browsingContextStorage.findContext(params.frameId)?.dispose(true); + } + #handleFrameSubtreeWillBeDetached(params) { + this.#browsingContextStorage.findContext(params.frameId)?.dispose(true); } #handleAttachedToTargetEvent(params, parentSessionCdpClient) { const { sessionId, targetInfo } = params; @@ -7883,7 +7988,7 @@ } const context = this.#browsingContextStorage.findContextBySession(sessionId); if (context) { - context.dispose(); + context.dispose(true); return; } const worker = this.#workers.get(sessionId); @@ -8142,7 +8247,7 @@ return null; } // Get virtual navigation ID from the browsing context. - return this.#networkStorage.getVirtualNavigationId(this.#context ?? undefined); + return this.#networkStorage.getNavigationId(this.#context ?? undefined); } get #cookies() { let cookies = []; @@ -8923,12 +9028,11 @@ /** * Gets the virtual navigation ID for the given navigable ID. */ - getVirtualNavigationId(contextId) { + getNavigationId(contextId) { if (contextId === undefined) { return null; } - return (this.#browsingContextStorage.findContext(contextId) - ?.virtualNavigationId ?? null); + return (this.#browsingContextStorage.findContext(contextId)?.navigationId ?? null); } } NetworkStorage$1.NetworkStorage = NetworkStorage;
diff --git a/third_party/blink/common/loader/lcp_critical_path_predictor_util.cc b/third_party/blink/common/loader/lcp_critical_path_predictor_util.cc index 015b1a5..8716f26 100644 --- a/third_party/blink/common/loader/lcp_critical_path_predictor_util.cc +++ b/third_party/blink/common/loader/lcp_critical_path_predictor_util.cc
@@ -4,28 +4,44 @@ #include "third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h" +#include <optional> + #include "base/feature_list.h" #include "third_party/blink/public/common/features.h" +namespace { + +constinit std::optional<bool> g_enabled; + +} // namespace + namespace blink { bool LcppEnabled() { - static const bool enabled = - base::FeatureList::IsEnabled( - blink::features::kLCPCriticalPathPredictor) || - base::FeatureList::IsEnabled(blink::features::kLCPScriptObserver) || - base::FeatureList::IsEnabled(blink::features::kLCPPFontURLPredictor) || - base::FeatureList::IsEnabled( - blink::features::kLCPPLazyLoadImagePreload) || - base::FeatureList::IsEnabled( - blink::features::kDelayAsyncScriptExecution) || - base::FeatureList::IsEnabled(blink::features::kHttpDiskCachePrewarming) || - base::FeatureList::IsEnabled( - blink::features::kLCPPAutoPreconnectLcpOrigin) || - base::FeatureList::IsEnabled( - blink::features::kLCPTimingPredictorPrerender2) || - base::FeatureList::IsEnabled(blink::features::kLCPPDeferUnusedPreload); - return enabled; + if (!g_enabled.has_value()) { + g_enabled = + base::FeatureList::IsEnabled( + blink::features::kLCPCriticalPathPredictor) || + base::FeatureList::IsEnabled(blink::features::kLCPScriptObserver) || + base::FeatureList::IsEnabled(blink::features::kLCPPFontURLPredictor) || + base::FeatureList::IsEnabled( + blink::features::kLCPPLazyLoadImagePreload) || + base::FeatureList::IsEnabled( + blink::features::kDelayAsyncScriptExecution) || + base::FeatureList::IsEnabled( + blink::features::kHttpDiskCachePrewarming) || + base::FeatureList::IsEnabled( + blink::features::kLCPPAutoPreconnectLcpOrigin) || + base::FeatureList::IsEnabled( + blink::features::kLCPTimingPredictorPrerender2) || + base::FeatureList::IsEnabled(blink::features::kLCPPDeferUnusedPreload); + } + + return *g_enabled; +} + +void ResetLcppEnabledForTesting() { + g_enabled.reset(); } bool LcppScriptObserverEnabled() {
diff --git a/third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h b/third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h index 7056cbc6..4c8460e8 100644 --- a/third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h +++ b/third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h
@@ -10,6 +10,7 @@ namespace blink { BLINK_COMMON_EXPORT bool LcppEnabled(); +BLINK_COMMON_EXPORT void ResetLcppEnabledForTesting(); BLINK_COMMON_EXPORT bool LcppScriptObserverEnabled(); } // namespace blink
diff --git a/third_party/blink/public/web/web_plugin.h b/third_party/blink/public/web/web_plugin.h index eaeb0ec..12ea08e 100644 --- a/third_party/blink/public/web/web_plugin.h +++ b/third_party/blink/public/web/web_plugin.h
@@ -32,6 +32,7 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PLUGIN_H_ #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PLUGIN_H_ +#include "base/containers/span.h" #include "cc/paint/paint_canvas.h" #include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/mojom/input/focus_type.mojom-shared.h" @@ -135,7 +136,7 @@ } virtual void DidReceiveResponse(const WebURLResponse&) = 0; - virtual void DidReceiveData(const char* data, size_t data_length) = 0; + virtual void DidReceiveData(base::span<const char> data) = 0; virtual void DidFinishLoading() = 0; virtual void DidFailLoading(const WebURLError&) = 0;
diff --git a/third_party/blink/renderer/core/dom/element_test.cc b/third_party/blink/renderer/core/dom/element_test.cc index 4c0c0e33..a5ed917 100644 --- a/third_party/blink/renderer/core/dom/element_test.cc +++ b/third_party/blink/renderer/core/dom/element_test.cc
@@ -529,7 +529,7 @@ return {}; } void DidReceiveResponse(const WebURLResponse&) override {} - void DidReceiveData(const char* data, size_t data_length) override {} + void DidReceiveData(base::span<const char> data) override {} void DidFinishLoading() override {} void DidFailLoading(const WebURLError&) override {}
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc index 0bb4262..2aea2172 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -700,9 +700,8 @@ web_plugin_->DidReceiveResponse(url_response); } -void WebPluginContainerImpl::DidReceiveData(const char* data, - size_t data_length) { - web_plugin_->DidReceiveData(data, data_length); +void WebPluginContainerImpl::DidReceiveData(base::span<const char> data) { + web_plugin_->DidReceiveData(data); } void WebPluginContainerImpl::DidFinishLoading() {
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h index dab671b..5b632dd 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -32,6 +32,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_WEB_PLUGIN_CONTAINER_IMPL_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_EXPORTED_WEB_PLUGIN_CONTAINER_IMPL_H_ +#include "base/containers/span.h" #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" #include "third_party/blink/public/common/input/web_touch_event.h" @@ -175,7 +176,7 @@ // Resource load events for the plugin's source data: void DidReceiveResponse(const ResourceResponse&); - void DidReceiveData(const char* data, size_t data_length); + void DidReceiveData(base::span<const char> data); void DidFinishLoading(); void DidFailLoading(const ResourceError&);
diff --git a/third_party/blink/renderer/core/html/parser/html_entity_parser.h b/third_party/blink/renderer/core/html/parser/html_entity_parser.h index 2e9224d7f..9efd9f4 100644 --- a/third_party/blink/renderer/core/html/parser/html_entity_parser.h +++ b/third_party/blink/renderer/core/html/parser/html_entity_parser.h
@@ -24,11 +24,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_ENTITY_PARSER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_PARSER_HTML_ENTITY_PARSER_H_ @@ -65,7 +60,7 @@ } unsigned length; - UChar data[kMaxLength]; + std::array<UChar, kMaxLength> data; }; void AppendLegalEntityFor(UChar32 c, DecodedHTMLEntity& decoded_entity);
diff --git a/third_party/blink/renderer/core/html/plugin_document.cc b/third_party/blink/renderer/core/html/plugin_document.cc index 96207c89..27753ed 100644 --- a/third_party/blink/renderer/core/html/plugin_document.cc +++ b/third_party/blink/renderer/core/html/plugin_document.cc
@@ -170,8 +170,7 @@ return; } if (WebPluginContainerImpl* view = GetPluginView()) { - base::span<const char> char_data = base::as_chars(data); - view->DidReceiveData(char_data.data(), char_data.size()); + view->DidReceiveData(base::as_chars(data)); } }
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc index d876ac1..d438de5d9 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.cc
@@ -27,24 +27,17 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h" #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h" namespace blink { -VTTScanner::VTTScanner(const String& line) : is_8bit_(line.Is8Bit()) { - if (is_8bit_) { - data_.characters8 = line.Characters8(); - end_.characters8 = data_.characters8 + line.length(); +VTTScanner::VTTScanner(const String& line) { + if (line.Is8Bit()) { + state_.emplace<base::span<const LChar>>(line.Span8()); } else { - data_.characters16 = line.Characters16(); - end_.characters16 = data_.characters16 + line.length(); + state_.emplace<base::span<const UChar>>(line.Span16()); } } @@ -60,28 +53,32 @@ if (Remaining() < characters.size()) { return false; } - bool matched; - if (is_8bit_) { - matched = WTF::Equal(data_.characters8, characters.data(), - base::checked_cast<wtf_size_t>(characters.size())); + if (Is8Bit()) { + auto [to_match, rest] = buf<LChar>().split_at(characters.size()); + if (to_match != characters) { + return false; + } + buf<LChar>() = rest; } else { - matched = WTF::Equal(data_.characters16, characters.data(), - base::checked_cast<wtf_size_t>(characters.size())); + auto [to_match, rest] = buf<UChar>().split_at(characters.size()); + if (to_match != characters) { + return false; + } + buf<UChar>() = rest; } - if (matched) - Advance(base::checked_cast<wtf_size_t>(characters.size())); - return matched; + return true; } String VTTScanner::ExtractString(size_t length) { - DCHECK_LE(length, Remaining()); String s; - if (is_8bit_) { - s = String(data_.characters8, base::checked_cast<wtf_size_t>(length)); - data_.characters8 += length; + if (Is8Bit()) { + auto [string_data, rest] = buf<LChar>().split_at(length); + s = String(string_data); + buf<LChar>() = rest; } else { - s = String(data_.characters16, base::checked_cast<wtf_size_t>(length)); - data_.characters16 += length; + auto [string_data, rest] = buf<UChar>().split_at(length); + s = String(string_data); + buf<UChar>() = rest; } return s; } @@ -97,16 +94,18 @@ return 0; } bool valid_number; - if (is_8bit_) { - number = CharactersToUInt(data_.characters8, num_digits, + if (Is8Bit()) { + auto [number_data, rest] = buf<LChar>().split_at(num_digits); + number = CharactersToUInt(number_data.data(), num_digits, WTF::NumberParsingOptions(), &valid_number); // Consume the digits. - data_.characters8 += num_digits; + buf<LChar>() = rest; } else { - number = CharactersToUInt(data_.characters16, num_digits, + auto [number_data, rest] = buf<UChar>().split_at(num_digits); + number = CharactersToUInt(number_data.data(), num_digits, WTF::NumberParsingOptions(), &valid_number); // Consume the digits. - data_.characters16 += num_digits; + buf<UChar>() = rest; } // Since we know that scanDigits only scanned valid (ASCII) digits (and @@ -119,7 +118,7 @@ } bool VTTScanner::ScanDouble(double& number) { - const Position saved_position = GetPosition(); + const State start_state = state_; const size_t num_integer_digits = CountWhile<IsASCIIDigit>(); AdvanceIfNonZero(num_integer_digits); size_t length_of_double = num_integer_digits; @@ -134,17 +133,16 @@ // At least one digit required. if (num_integer_digits == 0 && num_decimal_digits == 0) { // Restore to starting position. - DCHECK_LE(saved_position, end()); - data_.characters8 = saved_position; + state_ = start_state; return false; } bool valid_number; - if (is_8bit_) { - number = - CharactersToDouble(saved_position, length_of_double, &valid_number); + if (Is8Bit()) { + number = CharactersToDouble(buf<LChar>(start_state).data(), + length_of_double, &valid_number); } else { - number = CharactersToDouble(reinterpret_cast<const UChar*>(saved_position), + number = CharactersToDouble(buf<UChar>(start_state).data(), length_of_double, &valid_number); } @@ -157,14 +155,14 @@ } bool VTTScanner::ScanPercentage(double& percentage) { - const Position saved_position = GetPosition(); + const State saved_state = state_; if (!ScanDouble(percentage)) return false; if (Scan('%')) return true; // Restore scanner position. - DCHECK_LE(saved_position, end()); - data_.characters8 = saved_position; + state_ = saved_state; return false; } + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h index ec2003e..9569b1d6 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h
@@ -27,11 +27,6 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_VTT_VTT_SCANNER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_VTT_VTT_SCANNER_H_ @@ -64,12 +59,12 @@ // Return the number of remaining characters. size_t Remaining() const { - return is_8bit_ - ? static_cast<size_t>(end_.characters8 - data_.characters8) - : static_cast<size_t>(end_.characters16 - data_.characters16); + return Is8Bit() ? buf<LChar>().size() : buf<UChar>().size(); } // Check if the input pointer points at the end of the input. - bool IsAtEnd() const { return GetPosition() == end(); } + bool IsAtEnd() const { + return Is8Bit() ? buf<LChar>().empty() : buf<UChar>().empty(); + } // Match the character |c| against the character at the input pointer // (~lookahead). bool Match(char c) const { return !IsAtEnd() && CurrentChar() == c; } @@ -129,59 +124,62 @@ bool ScanPercentage(double& percentage); protected: - typedef const LChar* Position; + using State = std::variant<base::span<const LChar>, base::span<const UChar>>; - VTTScanner(Position start, Position end, bool is_8bit) : is_8bit_(is_8bit) { - data_.characters8 = start; - end_.characters8 = end; + template <typename CharType> + static base::span<const CharType>& buf(State& state) { + return std::get<base::span<const CharType>>(state); + } + template <typename CharType> + static const base::span<const CharType>& buf(const State& state) { + return std::get<base::span<const CharType>>(state); } - Position GetPosition() const { return data_.characters8; } - Position end() const { return end_.characters8; } + template <typename CharType> + base::span<const CharType>& buf() { + return buf<CharType>(state_); + } + template <typename CharType> + const base::span<const CharType>& buf() const { + return buf<CharType>(state_); + } + bool Is8Bit() const { + return std::holds_alternative<base::span<const LChar>>(state_); + } + + explicit VTTScanner(State state) : state_(std::move(state)) {} + UChar CurrentChar() const; - void Advance(unsigned amount = 1); + void Advance(size_t amount = 1); void AdvanceIfNonZero(size_t amount); - // Adapt a UChar-predicate to an LChar-predicate. - // (For use with SkipWhile/Until from parsing_utilities.h). - template <bool characterPredicate(UChar)> - static inline bool LCharPredicateAdapter(LChar c) { - return characterPredicate(c); - } - union { - const LChar* characters8; - const UChar* characters16; - } data_; - union { - const LChar* characters8; - const UChar* characters16; - } end_; - bool is_8bit_; + + State state_; }; template <bool predicate(UChar)> inline size_t VTTScanner::CountWhile() { - if (is_8bit_) { - const LChar* current = data_.characters8; - WTF::SkipWhile<LChar, LCharPredicateAdapter<predicate>>(current, - end_.characters8); - return current - data_.characters8; + size_t skipped = 0; + if (Is8Bit()) { + auto it = base::ranges::find_if_not(buf<LChar>(), predicate); + skipped = std::distance(buf<LChar>().begin(), it); + } else { + auto it = base::ranges::find_if_not(buf<UChar>(), predicate); + skipped = std::distance(buf<UChar>().begin(), it); } - const UChar* current = data_.characters16; - WTF::SkipWhile<UChar, predicate>(current, end_.characters16); - return current - data_.characters16; + return skipped; } template <bool predicate(UChar)> inline size_t VTTScanner::CountUntil() { - if (is_8bit_) { - const LChar* current = data_.characters8; - WTF::SkipUntil<LChar, LCharPredicateAdapter<predicate>>(current, - end_.characters8); - return current - data_.characters8; + size_t skipped = 0; + if (Is8Bit()) { + auto it = base::ranges::find_if(buf<LChar>(), predicate); + skipped = std::distance(buf<LChar>().begin(), it); + } else { + auto it = base::ranges::find_if(buf<UChar>(), predicate); + skipped = std::distance(buf<UChar>().begin(), it); } - const UChar* current = data_.characters16; - WTF::SkipUntil<UChar, predicate>(current, end_.characters16); - return current - data_.characters16; + return skipped; } template <bool predicate(UChar)> @@ -197,35 +195,42 @@ template <bool predicate(UChar)> inline VTTScanner VTTScanner::SubrangeWhile() { const size_t count = CountWhile<predicate>(); - const Position start = GetPosition(); - AdvanceIfNonZero(count); - return VTTScanner(start, GetPosition(), is_8bit_); + State collected; + if (Is8Bit()) { + std::tie(collected, buf<LChar>()) = buf<LChar>().split_at(count); + } else { + std::tie(collected, buf<UChar>()) = buf<UChar>().split_at(count); + } + return VTTScanner(collected); } template <bool predicate(UChar)> inline VTTScanner VTTScanner::SubrangeUntil() { const size_t count = CountUntil<predicate>(); - const Position start = GetPosition(); - AdvanceIfNonZero(count); - return VTTScanner(start, GetPosition(), is_8bit_); + State collected; + if (Is8Bit()) { + std::tie(collected, buf<LChar>()) = buf<LChar>().split_at(count); + } else { + std::tie(collected, buf<UChar>()) = buf<UChar>().split_at(count); + } + return VTTScanner(collected); } inline UChar VTTScanner::CurrentChar() const { - DCHECK_LT(GetPosition(), end()); - return is_8bit_ ? *data_.characters8 : *data_.characters16; + return Is8Bit() ? buf<LChar>().front() : buf<UChar>().front(); } -inline void VTTScanner::Advance(unsigned amount) { - DCHECK_LT(GetPosition(), end()); - if (is_8bit_) - data_.characters8 += amount; - else - data_.characters16 += amount; +inline void VTTScanner::Advance(size_t amount) { + if (Is8Bit()) { + buf<LChar>() = buf<LChar>().subspan(amount); + } else { + buf<UChar>() = buf<UChar>().subspan(amount); + } } inline void VTTScanner::AdvanceIfNonZero(size_t amount) { if (amount) { - Advance(base::checked_cast<wtf_size_t>(amount)); + Advance(amount); } }
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_tokenizer.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_tokenizer.cc index 0d7cb9d..c548bbb0 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_tokenizer.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_tokenizer.cc
@@ -28,11 +28,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "third_party/blink/renderer/core/html/track/vtt/vtt_tokenizer.h" #include "base/notreached.h"
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc index 81de439..e9730aa 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -15,7 +15,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_intersection_observer_init.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_document_element.h" #include "third_party/blink/renderer/bindings/core/v8/v8_union_double_doublesequence.h" -#include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h" +#include "third_party/blink/renderer/core/css/parser/css_parser_token_stream.h" #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -41,7 +41,6 @@ // IntersectionObserver with an EventCallback. class IntersectionObserverDelegateImpl final : public IntersectionObserverDelegate { - public: IntersectionObserverDelegateImpl( ExecutionContext* context, @@ -101,11 +100,9 @@ // "1px 2px 3px" = top left/right bottom // "1px 2px 3px 4px" = top left right bottom - CSSTokenizer tokenizer(margin_parameter); - const auto tokens = tokenizer.TokenizeToEOF(); - CSSParserTokenRange token_range(tokens); - token_range.ConsumeWhitespace(); - while (token_range.Peek().GetType() != kEOFToken && + CSSParserTokenStream stream(margin_parameter); + stream.ConsumeWhitespace(); + while (stream.Peek().GetType() != kEOFToken && !exception_state.HadException()) { if (margin.size() == 4) { exception_state.ThrowDOMException( @@ -113,10 +110,11 @@ "Extra text found at the end of " + marginName + "Margin."); break; } - const CSSParserToken& token = token_range.ConsumeIncludingWhitespace(); + const CSSParserToken token = stream.Peek(); switch (token.GetType()) { case kPercentageToken: margin.push_back(Length::Percent(token.NumericValue())); + stream.ConsumeIncludingWhitespace(); break; case kDimensionToken: switch (token.GetUnitType()) { @@ -132,6 +130,7 @@ DOMExceptionCode::kSyntaxError, marginName + "Margin must be specified in pixels or percent."); } + stream.ConsumeIncludingWhitespace(); break; default: exception_state.ThrowDOMException( @@ -141,10 +140,9 @@ } } -void ParseThresholds( - const V8UnionDoubleOrDoubleSequence* threshold_parameter, - Vector<float>& thresholds, - ExceptionState& exception_state) { +void ParseThresholds(const V8UnionDoubleOrDoubleSequence* threshold_parameter, + Vector<float>& thresholds, + ExceptionState& exception_state) { switch (threshold_parameter->GetContentType()) { case V8UnionDoubleOrDoubleSequence::ContentType::kDouble: thresholds.push_back(
diff --git a/third_party/blink/renderer/core/testing/fake_web_plugin.h b/third_party/blink/renderer/core/testing/fake_web_plugin.h index 87200e9..07d5ee0 100644 --- a/third_party/blink/renderer/core/testing/fake_web_plugin.h +++ b/third_party/blink/renderer/core/testing/fake_web_plugin.h
@@ -74,7 +74,7 @@ return false; } void DidReceiveResponse(const WebURLResponse&) override {} - void DidReceiveData(const char* data, size_t data_length) override {} + void DidReceiveData(base::span<const char> data) override {} void DidFinishLoading() override {} void DidFailLoading(const WebURLError&) override {}
diff --git a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc index 5671138..b8a10c85 100644 --- a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc +++ b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -228,9 +228,7 @@ receiver_(this, execution_context), remote_client_(execution_context), associated_remote_(execution_context) { - // TODO(crbug.com/327075943): Support BroadcastChannel created on workers. - if (!execution_context->IsWindow() || - !base::FeatureList::IsEnabled(features::kBFCacheOpenBroadcastChannel)) { + if (!base::FeatureList::IsEnabled(features::kBFCacheOpenBroadcastChannel)) { feature_handle_for_scheduler_ = execution_context->GetScheduler()->RegisterFeature( SchedulingPolicy::Feature::kBroadcastChannel, @@ -269,9 +267,7 @@ receiver_(this, execution_context), remote_client_(execution_context), associated_remote_(execution_context) { - // TODO(crbug.com/327075943): Support BroadcastChannel created on workers. - if (!execution_context->IsWindow() || - !base::FeatureList::IsEnabled(features::kBFCacheOpenBroadcastChannel)) { + if (!base::FeatureList::IsEnabled(features::kBFCacheOpenBroadcastChannel)) { feature_handle_for_scheduler_ = execution_context->GetScheduler()->RegisterFeature( SchedulingPolicy::Feature::kBroadcastChannel,
diff --git a/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc b/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc index 231ace4..4488f44 100644 --- a/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc +++ b/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc
@@ -13,7 +13,6 @@ #include "third_party/blink/renderer/platform/graphics/graphics_types_3d.h" #include "third_party/blink/renderer/platform/graphics/image.h" #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" - #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" namespace blink { @@ -35,11 +34,20 @@ dest_image_size_ = size; + viz::SharedImageFormat color_buffer_format = + viz::SinglePlaneFormat::kRGBA_8888; +#if BUILDFLAG(IS_MAC) + // For Mac, explicitly specify BGRA instead of RGBA so that IOSurface + // format matches shared image format. This is necessary for Graphite where + // IOSurfaces are always used to allow sharing between ANGLE and Dawn. + color_buffer_format = viz::SinglePlaneFormat::kBGRA_8888; +#endif // BUILDFLAG(IS_MAC) + // We copy the contents of the source image into the destination SharedImage // via GL, followed by giving out the destination SharedImage's native // buffer handle to eventually be read by the display compositor. dest_shared_image_ = sii_->CreateSharedImage( - {viz::SinglePlaneFormat::kRGBA_8888, size, gfx::ColorSpace(), + {color_buffer_format, size, gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2_WRITE, "ImageToBufferCopier"}, gpu::kNullSurfaceHandle, gfx::BufferUsage::SCANOUT); CHECK(dest_shared_image_); @@ -63,7 +71,7 @@ auto dest_scoped_si_access = dest_si_texture->BeginAccess(gpu::SyncToken(), /*readonly=*/false); - GLenum target = GL_TEXTURE_2D; + GLenum target = dest_shared_image_->GetTextureTarget(); { gl_->BindTexture(target, dest_scoped_si_access->texture_id()); gl_->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -71,7 +79,7 @@ gl_->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl_->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - gl_->BindTexture(GL_TEXTURE_2D, 0); + gl_->BindTexture(target, 0); // Bind the read framebuffer to our image. StaticBitmapImage* static_image = static_cast<StaticBitmapImage*>(image); @@ -86,9 +94,10 @@ gl_->BeginSharedImageAccessDirectCHROMIUM( source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); - gl_->CopySubTextureCHROMIUM( - source_texture_id, 0, GL_TEXTURE_2D, dest_scoped_si_access->texture_id(), - 0, 0, 0, 0, 0, size.width(), size.height(), false, false, false); + gl_->CopySubTextureCHROMIUM(source_texture_id, 0, target, + dest_scoped_si_access->texture_id(), 0, 0, 0, 0, + 0, size.width(), size.height(), + !static_image->IsOriginTopLeft(), false, false); // Cleanup the read framebuffer and texture. gl_->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc index 274bc2a..4f001f38 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -43,6 +43,7 @@ #include "services/network/public/mojom/ip_address_space.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/loader/lcp_critical_path_predictor_util.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h" #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h" @@ -111,6 +112,9 @@ ResourceFetcherTest() : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { Resource::SetClockForTesting(task_environment_.GetMockClock()); + // The state of global LcppEnabled flag depends on several feature flags + // which can be enabled/disabled in tests. Clear the global flag value. + ResetLcppEnabledForTesting(); } ~ResourceFetcherTest() override { MemoryCache::Get()->EvictResources();
diff --git a/third_party/blink/renderer/platform/text/emoji_segmentation_category.h b/third_party/blink/renderer/platform/text/emoji_segmentation_category.h index f1df476..c42814d 100644 --- a/third_party/blink/renderer/platform/text/emoji_segmentation_category.h +++ b/third_party/blink/renderer/platform/text/emoji_segmentation_category.h
@@ -41,6 +41,15 @@ inline bool operator>(EmojiSegmentationCategory a, uint8_t b) { return static_cast<uint8_t>(a) > b; } +inline bool operator<=(EmojiSegmentationCategory a, uint8_t b) { + return static_cast<uint8_t>(a) <= b; +} +inline bool operator<=(uint8_t a, EmojiSegmentationCategory b) { + return a <= static_cast<uint8_t>(b); +} +inline uint8_t operator-(EmojiSegmentationCategory a, uint8_t b) { + return static_cast<uint8_t>(a) - b; +} // If this function returns true for categories of any characters in a string, // it may produce Emoji presentation, and thus cannot skip being run through the
diff --git a/third_party/blink/renderer/platform/wtf/text/string_hasher.h b/third_party/blink/renderer/platform/wtf/text/string_hasher.h index 11f322a..fa50bc8 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_hasher.h +++ b/third_party/blink/renderer/platform/wtf/text/string_hasher.h
@@ -68,7 +68,7 @@ __m128i x = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p)); return _mm_cvtsi128_si64(_mm_packus_epi16(x, x)); #elif defined(__ARM_NEON__) - int16x8_t x; + uint16x8_t x; memcpy(&x, p, sizeof(x)); return vget_lane_u64(vreinterpret_u64_u8(vmovn_u16(x)), 0); #else @@ -88,9 +88,9 @@ __m128i x = _mm_loadu_si64(reinterpret_cast<const __m128i*>(p)); return _mm_cvtsi128_si64(_mm_packus_epi16(x, x)); #elif defined(__ARM_NEON__) - int8x8_t x; + uint16x4_t x; memcpy(&x, p, sizeof(x)); - int16x8_t x_wide = vcombine_u64(x, x); + uint16x8_t x_wide = vcombine_u16(x, x); return vget_lane_u32(vreinterpret_u32_u8(vmovn_u16(x_wide)), 0); #else return (uint64_t{p[0]}) | (uint64_t{p[1]} << 8) | (uint64_t{p[2]} << 16) |
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 3dc6eb7..a5d8004 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -3713,5 +3713,17 @@ ], "expires": "Jan 1, 2025", "owners": ["moonira@google.com"] + }, + { + "prefix": "bfcache-broadcastchannel", + "platforms": ["Linux", "Mac", "Win"], + "bases": [ + "external/wpt/html/browsers/browsing-the-web/back-forward-cache/eligibility/broadcast-channel.html", + "external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window.html", + "external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window.html" + ], + "args": ["--enable-features=BFCacheOpenBroadcastChannel"], + "owners": ["yuzus@chromium.org"], + "expires": "Jan 1, 2025" } ]
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-constrainterror.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-constrainterror.htm deleted file mode 100644 index 6d61ea2..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-constrainterror.htm +++ /dev/null
@@ -1,73 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Keygenerator ConstraintError when using same id as already generated</title> -<link rel="author" href="mailto:odinho@opera.com" title="Odin Hørthe Omdal"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/support.js"></script> - -<script> - - var db, - t = async_test(), - objects = [1, null, {id: 2}, null, 2.00001, 5, null, {id: 6} ], - expected = [1, 2, 2.00001, 3, 5, 6], - errors = 0; - - var open_rq = createdb(t); - open_rq.onupgradeneeded = function(e) { - db = e.target.result; - var objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); - - for (var i = 0; i < objects.length; i++) - { - if (objects[i] === null) - { - objStore.add({}); - } - else if (typeof objects[i] === "object") - { - var rq = objStore.add(objects[i]) - rq.yeh = objects[i]; - rq.onerror = t.step_func(function(e) { - errors++; - - assert_equals(e.target.error.name, "ConstraintError"); - assert_equals(e.type, "error"); - - e.stopPropagation(); - e.preventDefault(); - }); - rq.onsuccess = t.step_func(function(e) { - assert_unreached("Got rq.success when adding duplicate id " + objects[i]); - }); - } - else - objStore.add({ id: objects[i] }); - } - }; - - open_rq.onsuccess = function(e) { - var actual_keys = [], - rq = db.transaction("store", "readonly", {durability: 'relaxed'}) - .objectStore("store") - .openCursor(); - - rq.onsuccess = t.step_func(function(e) { - var cursor = e.target.result; - - if (cursor) { - actual_keys.push(cursor.key.valueOf()); - cursor.continue(); - } - else { - assert_equals(errors, 2, "expected ConstraintError's"); - assert_array_equals(actual_keys, expected, "keygenerator array"); - t.done(); - } - }); - }; - -</script> - -<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-explicit.html b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-explicit.html deleted file mode 100644 index e2d65e1..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-explicit.html +++ /dev/null
@@ -1,146 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Key Generator behavior with explicit keys generator overflow</title> -<link rel=help href="https://w3c.github.io/IndexedDB/#key-generator-construct"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/support.js"></script> -<script> - -function big_key_test(key, description) { - indexeddb_test( - (t, db) => { - assert_equals(indexedDB.cmp(key, key), 0, 'Key is valid'); - - db.createObjectStore('store', {autoIncrement: true}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - const store = tx.objectStore('store'); - const value = 0; - let request; - - request = store.put(value); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 1, - 'Key generator should initially be 1'); - }); - - request = store.put(value); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 2, - 'Key generator should increment'); - }); - - request = store.put(value, 1000); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 1000, - 'Explicit key should be used'); - }); - - request = store.put(value); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 1001, - 'Key generator should have updated'); - }); - - request = store.put(value, key); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, key, - 'Explicit key should be used'); - }); - - if (key >= 0) { - // Large positive values will max out the key generator, so it - // can no longer produce keys. - request = store.put(value); - request.onsuccess = t.unreached_func('put should fail'); - request.onerror = t.step_func(e => { - e.preventDefault(); - assert_equals(e.target.error.name, 'ConstraintError', - 'Key generator should have returned failure'); - }); - } else { - // Large negative values are always lower than the key generator's - // current number, so have no effect on the generator. - request = store.put(value); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 1002, - 'Key generator should have updated'); - }); - } - - request = store.put(value, 2000); - request.onerror = t.unreached_func('put should succeed'); - request.onsuccess = t.step_func(e => { - assert_equals(e.target.result, 2000, - 'Explicit key should be used'); - }); - - tx.onabort = t.step_func(() => { - assert_unreached(`Transaction aborted: ${tx.error.message}`); - }); - tx.oncomplete = t.step_func(() => { t.done(); }); - }, - description); -} - -[ - { - key: Number.MAX_SAFE_INTEGER + 1, - description: '53 bits' - }, - { - key: Math.pow(2, 60), - description: 'greater than 53 bits, less than 64 bits' - }, - { - key: -Math.pow(2, 60), - description: 'greater than 53 bits, less than 64 bits (negative)' - }, - { - key: Math.pow(2, 63), - description: '63 bits' - }, - { - key: -Math.pow(2, 63), - description: '63 bits (negative)' - }, - { - key: Math.pow(2, 64), - description: '64 bits' - }, - { - key: -Math.pow(2, 64), - description: '64 bits (negative)' - }, - { - key: Math.pow(2, 70), - description: 'greater than 64 bits, but still finite' - }, - { - key: -Math.pow(2, 70), - description: 'greater than 64 bits, but still finite (negative)' - }, - { - key: Infinity, - description: 'equal to Infinity' - }, - { - key: -Infinity, - description: 'equal to -Infinity' - } -].forEach(function(testCase) { - big_key_test(testCase.key, - `Key generator vs. explicit key ${testCase.description}`); -}); - - - -</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-inject.html b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-inject.html deleted file mode 100644 index 57f3a538..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-inject.html +++ /dev/null
@@ -1,119 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Key Generator behavior with explicit keys and value injection</title> -<link rel=help href="https://w3c.github.io/IndexedDB/#inject-key-into-value"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/support.js"></script> -<script> - -indexeddb_test( - (t, db) => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - t.onabort = t.unreached_func('transaction should not abort'); - - const store = tx.objectStore('store'); - - store.put({name: 'n'}).onsuccess = t.step_func(e => { - const key = e.target.result; - assert_equals(key, 1, 'Key generator initial value should be 1'); - store.get(key).onsuccess = t.step_func(e => { - const value = e.target.result; - assert_equals(typeof value, 'object', 'Result should be object'); - assert_equals(value.name, 'n', 'Result should have name property'); - assert_equals(value.id, key, 'Key should be injected'); - t.done(); - }); - }); - }, - 'Key is injected into value - single segment path'); - -indexeddb_test( - (t, db) => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - t.onabort = t.unreached_func('transaction should not abort'); - - const store = tx.objectStore('store'); - - store.put({name: 'n'}).onsuccess = t.step_func(e => { - const key = e.target.result; - assert_equals(key, 1, 'Key generator initial value should be 1'); - store.get(key).onsuccess = t.step_func(e => { - const value = e.target.result; - assert_equals(typeof value, 'object', 'Result should be object'); - assert_equals(value.name, 'n', 'Result should have name property'); - assert_equals(value.a.b.id, key, 'Key should be injected'); - t.done(); - }); - }); - }, - 'Key is injected into value - multi-segment path'); - -indexeddb_test( - (t, db) => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - t.onabort = t.unreached_func('transaction should not abort'); - - const store = tx.objectStore('store'); - - store.put({name: 'n1', b: {name: 'n2'}}).onsuccess = t.step_func(e => { - const key = e.target.result; - assert_equals(key, 1, 'Key generator initial value should be 1'); - store.get(key).onsuccess = t.step_func(e => { - const value = e.target.result; - assert_equals(typeof value, 'object', 'Result should be object'); - assert_equals(value.name, 'n1', 'Result should have name property'); - assert_equals(value.b.name, 'n2', 'Result should have name property'); - assert_equals(value.a.b.id, key, 'Key should be injected'); - t.done(); - }); - }); - }, - 'Key is injected into value - multi-segment path, partially populated'); - -indexeddb_test( - (t, db) => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - const store = tx.objectStore('store'); - - assert_throws_dom('DataError', () => { - store.put(123); - }, 'Key path should be checked against value'); - - t.done(); - }, - 'put() throws if key cannot be injected - single segment path'); - -indexeddb_test( - (t, db) => { - db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); - }, - (t, db) => { - const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); - const store = tx.objectStore('store'); - - assert_throws_dom('DataError', () => { - store.put({a: 123}); - }, 'Key path should be checked against value'); - - assert_throws_dom('DataError', () => { - store.put({a: {b: 123} }); - }, 'Key path should be checked against value'); - - t.done(); - }, - 'put() throws if key cannot be injected - multi-segment path'); - -</script>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-overflow.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-overflow.htm deleted file mode 100644 index 2dd6a8dc..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator-overflow.htm +++ /dev/null
@@ -1,70 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Keygenerator overflow</title> -<link rel="author" href="mailto:odinho@opera.com" title="Odin Hørthe Omdal"> -<link rel=help href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#key-generator-concept"> -<link rel=assert title="When the current number of a key generator reaches above the value 2^53 (9007199254740992) any attempts to use the key generator to generate a new key will result in an error. It's still possible to insert records into the object store by specifying an explicit key, however the only way to use a key generator again for the object store is to delete the object store and create a new one."> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/support.js"></script> - -<script> - - var db, - t = async_test(), - overflow_error_fired = false, - objects = [9007199254740991, null, "error", 2, "error" ], - expected_keys = [2, 9007199254740991, 9007199254740992]; - - var open_rq = createdb(t); - open_rq.onupgradeneeded = function(e) { - db = e.target.result; - var objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); - - for (var i = 0; i < objects.length; i++) - { - if (objects[i] === null) - { - objStore.add({}); - } - else if (objects[i] === "error") - { - var rq = objStore.add({}); - rq.onsuccess = fail(t, 'When "current number" overflows, error event is expected'); - rq.onerror = t.step_func(function(e) { - overflow_error_fired = true; - assert_equals(e.target.error.name, "ConstraintError", "error name"); - e.preventDefault(); - e.stopPropagation(); - }); - } - else - objStore.add({ id: objects[i] }); - } - }; - - open_rq.onsuccess = function(e) { - var actual_keys = [], - rq = db.transaction("store", "readonly", {durability: 'relaxed'}) - .objectStore("store") - .openCursor(); - - rq.onsuccess = t.step_func(function(e) { - var cursor = e.target.result; - - if (cursor) { - actual_keys.push(cursor.key.valueOf()); - cursor.continue(); - } - else { - assert_true(overflow_error_fired, "error fired on 'current number' overflow"); - assert_array_equals(actual_keys, expected_keys, "keygenerator array"); - - t.done(); - } - }); - }; - -</script> - -<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.any.js new file mode 100644 index 0000000..90f23ed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.any.js
@@ -0,0 +1,389 @@ +// META: global=window,worker +// META: script=resources/support.js + +'use strict'; + +function keygenerator(objects, expected_keys, desc, func) { + let db; + let t = async_test("Keygenerator" + " - " + desc); + let open_rq = createdb(t); + open_rq.onupgradeneeded = function(e) { + db = e.target.result; + let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); + for (let i = 0; i < objects.length; i++) + { + if (objects[i] === null) + objStore.add({}); + else + objStore.add({ id: objects[i] }); + } + }; + + open_rq.onsuccess = function(e) { + let actual_keys = []; + let rq = db.transaction("store", "readonly", {durability: 'relaxed'}) + .objectStore("store") + .openCursor(); + rq.onsuccess = t.step_func(function(e) { + let cursor = e.target.result; + if (cursor) { + actual_keys.push(cursor.key.valueOf()); + cursor.continue(); + } + else { + assert_key_equals(actual_keys, expected_keys, "keygenerator array - " + desc); + t.done(); + } + }); + }; +} +keygenerator([null, null, null, null], [1, 2, 3, 4], + "starts at one, and increments by one"); + +keygenerator([2, null, 5, null, 6.66, 7], [2, 3, 5, 6, 6.66, 7], + "increments by one from last set key"); + +keygenerator([-10, null, "6", 6.3, [10], -2, 4, null], [-10, -2, 1, 4, 6.3, 7, "6", [10]], + "don't increment when new key is not bigger than current"); + +async_test(t => { + let db; + let objects = [1, null, { id: 2 }, null, 2.00001, 5, null, { id: 6 }]; + let expected = [1, 2, 2.00001, 3, 5, 6]; + let errors = 0; + let open_rq = createdb(t); + open_rq.onupgradeneeded = function(e) { + db = e.target.result; + let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); + + for (let i = 0; i < objects.length; i++) + { + if (objects[i] === null) + { + objStore.add({}); + } + else if (typeof objects[i] === "object") + { + let rq = objStore.add(objects[i]); + rq.onerror = t.step_func(function(e) { + errors++; + assert_equals(e.target.error.name, "ConstraintError"); + assert_equals(e.type, "error"); + e.stopPropagation(); + e.preventDefault(); + }); + rq.onsuccess = t.step_func(function(e) { + assert_unreached("Got rq.success when adding duplicate id " + objects[i]); + }); + } + else + objStore.add({ id: objects[i] }); + } + }; + + open_rq.onsuccess = function(e) { + let actual_keys = []; + let rq = db.transaction("store", "readonly", {durability: 'relaxed'}) + .objectStore("store") + .openCursor(); + rq.onsuccess = t.step_func(function(e) { + let cursor = e.target.result; + if (cursor) { + actual_keys.push(cursor.key.valueOf()); + cursor.continue(); + } + else { + assert_equals(errors, 2, "expected ConstraintError's"); + assert_array_equals(actual_keys, expected, "keygenerator array"); + t.done(); + } + }); + }; + +}, "Keygenerator ConstraintError when using same id as already generated"); + +function big_key_test(key, description) { + indexeddb_test( + (t, db) => { + assert_equals(indexedDB.cmp(key, key), 0, 'Key is valid'); + db.createObjectStore('store', {autoIncrement: true}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + const store = tx.objectStore('store'); + const value = 0; + let request; + request = store.put(value); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 1, + 'Key generator should initially be 1'); + }); + + request = store.put(value); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 2, + 'Key generator should increment'); + }); + + request = store.put(value, 1000); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 1000, + 'Explicit key should be used'); + }); + + request = store.put(value); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 1001, + 'Key generator should have updated'); + }); + + request = store.put(value, key); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, key, + 'Explicit key should be used'); + }); + + if (key >= 0) { + // Large positive values will max out the key generator, so it + // can no longer produce keys. + request = store.put(value); + request.onsuccess = t.unreached_func('put should fail'); + request.onerror = t.step_func(e => { + e.preventDefault(); + assert_equals(e.target.error.name, 'ConstraintError', + 'Key generator should have returned failure'); + }); + } else { + // Large negative values are always lower than the key generator's + // current number, so have no effect on the generator. + request = store.put(value); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 1002, + 'Key generator should have updated'); + }); + } + + request = store.put(value, 2000); + request.onerror = t.unreached_func('put should succeed'); + request.onsuccess = t.step_func(e => { + assert_equals(e.target.result, 2000, + 'Explicit key should be used'); + }); + tx.onabort = t.step_func(() => { + assert_unreached(`Transaction aborted: ${tx.error.message}`); + }); + tx.oncomplete = t.step_func(() => { t.done(); }); + }, + description); +} + +[ + { + key: Number.MAX_SAFE_INTEGER + 1, + description: '53 bits' + }, + { + key: Math.pow(2, 60), + description: 'greater than 53 bits, less than 64 bits' + }, + { + key: -Math.pow(2, 60), + description: 'greater than 53 bits, less than 64 bits (negative)' + }, + { + key: Math.pow(2, 63), + description: '63 bits' + }, + { + key: -Math.pow(2, 63), + description: '63 bits (negative)' + }, + { + key: Math.pow(2, 64), + description: '64 bits' + }, + { + key: -Math.pow(2, 64), + description: '64 bits (negative)' + }, + { + key: Math.pow(2, 70), + description: 'greater than 64 bits, but still finite' + }, + { + key: -Math.pow(2, 70), + description: 'greater than 64 bits, but still finite (negative)' + }, + { + key: Infinity, + description: 'equal to Infinity' + }, + { + key: -Infinity, + description: 'equal to -Infinity' + } +].forEach(function(testCase) { + big_key_test(testCase.key, + `Key generator vs. explicit key ${testCase.description}`); +}); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + t.onabort = t.unreached_func('transaction should not abort'); + const store = tx.objectStore('store'); + store.put({name: 'n'}).onsuccess = t.step_func(e => { + const key = e.target.result; + assert_equals(key, 1, 'Key generator initial value should be 1'); + store.get(key).onsuccess = t.step_func(e => { + const value = e.target.result; + assert_equals(typeof value, 'object', 'Result should be object'); + assert_equals(value.name, 'n', 'Result should have name property'); + assert_equals(value.id, key, 'Key should be injected'); + t.done(); + }); + }); + }, + 'Key is injected into value - single segment path'); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + t.onabort = t.unreached_func('transaction should not abort'); + const store = tx.objectStore('store'); + store.put({name: 'n'}).onsuccess = t.step_func(e => { + const key = e.target.result; + assert_equals(key, 1, 'Key generator initial value should be 1'); + store.get(key).onsuccess = t.step_func(e => { + const value = e.target.result; + assert_equals(typeof value, 'object', 'Result should be object'); + assert_equals(value.name, 'n', 'Result should have name property'); + assert_equals(value.a.b.id, key, 'Key should be injected'); + t.done(); + }); + }); + }, + 'Key is injected into value - multi-segment path'); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + t.onabort = t.unreached_func('transaction should not abort'); + const store = tx.objectStore('store'); + store.put({name: 'n1', b: {name: 'n2'}}).onsuccess = t.step_func(e => { + const key = e.target.result; + assert_equals(key, 1, 'Key generator initial value should be 1'); + store.get(key).onsuccess = t.step_func(e => { + const value = e.target.result; + assert_equals(typeof value, 'object', 'Result should be object'); + assert_equals(value.name, 'n1', 'Result should have name property'); + assert_equals(value.b.name, 'n2', 'Result should have name property'); + assert_equals(value.a.b.id, key, 'Key should be injected'); + t.done(); + }); + }); + }, + 'Key is injected into value - multi-segment path, partially populated'); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + const store = tx.objectStore('store'); + + assert_throws_dom('DataError', () => { + store.put(123); + }, 'Key path should be checked against value'); + + t.done(); + }, + 'put() throws if key cannot be injected - single segment path'); + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + const store = tx.objectStore('store'); + + assert_throws_dom('DataError', () => { + store.put({a: 123}); + }, 'Key path should be checked against value'); + + assert_throws_dom('DataError', () => { + store.put({a: {b: 123} }); + }, 'Key path should be checked against value'); + + t.done(); + }, + 'put() throws if key cannot be injected - multi-segment path'); + +async_test(t => { + let db; + let overflow_error_fired = false; + let objects = [9007199254740991, null, "error", 2, "error"]; + let expected_keys = [2, 9007199254740991, 9007199254740992]; + let open_rq = createdb(t); + open_rq.onupgradeneeded = function(e) { + db = e.target.result; + let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); + for (let i = 0; i < objects.length; i++) + { + if (objects[i] === null) + { + objStore.add({}); + } + else if (objects[i] === "error") + { + let rq = objStore.add({}); + rq.onsuccess = fail(t, 'When "current number" overflows, error event is expected'); + rq.onerror = t.step_func(function(e) { + overflow_error_fired = true; + assert_equals(e.target.error.name, "ConstraintError", "error name"); + e.preventDefault(); + e.stopPropagation(); + }); + } + else + objStore.add({ id: objects[i] }); + } + }; + + open_rq.onsuccess = function(e) { + let actual_keys = []; + let rq = db.transaction("store", "readonly", {durability: 'relaxed'}) + .objectStore("store") + .openCursor(); + rq.onsuccess = t.step_func(function(e) { + let cursor = e.target.result; + if (cursor) { + actual_keys.push(cursor.key.valueOf()); + cursor.continue(); + } + else { + assert_true(overflow_error_fired, "error fired on 'current number' overflow"); + assert_array_equals(actual_keys, expected_keys, "keygenerator array"); + + t.done(); + } + }); + }; +}, "Keygenerator overflow");
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.htm b/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.htm deleted file mode 100644 index b4eeef95..0000000 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/keygenerator.htm +++ /dev/null
@@ -1,65 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>Keygenerator</title> -<link rel="author" href="mailto:odinho@opera.com" title="Odin Hørthe Omdal"> -<link rel=help href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#key-generator-concept"> -<link rel=assert title="The current number of a key generator is always set to 1 when the object store for that key generator is first created."> -<link rel=assert title="When a key generator is used to generate a new key for a object store, the key generator's current number is used as the new key value and then the key generator's current number is increased by 1."> -<link rel=assert title="When a record is stored in a object store which uses a key generator, and an explicit key is defined, if the key's value is a float greater than or equal to the key generator's current number, then the key generator's current number is set to the smallest integer number larger than the explicit key. Only explicit keys which are float values affect the current number of the key generator."> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/support.js"></script> - -<script> - function keygenerator(objects, expected_keys, desc, func) { - var db, - t = async_test(document.title + " - " + desc); - - var open_rq = createdb(t); - open_rq.onupgradeneeded = function(e) { - db = e.target.result; - var objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); - - for (var i = 0; i < objects.length; i++) - { - if (objects[i] === null) - objStore.add({}); - else - objStore.add({ id: objects[i] }); - } - }; - - open_rq.onsuccess = function(e) { - var actual_keys = [], - rq = db.transaction("store", "readonly", {durability: 'relaxed'}) - .objectStore("store") - .openCursor(); - - rq.onsuccess = t.step_func(function(e) { - var cursor = e.target.result; - - if (cursor) { - actual_keys.push(cursor.key.valueOf()); - cursor.continue(); - } - else { - assert_key_equals(actual_keys, expected_keys, "keygenerator array"); - t.done(); - } - }); - }; - } - - - keygenerator([null, null, null, null], [1, 2, 3, 4], - "starts at one, and increments by one"); - - keygenerator([2, null, 5, null, 6.66, 7], [2, 3, 5, 6, 6.66, 7], - "increments by one from last set key"); - - keygenerator([-10, null, "6", 6.3, [10], -2, 4, null], [-10, -2, 1, 4, 6.3, 7, "6", [10]], - "don't increment when new key is not bigger than current"); - -</script> - -<div id="log"></div>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window-expected.txt new file mode 100644 index 0000000..364e821 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[PRECONDITION_FAILED] Ensure that open broadcastchannel does not block bfcache. + BFCache not supported. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window.js new file mode 100644 index 0000000..71d3d38 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/broadcastchannel.window.js
@@ -0,0 +1,26 @@ +// META: title=Ensure that open broadcastchannel does not block bfcache. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js +// META: timeout=long + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*extraConfig=*/ { + origin: 'HTTP_ORIGIN', + scripts: [], + headers: [], + }, + /*options=*/ {features: 'noopener'}); + await rc1.executeScript(() => { + window.foo = new BroadcastChannel('foo'); + }); + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBfcache=*/ true); +});
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt new file mode 100644 index 0000000..475b249 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[PRECONDITION_FAILED] BroadcastChannel messages dispatched to dedicated worker in bfcache should be queued. + BFCache not supported. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window.js new file mode 100644 index 0000000..b7ebd48 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window.js
@@ -0,0 +1,44 @@ +// META: title=BroadcastChannel messages dispatched to dedicated worker in bfcache should be queued. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js + +'use strict'; + +// Ensure that broadcast channel messages sent to a dedicated +// worker in bfcache are queued and dispatched upon restore. +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*extraConfig=*/ {}, /*options=*/ {features: 'noopener'}); + let workerVar; + const worker = await rc1.addWorker( + workerVar, + { + scripts: ['../resources/worker-with-broadcastchannel.js'], + }, + ); + await assertSimplestScriptRuns(worker); + + await prepareForBFCache(rc1); + const newRemoteContextHelper = await rc1.navigateToNew(); + await assertSimplestScriptRuns(newRemoteContextHelper); + + // Send a message to a dedicated worker in bfcache. + let channel = new BroadcastChannel('foo'); + channel.postMessage('bar'); + + await newRemoteContextHelper.historyBack(); + // Make sure that rc1 gets restored without getting evicted. Messages + // while in bfcache should be queued. + await assertImplementsBFCacheOptional(rc1); + + // A message should arrive upon bfcache restore. + await worker.executeScript(() => { + return waitForEventsPromise(1); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt new file mode 100644 index 0000000..d2462ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +[PRECONDITION_FAILED] BroadcastChannel message while in bfcache should evict the entry. + Precondition fail reasons are reported. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window.js new file mode 100644 index 0000000..1134855 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window.js
@@ -0,0 +1,38 @@ +// META: title=BroadcastChannel message while in bfcache should evict the entry. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + // Open a window with noopener so that BFCache will work. + const rc1 = await rcHelper.addWindow( + /*extraConfig=*/ {}, /*options=*/ {features: 'noopener'}); + await rc1.executeScript(() => { + const channel = new BroadcastChannel('foo'); + channel.addEventListener('message', event => { + channel.postMessage('Message received: ' + event.data); + }); + }); + await prepareForBFCache(rc1); + const newRemoteContextHelper = await rc1.navigateToNew(); + await assertSimplestScriptRuns(newRemoteContextHelper); + + // Post a message to a channel in bfcache. This should trigger eviction. + const channel = new BroadcastChannel('foo'); // Access shared channel + channel.postMessage('Sending a message should evict a bfcache entry.'); + + await newRemoteContextHelper.historyBack(); + + // It's possible that the pages with open broadcastchannel are not allowed + // into bfcache. Set preconditionFailReasons to catch that case. Otherwise + // expect the eviction reason. + await assertNotRestoredFromBFCache( + rc1, ['broadcastchannel-message'], + /*preconditonFailReasons=*/['broadcastchannel']); +});
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js index ad2119b..9c04f81 100644 --- a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js
@@ -45,9 +45,9 @@ // as UAs might block bfcache for their specific reasons. function matchReasons(expectedNotRestoredReasonsSet, notRestoredReasonsSet) { const missing = setMinus( - expectedNotRestoredReasonsSet, notRestoredReasonsSet, 'Missing reasons'); + expectedNotRestoredReasonsSet, notRestoredReasonsSet); const extra = setMinus( - notRestoredReasonsSet, expectedNotRestoredReasonsSet, 'Extra reasons'); + notRestoredReasonsSet, expectedNotRestoredReasonsSet); assert_true(missing.size == 0, `Expected: ${sorted(expectedNotRestoredReasonsSet)}\n` + `Got: ${sorted(notRestoredReasonsSet)}\n` + `Missing: ${sorted(missing)}\n` + @@ -77,8 +77,11 @@ // If the API is not available, the function will terminate instead of marking // the assertion failed. // Call `prepareForBFCache()` before navigating away to call this function. +// `preconditionFailReasons` is a set of reasons that could be reported but +// should PRECONDITION_FAIL if so. If `preconditionFailReasons` are reported, +// this function will not check if `notRestoredReasons` are reported. async function assertNotRestoredFromBFCache( - remoteContextHelper, notRestoredReasons) { + remoteContextHelper, notRestoredReasons, preconditionFailReasons = null) { var beforeBFCache = await getBeforeBFCache(remoteContextHelper); assert_equals(beforeBFCache, undefined, 'document unexpectedly BFCached'); @@ -115,6 +118,20 @@ } }; collectReason(result); + + // Check for preconditionFailReasons if set. + if (preconditionFailReasons) { + let preconditionFailReasonsSet = new Set(preconditionFailReasons); + const missing = setMinus( + preconditionFailReasonsSet, notRestoredReasonsSet); + const extra = setMinus( + notRestoredReasonsSet, preconditionFailReasonsSet); + // preconditionFailReasons were reported. PRECONDION_FAIL here. + assert_implements_optional( + !(missing.size == 0 && extra.size == 0), + 'Precondition fail reasons are reported.'); + } + matchReasons(expectedNotRestoredReasonsSet, notRestoredReasonsSet); }
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/worker-with-broadcastchannel.js b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/worker-with-broadcastchannel.js new file mode 100644 index 0000000..e4126b6e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/browsing-the-web/back-forward-cache/resources/worker-with-broadcastchannel.js
@@ -0,0 +1,19 @@ +let messages = []; +const channel = new BroadcastChannel('foo'); // Access shared channel + +channel.addEventListener('message', event => { + messages.push(event.data); +}); + +function waitForEventsPromise(count) { + return new Promise(resolve => { + function checkMessages() { + if (messages.length >= count) { + channel.removeEventListener('message', checkMessages); // Cleanup + resolve(messages.length); + } + } + checkMessages(); + channel.addEventListener('message', checkMessages); + }); +} \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/pytest.ini b/third_party/blink/web_tests/external/wpt/webdriver/tests/pytest.ini new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/pytest.ini
diff --git a/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/README.md b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/README.md new file mode 100644 index 0000000..84daee4 --- /dev/null +++ b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/README.md
@@ -0,0 +1,4 @@ +This directory contains tests that should be run with the following flag on. +``` +--enable-features=BFCacheOpenBroadcastChannel +``` \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt new file mode 100644 index 0000000..d2490db --- /dev/null +++ b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/dedicatedworker.tentative.window-expected.txt
@@ -0,0 +1,3 @@ +This is a testharness.js-based test. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt new file mode 100644 index 0000000..d2490db --- /dev/null +++ b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/broadcastchannel/evict-on-message.tentative.window-expected.txt
@@ -0,0 +1,3 @@ +This is a testharness.js-based test. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/eligibility/broadcast-channel-expected.txt b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/eligibility/broadcast-channel-expected.txt new file mode 100644 index 0000000..d2490db --- /dev/null +++ b/third_party/blink/web_tests/virtual/bfcache-broadcastchannel/external/wpt/html/browsers/browsing-the-web/back-forward-cache/eligibility/broadcast-channel-expected.txt
@@ -0,0 +1,3 @@ +This is a testharness.js-based test. +Harness: the test ran to completion. +
diff --git a/third_party/cros-components/src b/third_party/cros-components/src index 4610f51..e8c2d53 160000 --- a/third_party/cros-components/src +++ b/third_party/cros-components/src
@@ -1 +1 @@ -Subproject commit 4610f51c64c848f5f8d7198a07a8f733ba716ce4 +Subproject commit e8c2d53fcc6214e81e8bcbea308eba65cc65e7ed
diff --git a/third_party/dawn b/third_party/dawn index f37b8fc..d3b7a44 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit f37b8fcef30b699ddb1b270bdeee84055016c8c8 +Subproject commit d3b7a448690d9a1e0f9fa7b1b300235ff378cffd
diff --git a/third_party/depot_tools b/third_party/depot_tools index 3a7d070..62fc3a1 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 3a7d070966a55bd1bb113e2ec262ddeffe144c6b +Subproject commit 62fc3a1d244368a430ffd7a6b55377a6dfd5e348
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index c3f7339..eaa06ed 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit c3f733925a3b742db17d2dfae5610f14180cb99a +Subproject commit eaa06ed5d71844de4663a3e8208c48e0de0bc980
diff --git a/third_party/emoji-segmenter/README.chromium b/third_party/emoji-segmenter/README.chromium index 96a30d8cc..e445490 100644 --- a/third_party/emoji-segmenter/README.chromium +++ b/third_party/emoji-segmenter/README.chromium
@@ -1,8 +1,8 @@ Name: Emoji Segmenter Short Name: emoji-segmenter URL: https://github.com/googlei18n/emoji-segmenter -Version: 0.1.0 -Date: 20190129 +Version: 0.2.0 +Date: 2024-02-20 Revision: 242460e9cbee7453880725be5b9bf352d1882a9f Security Critical: yes Shipped: yes
diff --git a/third_party/emoji-segmenter/src b/third_party/emoji-segmenter/src index 9ba6d25..b2c0458 160000 --- a/third_party/emoji-segmenter/src +++ b/third_party/emoji-segmenter/src
@@ -1 +1 @@ -Subproject commit 9ba6d25d0d9313569665d4a9d2b34f0f39f9a50e +Subproject commit b2c045838114ee993bd8f9830caf40a9500a79e5
diff --git a/third_party/skia b/third_party/skia index 20b42bf..132c9e8 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 20b42bf48559cef3d1f6ca6ee92b872cf3dc8d90 +Subproject commit 132c9e886e6d34136b892314dece368b3cebbb0a
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 230418e..3763a16 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 230418ea04675aa41ffc7fee5a06640ba5ce1684 +Subproject commit 3763a16adf089ba25715e5587104f6890acf88c7
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index 0bcac36..9abfdd2 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit 0bcac3621c4a742f7187b0a10ecab5088d42c2e8 +Subproject commit 9abfdd2897a8a130524bb31caf934440804068d2
diff --git a/third_party/webrtc b/third_party/webrtc index af8f626..b2a2b1b 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit af8f6264cad70562649792288834422df5e05995 +Subproject commit b2a2b1b51e18436d32531f80bfc509ebebc12e9e
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index 23b188c..812aaeb 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1302,6 +1302,7 @@ for target in ninja_targets: target_type = isolate_map[target]['type'] label = isolate_map[target]['label'] + target_runtime_deps = 'obj/%s.runtime_deps' % label.replace(':', '/') stamp_runtime_deps = 'obj/%s.stamp.runtime_deps' % label.replace(':', '/') # TODO(crbug.com/40590196): 'official_tests' use # type='additional_compile_target' to isolate tests. This is not the @@ -1315,15 +1316,15 @@ if fuchsia or ios or target_type == 'generated_script': # iOS and Fuchsia targets end up as groups. # generated_script targets are always actions. - rpaths = [stamp_runtime_deps] + rpaths = [stamp_runtime_deps, target_runtime_deps] elif android: # Android targets may be either android_apk or executable. The former # will result in runtime_deps associated with the stamp file, while the # latter will result in runtime_deps associated with the executable. label = isolate_map[target]['label'] rpaths = [ - target + '.runtime_deps', - stamp_runtime_deps] + target + '.runtime_deps', stamp_runtime_deps, target_runtime_deps + ] elif (target_type == 'script' or isolate_map[target].get('label_type') == 'group'): # For script targets, the build target is usually a group, @@ -1331,7 +1332,7 @@ # for the label, which lives under the obj/ directory, but it may # also be an executable. label = isolate_map[target]['label'] - rpaths = [stamp_runtime_deps] + rpaths = [stamp_runtime_deps, target_runtime_deps] if win: rpaths += [ target + '.exe.runtime_deps' ] else:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e8c4b23..d7b6e1bf 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -28926,6 +28926,7 @@ File name too long on Linux. Operation now in progress on Mac. Resource deadlock avoided on Windows. </int> + <int value="39" label="ENOTEMPTY">Directory not empty</int> <int value="45" label="EL2NSYNC/EOPNOTSUPP/_"> Level 2 not synchronized on Linux. Operation not supported on Mac. Resource deadlock avoided on Windows.
diff --git a/tools/metrics/histograms/metadata/families/histograms.xml b/tools/metrics/histograms/metadata/families/histograms.xml index f72c2b0..d2e5adb 100644 --- a/tools/metrics/histograms/metadata/families/histograms.xml +++ b/tools/metrics/histograms/metadata/families/histograms.xml
@@ -1080,35 +1080,6 @@ <token key="RequestType" variants="ProtoFetcherRequestType"/> </histogram> -<histogram name="{RequestType}.{AuthErrorState}.AccessTokenLatency" units="ms" - expires_after="2023-11-01"> - <owner>tju@google.com</owner> - <owner>chrome-kids-eng@google.com</owner> - <summary> - Latency of the access token fetching before calls to {RequestType}. - Currently only successful authentication is counted. - </summary> - <token key="RequestType" variants="ProtoFetcherRequestType"/> - <token key="AuthErrorState"> - <variant name="NONE"/> - </token> -</histogram> - -<histogram name="{RequestType}.{HttpStatusOrNetError}.ApiLatency" units="ms" - expires_after="2023-11-01"> - <owner>tju@google.com</owner> - <owner>chrome-kids-eng@google.com</owner> - <summary> - Latency of the calls to {RequestType} that resulted in - "{HttpStatusOrNetError}" status. Currently only succesful - communication is recorded. - </summary> - <token key="RequestType" variants="ProtoFetcherRequestType"/> - <token key="HttpStatusOrNetError"> - <variant name="HTTP_OK"/> - </token> -</histogram> - <histogram name="{RequestType}.{Status}.Latency" units="ms" expires_after="2025-02-09"> <owner>tju@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml index 4679621..e039287 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -2938,7 +2938,11 @@ <suffix name="Malloc.CommittedSize" label="Committed memory size for malloc(). Recorded only when PartitionAlloc is used as malloc()."/> - <suffix name="Malloc.ExtremeLUD.CumulativeSizeInBytes" + <suffix name="Malloc.ExtremeLUD.LargeObjects.CumulativeSizeInBytes" + label="Total size of quarantined allocations in the ELUD quarantine + since process start, including already dequarantined + allocations."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.CumulativeSizeInBytes" label="Total size of quarantined allocations in the ELUD quarantine since process start, including already dequarantined allocations."/> @@ -3315,18 +3319,32 @@ <suffix name="Malloc.BRPQuarantinedBytesPerMinute" label="Total size of BRP quarantined bytes per minute, averaged during the last memory dump interval."/> - <suffix name="Malloc.ExtremeLUD.BytesPerMinute" + <suffix name="Malloc.ExtremeLUD.LargeObjects.BytesPerMinute" label="Size of ELUD quarantined bytes per minute, averaged during the last memory dump interval."/> - <suffix name="Malloc.ExtremeLUD.CumulativeCount" + <suffix name="Malloc.ExtremeLUD.LargeObjects.CumulativeCount" label="Total count of quarantined allocations in the ELUD quarantine since process start, including already dequarantined allocations."/> - <suffix name="Malloc.ExtremeLUD.QuarantinedTime" + <suffix name="Malloc.ExtremeLUD.LargeObjects.QuarantinedTime" label="Time to use up the capacity of the ELUD quarantine in milliseconds, estimated from BytesPerMinute. Very rough approximation to how long time allocations are quarantined."/> - <suffix name="Malloc.ExtremeLUD.SizeInBytes" + <suffix name="Malloc.ExtremeLUD.LargeObjects.SizeInBytes" + label="Size of quarantined allocations in the ELUD quarantine at dump + time."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.BytesPerMinute" + label="Size of ELUD quarantined bytes per minute, averaged during the + last memory dump interval."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.CumulativeCount" + label="Total count of quarantined allocations in the ELUD quarantine + since process start, including already dequarantined + allocations."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.QuarantinedTime" + label="Time to use up the capacity of the ELUD quarantine in + milliseconds, estimated from BytesPerMinute. Very rough + approximation to how long time allocations are quarantined."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.SizeInBytes" label="Size of quarantined allocations in the ELUD quarantine at dump time."/> <suffix name="Malloc.Original.ObjectCount" @@ -3422,16 +3440,29 @@ <suffix name="Malloc.BRPQuarantinedCountPerMinute" label="Number of BRP quarantined allocations per minute, averaged during the last memory dump interval."/> - <suffix name="Malloc.ExtremeLUD.Count" + <suffix name="Malloc.ExtremeLUD.LargeObjects.Count" label="Count of all quarantined allocations in the ELUD quarantine at dump time."/> - <suffix name="Malloc.ExtremeLUD.CountPerMinute" + <suffix name="Malloc.ExtremeLUD.LargeObjects.CountPerMinute" label="Number of ELUD quarantined allocations per minute, averaged during the last memory dump interval."/> - <suffix name="Malloc.ExtremeLUD.MissCountPerMinute" + <suffix name="Malloc.ExtremeLUD.LargeObjects.MissCountPerMinute" label="Number of ELUD quarantine requests that were not satisfied per minute, averaged during the last memory dump interval."/> - <suffix name="Malloc.ExtremeLUD.QuarantineMissCount" + <suffix name="Malloc.ExtremeLUD.LargeObjects.QuarantineMissCount" + label="Monotonically increasing count of quarantine requests that were + not satisfied due to the configured size limit of the ELUD + quarantine."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.Count" + label="Count of all quarantined allocations in the ELUD quarantine at + dump time."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.CountPerMinute" + label="Number of ELUD quarantined allocations per minute, averaged + during the last memory dump interval."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.MissCountPerMinute" + label="Number of ELUD quarantine requests that were not satisfied per + minute, averaged during the last memory dump interval."/> + <suffix name="Malloc.ExtremeLUD.SmallObjects.QuarantineMissCount" label="Monotonically increasing count of quarantine requests that were not satisfied due to the configured size limit of the ELUD quarantine."/>
diff --git a/tools/metrics/histograms/metadata/oobe/histograms.xml b/tools/metrics/histograms/metadata/oobe/histograms.xml index 97f327a..9e49f2e 100644 --- a/tools/metrics/histograms/metadata/oobe/histograms.xml +++ b/tools/metrics/histograms/metadata/oobe/histograms.xml
@@ -443,7 +443,8 @@ </variants> <variants name="PerksID"> - <variant name="G1"/> + <variant name="Gamgee"/> + <variant name="StandardGamgee"/> </variants> <variants name="PersonalizedAppsType">
diff --git a/tools/metrics/histograms/metadata/user_annotations/histograms.xml b/tools/metrics/histograms/metadata/user_annotations/histograms.xml index 2d65583..c0e738a 100644 --- a/tools/metrics/histograms/metadata/user_annotations/histograms.xml +++ b/tools/metrics/histograms/metadata/user_annotations/histograms.xml
@@ -19,6 +19,28 @@ </summary> </histogram> +<histogram name="UserAnnotations.RemoveAllEntries.Result" + enum="UserAnnotationsExecutionResult" expires_after="M135"> + <owner>rajendrant@chromium.org</owner> + <owner>sophiechang@chromium.org</owner> + <summary> + Records the result of removing all entries from user annotations service. + Recorded for each remove all entries call from the database via the + management UI. + </summary> +</histogram> + +<histogram name="UserAnnotations.RemoveEntry.Result" + enum="UserAnnotationsExecutionResult" expires_after="M135"> + <owner>rajendrant@chromium.org</owner> + <owner>sophiechang@chromium.org</owner> + <summary> + Records the result of removing a single entry from user annotations service. + Recorded for each user annotation entry removal from the database via the + management UI. + </summary> +</histogram> + </histograms> </histogram-configuration>
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc index 64f1fe4..915a10f 100644 --- a/ui/base/ui_base_switches.cc +++ b/ui/base/ui_base_switches.cc
@@ -75,6 +75,8 @@ // The language file that we want to try to open. Of the form // language[-country] where language is the 2 letter code from ISO-639. +// On Linux, this flag does not work; use the LC_*/LANG environment variables +// instead. const char kLang[] = "lang"; // Transform localized strings to be longer, with beginning and end markers to
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn index d713b0c8..45da5d0 100644 --- a/ui/file_manager/BUILD.gn +++ b/ui/file_manager/BUILD.gn
@@ -361,10 +361,16 @@ ] input_files_base_dir = rebase_path(target_gen_dir, root_build_dir) - input_files = [ "image_loader/background.rollup.js" ] + input_files = [ + "image_loader/background.rollup.js", + "image_loader/shared.rollup.js", + "image_loader/service_worker.rollup.js", + ] - resource_path_rewrites = - [ "image_loader/background.rollup.js|image_loader/background.js" ] + resource_path_rewrites = [ + "image_loader/background.rollup.js|image_loader/background.js", + "image_loader/service_worker.rollup.js|image_loader/service_worker.js", + ] if (optimize_webui) { input_files +=
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index 3f33611..c103189 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -20,6 +20,7 @@ "image_loader/image_request_task.ts", "image_loader/piex_loader.ts", "image_loader/scheduler.ts", + "image_loader/service_worker.ts", "image_loader/sw_od_messages.ts", ] + shared_image_loader_ts @@ -517,6 +518,7 @@ "//tools/typescript/definitions/chrome_event.d.ts", "//tools/typescript/definitions/chrome_test.d.ts", "//tools/typescript/definitions/metrics_private.d.ts", + "//tools/typescript/definitions/offscreen.d.ts", "//tools/typescript/definitions/runtime.d.ts", "//tools/typescript/definitions/tabs.d.ts", "//tools/typescript/definitions/wallpaper.d.ts",
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn index a84d14b..171b93b 100644 --- a/ui/file_manager/image_loader/BUILD.gn +++ b/ui/file_manager/image_loader/BUILD.gn
@@ -39,6 +39,7 @@ "image_loader_private.d.ts", "overrides.d.ts", "//tools/typescript/definitions/chrome_event.d.ts", + "//tools/typescript/definitions/offscreen.d.ts", "//tools/typescript/definitions/runtime.d.ts", ] @@ -76,7 +77,10 @@ host = "image_loader" input = image_loader_path - js_module_in_files = [ "background.js" ] + js_module_in_files = [ + "background.js", + "service_worker.js", + ] external_paths = [ "chrome://file-manager|$files_app_path",
diff --git a/ui/file_manager/image_loader/background.html b/ui/file_manager/image_loader/background.html index 51bb786..889839f 100644 --- a/ui/file_manager/image_loader/background.html +++ b/ui/file_manager/image_loader/background.html
@@ -2,4 +2,9 @@ <meta charset="utf-8"> <script src="piex/piex.js.wasm"></script> +<!-- The background.js file and this background.html file are both called + "background" for historical reasons. In Manifest V2, they (and the piex code) + ran in the background page of the image_loader extension. With Manifest V3 + (adopted in 2024), that was split into an offscreen document (where the piex + code, background.js and background.html all run) and a service worker. --> <script type="module" src="background.js"></script>
diff --git a/ui/file_manager/image_loader/background.ts b/ui/file_manager/image_loader/background.ts index eff46fa..14e8a8fe 100644 --- a/ui/file_manager/image_loader/background.ts +++ b/ui/file_manager/image_loader/background.ts
@@ -3,10 +3,19 @@ // found in the LICENSE file. /** - * @fileoverview Entry point for Image Loader. + * @fileoverview Entry point for the Image Loader's offscreen document. */ import {ImageLoader} from './image_loader.js'; +import type {LoadImageRequest, LoadImageResponse} from './load_image_request.js'; -// Load the extension. -ImageLoader.getInstance(); +const EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp'; + +chrome.runtime.onMessage.addListener( + (msg: LoadImageRequest, sender: chrome.runtime.MessageSender, + sendResponse: (r: LoadImageResponse) => void) => { + if ((sender.id !== EXTENSION_ID) || !msg.imageLoaderRequestId) { + return false; + } + return ImageLoader.getInstance().handle(msg, sendResponse); + });
diff --git a/ui/file_manager/image_loader/image_loader.ts b/ui/file_manager/image_loader/image_loader.ts index 492af19..581c0430 100644 --- a/ui/file_manager/image_loader/image_loader.ts +++ b/ui/file_manager/image_loader/image_loader.ts
@@ -8,8 +8,7 @@ import type {ImageTransformParam} from './image_orientation.js'; import {ImageOrientation} from './image_orientation.js'; import {ImageRequestTask} from './image_request_task.js'; -import type {LoadImageResponse} from './load_image_request.js'; -import {type LoadImageRequest} from './load_image_request.js'; +import type {LoadImageRequest, LoadImageResponse} from './load_image_request.js'; import {Scheduler} from './scheduler.js'; let instance: ImageLoader|null = null; @@ -31,52 +30,29 @@ constructor() { // Initialize the cache and then start the scheduler. this.cache_.initialize(() => this.scheduler_.start()); - - // Listen for incoming requests. - chrome.runtime.onMessageExternal.addListener( - (msg, sender, sendResponse) => { - if (!sender.origin || !msg) { - return; - } - - if (ALLOWED_CLIENT_ORIGINS.indexOf(sender.origin) === -1) { - return; - } - - this.onIncomingRequest_(msg, sender.origin, sendResponse); - }); - - chrome.runtime.onConnectNative.addListener(port => { - assert(port.sender); - if (port.sender.nativeApplication !== 'com.google.ash_thumbnail_loader') { - port.disconnect(); - return; - } - - port.onMessage.addListener(msg => { - // Each connection is expected to handle a single request only. - const started = this.onIncomingRequest_( - msg, port.sender!.nativeApplication!, response => { - port.postMessage(response); - port.disconnect(); - }); - - if (!started) { - port.disconnect(); - } - }); - }); } /** - * Handler for incoming requests. + * Handles a request. Depending on type of the request, starts or stops + * an image task. + * @return True if the message channel should stay alive until the + * sendResponse callback is called. */ - private onIncomingRequest_( - request: LoadImageRequest, senderOrigin: string, - sendResponse: (r: unknown) => void) { + handle( + request: LoadImageRequest, + sendResponse: (r: LoadImageResponse) => void): boolean { + assert(request.imageLoaderRequestId); + if (request.cancel) { + this.scheduler_.remove(request.imageLoaderRequestId); + return false; + } + + // When manually debugging the Image Loader extension, you can reply with + // a placeholder image here by patching in https://crrev.com/c/5796592 + // Sending a response may fail if the receiver already went offline. // This is not an error, but a normal and quite common situation. - const failSafeSendResponse = function(response: unknown) { + const failSafeSendResponse = function(response: LoadImageResponse) { try { sendResponse(response); } catch (e) { @@ -93,29 +69,12 @@ } else { request.orientation = new ImageOrientation(1, 0, 0, 1); } - return this.onMessage_(senderOrigin, request, failSafeSendResponse); - } - /** - * Handles a request. Depending on type of the request, starts or stops - * an image task. - * @return True if the message channel should stay alive until the - * callback is called. - */ - private onMessage_( - senderOrigin: string, request: LoadImageRequest, - callback: (r: LoadImageResponse) => void): boolean { - const requestId = senderOrigin + ':' + request.taskId; - if (request.cancel) { - // Cancel a task. - this.scheduler_.remove(requestId); - return false; // No callback calls. - } - // Create a request task and add it to the scheduler (queue). - const requestTask = - new ImageRequestTask(requestId, this.cache_, request, callback); - this.scheduler_.add(requestTask); - return true; // Request will call the callback. + // Add a new request task to the scheduler (queue). + this.scheduler_.add(new ImageRequestTask( + request.imageLoaderRequestId, this.cache_, request, + failSafeSendResponse)); + return true; } /** @@ -128,10 +87,3 @@ return instance; } } - -/** - * List of extensions allowed to perform image requests. - */ -const ALLOWED_CLIENT_ORIGINS = [ - 'chrome://file-manager', // File Manager SWA -];
diff --git a/ui/file_manager/image_loader/image_request_task.ts b/ui/file_manager/image_loader/image_request_task.ts index 40ea430..a2d44bd 100644 --- a/ui/file_manager/image_loader/image_request_task.ts +++ b/ui/file_manager/image_loader/image_request_task.ts
@@ -32,38 +32,17 @@ */ function callImageLoaderPrivate(msg: PrivateApi): Promise<string> { return new Promise<string>((resolve, reject) => { - const callback = (thumbnailDataUrl: string) => { - if (chrome.runtime.lastError) { - console.warn(chrome.runtime.lastError.message); - reject(chrome.runtime.lastError); - } else if (thumbnailDataUrl) { - resolve(thumbnailDataUrl); - } else { - reject(); - } - }; - - if (msg.apiMethod === 'getDriveThumbnail') { - chrome.imageLoaderPrivate.getDriveThumbnail( - msg.params.url, - msg.params.cropToSquare, - callback, - ); - } else if (msg.apiMethod === 'getPdfThumbnail') { - chrome.imageLoaderPrivate.getPdfThumbnail( - msg.params.url, - msg.params.width, - msg.params.height, - callback, - ); - } else if (msg.apiMethod === 'getArcDocumentsProviderThumbnail') { - chrome.imageLoaderPrivate.getArcDocumentsProviderThumbnail( - msg.params.url, - msg.params.widthHint, - msg.params.heightHint, - callback, - ); - } + chrome.runtime.sendMessage( + null, msg, undefined, (thumbnailDataUrl: string) => { + if (chrome.runtime.lastError) { + console.warn(chrome.runtime.lastError.message); + reject(chrome.runtime.lastError); + } else if (thumbnailDataUrl) { + resolve(thumbnailDataUrl); + } else { + reject(); + } + }); }); }
diff --git a/ui/file_manager/image_loader/load_image_request.ts b/ui/file_manager/image_loader/load_image_request.ts index 53993656..ca5c0ea 100644 --- a/ui/file_manager/image_loader/load_image_request.ts +++ b/ui/file_manager/image_loader/load_image_request.ts
@@ -105,6 +105,7 @@ maxHeight?: number; // Parts that control the request flow. + imageLoaderRequestId?: string; taskId?: number; cancel?: boolean; crop?: boolean;
diff --git a/ui/file_manager/image_loader/manifest.json b/ui/file_manager/image_loader/manifest.json index c0d36ae..e174325e 100644 --- a/ui/file_manager/image_loader/manifest.json +++ b/ui/file_manager/image_loader/manifest.json
@@ -2,18 +2,21 @@ // chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDowC9B4+K6zbl4PnALNyOUgra/MPdD8gZ39Fk/IAJWt03qrN7vz1gd/mmrBg0EEIsyLRmUmfyVEfvcIUOZxFqn4A9D2aaRSvNHy9qkasZMBDEql8Nt2iNZm/kGS7sizidDV6Bc/vyLNiH1gKOXBQ42JIxKjgtrmnhGV2giw2vJGwIDAQAB", "name": "Image loader", - "version": "0.2", + "version": "0.3", "description": "Image loader", "incognito" : "split", - "manifest_version": 2, + "manifest_version": 3, "permissions": [ "imageLoaderPrivate", - "nativeMessaging" + "nativeMessaging", + "offscreen" ], - "content_security_policy": "default-src 'none'; script-src 'self' 'wasm-eval' blob: filesystem:; style-src 'self' blob: filesystem:; frame-src 'self' blob: filesystem:; img-src 'self' blob: filesystem: data:; media-src 'self' blob: filesystem:; connect-src 'self' blob: filesystem:", + "content_security_policy": { + "extension_pages": "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self' blob: filesystem:; img-src 'self' blob: filesystem: data:; media-src 'self' blob: filesystem:; connect-src 'self' blob: filesystem:" + }, "background": { - "page": "background.html", - "persistent": false + "service_worker": "service_worker.js", + "type": "module" }, "externally_connectable": { "matches": [ @@ -22,8 +25,16 @@ }, "natively_connectable": ["com.google.ash_thumbnail_loader"], "web_accessible_resources": [ - "image_loader_client.js", - "image_orientation.js", - "load_image_request.js" + { + "resources": [ + "image_loader_client.js", + "image_orientation.js", + "load_image_request.js" + ], + "matches": [ + "chrome://file-manager/*", // File Manager SWA + "chrome://webui-test/*" + ] + } ] }
diff --git a/ui/file_manager/image_loader/service_worker.ts b/ui/file_manager/image_loader/service_worker.ts new file mode 100644 index 0000000..4b81695 --- /dev/null +++ b/ui/file_manager/image_loader/service_worker.ts
@@ -0,0 +1,143 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Entry point for the Image Loader's service worker. + */ + +import {assert} from 'chrome://resources/js/assert.js'; + +import type {LoadImageRequest, LoadImageResponse} from './load_image_request.js'; +import type {PrivateApi} from './sw_od_messages.js'; + +const EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp'; + +const ALLOW_LISTED_FILE_MANAGER_SWA = 'chrome://file-manager'; +const ALLOW_LISTED_NATIVE = 'com.google.ash_thumbnail_loader'; + +// setupOffscreenDocument is based on +// https://developer.chrome.com/docs/extensions/reference/api/offscreen#maintain_the_lifecycle_of_an_offscreen_document +let creatingOffscreenDocument: Promise<void>|undefined; +async function setupOffscreenDocument() { + const url = chrome.runtime.getURL('background.html'); + const existingContexts = await chrome.runtime.getContexts({ + contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT], + documentUrls: [url], + }); + if (existingContexts.length > 0) { + return; + } + + if (creatingOffscreenDocument) { + await creatingOffscreenDocument; + return; + } + + creatingOffscreenDocument = chrome.offscreen.createDocument({ + url: url, + // 'USER_MEDIA' isn't quite right, since we never call getUserMedia, but + // it's the closest listed reason from + // https://developer.chrome.com/docs/extensions/reference/api/offscreen#type-Reason + reasons: [chrome.offscreen.Reason.USER_MEDIA], + justification: 'Lets us use <img>, <canvas> and XMLHttpRequest', + }); + await creatingOffscreenDocument; + creatingOffscreenDocument = undefined; +} + +// Forwards a message from the service worker to the offscreen document. +// +// sendResponse will not be called if msg.cancel is truthy. See the +// ImageLoader.handle method. +async function sendToOffscreenDocument( + msg: LoadImageRequest, senderOrigin: string, + sendResponse: (r: LoadImageResponse) => void) { + assert(msg); + await setupOffscreenDocument(); + msg.imageLoaderRequestId = senderOrigin + ':' + msg.taskId; + chrome.runtime.sendMessage( + null, msg, undefined, (response: LoadImageResponse) => { + sendResponse(response); + }); +} + +// Handle imageLoaderPrivate calls on behalf of the offscreen document. +chrome.runtime.onMessage.addListener( + (msg: PrivateApi, sender: chrome.runtime.MessageSender, + sendResponse: (thumbnailDataUrl: string) => void) => { + if (sender.id !== EXTENSION_ID) { + return false; + } else if (msg.apiMethod === 'getArcDocumentsProviderThumbnail') { + chrome.imageLoaderPrivate.getArcDocumentsProviderThumbnail( + msg.params.url, + msg.params.widthHint, + msg.params.heightHint, + sendResponse, + ); + return true; + } else if (msg.apiMethod === 'getDriveThumbnail') { + chrome.imageLoaderPrivate.getDriveThumbnail( + msg.params.url, + msg.params.cropToSquare, + sendResponse, + ); + return true; + } else if (msg.apiMethod === 'getPdfThumbnail') { + chrome.imageLoaderPrivate.getPdfThumbnail( + msg.params.url, + msg.params.width, + msg.params.height, + sendResponse, + ); + return true; + } + return false; + }); + +// Listen to messages from the Files app SWA. +chrome.runtime.onMessageExternal.addListener( + (msg: LoadImageRequest, sender: chrome.runtime.MessageSender, + sendResponse: (r: LoadImageResponse) => void) => { + if (!msg || (sender.origin !== ALLOW_LISTED_FILE_MANAGER_SWA)) { + return false; + } + sendToOffscreenDocument(msg, ALLOW_LISTED_FILE_MANAGER_SWA, sendResponse); + // Return true (or false) if the runtime should keep sendResponse + // valid-to-call (or invalid) after this closure returns. + // + // If msg.cancel is truthy then sendToOffscreenDocument will not call + // sendResponse, so we can return false. + // + // If msg.cancel is falsy then sendToOffscreenDocument will call it, but + // also asynchronously, so return true. + return !msg.cancel; + }); + +// Listen to messages from ash-chrome itself, e.g. thumbnails in the "tote" +// (also known as the "holding space"), after taking a screenshot. +// +// Each native connection is expected to send a single request only, so we +// disconnect after handling a message. +chrome.runtime.onConnectNative.addListener((port: chrome.runtime.Port) => { + assert(port.sender); + if (port.sender.nativeApplication !== ALLOW_LISTED_NATIVE) { + port.disconnect(); + return; + } + + port.onMessage.addListener((msg: LoadImageRequest) => { + if (!msg) { + port.disconnect(); + return; + } else if (msg.cancel) { + port.disconnect(); + } + sendToOffscreenDocument( + msg, ALLOW_LISTED_NATIVE, (response: LoadImageResponse) => { + assert(!msg.cancel); + port.postMessage(response); + port.disconnect(); + }); + }); +});
diff --git a/v8 b/v8 index 3babfc4..68c1142 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 3babfc4ae2a1ceb3454a1f0d19073263f67829df +Subproject commit 68c1142d37c4edb8e02e022dd8fbacaf396c4dd9