diff --git a/BUILD.gn b/BUILD.gn index e705d6b..6d73d23 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -1607,7 +1607,7 @@ "chrome/test:closure_compile", "components/flags_ui/resources:closure_compile", "components/neterror/resources:closure_compile", - "components/security_interstitials/core/common/resources:closure_compile", + "components/security_interstitials:closure_compile", "components/sync/driver/resources:closure_compile", "components/ukm/debug:closure_compile", "content/browser/resources:closure_compile",
diff --git a/DEPS b/DEPS index ee1ebb40..aebce120 100644 --- a/DEPS +++ b/DEPS
@@ -257,11 +257,11 @@ # 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': '4a29e433a8ca9aae93e896b17c5b802a941573a5', + 'v8_revision': 'eef950da8dd11f337e13a68123fc24b7a1e47ea1', # 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': '3154b00bab776e366538e712558a7f8c2967d4ca', + 'angle_revision': '223a25f0133d18935ef507108b7320e8d7024f96', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -320,7 +320,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '4ac0eac51b57114d5a50793dee6ffbda9859850f', + 'catapult_revision': '58ce6f9e689bd01661c62e7464497f03e8ec003f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -328,7 +328,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '38e1e62439337f92c85c952ebafbd1f6e99bacf2', + 'devtools_frontend_revision': 'e0e85d0a5a6c4337ff3b496b20257ab41e09aaec', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -368,7 +368,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': 'bf44da52b98e7b3d8bd3a8b8aae39c38ec480ad9', + 'dawn_revision': 'b573ec0cda64b62f14de7732f424970a90865752', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1131,7 +1131,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '64f5f26f1a0c8b8333514cdb861847f02d405f36', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '306b03b1912affcae0dbecbe5aa36b414fb4ae2a', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1592,7 +1592,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/android/aemu/release/linux-amd64', - 'version': 'j_0klEfkeAK-jFzzDKYCntyRDJ8Kv5mtaXHQhMA2vzIC' + 'version': 'IA5TOLWvQAyOg7VT0EEiRUO0WmTSicdQksvsnBBcIUEC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1735,7 +1735,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '30f22785e9b13ea82b2a9f67208a13fcc7b017c3', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '36cf4787d064635578cde107c9b993379b17fec6', + Var('webrtc_git') + '/src.git' + '@' + '3b393ec991ed26a36195c9f41e74b0d7d72e6953', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1762,7 +1762,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': 'td7IhN6Q3eTDLXn6p5jlbeSIDYl7rI75dlX0qj8fEEsC', + 'version': 'eZ3k373CYgRxlu4JKph6e-_7xkP02swy_jePFFMiyIQC', }, ], 'dep_type': 'cipd', @@ -1772,7 +1772,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': '5k9ZnDE42Xoqs07enkcOdWOf9jT-bhW-OXOp2fY-IR4C', + 'version': 'iEqqRADI7znrc6pG-MVnc5pBZwD25koILREPC6x2AFAC', }, ], 'dep_type': 'cipd', @@ -1783,7 +1783,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'im5u9GiTMHxNcLH_Nc2X3RqzjfDs2oDmC0VhkLgUCeYC', + 'version': 'nHUjLIViYsLxRjv-zDdmzqT8p1R3VoyHq5gdGkKeMYwC', }, ], 'dep_type': 'cipd', @@ -1794,7 +1794,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-arm64', - 'version': 'edDMT5wDXf_HjD5qeNPgIEmYXDGUB1BswQ0G84CQBdUC', + 'version': '-mc865SGfJAqreLZM6fkn8tgCJ7u5QLk5zm7r-ZRJ9gC', }, ], 'dep_type': 'cipd', @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a0657139bdfb2bb07c4046abab66c0a2c6c3ff27', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@37960f1892877ac789c8d8eed734048272e60b4c', 'condition': 'checkout_src_internal', }, @@ -1857,7 +1857,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'G3YbquTP38UsyZKhNKvJa-ujaz4g3GiPsi7WjcaA3ucC', + 'version': 'khvsZHSVS5sYkhT--IuQFMPYy_A6D2forFACfSue-OQC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/system/accessibility/dictation_bubble_view.cc b/ash/system/accessibility/dictation_bubble_view.cc index 3be13c9..01d6ce01 100644 --- a/ash/system/accessibility/dictation_bubble_view.cc +++ b/ash/system/accessibility/dictation_bubble_view.cc
@@ -39,24 +39,42 @@ constexpr SkColor kDefaultTextAndIconColorPrimary = SK_ColorBLACK; constexpr SkColor kDefaultTextAndIconColorSecondary = SK_ColorDKGRAY; +SkColor text_color_primary() { + if (!features::IsDarkLightModeEnabled()) + return kDefaultTextAndIconColorPrimary; + + return AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorPrimary); +} + +SkColor icon_color_primary() { + if (!features::IsDarkLightModeEnabled()) + return kDefaultTextAndIconColorPrimary; + + return AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kIconColorPrimary); +} + +SkColor text_color_secondary() { + if (!features::IsDarkLightModeEnabled()) + return kDefaultTextAndIconColorSecondary; + + return AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorSecondary); +} + std::unique_ptr<views::ImageView> CreateImageView( views::ImageView** destination_view, const gfx::VectorIcon& icon) { - SkColor color = - features::IsDarkLightModeEnabled() - ? AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary) - : kDefaultTextAndIconColorPrimary; return views::Builder<views::ImageView>() .CopyAddressTo(destination_view) - .SetImage(gfx::CreateVectorIcon(icon, kIconSizeDip, color)) + .SetImage(gfx::CreateVectorIcon(icon, kIconSizeDip, icon_color_primary())) .Build(); } -void SetImageHelper(views::ImageView* image_view, - const gfx::VectorIcon& icon, - SkColor color) { - image_view->SetImage(gfx::CreateVectorIcon(icon, kIconSizeDip, color)); +void SetImageHelper(views::ImageView* image_view, const gfx::VectorIcon& icon) { + image_view->SetImage( + gfx::CreateVectorIcon(icon, kIconSizeDip, icon_color_primary())); } std::unique_ptr<views::Label> CreateLabelView(views::Label** destination_view, @@ -109,13 +127,8 @@ kDictationBubbleMacroSucceededIcon)); AddChildView( CreateImageView(¯o_failed_image_, kDictationBubbleMacroFailedIcon)); - - SkColor text_color = - features::IsDarkLightModeEnabled() - ? AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary) - : kDefaultTextAndIconColorPrimary; - AddChildView(CreateLabelView(&label_, std::u16string(), text_color)); + AddChildView( + CreateLabelView(&label_, std::u16string(), text_color_primary())); } TopRowView(const TopRowView&) = delete; @@ -127,12 +140,12 @@ void Update(DictationBubbleIconType icon, const absl::optional<std::u16string>& text) { // Update visibility. + bool is_standby = icon == DictationBubbleIconType::kStandby; if (use_standby_animation_) { - standby_animation_->SetVisible(icon == DictationBubbleIconType::kStandby); - icon == DictationBubbleIconType::kStandby ? standby_animation_->Play() - : standby_animation_->Stop(); + standby_animation_->SetVisible(is_standby); + is_standby ? standby_animation_->Play() : standby_animation_->Stop(); } else { - standby_image_->SetVisible(icon == DictationBubbleIconType::kStandby); + standby_image_->SetVisible(is_standby); } macro_succeeded_image_->SetVisible(icon == @@ -148,21 +161,12 @@ // Updates this view so that it respects the global dark mode setting. void OnColorModeChanged(bool dark_mode_enabled) { - AshColorProvider* color_provider = AshColorProvider::Get(); - if (!color_provider) - return; - - SkColor icon_color = color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary); - SkColor text_color = color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary); if (!use_standby_animation_) - SetImageHelper(standby_image_, kDictationBubbleIcon, icon_color); - SetImageHelper(macro_succeeded_image_, kDictationBubbleMacroSucceededIcon, - icon_color); - SetImageHelper(macro_failed_image_, kDictationBubbleMacroFailedIcon, - icon_color); - label_->SetEnabledColor(text_color); + SetImageHelper(standby_image_, kDictationBubbleIcon); + + SetImageHelper(macro_succeeded_image_, kDictationBubbleMacroSucceededIcon); + SetImageHelper(macro_failed_image_, kDictationBubbleMacroFailedIcon); + label_->SetEnabledColor(text_color_primary()); } // views::View: @@ -171,7 +175,7 @@ } private: - friend DictationBubbleView; + friend class ash::DictationBubbleView; // Returns a std::unique_ptr<AnimatedImageView> if the standby animation // can successfully be loaded. Otherwise, returns a std::unique_ptr<ImageView> @@ -223,18 +227,11 @@ layout->set_between_child_spacing(kSpaceBetweenHintLabelsDip); SetLayoutManager(std::move(layout)); - bool is_dark_light_mode_enabled = features::IsDarkLightModeEnabled(); - SkColor primary = - is_dark_light_mode_enabled - ? AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary) - : kDefaultTextAndIconColorPrimary; - SkColor secondary = - is_dark_light_mode_enabled - ? AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorSecondary) - : kDefaultTextAndIconColorSecondary; + SkColor primary = text_color_primary(); + SkColor secondary = text_color_secondary(); for (size_t i = 0; i < labels_.size(); ++i) { + // The first label should use the secondary text color. All other labels + // should use the primary text color. SkColor color = i == 0 ? secondary : primary; AddChildView(CreateLabelView(&labels_[i], std::u16string(), color)); } @@ -270,8 +267,6 @@ // hints to the user. if (num_visible_hints > 0) { SetVisible(true); - // TODO(crbug.com/1252037): Write a DictationUITest to verify that - // ChromeVox announces hints. NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); } else { SetVisible(false); @@ -281,15 +276,11 @@ // Updates this view so that it respects the global dark mode setting. void OnColorModeChanged(bool dark_mode_enabled) { - AshColorProvider* color_provider = AshColorProvider::Get(); - if (!color_provider) - return; - - SkColor primary = color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary); - SkColor secondary = color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorSecondary); + SkColor primary = text_color_primary(); + SkColor secondary = text_color_secondary(); for (size_t i = 0; i < labels_.size(); ++i) { + // The first label should use the secondary text color. All other labels + // should use the primary text color. labels_[i]->SetEnabledColor(i == 0 ? secondary : primary); } } @@ -300,7 +291,7 @@ } private: - friend DictationBubbleView; + friend class ash::DictationBubbleView; // Labels containing hints for users of Dictation. A max of five hints can be // shown at any given time.
diff --git a/ash/webui/camera_app_ui/resources/.eslintrc.js b/ash/webui/camera_app_ui/resources/.eslintrc.js index 8825ca3c..4a9a308 100644 --- a/ash/webui/camera_app_ui/resources/.eslintrc.js +++ b/ash/webui/camera_app_ui/resources/.eslintrc.js
@@ -478,5 +478,38 @@ // This is covered by @typescript-eslint/naming-convention. 'camelcase': 'off', + + // go/tsstyle#arrayt-type + '@typescript-eslint/array-type': [ + 'error', + { + 'default': 'array-simple', + }, + ], + + // go/tsstyle#type-assertions-syntax + // go/tsstyle#type-assertions-and-object-literals + '@typescript-eslint/consistent-type-assertions': [ + 'error', + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'never', + }, + ], + + // go/tsstyle#interfaces-vs-type-aliases + '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], }), + 'overrides': [{ + files: ['**/*.ts'], + parserOptions: { + // eslint-disable-next-line no-undef + tsconfigRootDir: __dirname, + project: './tsconfig_base.json', + }, + rules: { + // go/tsstyle#use-readonly + '@typescript-eslint/prefer-readonly': 'error', + }, + }], };
diff --git a/ash/webui/camera_app_ui/resources/js/app_window.ts b/ash/webui/camera_app_ui/resources/js/app_window.ts index 57157d0..af7a61a 100644 --- a/ash/webui/camera_app_ui/resources/js/app_window.ts +++ b/ash/webui/camera_app_ui/resources/js/app_window.ts
@@ -52,7 +52,7 @@ private inClosingItself = false; private readonly errors: ErrorInfo[] = []; private readonly perfs: PerfEntry[] = []; - private launchedTime = performance.now(); + private readonly launchedTime = performance.now(); /** * @param fromColdStart Whether this app is launched from a cold start. It is * used for performance measurement.
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts index 97ea1919..35b77bfc 100644 --- a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts +++ b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
@@ -322,12 +322,12 @@ export class OperationScheduler { public cameraInfo: CameraInfo|null = null; private pendingUpdateInfo: CameraInfo|null = null; - private firstInfoUpdate = new WaitableEvent(); + private readonly firstInfoUpdate = new WaitableEvent(); readonly reconfigurer: Reconfigurer; readonly capturer: Capturer; private ongoingOperationType: OperationType|null = null; - private pendingReconfigureWaiters: CancelableEvent<boolean>[] = []; + private pendingReconfigureWaiters: Array<CancelableEvent<boolean>> = []; public readonly photoPreferrer = new PhotoConstraintsPreferrer(); public readonly videoPreferrer = new VideoConstraintsPreferrer(); public readonly modes: Modes;
diff --git a/ash/webui/camera_app_ui/resources/js/device/device_info_updater.ts b/ash/webui/camera_app_ui/resources/js/device/device_info_updater.ts index 6d0ea98b..9ef595f 100644 --- a/ash/webui/camera_app_ui/resources/js/device/device_info_updater.ts +++ b/ash/webui/camera_app_ui/resources/js/device/device_info_updater.ts
@@ -164,7 +164,7 @@ /** * Gets Camera3DeviceInfo for all available video devices. */ - getCamera3DevicesInfo(): Array<Camera3DeviceInfo>|null { + getCamera3DevicesInfo(): Camera3DeviceInfo[]|null { return this.camera3DevicesInfo; } }
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts index c415cfb5..609f244 100644 --- a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts +++ b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
@@ -179,7 +179,7 @@ /** * Record-time for the elapsed gif recording time. */ - private gifRecordTime: GifRecordTime; + private readonly gifRecordTime: GifRecordTime; /** * Record type of ongoing recording.
diff --git a/ash/webui/camera_app_ui/resources/js/device/stream_manager.ts b/ash/webui/camera_app_ui/resources/js/device/stream_manager.ts index 1674b05..31a9115 100644 --- a/ash/webui/camera_app_ui/resources/js/device/stream_manager.ts +++ b/ash/webui/camera_app_ui/resources/js/device/stream_manager.ts
@@ -85,7 +85,7 @@ /** * Filter out lagging 720p on grunt. See https://crbug.com/1122852. */ - private videoConfigFilter: (config: VideoConfig) => boolean; + private readonly videoConfigFilter: (config: VideoConfig) => boolean; private constructor() { this.videoConfigFilter = (() => {
diff --git a/ash/webui/camera_app_ui/resources/js/device/type.ts b/ash/webui/camera_app_ui/resources/js/device/type.ts index 7819819..e59f0be 100644 --- a/ash/webui/camera_app_ui/resources/js/device/type.ts +++ b/ash/webui/camera_app_ui/resources/js/device/type.ts
@@ -17,8 +17,8 @@ export type CameraViewUI = CaptureHandler; export class CameraInfo { - readonly devicesInfo: Array<MediaDeviceInfo>; - readonly camera3DevicesInfo: Array<Camera3DeviceInfo>|null; + readonly devicesInfo: MediaDeviceInfo[]; + readonly camera3DevicesInfo: Camera3DeviceInfo[]|null; private readonly idToDeviceInfo: Map<string, MediaDeviceInfo>; private readonly idToCamera3DeviceInfo: Map<string, Camera3DeviceInfo>|null;
diff --git a/ash/webui/camera_app_ui/resources/js/externs/types.d.ts b/ash/webui/camera_app_ui/resources/js/externs/types.d.ts index fc01b20..c1e5fbd7 100644 --- a/ash/webui/camera_app_ui/resources/js/externs/types.d.ts +++ b/ash/webui/camera_app_ui/resources/js/externs/types.d.ts
@@ -85,7 +85,7 @@ interface Window { loadTimeData: { getBoolean(id: string): boolean; getString(id: string): string; - getStringF(id: string, ...args: (number|string)[]): string; + getStringF(id: string, ...args: Array<number|string>): string; } } @@ -104,16 +104,16 @@ // Chrome private API for crash report. declare namespace chrome.crashReportPrivate { - export type ErrorInfo = { - message: string, - url: string, - columnNumber?: number, - debugId?: string, - lineNumber?: number, - product?: string, - stackTrace?: string, - version?: string, - }; + export interface ErrorInfo { + message: string; + url: string; + columnNumber?: number; + debugId?: string; + lineNumber?: number; + product?: string; + stackTrace?: string; + version?: string; + } export const reportError: (info: ErrorInfo, callback: () => void) => void; } @@ -152,7 +152,7 @@ type LaunchConsumer = (params: LaunchParams) => void; interface LaunchParams { - readonly files: ReadonlyArray<FileSystemHandle>; + readonly files: readonly FileSystemHandle[]; } // HTMLVideoElement.requestVideoFrameCallback, this is currently available in @@ -196,7 +196,7 @@ boundingBox: DOMRectReadOnly; rawValue: string; format: BarcodeFormat; - cornerPoints: ReadonlyArray<Point2D>; + cornerPoints: readonly Point2D[]; } type BarcodeFormat =
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts index aa7188b..174106f6 100644 --- a/ash/webui/camera_app_ui/resources/js/main.ts +++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -52,11 +52,11 @@ * Creates the Camera App main object. */ export class App { - private perfLogger: PerfLogger; - private intent: Intent|null; + private readonly perfLogger: PerfLogger; + private readonly intent: Intent|null; private readonly cameraManager: CameraManager; - private galleryButton = new GalleryButton(); - private cameraView: Camera; + private readonly galleryButton = new GalleryButton(); + private readonly cameraView: Camera; constructor({perfLogger, intent, facing, mode: defaultMode}: { perfLogger: PerfLogger,
diff --git a/ash/webui/camera_app_ui/resources/js/models/load_time_data.ts b/ash/webui/camera_app_ui/resources/js/models/load_time_data.ts index 75cb4d5..cb70c45 100644 --- a/ash/webui/camera_app_ui/resources/js/models/load_time_data.ts +++ b/ash/webui/camera_app_ui/resources/js/models/load_time_data.ts
@@ -23,7 +23,7 @@ * Returns the I18N message generated by given |name| and |substitutions|. */ export function getI18nMessage( - name: I18nString, ...substitutions: (string|number)[]): string { + name: I18nString, ...substitutions: Array<string|number>): string { return window.loadTimeData.getStringF(name, ...substitutions); }
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts index 975c583b..24498bbc 100644 --- a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts +++ b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
@@ -64,7 +64,7 @@ /** * An interface remote that is used to communicate with Chrome. */ - private remote: CameraAppHelperRemote = + private readonly remote: CameraAppHelperRemote = wrapEndpoint(CameraAppHelper.getRemote()); /**
diff --git a/ash/webui/camera_app_ui/resources/js/views/crop_document.ts b/ash/webui/camera_app_ui/resources/js/views/crop_document.ts index 3e175f2..ffa4398 100644 --- a/ash/webui/camera_app_ui/resources/js/views/crop_document.ts +++ b/ash/webui/camera_app_ui/resources/js/views/crop_document.ts
@@ -119,7 +119,7 @@ * View controller for review document crop area page. */ export class CropDocument extends Review<boolean> { - private imageFrame: HTMLDivElement; + private readonly imageFrame: HTMLDivElement; /** * Size of image frame. @@ -137,8 +137,8 @@ */ private cornerSpaceSize: Size|null = null; - private cropAreaContainer: SVGElement; - private cropArea: SVGPolygonElement; + private readonly cropAreaContainer: SVGElement; + private readonly cropArea: SVGPolygonElement; /** * Index of |ROTATION| as current photo rotation. @@ -146,7 +146,7 @@ private rotation = 0; private initialCorners: Point[] = []; - private corners: Corner[]; + private readonly corners: Corner[]; constructor() { super(ViewName.CROP_DOCUMENT);
diff --git a/ash/webui/camera_app_ui/resources/js/views/dialog.ts b/ash/webui/camera_app_ui/resources/js/views/dialog.ts index 36748ffa..0645d734 100644 --- a/ash/webui/camera_app_ui/resources/js/views/dialog.ts +++ b/ash/webui/camera_app_ui/resources/js/views/dialog.ts
@@ -12,7 +12,7 @@ * Creates the Dialog view controller. */ export class Dialog extends View { - private positiveButton: HTMLButtonElement; + private readonly positiveButton: HTMLButtonElement; private negativeButton: HTMLButtonElement|null; private messageHolder: HTMLElement;
diff --git a/ash/webui/camera_app_ui/resources/js/views/review.ts b/ash/webui/camera_app_ui/resources/js/views/review.ts index dfcda98..6bedacf 100644 --- a/ash/webui/camera_app_ui/resources/js/views/review.ts +++ b/ash/webui/camera_app_ui/resources/js/views/review.ts
@@ -57,7 +57,7 @@ * Group of review options. */ export class OptionGroup<T> { - readonly options: Option<T>[]; + readonly options: Array<Option<T>>; readonly template: ButtonGroupTemplate; /** Constructs Options. */
diff --git a/ash/webui/camera_app_ui/resources/js/waitable_event.ts b/ash/webui/camera_app_ui/resources/js/waitable_event.ts index 0365bcd..593308a 100644 --- a/ash/webui/camera_app_ui/resources/js/waitable_event.ts +++ b/ash/webui/camera_app_ui/resources/js/waitable_event.ts
@@ -12,7 +12,7 @@ // recognize that. Disable the check by adding "!" to the property name. protected resolve!: (val: T) => void; protected reject!: (val: Error) => void; - private promise: Promise<T>; + private readonly promise: Promise<T>; constructor() { this.promise = new Promise((resolve, reject) => {
diff --git a/ash/webui/eche_app_ui/eche_message_receiver_impl_unittest.cc b/ash/webui/eche_app_ui/eche_message_receiver_impl_unittest.cc index 2f79bd9..a03362d 100644 --- a/ash/webui/eche_app_ui/eche_message_receiver_impl_unittest.cc +++ b/ash/webui/eche_app_ui/eche_message_receiver_impl_unittest.cc
@@ -23,6 +23,8 @@ size_t apps_setup_response_num_calls() const { return apps_setup_response_; } + size_t status_change_num_calls() const { return status_change_num_calls_; } + proto::GetAppsAccessStateResponse get_last_apps_access_state() const { return last_apps_access_state_response_; } @@ -31,6 +33,10 @@ return last_apps_setup_reponse_; } + proto::StatusChangeType get_last_status_change_type() const { + return last_status_change_type_; + } + // EcheMessageReceiver::Observer: void OnGetAppsAccessStateResponseReceived( proto::GetAppsAccessStateResponse apps_access_state_response) override { @@ -42,13 +48,18 @@ last_apps_setup_reponse_ = apps_setup_response; ++apps_setup_response_; } - void OnStatusChange(proto::StatusChangeType status_change_type) override {} + void OnStatusChange(proto::StatusChangeType status_change_type) override { + last_status_change_type_ = status_change_type; + ++status_change_num_calls_; + } private: size_t apps_access_state_response_num_calls_ = 0; size_t apps_setup_response_ = 0; + size_t status_change_num_calls_ = 0; proto::GetAppsAccessStateResponse last_apps_access_state_response_; proto::SendAppsSetupResponse last_apps_setup_reponse_; + proto::StatusChangeType last_status_change_type_; }; } // namespace @@ -81,6 +92,10 @@ return fake_observer_.apps_setup_response_num_calls(); } + size_t GetNumStatusChangeCalls() const { + return fake_observer_.status_change_num_calls(); + } + proto::GetAppsAccessStateResponse GetLastAppsAccessState() const { return fake_observer_.get_last_apps_access_state(); } @@ -89,6 +104,10 @@ return fake_observer_.get_last_apps_setup_response(); } + proto::StatusChangeType GetLastStatusChangeType() const { + return fake_observer_.get_last_status_change_type(); + } + FakeObserver fake_observer_; std::unique_ptr<secure_channel::FakeConnectionManager> fake_connection_manager_; @@ -110,6 +129,7 @@ EXPECT_EQ(1u, GetNumAppsAccessStateResponseCalls()); EXPECT_EQ(0u, GetNumAppsSetupResponseCalls()); + EXPECT_EQ(0u, GetNumStatusChangeCalls()); EXPECT_EQ(eche_app::proto::Result::RESULT_ERROR_ACTION_FAILED, actual_apps_state.result()); EXPECT_EQ(eche_app::proto::AppsAccessState::ACCESS_GRANTED, @@ -131,11 +151,28 @@ EXPECT_EQ(0u, GetNumAppsAccessStateResponseCalls()); EXPECT_EQ(1u, GetNumAppsSetupResponseCalls()); + EXPECT_EQ(0u, GetNumStatusChangeCalls()); EXPECT_EQ(eche_app::proto::Result::RESULT_ERROR_ACTION_FAILED, actual_apps_setup_response.result()); EXPECT_EQ(eche_app::proto::AppsAccessState::ACCESS_GRANTED, actual_apps_setup_response.apps_access_state()); } +TEST_F(EcheMessageReceiverImplTest, OnStatusChangeReceived) { + proto::StatusChange status_change; + status_change.set_type(proto::StatusChangeType::TYPE_STREAM_START); + proto::ExoMessage message; + *message.mutable_status_change() = std::move(status_change); + + fake_connection_manager_->NotifyMessageReceived(message.SerializeAsString()); + + proto::StatusChangeType status_change_type = GetLastStatusChangeType(); + + EXPECT_EQ(0u, GetNumAppsAccessStateResponseCalls()); + EXPECT_EQ(0u, GetNumAppsSetupResponseCalls()); + EXPECT_EQ(1u, GetNumStatusChangeCalls()); + EXPECT_EQ(proto::StatusChangeType::TYPE_STREAM_START, status_change_type); +} + } // namespace eche_app } // namespace ash
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc index ffabc6b3..d5a0e6e 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -273,6 +273,20 @@ TransitionNextStateGeneric(std::move(callback)); } +void ShimlessRmaService::SetWipeDevice(bool should_wipe_device, + SetWipeDeviceCallback callback) { + if (state_proto_.state_case() != rmad::RmadState::kWipeSelection) { + LOG(ERROR) << "SetWipeDevice called from incorrect state " + << state_proto_.state_case(); + std::move(callback).Run(RmadStateToMojo(state_proto_.state_case()), + can_abort_, can_go_back_, + rmad::RmadErrorCode::RMAD_ERROR_REQUEST_INVALID); + return; + } + state_proto_.mutable_wipe_selection()->set_wipe_device(should_wipe_device); + TransitionNextStateGeneric(std::move(callback)); +} + void ShimlessRmaService::ChooseManuallyDisableWriteProtect( ChooseManuallyDisableWriteProtectCallback callback) { if (state_proto_.state_case() != rmad::RmadState::kWpDisableMethod) {
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.h b/ash/webui/shimless_rma/backend/shimless_rma_service.h index 3b7f747be..f909a85 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service.h +++ b/ash/webui/shimless_rma/backend/shimless_rma_service.h
@@ -52,6 +52,8 @@ void SetSameOwner(SetSameOwnerCallback callback) override; void SetDifferentOwner(SetDifferentOwnerCallback callback) override; + void SetWipeDevice(bool wipe_device, SetWipeDeviceCallback) override; + void ChooseManuallyDisableWriteProtect( ChooseManuallyDisableWriteProtectCallback callback) override; void ChooseRsuDisableWriteProtect(
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc index 1a26025..5c97e3d 100644 --- a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc +++ b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
@@ -123,6 +123,9 @@ state->set_allocated_device_destination( new rmad::DeviceDestinationState()); break; + case rmad::RmadState::kWipeSelection: + state->set_allocated_wipe_selection(new rmad::WipeSelectionState()); + break; case rmad::RmadState::kWpDisableMethod: state->set_allocated_wp_disable_method( new rmad::WriteProtectDisableMethodState()); @@ -630,6 +633,39 @@ run_loop.Run(); } +TEST_F(ShimlessRmaServiceTest, SetWipeDevice) { + const std::vector<rmad::GetStateReply> fake_states = { + CreateStateReply(rmad::RmadState::kWipeSelection, rmad::RMAD_ERROR_OK), + CreateStateReply(rmad::RmadState::kDeviceDestination, + rmad::RMAD_ERROR_OK)}; + fake_rmad_client_()->SetFakeStateReplies(std::move(fake_states)); + fake_rmad_client_()->check_state_callback = + base::BindRepeating([](const rmad::RmadState& state) { + EXPECT_EQ(state.state_case(), rmad::RmadState::kWipeSelection); + EXPECT_TRUE(state.wipe_selection().wipe_device()); + }); + base::RunLoop run_loop; + shimless_rma_provider_->GetCurrentState(base::BindLambdaForTesting( + [&](mojom::State state, bool can_cancel, bool can_go_back, + rmad::RmadErrorCode error) { + EXPECT_EQ(state, mojom::State::kChooseWipeDevice); + EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK); + })); + run_loop.RunUntilIdle(); + + const bool expected_wipe_device = true; + shimless_rma_provider_->SetWipeDevice( + expected_wipe_device, + base::BindLambdaForTesting([&](mojom::State state, bool can_cancel, + bool can_go_back, + rmad::RmadErrorCode error) { + EXPECT_EQ(state, mojom::State::kChooseDestination); + EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK); + run_loop.Quit(); + })); + run_loop.Run(); +} + TEST_F(ShimlessRmaServiceTest, SetDifferentOwnerFromWrongStateFails) { const std::vector<rmad::GetStateReply> fake_states = { CreateStateReply(rmad::RmadState::kRestock, rmad::RMAD_ERROR_OK)};
diff --git a/ash/webui/shimless_rma/mojom/shimless_rma.mojom b/ash/webui/shimless_rma/mojom/shimless_rma.mojom index 35afc98..436b4822 100644 --- a/ash/webui/shimless_rma/mojom/shimless_rma.mojom +++ b/ash/webui/shimless_rma/mojom/shimless_rma.mojom
@@ -489,6 +489,14 @@ RmadErrorCode error); /////////////////////////////////////// + // Method for kChooseWipeDevice state. + // + // Set the RMA state to wipe or preserve the device data on RMA completion. + SetWipeDevice(bool should_wipe_device) + => (State state, bool can_cancel, bool can_go_back, + RmadErrorCode error); + + /////////////////////////////////////// // Methods for kChooseWriteProtectDisableMethod state. // // Choose to disabled HWWP manually e.g. by disconnecting the battery
diff --git a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js index 871082d..e2cb3f26 100644 --- a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js +++ b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js
@@ -278,6 +278,15 @@ } /** + * @param {boolean} shouldWipeDevice + * @return {!Promise<!StateResult>} + */ + setWipeDevice(shouldWipeDevice) { + return this.getNextStateForMethod_( + 'setWipeDevice', State.kChooseWipeDevice); + } + + /** * @return {!Promise<!{available: boolean}>} */ manualDisableWriteProtectAvailable() {
diff --git a/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.html b/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.html index 4b7f702..951ccef 100644 --- a/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.html +++ b/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.html
@@ -4,14 +4,15 @@ <div slot="left-pane"> <h1>[[i18n('wipeDeviceTitleText')]]</h1> <!-- TODO(gavinwill): Replace |disabled| with variable --> - <cr-radio-group id="wipeDeviceRadioGroup" disabled> - <cr-radio-button name="wipeDevice"> + <cr-radio-group id="wipeDeviceRadioGroup" disabled="[[allButtonsDisabled]]" + on-selected-changed="onOptionChanged_"> + <cr-radio-button name="[[wipeDeviceOption_.WIPE_DEVICE]]"> [[i18n('wipeDeviceRemoveDataLabel')]] </cr-radio-button> <div class="indented-description"> [[i18n('wipeDeviceRemoveDataDescription')]] </div> - <cr-radio-button name="preserveData"> + <cr-radio-button name="[[wipeDeviceOption_.PRESERVE_DATA]]"> [[i18n('wipeDevicePreserveDataLabel')]] </cr-radio-button> <div class="indented-description">
diff --git a/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.js b/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.js index 962d6ee..ea553d0 100644 --- a/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.js +++ b/ash/webui/shimless_rma/resources/onboarding_choose_wipe_device_page.js
@@ -8,9 +8,13 @@ import '//resources/cr_elements/cr_radio_button/cr_radio_button.m.js'; import '//resources/cr_elements/cr_radio_group/cr_radio_group.m.js'; +import {assert} from 'chrome://resources/js/assert.m.js'; import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {getShimlessRmaService} from './mojo_interface_provider.js'; +import {ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js'; + /** * @fileoverview * 'onboarding-choose-wipe-device-page' allows user to select between wiping all @@ -25,6 +29,15 @@ const OnboardingChooseWipeDevicePageBase = mixinBehaviors([I18nBehavior], PolymerElement); +/** + * Supported options for the wipe device state. + * @enum {string} + */ +const WipeDeviceOption = { + WIPE_DEVICE: 'wipeDevice', + PRESERVE_DATA: 'preserveData', +}; + /** @polymer */ export class OnboardingChooseWipeDevicePage extends OnboardingChooseWipeDevicePageBase { @@ -35,6 +48,57 @@ static get template() { return html`{__html_template__}`; } + + static get properties() { + return { + /** + * Used to refer to the enum values in HTML file. + * @protected {?WipeDeviceOption} + */ + wipeDeviceOption_: { + type: Object, + value: WipeDeviceOption, + }, + + // Set by shimless_rma.js. + allButtonsDisabled: Boolean, + + /** @protected */ + selectedWipeDeviceOption_: { + type: String, + value: '', + }, + }; + } + + constructor() { + super(); + /** @private {ShimlessRmaServiceInterface} */ + this.shimlessRmaService_ = getShimlessRmaService(); + } + + + /** + * @param {!CustomEvent<{value: string}>} event + * @protected + */ + onOptionChanged_(event) { + this.selectedWipeDeviceOption_ = + /** @type {!WipeDeviceOption} */ (event.detail.value); + + // Enable the next button when an option is chosen. + this.dispatchEvent(new CustomEvent( + 'disable-next-button', + {bubbles: true, composed: true, detail: false}, + )); + } + + /** @return {!Promise<!StateResult>} */ + onNextButtonClick() { + assert(!!this.selectedWipeDeviceOption_); + return this.shimlessRmaService_.setWipeDevice( + this.selectedWipeDeviceOption_ === WipeDeviceOption.WIPE_DEVICE); + } } customElements.define(
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 138b620..e817926 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -7.20220222.2.2 +7.20220223.0.1
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 7079ef7..e817926 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -7.20220222.4.1 +7.20220223.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 37c86238..e817926 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -7.20220222.2.1 +7.20220223.0.1
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc index 62e33bb1..c641fca 100644 --- a/cc/paint/image_transfer_cache_entry.cc +++ b/cc/paint/image_transfer_cache_entry.cc
@@ -26,10 +26,6 @@ namespace cc { namespace { -// TODO(https://crbug.com/1286076): Plumb the true parameters in here. -constexpr float kTempMaxLuminanceNits = 100.f; -constexpr float kTempHDRMaxLuminanceRelative = 1.f; - struct Context { const std::vector<sk_sp<SkImage>> sk_planes_; }; @@ -92,42 +88,104 @@ return image; } -// TODO(ericrk): Replace calls to this with calls to SkImage::makeTextureImage, -// once that function handles colorspaces. https://crbug.com/834837 -sk_sp<SkImage> MakeTextureImage( +sk_sp<SkImage> MakeGpuSkImage( GrDirectContext* context, - sk_sp<SkImage> source_image, - absl::optional<TargetColorParams> target_color_params, - GrMipMapped mip_mapped) { - // Step 1: Upload image and generate mips if necessary. If we will be applying - // a color-space conversion, don't generate mips yet, instead do it after - // conversion, in step 3. - // NOTE: |target_color_space| is only passed over the transfer cache if needed - // (non-null, different from the source color space). - bool add_mips_after_color_conversion = - target_color_params && mip_mapped == GrMipMapped::kYes; - sk_sp<SkImage> uploaded_image = source_image->makeTextureImage( - context, add_mips_after_color_conversion ? GrMipMapped::kNo : mip_mapped, - SkBudgeted::kNo); + const SkPixmap& pixmap, + uint32_t width, + uint32_t height, + bool needs_mips, + absl::optional<TargetColorParams> target_color_params) { + sk_sp<SkImage> source_image = + SkImage::MakeFromRaster(pixmap, nullptr, nullptr); + if (!source_image) + return nullptr; - // Step 2: Apply a color-space conversion if necessary. - if (uploaded_image && target_color_params) { + // If we are going to be applying color space conversion, then we defer mipmap + // generation until after the conversion. + bool add_mips_after_color_conversion = target_color_params && needs_mips; + GrMipMapped mip_mapped_for_upload = + needs_mips && !add_mips_after_color_conversion ? GrMipMapped::kYes + : GrMipMapped::kNo; + + // Upload the image. + sk_sp<SkImage> image = source_image->makeTextureImage( + context, mip_mapped_for_upload, SkBudgeted::kNo); + if (!image) { + DLOG(ERROR) << "Image upload failed."; + return nullptr; + } + + // Apply a color-space conversion if necessary. + if (target_color_params) { // TODO(https://crbug.com/1286088): Pass a shared cache as a parameter. gfx::ColorConversionSkFilterCache cache; - uploaded_image = cache.ConvertImage( - uploaded_image, target_color_params->color_space.ToSkColorSpace(), + image = cache.ConvertImage( + image, target_color_params->color_space.ToSkColorSpace(), target_color_params->sdr_max_luminance_nits, target_color_params->hdr_max_luminance_relative, context); + if (!image) { + DLOG(ERROR) << "Color conversion failed."; + return nullptr; + } + + // Perform the deferred mipmap generation. + if (add_mips_after_color_conversion) { + image = + image->makeTextureImage(context, GrMipMapped::kYes, SkBudgeted::kNo); + if (!image) { + DLOG(ERROR) << "Mipmap generation using makeTextureImage failed."; + return nullptr; + } + } } - // Step 3: If we had a colorspace conversion, we couldn't mipmap in step 1, so - // add mips here. - if (uploaded_image && add_mips_after_color_conversion) { - uploaded_image = uploaded_image->makeTextureImage( - context, GrMipMapped::kYes, SkBudgeted::kNo); - } + // Make sure the GPU work to create the backing texture is issued. + image->getBackendTexture(true /* flushPendingGrContextIO */); + return image; +} - return uploaded_image; +sk_sp<SkImage> MakeCpuSkImage( + const SkPixmap& pixmap, + uint32_t width, + uint32_t height, + absl::optional<TargetColorParams> target_color_params) { + sk_sp<SkImage> original = SkImage::MakeFromRaster( + pixmap, [](const void*, void*) {}, nullptr); + if (!original) + return nullptr; + sk_sp<SkImage> image; + if (target_color_params) { + // TODO(https://crbug.com/1286088): Pass a shared cache as a parameter. + gfx::ColorConversionSkFilterCache cache; + image = cache.ConvertImage( + original, target_color_params->color_space.ToSkColorSpace(), + target_color_params->sdr_max_luminance_nits, + target_color_params->hdr_max_luminance_relative, /*context=*/nullptr); + // If color space conversion is a noop, use original data. + if (image == original) + image = SkImage::MakeRasterCopy(pixmap); + } else { + // No color conversion to do, use original data. + image = SkImage::MakeRasterCopy(pixmap); + } + return image; +} + +size_t TargetColorParamsSize( + const absl::optional<TargetColorParams>& target_color_params) { + // uint32 for whether or not there are going to be parameters. + size_t target_color_params_size = sizeof(uint32_t); + if (target_color_params) { + // The target color space. + target_color_params_size += + sizeof(uint64_t) + + target_color_params->color_space.ToSkColorSpace()->writeToMemory( + nullptr); + // floats for the SDR and HDR maximum luminance. + target_color_params_size += sizeof(float); + target_color_params_size += sizeof(float); + } + return target_color_params_size; } } // namespace @@ -148,18 +206,19 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry( const SkPixmap* pixmap, - const SkColorSpace* target_color_space, + absl::optional<TargetColorParams> target_color_params, bool needs_mips) : needs_mips_(needs_mips), + target_color_params_(target_color_params), id_(GetNextId()), pixmap_(pixmap), - target_color_space_(target_color_space), decoded_color_space_(nullptr) { - size_t target_color_space_size = - target_color_space ? target_color_space->writeToMemory(nullptr) : 0u; - size_t pixmap_color_space_size = - pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr) - : 0u; + const size_t target_color_params_size = + TargetColorParamsSize(target_color_params_); + const size_t pixmap_color_space_size = + sizeof(uint64_t) + (pixmap_->colorSpace() + ? pixmap_->colorSpace()->writeToMemory(nullptr) + : 0); // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte // alignment. Always use 8 byte alignment. @@ -175,8 +234,8 @@ safe_size += sizeof(uint32_t); // has mips safe_size += sizeof(uint64_t) + align; // pixels size + alignment safe_size += sizeof(uint64_t) + align; // row bytes + alignment - safe_size += target_color_space_size + sizeof(uint64_t) + align; - safe_size += pixmap_color_space_size + sizeof(uint64_t) + align; + safe_size += target_color_params_size + align; + safe_size += pixmap_color_space_size + align; // Include 4 bytes of padding so we can always align our data pointer to a // 4-byte boundary. safe_size += 4; @@ -190,12 +249,13 @@ SkYUVAInfo::Subsampling subsampling, const SkColorSpace* decoded_color_space, SkYUVColorSpace yuv_color_space, + absl::optional<TargetColorParams> target_color_params, bool needs_mips) : needs_mips_(needs_mips), plane_config_(plane_config), + target_color_params_(target_color_params), id_(GetNextId()), pixmap_(nullptr), - target_color_space_(nullptr), decoded_color_space_(decoded_color_space), subsampling_(subsampling), yuv_color_space_(yuv_color_space) { @@ -208,8 +268,13 @@ yuv_pixmaps_->at(i) = &yuva_pixmaps[i]; } DCHECK(IsYuv()); - size_t decoded_color_space_size = - decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u; + + const size_t target_color_params_size = + TargetColorParamsSize(target_color_params_); + const size_t decoded_color_space_size = + sizeof(uint64_t) + (decoded_color_space_ + ? decoded_color_space_->writeToMemory(nullptr) + : 0u); // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte // alignment. Always use 8 byte alignment. @@ -223,6 +288,7 @@ safe_size += sizeof(uint32_t); // has mips safe_size += sizeof(uint32_t); // yuv_color_space safe_size += sizeof(uint32_t); // yuv_color_type + safe_size += target_color_params_size + align; safe_size += decoded_color_space_size + align; safe_size += num_yuva_pixmaps * sizeof(uint64_t); // plane widths safe_size += num_yuva_pixmaps * sizeof(uint64_t); // plane heights @@ -274,6 +340,17 @@ PaintOpWriter writer(data.data(), data.size(), options); writer.Write(plane_config_); + if (target_color_params_) { + const uint32_t has_target_color_params = 1; + writer.Write(has_target_color_params); + writer.Write(target_color_params_->color_space.ToSkColorSpace().get()); + writer.Write(target_color_params_->sdr_max_luminance_nits); + writer.Write(target_color_params_->hdr_max_luminance_relative); + } else { + const uint32_t has_target_color_params = 0; + writer.Write(has_target_color_params); + } + if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) { ValidateYUVDataBeforeSerializing(); writer.Write(subsampling_); @@ -317,7 +394,6 @@ writer.WriteSize(pixmap_size); writer.WriteSize(pixmap_->rowBytes()); writer.Write(pixmap_->colorSpace()); - writer.Write(target_color_space_); writer.AlignMemory(4); writer.WriteData(pixmap_size, pixmap_->addr()); @@ -403,92 +479,120 @@ PaintOpReader reader(data.data(), data.size(), options); plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown; reader.Read(&plane_config_); - if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) { - SkYUVAInfo::Subsampling subsampling = SkYUVAInfo::Subsampling::kUnknown; - reader.Read(&subsampling); - if (subsampling == SkYUVAInfo::Subsampling::kUnknown) + + uint32_t has_target_color_params; + reader.Read(&has_target_color_params); + absl::optional<TargetColorParams> target_color_params; + if (has_target_color_params) { + sk_sp<SkColorSpace> target_color_space; + reader.Read(&target_color_space); + if (!target_color_space) return false; - subsampling_ = subsampling; - uint32_t needs_mips; - reader.Read(&needs_mips); - has_mips_ = needs_mips; - SkYUVColorSpace yuv_color_space; - reader.Read(&yuv_color_space); - yuv_color_space_ = yuv_color_space; - sk_sp<SkColorSpace> decoded_color_space; - reader.Read(&decoded_color_space); - SkColorType yuv_plane_color_type = kUnknown_SkColorType; - reader.Read(&yuv_plane_color_type); - - int num_planes = SkYUVAInfo::NumPlanes(plane_config_); - // Read in each plane and reconstruct pixmaps. - for (int i = 0; i < num_planes; i++) { - uint32_t plane_width = 0; - reader.Read(&plane_width); - uint32_t plane_height = 0; - reader.Read(&plane_height); - size_t plane_stride = 0; - reader.ReadSize(&plane_stride); - // Because Skia does not support YUV rasterization from software planes, - // we require that each pixmap fits in a GPU texture. In the - // GpuImageDecodeCache, we veto YUV decoding if the planes would be too - // big. - uint32_t max_size = static_cast<uint32_t>(context_->maxTextureSize()); - // We compute this for each plane in case a malicious renderer tries to - // send very large U or V planes. - fits_on_gpu_ = plane_stride <= max_size && plane_width <= max_size && - plane_height <= max_size; - if (!fits_on_gpu_ || plane_width == 0 || plane_height == 0 || - plane_stride == 0) - return false; - - size_t plane_bytes = 0; - reader.ReadSize(&plane_bytes); - SkImageInfo plane_pixmap_info = - SkImageInfo::Make(plane_width, plane_height, yuv_plane_color_type, - kPremul_SkAlphaType, decoded_color_space); - if (plane_pixmap_info.computeMinByteSize() > plane_bytes) - return false; - // Align data to a 4-byte boundary, to match what we did when writing. - reader.AlignMemory(4); - const volatile void* plane_pixel_data = - reader.ExtractReadableMemory(plane_bytes); - if (!reader.valid()) - return false; - DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(plane_pixel_data))); - - // Const-cast away the "volatile" on |pixel_data|. We specifically - // understand that a malicious caller may change our pixels under us, and - // are OK with this as the worst case scenario is visual corruption. - SkPixmap plane_pixmap(plane_pixmap_info, - const_cast<const void*>(plane_pixel_data), - plane_stride); - if (plane_pixmap.computeByteSize() > plane_bytes) - return false; - - // Nothing should read the colorspace of individual planes because that - // information is stored in image_, so we pass nullptr. - sk_sp<SkImage> plane = - MakeSkImage(plane_pixmap, plane_width, plane_height, - /*target_color_params=*/absl::nullopt); - if (!plane) - return false; - DCHECK(plane->isTextureBacked()); - - plane_sizes_.push_back(plane->textureSize()); - size_ += plane_sizes_.back(); - - // |plane_images_| must be set for use in EnsureMips(), memory dumps, and - // unit tests. - plane_images_.push_back(std::move(plane)); - } - DCHECK(yuv_color_space_.has_value()); - image_ = MakeYUVImageFromUploadedPlanes( - context_, plane_images_, plane_config_, subsampling_.value(), - yuv_color_space_.value(), decoded_color_space); - return !!image_; + target_color_params = TargetColorParams(); + target_color_params->color_space = gfx::ColorSpace(*target_color_space); + reader.Read(&target_color_params->sdr_max_luminance_nits); + reader.Read(&target_color_params->hdr_max_luminance_relative); } + if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) + return DeserializeYUVA(reader); + return DeserializeRGBA(reader, target_color_params); +} + +bool ServiceImageTransferCacheEntry::DeserializeYUVA(PaintOpReader& reader) { + SkYUVAInfo::Subsampling subsampling = SkYUVAInfo::Subsampling::kUnknown; + reader.Read(&subsampling); + if (subsampling == SkYUVAInfo::Subsampling::kUnknown) + return false; + subsampling_ = subsampling; + uint32_t needs_mips; + reader.Read(&needs_mips); + has_mips_ = needs_mips; + SkYUVColorSpace yuv_color_space; + reader.Read(&yuv_color_space); + yuv_color_space_ = yuv_color_space; + sk_sp<SkColorSpace> decoded_color_space; + reader.Read(&decoded_color_space); + SkColorType yuv_plane_color_type = kUnknown_SkColorType; + reader.Read(&yuv_plane_color_type); + + // In the GpuImageDecodeCache, we veto YUV decoding if the planes would be + // too big. Below, we will reject the image if any plane is too large. + fits_on_gpu_ = true; + + int num_planes = SkYUVAInfo::NumPlanes(plane_config_); + // Read in each plane and reconstruct pixmaps. + for (int i = 0; i < num_planes; i++) { + uint32_t plane_width = 0; + reader.Read(&plane_width); + uint32_t plane_height = 0; + reader.Read(&plane_height); + size_t plane_stride = 0; + reader.ReadSize(&plane_stride); + // Because Skia does not support YUV rasterization from software planes, + // we require that each pixmap fits in a GPU texture. In the + // GpuImageDecodeCache, we veto YUV decoding if the planes would be too + // big. + const uint32_t max_texture_size = + static_cast<uint32_t>(context_->maxTextureSize()); + // We compute this for each plane in case a malicious renderer tries to + // send very large U or V planes. + if (plane_width > max_texture_size || plane_width == 0 || + plane_height > max_texture_size || plane_height == 0 || + plane_stride > max_texture_size || plane_stride == 0) { + return false; + } + + size_t plane_bytes = 0; + reader.ReadSize(&plane_bytes); + SkImageInfo plane_pixmap_info = + SkImageInfo::Make(plane_width, plane_height, yuv_plane_color_type, + kPremul_SkAlphaType, decoded_color_space); + if (plane_pixmap_info.computeMinByteSize() > plane_bytes) + return false; + // Align data to a 4-byte boundary, to match what we did when writing. + reader.AlignMemory(4); + const volatile void* plane_pixel_data = + reader.ExtractReadableMemory(plane_bytes); + if (!reader.valid()) + return false; + DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(plane_pixel_data))); + + // Const-cast away the "volatile" on |pixel_data|. We specifically + // understand that a malicious caller may change our pixels under us, and + // are OK with this as the worst case scenario is visual corruption. + SkPixmap plane_pixmap(plane_pixmap_info, + const_cast<const void*>(plane_pixel_data), + plane_stride); + if (plane_pixmap.computeByteSize() > plane_bytes) + return false; + + // Nothing should read the colorspace of individual planes because that + // information is stored in image_, so we pass nullptr. + sk_sp<SkImage> plane = MakeGpuSkImage( + context_, plane_pixmap, plane_width, plane_height, has_mips_, + /*target_color_params=*/absl::nullopt); + if (!plane) + return false; + DCHECK(plane->isTextureBacked()); + + plane_sizes_.push_back(plane->textureSize()); + size_ += plane_sizes_.back(); + + // |plane_images_| must be set for use in EnsureMips(), memory dumps, and + // unit tests. + plane_images_.push_back(std::move(plane)); + } + DCHECK(yuv_color_space_.has_value()); + image_ = MakeYUVImageFromUploadedPlanes( + context_, plane_images_, plane_config_, subsampling_.value(), + yuv_color_space_.value(), decoded_color_space); + return !!image_; +} + +bool ServiceImageTransferCacheEntry::DeserializeRGBA( + PaintOpReader& reader, + absl::optional<TargetColorParams> target_color_params) { SkColorType color_type = kUnknown_SkColorType; reader.Read(&color_type); @@ -510,17 +614,6 @@ reader.ReadSize(&row_bytes); sk_sp<SkColorSpace> pixmap_color_space; reader.Read(&pixmap_color_space); - sk_sp<SkColorSpace> target_color_space; - reader.Read(&target_color_space); - - absl::optional<TargetColorParams> target_color_params; - if (target_color_space) { - target_color_params = TargetColorParams(); - target_color_params->color_space = gfx::ColorSpace(*target_color_space); - target_color_params->sdr_max_luminance_nits = kTempMaxLuminanceNits; - target_color_params->hdr_max_luminance_relative = - kTempHDRMaxLuminanceRelative; - } if (!reader.valid()) return false; @@ -547,7 +640,17 @@ // that a malicious caller may change our pixels under us, and are OK with // this as the worst case scenario is visual corruption. SkPixmap pixmap(image_info, const_cast<const void*>(pixel_data), row_bytes); - image_ = MakeSkImage(pixmap, width, height, target_color_params); + const uint32_t max_texture_size = + static_cast<uint32_t>(context_->maxTextureSize()); + fits_on_gpu_ = width <= max_texture_size && height <= max_texture_size; + if (fits_on_gpu_) { + image_ = MakeGpuSkImage(context_, pixmap, width, height, has_mips_, + target_color_params); + } else { + // If the image is on the CPU, no work is needed to generate mips. + has_mips_ = true; + image_ = MakeCpuSkImage(pixmap, width, height, target_color_params); + } if (image_) size_ = image_->textureSize(); @@ -555,54 +658,6 @@ return !!image_; } -sk_sp<SkImage> ServiceImageTransferCacheEntry::MakeSkImage( - const SkPixmap& pixmap, - uint32_t width, - uint32_t height, - absl::optional<TargetColorParams> target_color_params) { - DCHECK(context_); - - // Depending on whether the pixmap will fit in a GPU texture, either create - // a software or GPU SkImage. - uint32_t max_size = context_->maxTextureSize(); - fits_on_gpu_ = width <= max_size && height <= max_size; - sk_sp<SkImage> image; - if (fits_on_gpu_) { - image = SkImage::MakeFromRaster(pixmap, nullptr, nullptr); - if (!image) - return nullptr; - image = MakeTextureImage(context_, std::move(image), target_color_params, - has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo); - } else { - // If the image is on the CPU, no work is needed to generate mips. - has_mips_ = true; - sk_sp<SkImage> original = - SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); - if (!original) - return nullptr; - if (target_color_params) { - // TODO(https://crbug.com/1286088): Pass a shared cache as a parameter. - gfx::ColorConversionSkFilterCache cache; - image = cache.ConvertImage( - original, target_color_params->color_space.ToSkColorSpace(), - target_color_params->sdr_max_luminance_nits, - target_color_params->hdr_max_luminance_relative, /*context=*/nullptr); - // If color space conversion is a noop, use original data. - if (image == original) - image = SkImage::MakeRasterCopy(pixmap); - } else { - // No color conversion to do, use original data. - image = SkImage::MakeRasterCopy(pixmap); - } - } - - // Make sure the GPU work to create the backing texture is issued. - if (image) - image->getBackendTexture(true /* flushPendingGrContextIO */); - - return image; -} - const sk_sp<SkImage>& ServiceImageTransferCacheEntry::GetPlaneImage( size_t index) const { DCHECK_GE(index, 0u);
diff --git a/cc/paint/image_transfer_cache_entry.h b/cc/paint/image_transfer_cache_entry.h index 1e61c8a..b233f51d 100644 --- a/cc/paint/image_transfer_cache_entry.h +++ b/cc/paint/image_transfer_cache_entry.h
@@ -27,6 +27,8 @@ namespace cc { +class PaintOpReader; + static constexpr uint32_t kInvalidImageTransferCacheEntryId = static_cast<uint32_t>(-1); @@ -47,15 +49,17 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry final : public ClientTransferCacheEntryBase<TransferCacheEntryType::kImage> { public: - explicit ClientImageTransferCacheEntry(const SkPixmap* pixmap, - const SkColorSpace* target_color_space, - bool needs_mips); + explicit ClientImageTransferCacheEntry( + const SkPixmap* pixmap, + absl::optional<TargetColorParams> target_color_params, + bool needs_mips); explicit ClientImageTransferCacheEntry( const SkPixmap yuva_pixmaps[], SkYUVAInfo::PlaneConfig plane_config, SkYUVAInfo::Subsampling subsampling, const SkColorSpace* decoded_color_space, SkYUVColorSpace yuv_color_space, + absl::optional<TargetColorParams> target_color_params, bool needs_mips); ~ClientImageTransferCacheEntry() final; @@ -72,15 +76,13 @@ private: const bool needs_mips_ = false; SkYUVAInfo::PlaneConfig plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown; + absl::optional<TargetColorParams> target_color_params_; uint32_t id_; uint32_t size_ = 0; static base::AtomicSequenceNumber s_next_id_; // RGBX-only members. const raw_ptr<const SkPixmap> pixmap_; - const raw_ptr<const SkColorSpace> - target_color_space_; // Unused for YUV because Skia handles colorspaces - // at raster. // YUVA-only members. absl::optional<std::array<const SkPixmap*, SkYUVAInfo::kMaxPlanes>> @@ -151,11 +153,9 @@ } private: - sk_sp<SkImage> MakeSkImage( - const SkPixmap& pixmap, - uint32_t width, - uint32_t height, - absl::optional<TargetColorParams> target_color_params); + bool DeserializeYUVA(PaintOpReader& reader); + bool DeserializeRGBA(PaintOpReader& reader, + absl::optional<TargetColorParams> target_color_params); raw_ptr<GrDirectContext> context_ = nullptr; std::vector<sk_sp<SkImage>> plane_images_;
diff --git a/cc/paint/image_transfer_cache_entry_unittest.cc b/cc/paint/image_transfer_cache_entry_unittest.cc index e57ab84..92064810 100644 --- a/cc/paint/image_transfer_cache_entry_unittest.cc +++ b/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -228,7 +228,8 @@ auto client_entry(std::make_unique<ClientImageTransferCacheEntry>( yuva_pixmaps.planes().data(), yuva_info.planeConfig(), yuva_info.subsampling(), nullptr /* decoded color space*/, - yuva_info.yuvColorSpace(), true /* needs_mips */)); + yuva_info.yuvColorSpace(), absl::nullopt /* target_color_params */, + true /* needs_mips */)); uint32_t size = client_entry->SerializedSize(); std::vector<uint8_t> data(size); ASSERT_TRUE(client_entry->Serialize( @@ -378,7 +379,8 @@ SkBitmap bitmap; bitmap.allocPixels( SkImageInfo::MakeN32Premul(gr_context->maxTextureSize() + 1, 10)); - ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), nullptr, true); + ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), absl::nullopt, + true); std::vector<uint8_t> storage(client_entry.SerializedSize()); client_entry.Serialize(base::make_span(storage.data(), storage.size())); @@ -404,7 +406,8 @@ SkBitmap bitmap; bitmap.allocPixels( SkImageInfo::MakeN32Premul(gr_context->maxTextureSize() + 1, 10)); - ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), nullptr, false); + ClientImageTransferCacheEntry client_entry(&bitmap.pixmap(), absl::nullopt, + false); std::vector<uint8_t> storage(client_entry.SerializedSize()); client_entry.Serialize(base::make_span(storage.data(), storage.size()));
diff --git a/cc/test/test_options_provider.cc b/cc/test/test_options_provider.cc index e239f9a..88e63cd 100644 --- a/cc/test/test_options_provider.cc +++ b/cc/test/test_options_provider.cc
@@ -100,9 +100,9 @@ SkBitmap::kZeroPixels_AllocFlag); // Create a transfer cache entry for this image. - auto color_space = SkColorSpace::MakeSRGB(); - ClientImageTransferCacheEntry cache_entry(&bitmap.pixmap(), color_space.get(), - false /* needs_mips */); + TargetColorParams target_color_params; + ClientImageTransferCacheEntry cache_entry( + &bitmap.pixmap(), target_color_params, false /* needs_mips */); std::vector<uint8_t> data; data.resize(cache_entry.SerializedSize()); if (!cache_entry.Serialize(base::span<uint8_t>(data.data(), data.size()))) {
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc index d54d1123..3cc7134 100644 --- a/cc/tiles/gpu_image_decode_cache.cc +++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -2131,6 +2131,12 @@ color_space = nullptr; } + absl::optional<TargetColorParams> target_color_params; + if (color_space) { + target_color_params = draw_image.target_color_params(); + target_color_params->color_space = gfx::ColorSpace(*color_space); + } + // Will be nullptr for non-HDR images or when we're using the default level. const bool needs_adjusted_color_space = NeedsColorSpaceAdjustedForUpload(draw_image); @@ -2144,11 +2150,11 @@ draw_image, image_data, color_space); } else if (image_data->yuva_pixmap_info.has_value()) { UploadImageIfNecessary_TransferCache_SoftwareDecode_YUVA( - draw_image, image_data, decoded_target_colorspace); + draw_image, image_data, decoded_target_colorspace, absl::nullopt); } else { UploadImageIfNecessary_TransferCache_SoftwareDecode_RGBA( draw_image, image_data, needs_adjusted_color_space, - decoded_target_colorspace, color_space); + decoded_target_colorspace, target_color_params); } } else { // Grab a reference to our decoded image. For the kCpu path, we will use @@ -2217,7 +2223,8 @@ UploadImageIfNecessary_TransferCache_SoftwareDecode_YUVA( const DrawImage& draw_image, ImageData* image_data, - sk_sp<SkColorSpace> decoded_target_colorspace) { + sk_sp<SkColorSpace> decoded_target_colorspace, + absl::optional<TargetColorParams> target_color_params) { DCHECK_EQ(image_data->mode, DecodedDataMode::kTransferCache); DCHECK(use_transfer_cache_); DCHECK(!image_data->decode.do_hardware_accelerated_decode()); @@ -2234,7 +2241,7 @@ image_data->yuva_pixmap_info->yuvaInfo().subsampling(), decoded_target_colorspace.get(), image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(), - image_data->needs_mips); + target_color_params, image_data->needs_mips); if (!image_entry.IsValid()) return; InsertTransferCacheEntry(image_entry, image_data); @@ -2246,7 +2253,7 @@ ImageData* image_data, bool needs_adjusted_color_space, sk_sp<SkColorSpace> decoded_target_colorspace, - sk_sp<SkColorSpace> color_space) { + absl::optional<TargetColorParams> target_color_params) { DCHECK_EQ(image_data->mode, DecodedDataMode::kTransferCache); DCHECK(use_transfer_cache_); DCHECK(!image_data->decode.do_hardware_accelerated_decode()); @@ -2258,7 +2265,7 @@ if (needs_adjusted_color_space) pixmap.setColorSpace(decoded_target_colorspace); - ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(), + ClientImageTransferCacheEntry image_entry(&pixmap, target_color_params, image_data->needs_mips); if (!image_entry.IsValid()) return;
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h index 127723d..51d3a9b9 100644 --- a/cc/tiles/gpu_image_decode_cache.h +++ b/cc/tiles/gpu_image_decode_cache.h
@@ -696,13 +696,14 @@ void UploadImageIfNecessary_TransferCache_SoftwareDecode_YUVA( const DrawImage& draw_image, ImageData* image_data, - sk_sp<SkColorSpace> decoded_target_colorspace); + sk_sp<SkColorSpace> decoded_target_colorspace, + absl::optional<TargetColorParams> target_color_params); void UploadImageIfNecessary_TransferCache_SoftwareDecode_RGBA( const DrawImage& draw_image, ImageData* image_data, bool needs_adjusted_color_space, sk_sp<SkColorSpace> decoded_target_colorspace, - sk_sp<SkColorSpace> color_space); + absl::optional<TargetColorParams> target_color_params); void UploadImageIfNecessary_GpuCpu_YUVA( const DrawImage& draw_image, ImageData* image_data,
diff --git a/chrome/VERSION b/chrome/VERSION index 385316a..26f2a3e6 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=101 MINOR=0 -BUILD=4905 +BUILD=4906 PATCH=0
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java index d79a4a5..3f0f4a5 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
@@ -339,11 +339,12 @@ } @CalledByNative - private void setSelectedShippingAddress( - @Nullable AssistantAutofillProfile shippingAddress, String[] errors) { + private void setSelectedShippingAddress(@Nullable AssistantAutofillProfile shippingAddress, + String fullDescription, String summaryDescription, String[] errors) { set(SELECTED_SHIPPING_ADDRESS, shippingAddress == null ? null - : new AddressModel(shippingAddress, Arrays.asList(errors))); + : new AddressModel(shippingAddress, fullDescription, + summaryDescription, Arrays.asList(errors))); } @CalledByNative @@ -484,9 +485,11 @@ } @CalledByNative - private static void addShippingAddress( - List<AddressModel> addresses, AssistantAutofillProfile address, String[] errors) { - addresses.add(new AddressModel(address, Arrays.asList(errors))); + private static void addShippingAddress(List<AddressModel> addresses, + AssistantAutofillProfile address, String fullDescription, String summaryDescription, + String[] errors) { + addresses.add(new AddressModel( + address, fullDescription, summaryDescription, Arrays.asList(errors))); } @CalledByNative
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java index 9e69a5e..3627a9d 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantShippingAddressSection.java
@@ -15,7 +15,6 @@ import org.chromium.base.Callback; import org.chromium.chrome.autofill_assistant.R; -import org.chromium.chrome.browser.autofill_assistant.AssistantAutofillUtilChrome; import org.chromium.chrome.browser.autofill_assistant.AssistantEditor.AssistantAddressEditor; import org.chromium.chrome.browser.autofill_assistant.AssistantOptionModel.AddressModel; @@ -70,9 +69,7 @@ hideIfEmpty(fullNameView); TextView fullAddressView = fullView.findViewById(R.id.full_address); - // TODO(b/211748133): Remove dependency to AutofillUtilChrome. - fullAddressView.setText(AssistantAutofillUtilChrome.getShippingAddressLabel( - model.mOption, /* withCountry= */ true)); + fullAddressView.setText(model.getFullDescription()); hideIfEmpty(fullAddressView); TextView errorView = fullView.findViewById(R.id.incomplete_error); @@ -95,9 +92,7 @@ hideIfEmpty(fullNameView); TextView shortAddressView = summaryView.findViewById(R.id.short_address); - // TODO(b/211748133): Remove dependency to AutofillUtilChrome. - shortAddressView.setText(AssistantAutofillUtilChrome.getShippingAddressLabel( - model.mOption, /* withCountry= */ false)); + shortAddressView.setText(model.getSummaryDescription()); hideIfEmpty(shortAddressView); TextView errorView = summaryView.findViewById(R.id.incomplete_error);
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java index 05b1bde..c505f1d0 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java
@@ -71,13 +71,13 @@ import org.chromium.chrome.browser.autofill_assistant.proto.ClickType; import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataProto; import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataProto.TermsAndConditionsState; -import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataProto.UserDataProto; import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataResultProto; import org.chromium.chrome.browser.autofill_assistant.proto.ContactDetailsProto; import org.chromium.chrome.browser.autofill_assistant.proto.DropdownSelectStrategy; import org.chromium.chrome.browser.autofill_assistant.proto.ElementAreaProto; import org.chromium.chrome.browser.autofill_assistant.proto.ElementAreaProto.Rectangle; import org.chromium.chrome.browser.autofill_assistant.proto.ElementConditionProto; +import org.chromium.chrome.browser.autofill_assistant.proto.GetUserDataResponseProto; import org.chromium.chrome.browser.autofill_assistant.proto.IntList; import org.chromium.chrome.browser.autofill_assistant.proto.KeyboardValueFillStrategy; import org.chromium.chrome.browser.autofill_assistant.proto.LoginDetailsProto; @@ -915,14 +915,17 @@ @Test @MediumTest public void testEnterBackendContact() throws Exception { - UserDataProto - .Builder data = UserDataProto.newBuilder().setLocale("en-US").addAvailableContacts( - ProfileProto.newBuilder() - .putValues(7, AutofillEntryProto.newBuilder().setValue("John Doe").build()) - .putValues(9, - AutofillEntryProto.newBuilder() - .setValue("johndoe@google.com") - .build())); + GetUserDataResponseProto.Builder data = + GetUserDataResponseProto.newBuilder().setLocale("en-US").addAvailableContacts( + ProfileProto.newBuilder() + .putValues(7, + AutofillEntryProto.newBuilder() + .setValue("John Doe") + .build()) + .putValues(9, + AutofillEntryProto.newBuilder() + .setValue("johndoe@google.com") + .build())); ArrayList<ActionProto> list = new ArrayList<>(); list.add(ActionProto.newBuilder() @@ -999,27 +1002,49 @@ @Test @MediumTest public void testShowBackendCard() throws Exception { - UserDataProto.Builder - data = UserDataProto.newBuilder().setLocale("en-US").addAvailablePaymentInstruments( - PaymentInstrumentProto.newBuilder() - .putCardValues(55, AutofillEntryProto.newBuilder().setValue("2050").build()) - .putCardValues(53, AutofillEntryProto.newBuilder().setValue("7").build()) - .putCardValues( - 51, AutofillEntryProto.newBuilder().setValue("John Doe").build()) - .setNetwork("visaCC") - .setLastFourDigits("1111") - .putAddressValues( - 35, AutofillEntryProto.newBuilder().setValue("80302").build()) - .putAddressValues( - 36, AutofillEntryProto.newBuilder().setValue("US").build()) - .putAddressValues( - 33, AutofillEntryProto.newBuilder().setValue("Boulder").build()) - .putAddressValues(30, - AutofillEntryProto.newBuilder().setValue("123 Broadway St").build()) - .putAddressValues( - 34, AutofillEntryProto.newBuilder().setValue("CO").build()) - .putAddressValues( - 7, AutofillEntryProto.newBuilder().setValue("John Doe").build())); + GetUserDataResponseProto.Builder data = + GetUserDataResponseProto.newBuilder() + .setLocale("en-US") + .addAvailablePaymentInstruments( + PaymentInstrumentProto.newBuilder() + .putCardValues(55, + AutofillEntryProto.newBuilder() + .setValue("2050") + .build()) + .putCardValues(53, + AutofillEntryProto.newBuilder() + .setValue("7") + .build()) + .putCardValues(51, + AutofillEntryProto.newBuilder() + .setValue("John Doe") + .build()) + .setNetwork("visaCC") + .setLastFourDigits("1111") + .putAddressValues(35, + AutofillEntryProto.newBuilder() + .setValue("80302") + .build()) + .putAddressValues(36, + AutofillEntryProto.newBuilder() + .setValue("US") + .build()) + .putAddressValues(33, + AutofillEntryProto.newBuilder() + .setValue("Boulder") + .build()) + .putAddressValues(30, + AutofillEntryProto.newBuilder() + .setValue("123 Broadway St") + .build()) + .putAddressValues(34, + AutofillEntryProto.newBuilder() + .setValue("CO") + .build()) + .putAddressValues(7, + AutofillEntryProto.newBuilder() + .setValue("John Doe") + .build())); ArrayList<ActionProto> list = new ArrayList<>(); list.add(ActionProto.newBuilder() @@ -1053,8 +1078,8 @@ @Test @MediumTest public void testEnterBackendPhoneNumber() throws Exception { - UserDataProto.Builder data = - UserDataProto.newBuilder().setLocale("en-US").addAvailablePhoneNumbers( + GetUserDataResponseProto.Builder data = + GetUserDataResponseProto.newBuilder().setLocale("en-US").addAvailablePhoneNumbers( PhoneNumberProto.newBuilder().setValue( AutofillEntryProto.newBuilder().setValue("+41234567890").build())); @@ -1119,8 +1144,8 @@ @Test @MediumTest public void testMergeBackendPhoneNumberIntoContact() throws Exception { - UserDataProto.Builder data = - UserDataProto.newBuilder() + GetUserDataResponseProto.Builder data = + GetUserDataResponseProto.newBuilder() .setLocale("en-US") .addAvailableContacts( ProfileProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java index 932d453..91990b33 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java
@@ -539,14 +539,13 @@ new ContactModel(contact)); AssistantAutofillProfile phone_number = createDummyContact(profile); model.set(AssistantCollectUserDataModel.AVAILABLE_PHONE_NUMBERS, - Collections.singletonList(new ContactModel(contact))); + Collections.singletonList(new ContactModel(phone_number))); model.set( AssistantCollectUserDataModel.SELECTED_PHONE_NUMBER, new ContactModel(contact)); - AssistantAutofillProfile address = createDummyAddress(profile); model.set(AssistantCollectUserDataModel.AVAILABLE_SHIPPING_ADDRESSES, - Collections.singletonList(new AddressModel(address))); + Collections.singletonList(createAddressModel(profile))); model.set(AssistantCollectUserDataModel.SELECTED_SHIPPING_ADDRESS, - new AddressModel(address)); + createAddressModel(profile)); AssistantPaymentInstrument paymentInstrument = AssistantCollectUserDataModel.createAssistantPaymentInstrument( createDummyCreditCard(creditCard), createDummyAddress(profile)); @@ -628,7 +627,7 @@ model.set(AssistantCollectUserDataModel.AVAILABLE_CONTACTS, Collections.singletonList(new ContactModel(contact))); model.set(AssistantCollectUserDataModel.AVAILABLE_SHIPPING_ADDRESSES, - Collections.singletonList(new AddressModel(createDummyAddress(profile)))); + Collections.singletonList(createAddressModel(profile))); AssistantPaymentInstrument paymentInstrument = AssistantCollectUserDataModel.createAssistantPaymentInstrument( createDummyCreditCard(creditCard), createDummyAddress(profile)); @@ -1139,4 +1138,14 @@ creditCard.getServerId(), creditCard.getInstrumentId(), creditCard.getNickname(), creditCard.getCardArtUrl(), creditCard.getVirtualCardEnrollmentState()); } + + private AddressModel createAddressModel(PersonalDataManager.AutofillProfile profile) { + String fullDescription = + PersonalDataManager.getInstance() + .getShippingAddressLabelWithCountryForPaymentRequest(profile); + String summaryDescription = + PersonalDataManager.getInstance() + .getShippingAddressLabelWithoutCountryForPaymentRequest(profile); + return new AddressModel(createDummyAddress(profile), fullDescription, summaryDescription); + } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAddressEditorAutofill.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAddressEditorAutofill.java index 91df573..62e2b9f 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAddressEditorAutofill.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAddressEditorAutofill.java
@@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import org.chromium.base.Callback; +import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.prefeditor.EditorDialog; import org.chromium.chrome.browser.autofill.settings.AddressEditor; import org.chromium.chrome.browser.autofill_assistant.AssistantEditor.AssistantAddressEditor; @@ -46,9 +47,17 @@ Callback<AutofillAddress> editorDoneCallback = editedAddress -> { assert (editedAddress != null && editedAddress.isComplete() && editedAddress.getProfile() != null); + String fullDescription = PersonalDataManager.getInstance() + .getShippingAddressLabelWithCountryForPaymentRequest( + editedAddress.getProfile()); + String summaryDescription = + PersonalDataManager.getInstance() + .getShippingAddressLabelWithoutCountryForPaymentRequest( + editedAddress.getProfile()); doneCallback.onResult(new AddressModel( AssistantAutofillUtilChrome.autofillProfileToAssistantAutofillProfile( - editedAddress.getProfile()))); + editedAddress.getProfile()), + fullDescription, summaryDescription)); }; Callback<AutofillAddress> editorCancelCallback =
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAutofillUtilChrome.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAutofillUtilChrome.java index ffd36c2..20b0616 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAutofillUtilChrome.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantAutofillUtilChrome.java
@@ -8,7 +8,6 @@ import androidx.annotation.Nullable; -import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.payments.AutofillAddress; @@ -88,26 +87,6 @@ CompletenessCheckType.IGNORE_PHONE); } - /** - * Get the label for an {@link AssistantAutofillProfile} used as a shipping address. - * - * @param profile The {@link AssistantAutofillProfile}. - * @param withCountry Flag to add country. - * @return The label. - */ - public static String getShippingAddressLabel( - AssistantAutofillProfile profile, boolean withCountry) { - if (withCountry) { - return PersonalDataManager.getInstance() - .getShippingAddressLabelWithCountryForPaymentRequest( - assistantAutofillProfileToAutofillProfile(profile)); - } else { - return PersonalDataManager.getInstance() - .getShippingAddressLabelWithoutCountryForPaymentRequest( - assistantAutofillProfileToAutofillProfile(profile)); - } - } - private static CreditCard assistantAutofillCreditCardToAutofillCreditCard( AssistantAutofillCreditCard creditCard) { return new CreditCard(creditCard.getGUID(), creditCard.getOrigin(), creditCard.getIsLocal(), @@ -165,15 +144,4 @@ ? null : autofillProfileToAssistantAutofillProfile(autofillBillingProfile)); } - - /** - * Get the label for an {@link AssistantAutofillProfile} used as a billing address. - * - * @param profile The {@link AssistantAutofillProfile}. - * @return The label. - */ - public static String getBillingAddressLabel(AssistantAutofillProfile profile) { - return PersonalDataManager.getInstance().getBillingAddressLabelForPaymentRequest( - assistantAutofillProfileToAutofillProfile(profile)); - } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOptionModel.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOptionModel.java index b2cab6ad..3c7def03 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOptionModel.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOptionModel.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.autofill_assistant; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -52,12 +53,27 @@ /** Model wrapper for an {@link AssistantAutofillProfile}. */ public static class AddressModel extends AssistantOptionModel<AssistantAutofillProfile> { - public AddressModel(AssistantAutofillProfile address, List<String> errors) { + private final String mFullDescription; + private final String mSummaryDescription; + + public AddressModel(AssistantAutofillProfile address, String fullDescription, + String summaryDescription, List<String> errors) { super(address, errors); + mFullDescription = fullDescription; + mSummaryDescription = summaryDescription; } - public AddressModel(AssistantAutofillProfile address) { - super(address); + public AddressModel(AssistantAutofillProfile address, String fullDescription, + String summaryDescription) { + this(address, fullDescription, summaryDescription, Collections.emptyList()); + } + + public String getFullDescription() { + return mFullDescription; + } + + public String getSummaryDescription() { + return mSummaryDescription; } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPaymentInstrumentEditorAutofill.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPaymentInstrumentEditorAutofill.java index 3647fd1..9a4db1a 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPaymentInstrumentEditorAutofill.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPaymentInstrumentEditorAutofill.java
@@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import org.chromium.base.Callback; +import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.autofill.prefeditor.EditorDialog; import org.chromium.chrome.browser.autofill.settings.AddressEditor; import org.chromium.chrome.browser.autofill.settings.CardEditor; @@ -142,7 +143,8 @@ address, mContext); if (autofillAddress.getProfile().getLabel() == null) { autofillAddress.getProfile().setLabel( - AssistantAutofillUtilChrome.getBillingAddressLabel(address)); + PersonalDataManager.getInstance().getBillingAddressLabelForPaymentRequest( + autofillAddress.getProfile())); } mEditor.updateBillingAddressIfComplete(autofillAddress); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 304f41d..545f34b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -58,6 +58,8 @@ import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.identity_disc.IdentityDiscController; import org.chromium.chrome.browser.image_descriptions.ImageDescriptionsController; +import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthController; +import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthManager; import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -180,6 +182,12 @@ protected LayoutStateProvider mLayoutStateProvider; private LayoutStateProvider.LayoutStateObserver mLayoutStateObserver; + /** + * A controller which is used to show an Incognito re-auth dialog when the feature is + * available. + */ + private @Nullable IncognitoReauthController mIncognitoReauthController; + /** A means of providing the theme color to different features. */ private TopUiThemeColorProvider mTopUiThemeColorProvider; @@ -542,6 +550,10 @@ mScrollCaptureManager = null; } + if (mIncognitoReauthController != null) { + mIncognitoReauthController.destroy(); + } + mActivity = null; } @@ -672,6 +684,13 @@ .getSubscriptionsManager()); }); } + + if (IncognitoReauthManager.isIncognitoReauthFeatureAvailable()) { + mIncognitoReauthController = + new IncognitoReauthController(mActivity, mTabModelSelectorSupplier.get(), + mActivityLifecycleDispatcher, mModalDialogManagerSupplier.get(), + mLayoutStateProviderOneShotSupplier, mProfileSupplier); + } } private void initMerchantTrustSignals() {
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 3ac31b5..78d760de 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -128,31 +128,31 @@ </message> <!-- Privacy Guide --> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY" desc="Body text of a card in the settings page that explains what the privacy guide feature is."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY" desc="Body text of a card in the settings page that explains what the 'Privacy Guide' feature is."> Review key privacy and security controls in Chromium </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> When you close all Chromium windows, cookies and site data are automatically cleared </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> You will be <ph name="BEGIN_BOLD"><b></ph>signed out of most sites<ph name="END_BOLD"></b></ph> when you close Chromium. If sync is off, you will also be <ph name="BEGIN_BOLD"><b></ph>signed out of Google services and Chromium<ph name="END_BOLD"></b></ph>. </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION3" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION3" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> Sites you visit remember your information until you close Chromium </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2" desc="A part of the feature description of the standard protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2" desc="A part of the feature description of the standard protection section of the safe browsing card in the 'Privacy Guide'."> Checks URLs with a list of unsafe sites stored in Chromium </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the standard protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the standard protection section of the safe browsing card in the 'Privacy Guide'."> If a site tries to steal your password, or when you download a harmful file, Chromium may also send URLs, including bits of page content, to Safe Browsing </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL" desc="Text of the Privacy Sandbox sublabel in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL" desc="Text of the Privacy Sandbox sublabel in the completion card of the 'Privacy Guide'."> Chromium is exploring new features that allow sites to deliver the same browsing experience using less of your data </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL" desc="Text of the Web and App Activity sublabel in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL" desc="Text of the Web and App Activity sublabel in the completion card of the 'Privacy Guide'."> Choose whether to include Chromium history for more personalized experiences in Google services </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of 'make searches and browsing better' in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of 'make searches and browsing better' in the 'Privacy Guide'."> If you also share Chromium usage reports, those reports include the URLs you visit </message>
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 5066d0bd..aa4c0d9c5 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -154,31 +154,31 @@ </message> <!-- Privacy Guide --> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY" desc="Body text of a card in the settings page that explains what the privacy guide feature is."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_BODY" desc="Body text of a card in the settings page that explains what the 'Privacy Guide' feature is."> Review key privacy and security controls in Chrome </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> When you close all Chrome windows, cookies and site data are automatically cleared </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> You will be <ph name="BEGIN_BOLD"><b></ph>signed out of most sites<ph name="END_BOLD"></b></ph> when you close Chrome. If sync is off, you will also be <ph name="BEGIN_BOLD"><b></ph>signed out of Google services and Chrome<ph name="END_BOLD"></b></ph>. </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION3" desc="A part of the feature description of 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_FEATURE_DESCRIPTION3" desc="A part of the feature description of 'clear cookies on exit' card in the 'Privacy Guide'."> Sites you visit remember your information until you close Chrome </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2" desc="A part of the feature description of the standard protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION2" desc="A part of the feature description of the standard protection section of the safe browsing card in the 'Privacy Guide'."> Checks URLs with a list of unsafe sites stored in Chrome </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the standard protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the standard protection section of the safe browsing card in the 'Privacy Guide'."> If a site tries to steal your password, or when you download a harmful file, Chrome may also send URLs, including bits of page content, to Safe Browsing </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL" desc="Text of the Privacy Sandbox sublabel in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_SUB_LABEL" desc="Text of the Privacy Sandbox sublabel in the completion card of the 'Privacy Guide'."> Chrome is exploring new features that allow sites to deliver the same browsing experience using less of your data </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL" desc="Text of the Web and App Activity sublabel in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_SUB_LABEL" desc="Text of the Web and App Activity sublabel in the completion card of the 'Privacy Guide'."> Choose whether to include Chrome history for more personalized experiences in Google services </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of 'make searches and browsing better' in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of 'make searches and browsing better' in the 'Privacy Guide'."> If you also share Chrome usage reports, those reports include the URLs you visit </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index c17cab0..a7ed516 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1498,127 +1498,127 @@ </message> <!-- Privacy Guide --> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_LABEL" desc="Label of the row in the Chrome privacy and security settings page that leads to the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_LABEL" desc="Label of the row in the Chrome privacy and security settings page that leads to the 'Privacy Guide'. 'Privacy Guide' is a term, see go/glossarymanager/termset?gid=27517723&tsid=28b420b3."> Privacy Guide </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SUBLABEL" desc="Sublabel of the row in the Chrome privacy and security of Chrome settings that leads to the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SUBLABEL" desc="Sublabel of the row in the Chrome privacy and security of Chrome settings that leads to the 'Privacy Guide'."> Review key privacy and security controls </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_HEADER" desc="Text of a button on a card in the settings page that starts the privacy guide feature."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_HEADER" desc="Text of a button on a card in the settings page that starts the 'Privacy Guide'. 'Privacy Guide' is a term, see go/glossarymanager/termset?gid=27517723&tsid=28b420b3."> Take the Privacy Guide </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_START_BUTTON" desc="Text of a button on a card in the settings page that starts the privacy guide feature."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_PROMO_START_BUTTON" desc="Text of a button on a card in the settings page that starts the 'Privacy Guide'."> Get started </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_BACK_BUTTON" desc="Text of a button in the privacy guide that reverses to the previous step in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_BACK_BUTTON" desc="Text of a button in the privacy guide that reverses to the previous step in the 'Privacy Guide'."> Back </message> <message name="IDS_SETTINGS_PRIVACY_GUIDE_STEPS" is_accessibility_with_no_ui="true" desc="Spoken by screenreaders indicating what step the user is in and how many steps there are in total."> Step <ph name="CURRENT_STEP">$1<ex>1</ex></ph> of <ph name="TOTAL_STEPS">$2<ex>2</ex></ph> </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_NEXT_BUTTON" desc="Text of a button in the privacy guide that advances to the next step in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_NEXT_BUTTON" desc="Text of a button in the 'Privacy Guide' that advances to the next step in the privacy guide."> Next </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_FEATURE_DESCRIPTION_HEADER" desc="Header of a description text that describes the behavior of a particular feature. This description is shown to users alongside the feature itself in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_FEATURE_DESCRIPTION_HEADER" desc="Header of a description text that describes the behavior of a particular feature. This description is shown to users alongside the feature itself in the 'Privacy Guide'."> When on </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_THINGS_TO_CONSIDER" desc="Header of a text column that describes things users should consider about a feature. This description is shown to users alongside the feature itself in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_THINGS_TO_CONSIDER" desc="Header of a text column that describes things users should consider about a feature. This description is shown to users alongside the feature itself in the 'Privacy Guide'."> Things to consider </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_HEADER" desc="A header shown at the top of the welcome card in the privacy guide, explaining to users what privacy guide is."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_HEADER" desc="A header shown at the top of the welcome card in the 'Privacy Guide', explaining to users what the 'Privacy Guide' is."> A guide of your privacy choices </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_SUB_HEADER" desc="A subheader shown at on the welcome card in the privacy guide, explaining to users what privacy guide is."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_WELCOME_CARD_SUB_HEADER" desc="A subheader shown at on the welcome card in the 'Privacy Guide', explaining to users what the 'Privacy Guide' is."> Take a guided tour of key privacy and security controls. For more options, go to individual settings. </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_HEADER" desc="A header shown at the top of the completion card in the privacy guide that informs users that they completed the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_HEADER" desc="A header shown at the top of the completion card in the 'Privacy Guide' that informs users that they completed the 'Privacy Guide'."> Review complete </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER" desc="A subheader shown at the top of the completion card in the privacy guide that informs users that they can explore more settings or complete the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_SUB_HEADER" desc="A subheader shown at the top of the completion card in the 'Privacy Guide' that informs users that they can explore more settings or complete the 'Privacy Guide'."> Explore more settings below or finish now </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_LEAVE_BUTTON" desc="Text of a button in the completion card in the privacy guide that leads the user back to Chrome settings."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_LEAVE_BUTTON" desc="Text of a button in the completion card in the 'Privacy Guide' that leads the user back to Chrome settings."> Done </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_LABEL" desc="Text of the Privacy Sandbox label in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_PRIVACY_SANDBOX_LABEL" desc="Text of the Privacy Sandbox label in the completion card of the 'Privacy Guide'."> Privacy Sandbox trial </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_LABEL" desc="Text of the Web and App Activity label in the completion card of the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COMPLETION_CARD_WAA_LABEL" desc="Text of the Web and App Activity label in the completion card of the 'Privacy Guide'."> Web & App Activity </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_CARD_HEADER" desc="Header of the 'make searches and browsing better' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_CARD_HEADER" desc="Header of the 'make searches and browsing better' card in the 'Privacy Guide'."> Choose your search and browsing quality </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'make searches and browsing better' in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION1" desc="A part of the feature description of 'make searches and browsing better' in the 'Privacy Guide'."> You'll browse faster because content is proactively loaded based on your current webpage visit </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'make searches and browsing better' in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_FEATURE_DESCRIPTION2" desc="A part of the feature description of 'make searches and browsing better' in the 'Privacy Guide'."> You'll get improved suggestions in the address bar </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of 'make searches and browsing better' in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_MSBB_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of 'make searches and browsing better' in the 'Privacy Guide'."> URLs you visit are sent to Google to predict what sites you might visit next </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_CARD_HEADER" desc="Header of the 'clear cookies on exit' card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_CLEAR_ON_EXIT_CARD_HEADER" desc="Header of the 'clear cookies on exit' card in the 'Privacy Guide'."> Review automatic data clearing </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_CARD_HEADER" desc="Header of the history sync card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_CARD_HEADER" desc="Header of the history sync card in the 'Privacy Guide'."> Choose whether to sync history </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_SETTING_LABEL" desc="Label of the history sync settings toggle in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_SETTING_LABEL" desc="Label of the history sync settings toggle in the 'Privacy Guide'."> History sync </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION1" desc="A part of the feature description of history sync in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION1" desc="A part of the feature description of history sync in the 'Privacy guide'."> You'll have your history on all your synced devices so you can continue what you were doing </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION2" desc="A part of the feature description of history sync in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_FEATURE_DESCRIPTION2" desc="A part of the feature description of history sync in the 'Privacy guide'."> If Google is also your default search engine, you'll see better, contextually relevant suggestions </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of history sync in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_HISTORY_SYNC_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of history sync in the 'Privacy guide'."> The URLs you visit are saved to your Google Account </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_HEADER" desc="Header of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_HEADER" desc="Header of the cookies card in the 'Privacy guide'."> Choose your third-party cookie preferences </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_SUBHEADER" desc="A subheader for the cookies card of the privacy guide, for blocking third party cookies in incognito."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_SUBHEADER" desc="A subheader for the cookies card of the 'Privacy guide', for blocking third party cookies in incognito."> Block third-party cookies in Incognito </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION1" desc="A part of the feature description of the third party cookie blocking in incognito section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION1" desc="A part of the feature description of the third party cookie blocking in incognito section of the cookies card in the 'Privacy guide'."> Sites can use cookies to improve your browsing experience, for example, to keep you signed in or to remember items in your shopping cart </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION2" desc="A part of the feature description of the third party cookie blocking in incognito section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_FEATURE_DESCRIPTION2" desc="A part of the feature description of the third party cookie blocking in incognito section of the cookies card in the 'Privacy guide'."> Features on some sites may not work in Incognito </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the third party cookie blocking in incognito section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the third party cookie blocking in incognito section of the cookies card in the 'Privacy guide'."> Sites can use cookies to see your browsing activity across different sites, for example, to personalize ads </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of the third party cookie blocking in incognito section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_INCOGNITO_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of the third party cookie blocking in incognito section of the cookies card in the 'Privacy guide'."> When you’re in Incognito mode, sites can only use cookies to see your browsing activity on their own site. Cookies are deleted at the end of the Incognito session. </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_SUBHEADER" desc="A subheader for the cookies card of the privacy guide, for blocking third party cookies."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_SUBHEADER" desc="A subheader for the cookies card of the 'Privacy guide', for blocking third party cookies."> Block all third-party cookies </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION1" desc="A part of the feature description of the third party cookie blocking section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION1" desc="A part of the feature description of the third party cookie blocking section of the cookies card in the 'Privacy guide'."> Sites can use cookies to improve your browsing experience, for example, to keep you signed in or to remember items in your shopping cart </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION2" desc="A part of the feature description of the third party cookie blocking section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_FEATURE_DESCRIPTION2" desc="A part of the feature description of the third party cookie blocking section of the cookies card in the 'Privacy guide'."> Features on some sites may not work </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the third party cookie blocking section of the cookies card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_COOKIES_CARD_BLOCK_TPC_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the third party cookie blocking section of the cookies card in the 'Privacy guide'."> Sites can only use cookies to see your browsing activity on their own site </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_HEADER" desc="Header of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_HEADER" desc="Header of the safe browsing card in the 'Privacy guide'."> Choose your Safe Browsing protection </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION1" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the 'Privacy guide'."> Sends URLs to Safe Browsing to check them </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION2" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the 'Privacy guide'."> Also sends a small sample of pages, downloads, extension activity, and system information to help discover new threats </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION3" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_ENHANCED_PROTECTION_PRIVACY_DESCRIPTION3" desc="A part of the privacy description of the enhanced protection section of the safe browsing card in the 'Privacy guide'."> Temporarily links this data to your Google Account when you're signed in, to protect you across Google apps </message> - <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION1" desc="A part of the feature description of the standard protection section of the safe browsing card in the privacy guide."> + <message name="IDS_SETTINGS_PRIVACY_GUIDE_SAFE_BROWSING_CARD_STANDARD_PROTECTION_FEATURE_DESCRIPTION1" desc="A part of the feature description of the standard protection section of the safe browsing card in the 'Privacy guide'."> Detects and warns you about dangerous events when they happen </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 82112c1..35b3cc1 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2520,8 +2520,12 @@ ] } if (is_linux || is_chromeos) { - deps += [ "//chrome/browser/error_reporting" ] + deps += [ + "//chrome/browser/error_reporting", + "//components/services/screen_ai/public/cpp:screen_ai_service_router_factory", + ] } + if (use_ozone) { deps += [ "//ui/events/ozone",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index d2b1ef8..5b1482c 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -310,6 +310,7 @@ "+components/session_manager", "+components/sessions/content", "+components/sessions/core", + "+components/services/screen_ai/public/cpp", "+components/signin/core/browser", "+components/signin/public", "+components/site_engagement",
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc index 2b2f3b66..075975d9 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -58,6 +58,7 @@ ConvertNativeOptionalStringToJava; using ::autofill_assistant::ui_controller_android_utils::CreateJavaInfoPopup; using ::base::android::AttachCurrentThread; +using ::base::android::ConvertUTF16ToJavaString; using ::base::android::ConvertUTF8ToJavaString; using ::base::android::JavaParamRef; using ::base::android::JavaRef; @@ -249,6 +250,43 @@ return input_result.selection().selected(selection_index); } +// Analog to +// PersonalDataManagerAndroid::GetShippingAddressLabelForPaymentRequest. +base::android::ScopedJavaLocalRef<jstring> GetShippingAddressLabel( + JNIEnv* env, + const autofill::AutofillProfile* profile, + bool with_country) { + if (!profile) { + return ConvertUTF8ToJavaString(env, std::string()); + } + + // The full name is not included in the label for shipping address. It is + // added separately instead. + static constexpr autofill::ServerFieldType kLabelFields[] = { + autofill::ServerFieldType::COMPANY_NAME, + autofill::ServerFieldType::ADDRESS_HOME_LINE1, + autofill::ServerFieldType::ADDRESS_HOME_LINE2, + autofill::ServerFieldType::ADDRESS_HOME_DEPENDENT_LOCALITY, + autofill::ServerFieldType::ADDRESS_HOME_CITY, + autofill::ServerFieldType::ADDRESS_HOME_STATE, + autofill::ServerFieldType::ADDRESS_HOME_ZIP, + autofill::ServerFieldType::ADDRESS_HOME_SORTING_CODE, + autofill::ServerFieldType::ADDRESS_HOME_COUNTRY, + }; + size_t fields_size = base::size(kLabelFields); + + // For the case where country is omitted, do not use the last field. + if (!with_country) { + --fields_size; + } + + return ConvertUTF16ToJavaString( + env, profile->ConstructInferredLabel( + kLabelFields, /* label_fields_size= */ fields_size, + /* num_fields_to_include= */ fields_size, + base::android::GetDefaultLocaleString())); +} + } // namespace // static @@ -1445,12 +1483,22 @@ ui_controller_android_utils::CreateAssistantAutofillProfile( env, *user_data.available_addresses_[index]->profile, base::android::GetDefaultLocaleString()), + GetShippingAddressLabel( + env, user_data.available_addresses_[index]->profile.get(), + /* with_country= */ true), + GetShippingAddressLabel( + env, user_data.available_addresses_[index]->profile.get(), + /* with_country= */ false), base::android::ToJavaArrayOfStrings(env, errors)); } Java_AssistantCollectUserDataModel_setAvailableShippingAddresses( env, jmodel, jshippinglist); Java_AssistantCollectUserDataModel_setSelectedShippingAddress( env, jmodel, jselected_shipping_address, + GetShippingAddressLabel(env, selected_shipping_address, + /* with_country= */ true), + GetShippingAddressLabel(env, selected_shipping_address, + /* with_country= */ false), base::android::ToJavaArrayOfStrings(env, selected_shipping_address_errors)); } @@ -1475,6 +1523,10 @@ // off case does not set updated shipping addresses. Java_AssistantCollectUserDataModel_setSelectedShippingAddress( env, jmodel, jselected_shipping_address, + GetShippingAddressLabel(env, selected_shipping_address, + /* with_country= */ true), + GetShippingAddressLabel(env, selected_shipping_address, + /* with_country= */ false), base::android::ToJavaArrayOfStrings(env, selected_shipping_address_errors)); }
diff --git a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc index 4bb176c..7c0d2cd 100644 --- a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc +++ b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/android/callback_android.h" #include "base/android/jni_string.h" #include "chrome/android/chrome_jni_headers/AutofillPaymentMethodsDelegate_jni.h" #include "chrome/android/chrome_jni_headers/VirtualCardEnrollmentFields_jni.h" @@ -30,6 +31,8 @@ using base::android::AttachCurrentThread; using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF8ToJavaString; +using base::android::JavaRef; +using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; namespace autofill { @@ -75,6 +78,14 @@ return java_object; } +// static +void RunVirtualCardEnrollmentFieldsLoadedCallback( + const JavaRef<jobject>& j_callback, + VirtualCardEnrollmentFields* virtual_card_enrollment_fields) { + RunObjectCallbackAndroid(j_callback, GetVirtualCardEnrollmentFieldsJavaObject( + virtual_card_enrollment_fields)); +} + AutofillPaymentMethodsDelegate::AutofillPaymentMethodsDelegate(Profile* profile) : profile_(profile) { personal_data_manager_ = PersonalDataManagerFactory::GetForProfile(profile); @@ -110,11 +121,13 @@ personal_data_manager_->GetCreditCardByInstrumentId(instrument_id); virtual_card_enrollment_manager_->OfferVirtualCardEnroll( *credit_card, VirtualCardEnrollmentSource::kSettingsPage, - profile_->GetPrefs(), base::BindOnce(&risk_util::LoadRiskDataHelper)); + profile_->GetPrefs(), base::BindOnce(&risk_util::LoadRiskDataHelper), + base::BindOnce(&RunVirtualCardEnrollmentFieldsLoadedCallback, + ScopedJavaGlobalRef<jobject>(jcallback))); } void AutofillPaymentMethodsDelegate::EnrollOfferedVirtualCard(JNIEnv* env) { - // TODO (crbug/1281695) Implement call to enroll Virtual Cards. + virtual_card_enrollment_manager_->Enroll(); } void AutofillPaymentMethodsDelegate::UnenrollVirtualCard(
diff --git a/chrome/browser/apps/app_service/app_service_proxy_ash.cc b/chrome/browser/apps/app_service/app_service_proxy_ash.cc index ef240fc..7b0a685 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_ash.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
@@ -279,7 +279,12 @@ return; } - if (uninstall_dialogs_.find(app_id) != uninstall_dialogs_.end()) { + // If the dialog exists for the app id, we bring the dialog to the front + auto it = uninstall_dialogs_.find(app_id); + if (it != uninstall_dialogs_.end()) { + if (it->second->GetWidget()) { + it->second->GetWidget()->Show(); + } if (!callback.is_null()) { std::move(callback).Run(false); }
diff --git a/chrome/browser/apps/app_service/uninstall_dialog.cc b/chrome/browser/apps/app_service/uninstall_dialog.cc index 37bfee43..5312617 100644 --- a/chrome/browser/apps/app_service/uninstall_dialog.cc +++ b/chrome/browser/apps/app_service/uninstall_dialog.cc
@@ -85,6 +85,10 @@ } } +views::Widget* UninstallDialog::GetWidget() { + return widget_; +} + void UninstallDialog::OnDialogClosed(bool uninstall, bool clear_site_data, bool report_abuse) { @@ -109,8 +113,8 @@ return; } - UiBase::Create(profile_, app_type_, app_id_, app_name_, - icon_value->uncompressed, parent_window_, this); + widget_ = UiBase::Create(profile_, app_type_, app_id_, app_name_, + icon_value->uncompressed, parent_window_, this); // For browser tests, if the callback is set, run the callback to stop the run // loop.
diff --git a/chrome/browser/apps/app_service/uninstall_dialog.h b/chrome/browser/apps/app_service/uninstall_dialog.h index 2e50ff6..c944b441 100644 --- a/chrome/browser/apps/app_service/uninstall_dialog.h +++ b/chrome/browser/apps/app_service/uninstall_dialog.h
@@ -14,6 +14,7 @@ #include "components/services/app_service/public/cpp/icon_types.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "ui/gfx/native_widget_types.h" +#include "ui/views/widget/widget.h" class NativeWindowTracker; class Profile; @@ -56,13 +57,13 @@ UiBase& operator=(const UiBase&) = delete; virtual ~UiBase() = default; - static void Create(Profile* profile, - apps::mojom::AppType app_type, - const std::string& app_id, - const std::string& app_name, - gfx::ImageSkia image, - gfx::NativeWindow parent_window, - UninstallDialog* uninstall_dialog); + static views::Widget* Create(Profile* profile, + apps::mojom::AppType app_type, + const std::string& app_id, + const std::string& app_name, + gfx::ImageSkia image, + gfx::NativeWindow parent_window, + UninstallDialog* uninstall_dialog); UninstallDialog* uninstall_dialog() const { return uninstall_dialog_; } @@ -98,6 +99,8 @@ void PrepareToShow(apps::mojom::IconKeyPtr mojom_icon_key, apps::IconLoader* icon_loader); + views::Widget* GetWidget(); + // Called when the uninstall dialog is closing to process uninstall or cancel // the uninstall. void OnDialogClosed(bool uninstall, bool clear_site_data, bool report_abuse); @@ -118,6 +121,8 @@ OnUninstallForTestingCallback uninstall_dialog_created_callback_; + views::Widget* widget_ = nullptr; + // Tracks whether |parent_window_| got destroyed. std::unique_ptr<NativeWindowTracker> parent_window_tracker_;
diff --git a/chrome/browser/ash/input_method/text_utils.cc b/chrome/browser/ash/input_method/text_utils.cc index 7dd0d69..8d76ca63 100644 --- a/chrome/browser/ash/input_method/text_utils.cc +++ b/chrome/browser/ash/input_method/text_utils.cc
@@ -29,7 +29,7 @@ while (idx <= pos && pos - idx <= kSpecialWordMaxLength && text[idx] != u' ' && text[idx] != u'(') idx--; - if (pos - idx > kSpecialWordMaxLength) + if (idx > pos || pos - idx > kSpecialWordMaxLength) return false; std::u16string last_word = text.substr(idx + 1, pos - idx); return (last_word == u"c.f." || last_word == u"cf." || last_word == u"e.g." || @@ -131,6 +131,8 @@ } Sentence FindLastSentence(const std::u16string& text, uint32_t pos) { + if (pos > text.size()) + return Sentence(); if (pos > 0 && (pos == text.size() || text[pos] == '\n' || text[pos] == '\r')) { pos--; @@ -153,6 +155,8 @@ } Sentence FindCurrentSentence(const std::u16string& text, uint32_t pos) { + if (pos > text.size()) + return Sentence(); if (pos > 0 && (pos == text.size() || text[pos] == '\n' || text[pos] == '\r')) { pos--;
diff --git a/chrome/browser/ash/login/screens/gaia_screen.cc b/chrome/browser/ash/login/screens/gaia_screen.cc index 3ff6793..6d7989f 100644 --- a/chrome/browser/ash/login/screens/gaia_screen.cc +++ b/chrome/browser/ash/login/screens/gaia_screen.cc
@@ -20,6 +20,7 @@ constexpr char kUserActionStartEnrollment[] = "startEnrollment"; constexpr char kUserActionReloadDefault[] = "reloadDefault"; constexpr char kUserActionSAMLVideoTimeout[] = "samlVideoTimeout"; +constexpr char kUserActionRetry[] = "retry"; } // namespace @@ -109,6 +110,8 @@ } else if (action_id == kUserActionReloadDefault) { DCHECK(features::IsRedirectToDefaultIdPEnabled()); LoadOnline(EmptyAccountId()); + } else if (action_id == kUserActionRetry) { + LoadOnline(EmptyAccountId()); } else if (action_id == kUserActionSAMLVideoTimeout) { DCHECK(features::IsRedirectToDefaultIdPEnabled()); exit_callback_.Run(Result::SAML_VIDEO_TIMEOUT);
diff --git a/chrome/browser/ash/login/ui/mock_login_display.h b/chrome/browser/ash/login/ui/mock_login_display.h index 069601ca..a95f418 100644 --- a/chrome/browser/ash/login/ui/mock_login_display.h +++ b/chrome/browser/ash/login/ui/mock_login_display.h
@@ -17,14 +17,13 @@ MockLoginDisplay(const MockLoginDisplay&) = delete; MockLoginDisplay& operator=(const MockLoginDisplay&) = delete; - ~MockLoginDisplay(); + ~MockLoginDisplay() override; MOCK_METHOD0(ClearAndEnablePassword, void(void)); MOCK_METHOD4(Init, void(const user_manager::UserList&, bool, bool, bool)); MOCK_METHOD0(OnPreferencesChanged, void(void)); MOCK_METHOD1(OnUserImageChanged, void(const user_manager::User&)); MOCK_METHOD1(SetUIEnabled, void(bool)); - MOCK_METHOD1(ShowSigninUI, void(const std::string&)); }; } // namespace ash
diff --git a/chrome/browser/ash/policy/enrollment/private_membership/psm_rlwe_id_provider_impl_unittest.cc b/chrome/browser/ash/policy/enrollment/private_membership/psm_rlwe_id_provider_impl_unittest.cc new file mode 100644 index 0000000..635a2aad --- /dev/null +++ b/chrome/browser/ash/policy/enrollment/private_membership/psm_rlwe_id_provider_impl_unittest.cc
@@ -0,0 +1,51 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ash/policy/enrollment/private_membership/psm_rlwe_id_provider_impl.h" + +#include "chromeos/system/fake_statistics_provider.h" +#include "chromeos/system/statistics_provider.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/private_membership/src/private_membership_rlwe.pb.h" + +namespace psm_rlwe = private_membership::rlwe; + +namespace policy { + +class PsmRlweIdProviderImplTest : public testing::Test { + protected: + PsmRlweIdProviderImplTest() = default; + + PsmRlweIdProviderImplTest(const PsmRlweIdProviderImplTest&) = delete; + PsmRlweIdProviderImplTest& operator=(const PsmRlweIdProviderImplTest&) = + delete; + ~PsmRlweIdProviderImplTest() override = default; + + chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_; + PsmRlweIdProviderImpl psm_rlwe_impl; + const std::string kTestSerialNumber = "111111"; + const std::string kTestBrandCode = "TEST"; + + // `kTestBrandCode` encoded in hex. + const std::string kTestBrandCodeHex = "54455354"; +}; + +TEST_F(PsmRlweIdProviderImplTest, VerifyConstructedRlweId) { + // Sets the values for serial number and RLZ brand code as the values must be + // present to construct the RLWE ID without CHECK-failures. + fake_statistics_provider_.SetMachineStatistic( + chromeos::system::kSerialNumberKeyForTest, kTestSerialNumber); + fake_statistics_provider_.SetMachineStatistic( + chromeos::system::kRlzBrandCodeKey, kTestBrandCode); + + // RLZ brand code "TEST" (as hex), "/" seperator, and serial number "111111". + const std::string kExpectedPsmRlweIdStr = + kTestBrandCodeHex + "/" + kTestSerialNumber; + + // Construct the PSM RLWE ID, and verify its value. + psm_rlwe::RlwePlaintextId rlwe_id = psm_rlwe_impl.ConstructRlweId(); + EXPECT_EQ(rlwe_id.sensitive_id(), kExpectedPsmRlweIdStr); +} + +} // namespace policy
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index 5df557b..4e47bb21 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -636,7 +636,7 @@ if (filter_builder->GetMode() == BrowsingDataFilterBuilder::Mode::kPreserve) { - PrivacySandboxSettings* privacy_sandbox_settings = + auto* privacy_sandbox_settings = PrivacySandboxSettingsFactory::GetForProfile(profile_); if (privacy_sandbox_settings) privacy_sandbox_settings->OnCookiesCleared();
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 22d8c6d..b455296fc 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -264,6 +264,11 @@ #include "ui/webui/resources/cr_components/app_management/app_management.mojom.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#include "components/services/screen_ai/public/cpp/screen_ai_service_router.h" +#include "components/services/screen_ai/public/cpp/screen_ai_service_router_factory.h" +#endif + #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) @@ -557,6 +562,16 @@ } #endif +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +void BindScreenAIAnnotator( + content::RenderFrameHost* frame_host, + mojo::PendingReceiver<screen_ai::mojom::ScreenAIAnnotator> receiver) { + ScreenAIServiceRouterFactory::GetForBrowserContext( + frame_host->GetProcess()->GetBrowserContext()) + ->BindScreenAIAnnotator(std::move(receiver)); +} +#endif + void PopulateChromeFrameBinders( mojo::BinderMapWithContext<content::RenderFrameHost*>* map, content::RenderFrameHost* render_frame_host) { @@ -687,6 +702,13 @@ base::BindRepeating(&web_app::SubAppsServiceImpl::CreateIfAllowed)); } #endif + +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + if (base::FeatureList::IsEnabled(features::kScreenAI)) { + map->Add<screen_ai::mojom::ScreenAIAnnotator>( + base::BindRepeating(&BindScreenAIAnnotator)); + } +#endif } void PopulateChromeWebUIFrameBinders(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index f7cd7ae..69a555f2 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2774,7 +2774,7 @@ const url::Origin& api_origin) { Profile* profile = Profile::FromBrowserContext(render_frame_host->GetBrowserContext()); - PrivacySandboxSettings* privacy_sandbox_settings = + auto* privacy_sandbox_settings = PrivacySandboxSettingsFactory::GetForProfile(profile); DCHECK(privacy_sandbox_settings); @@ -2804,7 +2804,7 @@ const url::Origin* reporting_origin) { Profile* profile = Profile::FromBrowserContext(browser_context); - PrivacySandboxSettings* privacy_sandbox_settings = + auto* privacy_sandbox_settings = PrivacySandboxSettingsFactory::GetForProfile(profile); if (!privacy_sandbox_settings) return false;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 6d3fcaf..98fa00d 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -431,6 +431,8 @@ "//components/services/app_service/public/cpp:instance_update", "//components/services/app_service/public/cpp:intents", "//components/services/app_service/public/cpp:types", + "//components/services/unzip/content:content", + "//components/services/unzip/public/cpp:cpp", "//components/session_manager/core", "//components/signin/public/identity_manager", "//components/signin/public/webdata", @@ -509,6 +511,7 @@ "//storage/common", "//third_party/blink/public/common", "//third_party/boringssl", + "//third_party/ced", "//third_party/icu", "//third_party/libaddressinput", "//third_party/libipp", @@ -4467,6 +4470,7 @@ "../ash/policy/enrollment/account_status_check_fetcher_unittest.cc", "../ash/policy/enrollment/auto_enrollment_client_impl_unittest.cc", "../ash/policy/enrollment/device_cloud_policy_initializer_unittest.cc", + "../ash/policy/enrollment/private_membership/psm_rlwe_id_provider_impl_unittest.cc", "../ash/policy/enrollment/private_membership/testing_private_membership_rlwe_client.cc", "../ash/policy/enrollment/private_membership/testing_private_membership_rlwe_client.h", "../ash/policy/enrollment/tpm_enrollment_key_signing_service_unittest.cc", @@ -4780,6 +4784,7 @@ "../ui/webui/settings/about_handler_unittest.cc", "../ui/webui/settings/ash/calculator/size_calculator_test_api.h", "../ui/webui/settings/ash/os_apps_page/app_notification_handler_unittest.cc", + "../ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc", "../ui/webui/settings/chromeos/ambient_mode_handler_unittest.cc", "../ui/webui/settings/chromeos/bluetooth_handler_unittest.cc", "../ui/webui/settings/chromeos/change_picture_handler_unittest.cc",
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS index 251c8bac..cd622ae 100644 --- a/chrome/browser/chromeos/DEPS +++ b/chrome/browser/chromeos/DEPS
@@ -30,6 +30,7 @@ "+services/network", "+services/tracing/public", "+services/viz/public/mojom", + "+third_party/ced", ] specific_include_rules = {
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc index 7199354b..4907fb09a 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -5,7 +5,6 @@ #include "chrome/browser/chromeos/extensions/file_manager/private_api_mount.h" #include <memory> -#include <string> #include <utility> #include "ash/components/disks/disk_mount_manager.h" @@ -27,6 +26,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/file_manager_private.h" #include "components/drive/event_logger.h" +#include "components/services/unzip/content/unzip_service.h" +#include "components/services/unzip/public/cpp/unzip.h" #include "content/public/browser/browser_thread.h" #include "google_apis/common/task_util.h" #include "storage/browser/file_system/file_system_url.h" @@ -41,6 +42,9 @@ FileManagerPrivateAddMountFunction::FileManagerPrivateAddMountFunction() = default; +FileManagerPrivateAddMountFunction::~FileManagerPrivateAddMountFunction() = + default; + ExtensionFunction::ResponseAction FileManagerPrivateAddMountFunction::Run() { using file_manager_private::AddMount::Params; const std::unique_ptr<Params> params = Params::Create(args()); @@ -55,10 +59,10 @@ } set_log_on_completion(true); - const base::FilePath path = file_manager::util::GetLocalPathFromURL( - render_frame_host(), profile, GURL(params->source)); + path_ = file_manager::util::GetLocalPathFromURL(render_frame_host(), profile, + GURL(params->source)); - if (path.empty()) + if (path_.empty()) return RespondNow(Error("Invalid path")); if (auto* notifier = @@ -77,19 +81,47 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); - std::vector<std::string> options; if (params->password) - options.push_back("password=" + *params->password); + options_.push_back("password=" + *params->password); - // MountPath() takes a std::string. - DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance(); - disk_mount_manager->MountPath( - path.AsUTF8Unsafe(), base::ToLowerASCII(path.Extension()), - path.BaseName().AsUTF8Unsafe(), options, chromeos::MOUNT_TYPE_ARCHIVE, - chromeos::MOUNT_ACCESS_MODE_READ_WRITE, base::DoNothing()); + extension_ = base::ToLowerASCII(path_.Extension()); + + // Detect the file path encoding of ZIP archives. + if (extension_ == ".zip") { + unzip::DetectEncoding( + unzip::LaunchUnzipper(), path_, + base::BindOnce(&FileManagerPrivateAddMountFunction::OnEncodingDetected, + this)); + } else { + FinishMounting(); + } // Pass back the actual source path of the mount point. - return RespondNow(OneArgument(base::Value(path.AsUTF8Unsafe()))); + return RespondNow(OneArgument(base::Value(path_.AsUTF8Unsafe()))); +} + +void FileManagerPrivateAddMountFunction::OnEncodingDetected( + const Encoding encoding) { + // Pass the detected ZIP encoding as a mount option. + std::string& option = options_.emplace_back("encoding="); + + if (IsShiftJisOrVariant(encoding) || encoding == RUSSIAN_CP866) { + option += MimeEncodingName(encoding); + } else { + option += "libzip"; + } + + FinishMounting(); +} + +void FileManagerPrivateAddMountFunction::FinishMounting() { + DiskMountManager* const disk_mount_manager = DiskMountManager::GetInstance(); + DCHECK(disk_mount_manager); + disk_mount_manager->MountPath( + path_.AsUTF8Unsafe(), std::move(extension_), + path_.BaseName().AsUTF8Unsafe(), std::move(options_), + chromeos::MOUNT_TYPE_ARCHIVE, chromeos::MOUNT_ACCESS_MODE_READ_WRITE, + base::DoNothing()); } ExtensionFunction::ResponseAction FileManagerPrivateRemoveMountFunction::Run() {
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.h b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.h index aaab168..8650fae5 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.h
@@ -7,8 +7,12 @@ #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_MOUNT_H_ #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_MOUNT_H_ +#include <string> +#include <vector> + #include "chrome/browser/chromeos/extensions/file_manager/logged_extension_function.h" #include "components/drive/file_errors.h" +#include "third_party/ced/src/util/encodings/encodings.h" namespace extensions { @@ -21,11 +25,26 @@ DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.addMount", FILEMANAGERPRIVATE_ADDMOUNT) - protected: - ~FileManagerPrivateAddMountFunction() override = default; + private: + ~FileManagerPrivateAddMountFunction() override; // ExtensionFunction overrides. ResponseAction Run() override; + + // Called when the encoding of a ZIP archive has been determined. + void OnEncodingDetected(Encoding encoding); + + // Finishes mounting after encoding is detected. + void FinishMounting(); + + // Path of the device or archive to mount. + base::FilePath path_; + + // Lowercase extension of the path to mount. + std::string extension_; + + // Mount options. + std::vector<std::string> options_; }; // Implements chrome.fileManagerPrivate.removeMount method.
diff --git a/chrome/browser/incognito/BUILD.gn b/chrome/browser/incognito/BUILD.gn index 53bec49..4446fc7 100644 --- a/chrome/browser/incognito/BUILD.gn +++ b/chrome/browser/incognito/BUILD.gn
@@ -10,6 +10,8 @@ "android/java/src/org/chromium/chrome/browser/incognito/IncognitoStartup.java", "android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabPersistence.java", "android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java", + "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthController.java", + "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthCoordinator.java", "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthManager.java", "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthSettingSwitchPreference.java", "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthSettingUtils.java", @@ -17,6 +19,7 @@ deps = [ ":java_resources", "//base:base_java", + "//chrome/browser/android/lifecycle:java", "//chrome/browser/dependency_injection:java", "//chrome/browser/device_reauth/android:java", "//chrome/browser/flags:java", @@ -25,6 +28,7 @@ "//chrome/browser/tab:java", "//chrome/browser/tabmodel:java", "//chrome/browser/tabpersistence:java", + "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/strings:ui_strings_grd", "//chrome/browser/util:java", "//components/browser_ui/settings/android:java", @@ -93,20 +97,31 @@ # Platform checks are broken for Robolectric. See https://crbug.com/1071638. bypass_platform_checks = true - sources = [ "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthManagerTest.java" ] + sources = [ + "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerTest.java", + "android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthManagerTest.java", + ] deps = [ ":java", "//base:base_java", "//base:base_java_test_support", "//base:base_junit_test_support", + "//chrome/android:chrome_java", + "//chrome/browser/android/lifecycle:java", "//chrome/browser/device_reauth/android:java", "//chrome/browser/flags:java", + "//chrome/browser/profiles/android:java", + "//chrome/browser/tab:java", + "//chrome/browser/tabmodel:java", + "//chrome/browser/ui/android/layouts:java", "//chrome/test/android:chrome_java_test_support", "//third_party/android_deps:robolectric_all_java", + "//third_party/android_support_test_runner:runner_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/junit:junit", "//third_party/mockito:mockito_java", "//ui/android:ui_java_test_support", + "//ui/android:ui_no_recycler_view_java", ] }
diff --git a/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthController.java b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthController.java new file mode 100644 index 0000000..2560773 --- /dev/null +++ b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthController.java
@@ -0,0 +1,265 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.incognito.reauth; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.base.Callback; +import org.chromium.base.CallbackController; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.OneshotSupplier; +import org.chromium.chrome.browser.layouts.LayoutStateProvider; +import org.chromium.chrome.browser.layouts.LayoutType; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData; +import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; +import org.chromium.ui.modaldialog.DialogDismissalCause; +import org.chromium.ui.modaldialog.ModalDialogManager; + +/** + * This is the access point for showing the Incognito re-auth dialog. It controls building the + * {@link IncognitoReauthCoordinator} and showing/hiding the re-auth dialog. The {@link + * IncognitoReauthCoordinator} is created and destroyed each time the dialog is shown and hidden. + */ +public class IncognitoReauthController + implements IncognitoTabModelObserver.IncognitoReauthDialogDelegate, + StartStopWithNativeObserver { + // This callback is fired when the user clicks on "Unlock Incognito" option. + // This contains the logic to not require further re-authentication if the last one was a + // success. Please note, a re-authentication would be required again when Chrome is brought to + // foreground again. + // TODO(crbug.com/1227656): Connect this callback to "Unlock Incognito" option once the MVC is + // added. + private final IncognitoReauthManager.IncognitoReauthCallback mIncognitoReauthCallback = + new IncognitoReauthManager.IncognitoReauthCallback() { + @Override + public void onIncognitoReauthNotPossible() { + // TODO(crbug.com/1227656): Add new dialog dismissal cause as the meaning can be + // ambiguous. + hideDialogIfShowing(DialogDismissalCause.UNKNOWN); + } + + @Override + public void onIncognitoReauthSuccess() { + mIncognitoReauthPending = false; + // TODO(crbug.com/1227656): Add new dialog dismissal cause as the meaning can be + // ambiguous. + hideDialogIfShowing(DialogDismissalCause.ACTION_ON_CONTENT); + } + + @Override + public void onIncognitoReauthFailure() {} + }; + + // If the user has closed all Incognito tabs, then they don't need to go through re-auth to open + // fresh Incognito tabs. + private final IncognitoTabModelObserver mIncognitoTabModelObserver = + new IncognitoTabModelObserver() { + @Override + public void didBecomeEmpty() { + mIncognitoReauthPending = false; + } + }; + + // An observer to handle cases for Incognito tabs restore cases. + private final TabModelSelectorObserver mTabModelSelectorObserver = + new TabModelSelectorObserver() { + @Override + public void onTabStateInitialized() { + onTabStateInitializedForReauth(); + } + }; + + // The {@link TabModelSelectorProfileSupplier} passed to the constructor may not have a {@link + // Profile} set if the Tab state is not initialized yet. We make use of the {@link Profile} when + // accessing {@link UserPrefs} in showDialogIfRequired. A null {@link Profile} would result in a + // crash when accessing the pref. Therefore this callback is fired when the Profile is ready + // which sets the |mProfile| and shows the re-auth dialog if required. + private final Callback<Profile> mProfileSupplierCallback = new Callback<Profile>() { + @Override + public void onResult(@NonNull Profile profile) { + mProfile = profile; + showDialogIfRequired(); + } + }; + + // The {@link CallbackController} to populate the |mLayoutStateProvider| when it becomes + // available. + private final CallbackController mLayoutStateProviderCallbackController = + new CallbackController(); + + private final @NonNull Context mContext; + private final @NonNull ActivityLifecycleDispatcher mActivityLifecycleDispatcher; + private final @NonNull TabModelSelector mTabModelSelector; + private final @NonNull ModalDialogManager mModalDialogManager; + private final @NonNull ObservableSupplier<Profile> mProfileObservableSupplier; + + // No strong reference to this should be made outside of this class because + // we set this to null in hideDialogIfShowing for it to be garbage collected. + private @Nullable IncognitoReauthCoordinator mIncognitoReauthCoordinator; + private @Nullable LayoutStateProvider mLayoutStateProvider; + + private @Nullable Profile mProfile; + private boolean mIncognitoReauthPending; + + /** + * @param context The {@link Context} of the Activity where the re-auth dialog would be shown. + * @param tabModelSelector The {@link TabModelSelector} in order to interact with the + * regular/Incognito {@link TabModel}. + * @param dispatcher The {@link ActivityLifecycleDispatcher} in order to register to + * onStartWithNative event. + * @param modalDialogManager The {@link ModalDialogManager} of the underlying {@link + * ChromeActivity} to handle dialogs. + * @param layoutStateProviderOneshotSupplier A supplier of {@link LayoutStateProvider} which is + * used to determine the current {@link LayoutType} which is shown. + * @param profileSupplier A Observable Supplier of {@link Profile} which is used to query the + * preference value of the Incognito lock setting. + */ + public IncognitoReauthController(@NonNull Context context, + @NonNull TabModelSelector tabModelSelector, + @NonNull ActivityLifecycleDispatcher dispatcher, + @NonNull ModalDialogManager modalDialogManager, + @NonNull OneshotSupplier<LayoutStateProvider> layoutStateProviderOneshotSupplier, + @NonNull ObservableSupplier<Profile> profileSupplier) { + mContext = context; + mTabModelSelector = tabModelSelector; + mActivityLifecycleDispatcher = dispatcher; + mModalDialogManager = modalDialogManager; + mProfileObservableSupplier = profileSupplier; + mProfileObservableSupplier.addObserver(mProfileSupplierCallback); + + layoutStateProviderOneshotSupplier.onAvailable( + mLayoutStateProviderCallbackController.makeCancelable(layoutStateProvider -> { + mLayoutStateProvider = layoutStateProvider; + showDialogIfRequired(); + })); + + mTabModelSelector.setIncognitoReauthDialogDelegate(this); + mTabModelSelector.addIncognitoTabModelObserver(mIncognitoTabModelObserver); + mTabModelSelector.addObserver(mTabModelSelectorObserver); + + mActivityLifecycleDispatcher.register(this); + + if (mTabModelSelector.isTabStateInitialized()) { + // It may happen that the tab state was initialized before the + // |mTabModelSelectorObserver| was added which explicitly takes care of restore case. + // Therefore, we need another restore check here for such a case. + onTabStateInitializedForReauth(); + } + } + + /** + * Should be called when the underlying {@link ChromeActivity} is destroyed. + */ + public void destroy() { + mActivityLifecycleDispatcher.unregister(this); + mTabModelSelector.setIncognitoReauthDialogDelegate(null); + mTabModelSelector.removeIncognitoTabModelObserver(mIncognitoTabModelObserver); + mTabModelSelector.removeObserver(mTabModelSelectorObserver); + mProfileObservableSupplier.removeObserver(mProfileSupplierCallback); + mLayoutStateProviderCallbackController.destroy(); + hideDialogIfShowing(DialogDismissalCause.ACTIVITY_DESTROYED); + } + + /** + * Returns true if the re-auth page is showing, false otherwise. + */ + public boolean isReauthPageShowing() { + return mIncognitoReauthCoordinator != null; + } + + /** + * Override from {@link StartStopWithNativeObserver}. This relays the signal that Chrome was + * brought to foreground. + */ + @Override + public void onStartWithNative() { + showDialogIfRequired(); + } + + /** + * Override from {@link StartStopWithNativeObserver}. + */ + @Override + public void onStopWithNative() { + // |mIncognitoReauthPending| also gets set in + // IncognitoReauthController#onTabStateInitializedForReauth when the tab state is + // initialized for the first time which is needed to handle cases of restored Incognito tabs + // where a re-auth should be required. To tackle the more general case, we track the + // onStopWithNative to update the |mIncognitoReauthPending| which gets called each time when + // Chrome goes to background. + mIncognitoReauthPending = (mTabModelSelector.getModel(/*incognito=*/true).getCount() > 0); + } + + /** + * Override from {@link IncognitoReauthDialogDelegate}. This relays the signal that the TabModal + * has changed. This is fired when all other observers of {@link onTabModelChanged} have been + * notified to bring determinism in the re-auth dialog. + */ + @Override + public void onAfterTabModelSelected(TabModel newModel, TabModel oldModel) { + if ((newModel.isIncognito())) { + showDialogIfRequired(); + } else { + // TODO(crbug.com/1227656): Add new dialog dismissal cause as the meaning can be + // ambiguous. + hideDialogIfShowing(DialogDismissalCause.NAVIGATE); + } + } + + /** + * TODO(crbug.com/1227656): Add an extra check on IncognitoReauthManager#canAuthenticate method + * if needed here to tackle the case where a re-authentication might not be possible from the + * systems end in which case we should not show a re-auth dialog. The method currently doesn't + * exists and may need to be exposed. + */ + private void showDialogIfRequired() { + if (mIncognitoReauthCoordinator != null) return; + if (mLayoutStateProvider == null) return; + if (!mIncognitoReauthPending) return; + if (!mTabModelSelector.isIncognitoSelected()) return; + if (mProfile == null) return; + if (!IncognitoReauthManager.isIncognitoReauthEnabled(mProfile)) return; + + boolean showFullScreen = !mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER); + mIncognitoReauthCoordinator = new IncognitoReauthCoordinator(mContext, mTabModelSelector, + mModalDialogManager, mIncognitoReauthCallback, showFullScreen); + mIncognitoReauthCoordinator.showDialog(); + } + + private void hideDialogIfShowing(@DialogDismissalCause int dismissalCause) { + if (mIncognitoReauthCoordinator != null) { + mIncognitoReauthCoordinator.hideDialogAndDestroy(dismissalCause); + mIncognitoReauthCoordinator = null; + } + } + + // Tab state initialized is called when creating tabs from launcher shortcut or restore. Re-auth + // dialogs should be shown iff any Incognito tabs were restored. + private void onTabStateInitializedForReauth() { + boolean hasRestoredIncognitoTabs = false; + TabModel incognitoTabModel = mTabModelSelector.getModel(/*incognito=*/true); + for (int i = 0; i < incognitoTabModel.getCount(); ++i) { + @TabLaunchType + Integer tabLaunchType = CriticalPersistedTabData.from(incognitoTabModel.getTabAt(i)) + .getTabLaunchTypeAtCreation(); + if (tabLaunchType == TabLaunchType.FROM_RESTORE) { + hasRestoredIncognitoTabs = true; + break; + } + } + mIncognitoReauthPending = hasRestoredIncognitoTabs; + showDialogIfRequired(); + } +}
diff --git a/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerTest.java b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerTest.java new file mode 100644 index 0000000..0f62075 --- /dev/null +++ b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthControllerTest.java
@@ -0,0 +1,304 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.incognito.reauth; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; + +import androidx.test.filters.MediumTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.UserDataHost; +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.supplier.OneshotSupplierImpl; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.layouts.LayoutStateProvider; +import org.chromium.chrome.browser.layouts.LayoutType; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabImpl; +import org.chromium.chrome.browser.tab.TabLaunchType; +import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData; +import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; +import org.chromium.ui.modaldialog.ModalDialogManager; + +/** + * Unit tests for {@link IncognitoReauthController}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class IncognitoReauthControllerTest { + @Mock + private Context mContextMock; + @Mock + private ActivityLifecycleDispatcher mActivityLifecycleDispatcherMock; + @Mock + private LayoutStateProvider mLayoutStateProviderMock; + @Mock + private TabModelSelector mTabModelSelectorMock; + @Mock + private ModalDialogManager mModalDialogManagerMock; + @Mock + private TabModel mIncognitoTabModelMock; + @Mock + private TabModel mRegularTabModelMock; + @Mock + private Profile mProfileMock; + + @Captor + ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; + @Captor + ArgumentCaptor<IncognitoTabModelObserver> mIncognitoTabModelObserverCaptor; + + private IncognitoReauthController mIncognitoReauthController; + private OneshotSupplierImpl<LayoutStateProvider> mLayoutStateProviderOneshotSupplier; + private ObservableSupplierImpl<Profile> mProfileObservableSupplier; + + private void switchToIncognitoTabModel() { + doReturn(true).when(mTabModelSelectorMock).isIncognitoSelected(); + mIncognitoReauthController.onAfterTabModelSelected( + /*newModel=*/mIncognitoTabModelMock, /*oldModel=*/mRegularTabModelMock); + } + + private void switchToRegularTabModel() { + doReturn(false).when(mTabModelSelectorMock).isIncognitoSelected(); + mIncognitoReauthController.onAfterTabModelSelected( + /*newModel=*/mRegularTabModelMock, /*oldModel=*/mIncognitoTabModelMock); + } + + private Tab prepareTabForRestoreOrLauncherShortcut(boolean isRestore) { + TabImpl tab = mock(TabImpl.class); + doReturn(true).when(tab).isInitialized(); + UserDataHost userDataHost = new UserDataHost(); + CriticalPersistedTabData criticalPersistedTabData = mock(CriticalPersistedTabData.class); + userDataHost.setUserData(CriticalPersistedTabData.class, criticalPersistedTabData); + doReturn(userDataHost).when(tab).getUserDataHost(); + doReturn(0).when(criticalPersistedTabData).getRootId(); + @TabLaunchType + Integer launchType = + isRestore ? TabLaunchType.FROM_RESTORE : TabLaunchType.FROM_LAUNCHER_SHORTCUT; + doReturn(launchType).when(criticalPersistedTabData).getTabLaunchTypeAtCreation(); + return tab; + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(false).when(mTabModelSelectorMock).isTabStateInitialized(); + doReturn(false).when(mTabModelSelectorMock).isIncognitoSelected(); + + doNothing() + .when(mTabModelSelectorMock) + .addObserver(mTabModelSelectorObserverCaptor.capture()); + doNothing() + .when(mTabModelSelectorMock) + .addIncognitoTabModelObserver(mIncognitoTabModelObserverCaptor.capture()); + doNothing().when(mTabModelSelectorMock).setIncognitoReauthDialogDelegate(any()); + doNothing().when(mActivityLifecycleDispatcherMock).register(any()); + + doReturn(mIncognitoTabModelMock).when(mTabModelSelectorMock).getModel(/*incognito=*/true); + doReturn(0).when(mIncognitoTabModelMock).getCount(); + doReturn(true).when(mIncognitoTabModelMock).isIncognito(); + doReturn(false).when(mRegularTabModelMock).isIncognito(); + doReturn(false).when(mLayoutStateProviderMock).isLayoutVisible(LayoutType.TAB_SWITCHER); + + mLayoutStateProviderOneshotSupplier = new OneshotSupplierImpl<>(); + mLayoutStateProviderOneshotSupplier.set(mLayoutStateProviderMock); + mProfileObservableSupplier = new ObservableSupplierImpl<>(); + IncognitoReauthManager.setIsIncognitoReauthFeatureAvailableForTesting(true); + + mIncognitoReauthController = new IncognitoReauthController(mContextMock, + mTabModelSelectorMock, mActivityLifecycleDispatcherMock, mModalDialogManagerMock, + mLayoutStateProviderOneshotSupplier, mProfileObservableSupplier); + mProfileObservableSupplier.set(mProfileMock); + } + + @After + public void tearDown() { + doNothing().when(mActivityLifecycleDispatcherMock).unregister(any()); + doNothing() + .when(mTabModelSelectorMock) + .removeObserver(mTabModelSelectorObserverCaptor.capture()); + doNothing() + .when(mTabModelSelectorMock) + .removeIncognitoTabModelObserver(mIncognitoTabModelObserverCaptor.capture()); + mIncognitoReauthController.destroy(); + + verify(mActivityLifecycleDispatcherMock, times(1)).unregister(any()); + verify(mTabModelSelectorMock, times(1)) + .removeObserver(mTabModelSelectorObserverCaptor.capture()); + verify(mTabModelSelectorMock, times(1)) + .removeIncognitoTabModelObserver(mIncognitoTabModelObserverCaptor.capture()); + } + + /** + * This tests that we don't show a re-auth for freshly created Incognito tabs where Chrome has + * not been backgrounded yet. + */ + @Test + @MediumTest + public void testIncognitoTabsCreated_BeforeBackground_DoesNotShowReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + + assertFalse("IncognitoReauthCoordinator should not be created for fresh Incognito" + + " session when Chrome has not been backgrounded yet.", + mIncognitoReauthController.isReauthPageShowing()); + } + + /** + * This tests that we do show a re-auth when Incognito tabs already exists after Chrome comes + * to foreground. + */ + @Test + @MediumTest + public void testIncognitoTabsCreated_BeforeForeground_ShowsReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + + mIncognitoReauthController.onStopWithNative(); + mIncognitoReauthController.onStartWithNative(); + + assertTrue("IncognitoReauthCoordinator should be created when Incognito tabs" + + " exists already after coming to foreground.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testRegularTabModel_DoesNotShowReauth() { + switchToRegularTabModel(); + mIncognitoReauthController.onStopWithNative(); + mIncognitoReauthController.onStartWithNative(); + + assertFalse("IncognitoReauthCoordinator should not be created on regular" + + " TabModel.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testIncognitoTabsExisting_AndChromeForegroundedWithRegularTabs_DoesNotShowReauth() { + doReturn(1).when(mIncognitoTabModelMock).getCount(); + doReturn(false).when(mTabModelSelectorMock).isIncognitoSelected(); + mIncognitoReauthController.onStopWithNative(); + mIncognitoReauthController.onStartWithNative(); + + assertFalse("IncognitoReauthCoordinator should not be created on regular" + + " TabModel.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testWhenTabModelChangesToRegularFromIncognito_HidesReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + assertFalse("IncognitoReauthCoordinator should not be created if Chrome has not" + + " been to background.", + mIncognitoReauthController.isReauthPageShowing()); + + // Chrome went to background. + mIncognitoReauthController.onStopWithNative(); + // Chrome coming to foregrounded. Re-auth would now be required since there are existing + // Incognito tabs. + mIncognitoReauthController.onStartWithNative(); + assertTrue("IncognitoReauthCoordinator should have been created.", + mIncognitoReauthController.isReauthPageShowing()); + + switchToRegularTabModel(); + assertFalse("IncognitoReauthCoordinator should have been destroyed" + + "when a user switches to regular TabModel.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testIncognitoTabsRestore_ShowsReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + Tab incognitoTab = prepareTabForRestoreOrLauncherShortcut(/*isRestore=*/true); + doReturn(true).when(incognitoTab).isIncognito(); + doReturn(incognitoTab).when(mIncognitoTabModelMock).getTabAt(0); + + mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); + assertTrue("IncognitoReauthCoordinator should be created for restored" + + " Incognito tabs.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testIncognitoTabsFromLauncherShortcut_DoesNotShowReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + Tab incognitoTab = prepareTabForRestoreOrLauncherShortcut(/*isRestore=*/false); + doReturn(true).when(incognitoTab).isIncognito(); + doReturn(incognitoTab).when(mIncognitoTabModelMock).getTabAt(0); + + mTabModelSelectorObserverCaptor.getValue().onTabStateInitialized(); + assertFalse("IncognitoReauthCoordinator should not be created for Incognito tabs" + + " opened from launcher.", + mIncognitoReauthController.isReauthPageShowing()); + } + + @Test + @MediumTest + public void testNewIncognitoSession_AfterClosingIncognitoTabs_DoesNotShowReauth() { + // Pretend there's one incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + assertFalse("IncognitoReauthCoordinator should not be created if Chrome has not" + + " been to background.", + mIncognitoReauthController.isReauthPageShowing()); + + // Chrome went to background. + mIncognitoReauthController.onStopWithNative(); + // Chrome coming to foregrounded. Re-auth would now be required since there are existing + // Incognito tabs. + doReturn(true).when(mTabModelSelectorMock).isIncognitoSelected(); + mIncognitoReauthController.onStartWithNative(); + switchToIncognitoTabModel(); + assertTrue("IncognitoReauthCoordinator should be created when all conditions are" + + " met.", + mIncognitoReauthController.isReauthPageShowing()); + + // Move to regular mode. + switchToRegularTabModel(); + // close all Incognito tabs. + mIncognitoTabModelObserverCaptor.getValue().didBecomeEmpty(); + // Open an Incognito tab. + doReturn(1).when(mIncognitoTabModelMock).getCount(); + switchToIncognitoTabModel(); + assertFalse("IncognitoReauthCoordinator should not be created when starting a" + + " fresh Incognito session.", + mIncognitoReauthController.isReauthPageShowing()); + } +} \ No newline at end of file
diff --git a/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthCoordinator.java b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthCoordinator.java new file mode 100644 index 0000000..b05818e --- /dev/null +++ b/chrome/browser/incognito/android/java/src/org/chromium/chrome/browser/incognito/reauth/IncognitoReauthCoordinator.java
@@ -0,0 +1,54 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.incognito.reauth; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.ui.modaldialog.DialogDismissalCause; +import org.chromium.ui.modaldialog.ModalDialogManager; + +/** + * The coordinator which is responsible for showing the Incognito re-authentication page. + * + * TODO(crbug.com/1227656): Add View inflation and set up the re-auth dialog. + */ +class IncognitoReauthCoordinator { + private final @NonNull Context mContext; + private final @NonNull ModalDialogManager mModalDialogManager; + private final @NonNull IncognitoReauthManager.IncognitoReauthCallback mIncognitoReauthCallback; + private final boolean mShowFullScreen; + + /** + * @param context The {@link Context} to use for inflating the Incognito re-auth view. + * @param tabModelSelector The {@link TabModelSelector} which will be passed to the mediator in + * order to switch {@link TabModel} when the user clicks on "See other tabs" button. + * @param modalDialogManager The {@link ModalDialogManager} which is used to fire the dialog + * containing the Incognito re-auth view. + * @param incognitoReauthCallback The {@link IncognitoReauthCallback} which would be executed + * after an authentication attempt. + * @param showFullScreen Whether to show a fullscreen / tab based re-auth dialog. + */ + public IncognitoReauthCoordinator(@NonNull Context context, + @NonNull TabModelSelector tabModelSelector, + @NonNull ModalDialogManager modalDialogManager, + @NonNull IncognitoReauthManager.IncognitoReauthCallback incognitoReauthCallback, + boolean showFullScreen) { + mContext = context; + mModalDialogManager = modalDialogManager; + mIncognitoReauthCallback = incognitoReauthCallback; + mShowFullScreen = showFullScreen; + } + + void showDialog() {} + + void hideDialogAndDestroy(@DialogDismissalCause int dismissalCause) { + destroy(); + } + + private void destroy() {} +}
diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h index a789338..6657018 100644 --- a/chrome/browser/net/profile_network_context_service.h +++ b/chrome/browser/net/profile_network_context_service.h
@@ -58,7 +58,7 @@ : public KeyedService, public content_settings::Observer, public content_settings::CookieSettings::Observer, - public PrivacySandboxSettings::Observer { + public privacy_sandbox::PrivacySandboxSettings::Observer { public: explicit ProfileNetworkContextService(Profile* profile); @@ -191,8 +191,8 @@ base::ScopedObservation<content_settings::CookieSettings, content_settings::CookieSettings::Observer> cookie_settings_observation_{this}; - base::ScopedObservation<PrivacySandboxSettings, - PrivacySandboxSettings::Observer> + base::ScopedObservation<privacy_sandbox::PrivacySandboxSettings, + privacy_sandbox::PrivacySandboxSettings::Observer> privacy_sandbox_settings_observer_{this}; // Used to post schedule CT policy updates
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc index 0a770cf..6441b30e 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
@@ -111,7 +111,7 @@ PrivacySandboxService::PrivacySandboxService() = default; PrivacySandboxService::PrivacySandboxService( - PrivacySandboxSettings* privacy_sandbox_settings, + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings, content_settings::CookieSettings* cookie_settings, PrefService* pref_service, policy::PolicyService* policy_service, @@ -261,6 +261,10 @@ prefs::kPrivacySandboxApisEnabledV2); } +bool PrivacySandboxService::IsPrivacySandboxRestricted() { + return privacy_sandbox_settings_->IsPrivacySandboxRestricted(); +} + void PrivacySandboxService::SetPrivacySandboxEnabled(bool enabled) { privacy_sandbox_settings_->SetPrivacySandboxEnabled(enabled); }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h index 0fc09ab..3077522 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
@@ -80,14 +80,15 @@ kMaxValue = kConsentClosedNoDecision, }; - PrivacySandboxService(PrivacySandboxSettings* privacy_sandbox_settings, - content_settings::CookieSettings* cookie_settings, - PrefService* pref_service, - policy::PolicyService* policy_service, - syncer::SyncService* sync_service, - signin::IdentityManager* identity_manager, - content::InterestGroupManager* interest_group_manager, - profile_metrics::BrowserProfileType profile_type); + PrivacySandboxService( + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings, + content_settings::CookieSettings* cookie_settings, + PrefService* pref_service, + policy::PolicyService* policy_service, + syncer::SyncService* sync_service, + signin::IdentityManager* identity_manager, + content::InterestGroupManager* interest_group_manager, + profile_metrics::BrowserProfileType profile_type); ~PrivacySandboxService() override; // Returns the dialog type that should be shown to the user. This consults @@ -159,6 +160,11 @@ // Returns whether the state of the API is managed. bool IsPrivacySandboxManaged(); + // Returns whether the Privacy Sandbox is currently restricted for the + // profile. UI code should consult this to ensure that when restricted, + // Privacy Sandbox related UI is updated appropriately. + bool IsPrivacySandboxRestricted(); + // Called when a preference relevant to the the Privacy Sandbox is changed. void OnPrivacySandboxPrefChanged(); @@ -310,7 +316,7 @@ profile_metrics::BrowserProfileType profile_type); private: - raw_ptr<PrivacySandboxSettings> privacy_sandbox_settings_; + raw_ptr<privacy_sandbox::PrivacySandboxSettings> privacy_sandbox_settings_; raw_ptr<content_settings::CookieSettings> cookie_settings_; raw_ptr<PrefService> pref_service_; raw_ptr<policy::PolicyService> policy_service_;
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_browsertest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_browsertest.cc index 1def27e..ecec501 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_browsertest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_browsertest.cc
@@ -36,7 +36,7 @@ policy_provider()->UpdateChromePolicy(third_party_cookies_blocked_policy); } - PrivacySandboxSettings* privacy_sandbox_settings() { + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings() { return PrivacySandboxSettingsFactory::GetForProfile(browser()->profile()); }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc index a240c57..b23e939 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
@@ -661,7 +661,7 @@ PrivacySandboxService* privacy_sandbox_service() { return privacy_sandbox_service_.get(); } - PrivacySandboxSettings* privacy_sandbox_settings() { + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings() { return PrivacySandboxSettingsFactory::GetForProfile(profile()); } base::test::ScopedFeatureList* feature_list() { return &feature_list_; }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc index cf71a972..6b4ac92 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc
@@ -64,7 +64,7 @@ observer.BlockUntilCompletion(); } - PrivacySandboxSettings* privacy_sandbox_settings() { + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings() { return PrivacySandboxSettingsFactory::GetForProfile(browser()->profile()); }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h index bd70af8..b9a9e460 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h
@@ -9,7 +9,8 @@ class Profile; -class PrivacySandboxSettingsDelegate : public PrivacySandboxSettings::Delegate { +class PrivacySandboxSettingsDelegate + : public privacy_sandbox::PrivacySandboxSettings::Delegate { public: explicit PrivacySandboxSettingsDelegate(Profile* profile); ~PrivacySandboxSettingsDelegate() override;
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc index 9c3dea5..91e083c 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc
@@ -19,9 +19,9 @@ return base::Singleton<PrivacySandboxSettingsFactory>::get(); } -PrivacySandboxSettings* PrivacySandboxSettingsFactory::GetForProfile( - Profile* profile) { - return static_cast<PrivacySandboxSettings*>( +privacy_sandbox::PrivacySandboxSettings* +PrivacySandboxSettingsFactory::GetForProfile(Profile* profile) { + return static_cast<privacy_sandbox::PrivacySandboxSettings*>( GetInstance()->GetServiceForBrowserContext(profile, true)); } @@ -34,7 +34,7 @@ content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); - return new PrivacySandboxSettings( + return new privacy_sandbox::PrivacySandboxSettings( std::make_unique<PrivacySandboxSettingsDelegate>(profile), HostContentSettingsMapFactory::GetForProfile(profile), CookieSettingsFactory::GetForProfile(profile).get(), profile->GetPrefs(),
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h index 0fbf226..ab31353 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h
@@ -8,13 +8,17 @@ #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" -class PrivacySandboxSettings; class Profile; +namespace privacy_sandbox { +class PrivacySandboxSettings; +} + class PrivacySandboxSettingsFactory : public BrowserContextKeyedServiceFactory { public: static PrivacySandboxSettingsFactory* GetInstance(); - static PrivacySandboxSettings* GetForProfile(Profile* profile); + static privacy_sandbox::PrivacySandboxSettings* GetForProfile( + Profile* profile); private: friend struct base::DefaultSingletonTraits<PrivacySandboxSettingsFactory>;
diff --git a/chrome/browser/resources/chromeos/login/components/notification_card.js b/chrome/browser/resources/chromeos/login/components/notification_card.js index 430e61f..b82ca1a 100644 --- a/chrome/browser/resources/chromeos/login/components/notification_card.js +++ b/chrome/browser/resources/chromeos/login/components/notification_card.js
@@ -63,4 +63,4 @@ } } -customElements.define(NotificationCard.is, NotificationCard); \ No newline at end of file +customElements.define(NotificationCard.is, NotificationCard);
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js index 62489b65..bc029a4d 100644 --- a/chrome/browser/resources/chromeos/login/cr_ui.js +++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -123,14 +123,6 @@ } /** - * Shows signin UI. - * @param {string} opt_email An optional email for signin UI. - */ - static showSigninUI(opt_email) { - Oobe.getInstance().showSigninUI(opt_email); - } - - /** * Sets the current height of the shelf area. * @param {number} height current shelf height */
diff --git a/chrome/browser/resources/chromeos/login/debug/debug.js b/chrome/browser/resources/chromeos/login/debug/debug.js index 78d3e89..045d420 100644 --- a/chrome/browser/resources/chromeos/login/debug/debug.js +++ b/chrome/browser/resources/chromeos/login/debug/debug.js
@@ -600,7 +600,7 @@ { id: 'allowlist-customer', trigger: (screen) => { - screen.showAllowlistCheckFailedError(true, { + screen.showAllowlistCheckFailedError({ enterpriseManaged: false, }); },
diff --git a/chrome/browser/resources/chromeos/login/display_manager.js b/chrome/browser/resources/chromeos/login/display_manager.js index af24585..52d5e599 100644 --- a/chrome/browser/resources/chromeos/login/display_manager.js +++ b/chrome/browser/resources/chromeos/login/display_manager.js
@@ -554,16 +554,6 @@ this.initializeDemoModeMultiTapListener(); } - /** - * Shows signin UI. - * @param {string} opt_email An optional email for signin UI. - */ - showSigninUI(opt_email) { - if (this.currentScreen.id == SCREEN_GAIA_SIGNIN) { - this.setOobeUIState(OOBE_UI_STATE.GAIA_SIGNIN); - } - chrome.send('showAddUser', [opt_email]); - } /** * Sets text content for a div with |labelId|.
diff --git a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.html b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.html index e24d284..b57a9a1 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.html +++ b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.html
@@ -124,8 +124,11 @@ </div> <notification-card id="gaia-allowlist-error" type="fail" class="fit" for-step="allowlist-error" + on-buttonclick="onAllowlistErrorTryAgainClick_" + on-linkclick="onAllowlistErrorLinkClick_" button-label="[[i18nDynamic(locale, 'tryAgainButton')]]" link-label="[[i18nDynamic(locale, 'learnMoreButton')]]"> + [[i18nDynamic(locale, allowListError_)]] </notification-card> </template> <script src="gaia_signin.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js index 8b53b35b..ee0f492 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screens/common/gaia_signin.js
@@ -269,6 +269,14 @@ type: Boolean, value: loadTimeData.getBoolean('isRedirectToDefaultIdPEnabled'), }, + + /** + * @private {string} + */ + allowlistError_: { + type: String, + value: 'allowlistErrorConsumer', + }, }; } @@ -385,14 +393,6 @@ this.authenticator_.getIsSamlUserPasswordlessCallback = this.getIsSamlUserPasswordless_.bind(this); - this.$['gaia-allowlist-error'].addEventListener('buttonclick', function() { - this.showAllowlistCheckFailedError(false); - }.bind(this)); - - this.$['gaia-allowlist-error'].addEventListener('linkclick', function() { - chrome.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT]); - }); - this.initializeLoginScreen('GaiaSigninScreen', { resetAllowed: true, }); @@ -445,6 +445,7 @@ */ loadAuthenticator_(doSamlRedirect) { this.loadingFrameContents_ = true; + this.isAllowlistErrorShown_ = false; this.isDefaultSsoProvider_ = doSamlRedirect; this.startLoadingTimer_(); @@ -536,8 +537,6 @@ * @param {Object} data Screen init payload */ onBeforeShow(data) { - // Show spinner early. - // this.loadingFrameContents_ = true; chrome.send('loginUIStateChanged', ['gaia-signin', true]); // Ensure that GAIA signin (or loading UI) is actually visible. @@ -1005,6 +1004,7 @@ return; this.authenticator_.reload(); this.loadingFrameContents_ = true; + this.isAllowlistErrorShown_ = false; this.startLoadingTimer_(); this.authCompleted_ = false; } @@ -1073,39 +1073,27 @@ /** * Show/Hide error when user is not in allowlist. When UI is hidden GAIA is * reloaded. - * @param {boolean} show Show/hide error UI. * @param {!Object=} opt_data Optional additional information. */ - showAllowlistCheckFailedError(show, opt_data) { - if (show) { - const isManaged = opt_data && opt_data.enterpriseManaged; - const isFamilyLinkAllowed = opt_data && opt_data.familyLinkAllowed; - let errorMessage = ''; - if (isManaged && isFamilyLinkAllowed) { - errorMessage = 'allowlistErrorEnterpriseAndFamilyLink'; - } else if (isManaged) { - errorMessage = 'allowlistErrorEnterprise'; - } else { - errorMessage = 'allowlistErrorConsumer'; - } - - this.$['gaia-allowlist-error'].textContent = - loadTimeData.getValue(errorMessage); - // To make animations correct, we need to make sure Gaia is completely - // reloaded. Otherwise ChromeOS overlays hide and Gaia page is shown - // somewhere in the middle of animations. - if (this.screenMode_ == ScreenAuthMode.DEFAULT) - this.authenticator_.resetWebview(); - - // It might show the OOBE screen id=SCREEN_CONFIRM_PASSWORD. - // Ensures showing the screen id=SCREEN_GAIA_SIGNIN. - Oobe.showScreen({id: SCREEN_GAIA_SIGNIN}); - this.$['gaia-allowlist-error'].submitButton.focus(); + showAllowlistCheckFailedError(opt_data) { + const isManaged = opt_data && opt_data.enterpriseManaged; + const isFamilyLinkAllowed = opt_data && opt_data.familyLinkAllowed; + if (isManaged && isFamilyLinkAllowed) { + this.allowlistError_ = 'allowlistErrorEnterpriseAndFamilyLink'; + } else if (isManaged) { + this.allowlistError_ = 'allowlistErrorEnterprise'; } else { - Oobe.showSigninUI(''); + this.allowlistError_ = 'allowlistErrorConsumer'; } - this.isAllowlistErrorShown_ = show; + // To make animations correct, we need to make sure Gaia is completely + // reloaded. Otherwise ChromeOS overlays hide and Gaia page is shown + // somewhere in the middle of animations. + if (this.screenMode_ == ScreenAuthMode.DEFAULT) + this.authenticator_.resetWebview(); + + this.$['gaia-allowlist-error'].submitButton.focus(); + this.isAllowlistErrorShown_ = true; } /** @@ -1293,6 +1281,14 @@ } return ''; } + + onAllowlistErrorTryAgainClick_() { + this.userActed('retry'); + } + + onAllowlistErrorLinkClick_() { + chrome.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT]); + } } customElements.define(GaiaSigninElement.is, GaiaSigninElement);
diff --git a/chrome/browser/resources/history/history.ts b/chrome/browser/resources/history/history.ts index 6e920d3f..bdada40 100644 --- a/chrome/browser/resources/history/history.ts +++ b/chrome/browser/resources/history/history.ts
@@ -19,3 +19,5 @@ export {HistoryToolbarElement} from './history_toolbar.js'; export {HistorySearchedLabelElement} from './searched_label.js'; export {HistorySideBarElement} from './side_bar.js'; +export {HistorySyncedDeviceCardElement} from './synced_device_card.js'; +export {HistorySyncedDeviceManagerElement} from './synced_device_manager.js';
diff --git a/chrome/browser/resources/history/synced_device_manager.ts b/chrome/browser/resources/history/synced_device_manager.ts index cf631f9..6c2d125 100644 --- a/chrome/browser/resources/history/synced_device_manager.ts +++ b/chrome/browser/resources/history/synced_device_manager.ts
@@ -46,6 +46,8 @@ export interface HistorySyncedDeviceManagerElement { $: { 'menu': CrLazyRenderElement<CrActionMenuElement>, + 'no-synced-tabs': HTMLElement, + 'sign-in-guide': HTMLElement, }; } @@ -129,6 +131,16 @@ this.focusGrid_!.destroy(); } + configureSignInForTest(data: { + signInState: boolean, + signInAllowed: boolean, + guestSession: boolean + }) { + this.signInState = data.signInState; + this.signInAllowed_ = data.signInAllowed; + this.guestSession_ = data.guestSession; + } + /** @return {HTMLElement} */ getContentScrollTarget() { return this; @@ -239,6 +251,10 @@ menu.close(); } + clearSyncedDevicesForTest() { + this.clearDisplayedSyncedDevices_(); + } + private clearDisplayedSyncedDevices_() { this.syncedDevices_ = []; }
diff --git a/chrome/browser/resources/tab_search/app.ts b/chrome/browser/resources/tab_search/app.ts index 8217c25..b40424d 100644 --- a/chrome/browser/resources/tab_search/app.ts +++ b/chrome/browser/resources/tab_search/app.ts
@@ -502,6 +502,15 @@ this.apiProxy_.saveRecentlyClosedExpandedPref(expanded); this.updateFilteredTabs_(); + + // If a section's title item is the last visible element in the list and the + // list's height is at its maximum, it will not be evident to the user that + // on expanding the section there are now section tab items available. By + // ensuring the first element of the section is visible, we can avoid this + // confusion. + if (expanded) { + this.$.tabsList.scrollIndexIntoView(this.filteredOpenTabsCount_); + } e.stopPropagation(); }
diff --git a/chrome/browser/resources/tab_search/infinite_list.ts b/chrome/browser/resources/tab_search/infinite_list.ts index 34a18f4..b10d7b38 100644 --- a/chrome/browser/resources/tab_search/infinite_list.ts +++ b/chrome/browser/resources/tab_search/infinite_list.ts
@@ -128,6 +128,15 @@ } } + scrollIndexIntoView(index: number) { + assert( + index >= 0 && index < this.selectableIndexToItemIndex_!.size(), + 'Index is out of range.'); + this.ensureSelectableDomItemAvailable_(index); + this.getSelectableDomItem_(index)!.scrollIntoView( + {behavior: 'smooth', block: 'nearest'}); + } + /** * @param key Keyboard event key value. * @param focusItem Whether to focus the selected item. @@ -252,15 +261,7 @@ private getDomItem_(index: number): HTMLElement|undefined { const instance = this.instances_[index]; - if (instance === undefined) { - // TODO(crbug.com/1225247): Remove this after we root cause the issue. - console.error(`Unexpected call to non-existing instance index: ${ - index}. Instance count: ${this.instances_.length}. Item count: ${ - this.items.length}`); - return undefined; - } - - return instance.children[0] as HTMLElement; + return instance!.children[0] as HTMLElement; } private getSelectableDomItem_(selectableItemIndex: number): HTMLElement
diff --git a/chrome/browser/resources/tab_search/tab_search_item.html b/chrome/browser/resources/tab_search/tab_search_item.html index 7a794112..37fd113 100644 --- a/chrome/browser/resources/tab_search/tab_search_item.html +++ b/chrome/browser/resources/tab_search/tab_search_item.html
@@ -1,16 +1,15 @@ <style include="mwb-element-shared-style"> - :host { - --audio-icon-color: var(--google-grey-700); - --media-recording-icon-color: var(--google-red-600); - } + :host { + --audio-icon-color: var(--google-grey-700); + --media-recording-icon-color: var(--google-red-600); + } - @media (prefers-color-scheme: dark) { - :host { - --audio-icon-color: var(--google-grey-300); - --media-recording-icon-color: var(--google-red-300); - } + @media (prefers-color-scheme: dark) { + :host { + --audio-icon-color: var(--google-grey-300); + --media-recording-icon-color: var(--google-red-300); } - + } :host(:focus) { outline: none; @@ -141,7 +140,6 @@ -webkit-mask-image: url(alert_indicators/tab_audio_muting_rounded.svg); background-color: var(--audio-icon-color); } - </style> <div class="favicon" style="background-image:[[faviconUrl_(data.tab)]]"></div>
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_data_pipe_getter_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_data_pipe_getter_unittest.cc index 1436661..916f621 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_data_pipe_getter_unittest.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_data_pipe_getter_unittest.cc
@@ -17,12 +17,17 @@ class MultipartDataPipeGetterTest : public testing::Test { public: - base::File CreateFile(const std::string& content) { + absl::optional<base::File> CreateFile(const std::string& content) { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath path = temp_dir_.GetPath().AppendASCII("test.txt"); base::File file(path, base::File::FLAG_CREATE | base::File::FLAG_READ | base::File::FLAG_WRITE); - file.WriteAtCurrentPos(content.data(), content.size()); + if (!file.IsValid()) + return absl::nullopt; + + if (file.WriteAtCurrentPos(content.data(), content.size()) < 0) + return absl::nullopt; + return file; } @@ -106,9 +111,12 @@ std::unique_ptr<MultipartDataPipeGetter> CreateDataPipeGetter( const std::string& content) { if (is_file_data_pipe()) { - base::File file = CreateFile(content); + absl::optional<base::File> file = CreateFile(content); + if (!file) + return nullptr; + return MultipartDataPipeGetter::Create("boundary", metadata_, - std::move(file)); + std::move(*file)); } else { base::ReadOnlySharedMemoryRegion page = CreatePage(content); return MultipartDataPipeGetter::Create("boundary", metadata_, @@ -140,6 +148,7 @@ std::unique_ptr<MultipartDataPipeGetter> data_pipe_getter = CreateDataPipeGetter("small file content"); + EXPECT_TRUE(data_pipe_getter); EXPECT_EQ(data_pipe_getter->is_page_data_pipe(), is_page_data_pipe()); EXPECT_EQ(data_pipe_getter->is_file_data_pipe(), is_file_data_pipe()); @@ -163,6 +172,11 @@ std::unique_ptr<MultipartDataPipeGetter> data_pipe_getter = CreateDataPipeGetter(large_file_content); + // It's possible the large file couldn't be created due to a lack of space on + // the device, in this case stop the test early. + if (!data_pipe_getter) + return; + EXPECT_EQ(data_pipe_getter->is_page_data_pipe(), is_page_data_pipe()); EXPECT_EQ(data_pipe_getter->is_file_data_pipe(), is_file_data_pipe()); @@ -188,6 +202,11 @@ set_metadata(large_data); std::unique_ptr<MultipartDataPipeGetter> data_pipe_getter = CreateDataPipeGetter(large_data); + // It's possible the large file couldn't be created due to a lack of space on + // the device, in this case stop the test early. + if (!data_pipe_getter) + return; + EXPECT_EQ(data_pipe_getter->is_page_data_pipe(), is_page_data_pipe()); EXPECT_EQ(data_pipe_getter->is_file_data_pipe(), is_file_data_pipe()); @@ -209,6 +228,7 @@ std::unique_ptr<MultipartDataPipeGetter> data_pipe_getter = CreateDataPipeGetter("small file content"); + EXPECT_TRUE(data_pipe_getter); EXPECT_EQ(data_pipe_getter->is_page_data_pipe(), is_page_data_pipe()); EXPECT_EQ(data_pipe_getter->is_file_data_pipe(), is_file_data_pipe()); @@ -234,6 +254,11 @@ std::unique_ptr<MultipartDataPipeGetter> data_pipe_getter = CreateDataPipeGetter(large_file_content); + // It's possible the large file couldn't be created due to a lack of space on + // the device, in this case stop the test early. + if (!data_pipe_getter) + return; + EXPECT_EQ(data_pipe_getter->is_page_data_pipe(), is_page_data_pipe()); EXPECT_EQ(data_pipe_getter->is_file_data_pipe(), is_file_data_pipe());
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc index a3e71aac..2be08ce 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -3166,7 +3166,7 @@ false, // has_server_redirect nav_list->GetNavigationEvent(1)); VerifyNavigationEvent(GURL(), // source_url - GURL(), // source_main_frame_url + initial_url, // source_main_frame_url landing_url, // original_request_url landing_url, // destination_url false, // is_user_initiated, @@ -3185,7 +3185,7 @@ ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); - EXPECT_EQ(3, referrer_chain.size()); + EXPECT_EQ(2, referrer_chain.size()); VerifyReferrerChainEntry( download_url, // url GURL(), // main_frame_url @@ -3202,23 +3202,12 @@ GURL(), // main_frame_url ReferrerChainEntry::LANDING_PAGE, // type test_server_ip, // ip_address - initial_url, // referrer_url - GURL(), // referrer_main_frame_url - true, // is_retargeting + GURL(), // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting std::vector<GURL>(), // server redirects - ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, + ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(1)); - VerifyReferrerChainEntry( - initial_url, // url - GURL(), // main_frame_url - ReferrerChainEntry::LANDING_REFERRER, // type - test_server_ip, // ip_address - GURL(), // referrer_url - GURL(), // referrer_main_frame_url - false, // is_retargeting - std::vector<GURL>(), // server redirects - ReferrerChainEntry::BROWSER_INITIATED, - referrer_chain.Get(2)); } // Click a link which creates a portal which redirects to the landing page and @@ -3288,7 +3277,7 @@ false, // has_server_redirect nav_list->GetNavigationEvent(1)); VerifyNavigationEvent(GURL(), // source_url - GURL(), // source_main_frame_url + initial_url, // source_main_frame_url redirect_to_landing_url, // original_request_url redirect_to_landing_url, // destination_url false, // is_user_initiated, @@ -3296,7 +3285,7 @@ false, // has_server_redirect nav_list->GetNavigationEvent(2)); VerifyNavigationEvent(redirect_to_landing_url, // source_url - redirect_to_landing_url, // source_main_frame_url + initial_url, // source_main_frame_url landing_url, // original_request_url landing_url, // destination_url false, // is_user_initiated, @@ -3315,7 +3304,7 @@ ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); - EXPECT_EQ(4, referrer_chain.size()); + EXPECT_EQ(3, referrer_chain.size()); VerifyReferrerChainEntry( download_url, // url GURL(), // main_frame_url @@ -3333,32 +3322,22 @@ ReferrerChainEntry::LANDING_PAGE, // type test_server_ip, // ip_address redirect_to_landing_url, // referrer_url - GURL(), // referrer_main_frame_url + initial_url, // referrer_main_frame_url false, // is_retargeting std::vector<GURL>(), // server redirects ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(1)); VerifyReferrerChainEntry( redirect_to_landing_url, // url - GURL(), // main_frame_url + initial_url, // main_frame_url ReferrerChainEntry::CLIENT_REDIRECT, // type test_server_ip, // ip_address - initial_url, // referrer_url - GURL(), // referrer_main_frame_url - true, // is_retargeting + GURL(), // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting std::vector<GURL>(), // server redirects - ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE, + ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE, referrer_chain.Get(2)); - VerifyReferrerChainEntry(initial_url, // url - GURL(), // main_frame_url - ReferrerChainEntry::LANDING_REFERRER, // type - test_server_ip, // ip_address - GURL(), // referrer_url - GURL(), // referrer_main_frame_url - false, // is_retargeting - std::vector<GURL>(), // server redirects - ReferrerChainEntry::BROWSER_INITIATED, - referrer_chain.Get(3)); } class SBNavigationObserverOmitNonUserGesturesBrowserTest
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc index 9ccc3f7..22fd3f1 100644 --- a/chrome/browser/safe_browsing/threat_details_unittest.cc +++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -151,6 +151,13 @@ run_loop_ = nullptr; } + void OnRedirectionCollectionReady() override { + ThreatDetails::OnRedirectionCollectionReady(); + if (should_stop_after_redirect_collection_ && run_loop_) { + run_loop_->Quit(); + } + } + // Used to synchronize ThreatDetailsDone() with WaitForThreatDetailsDone(). // RunLoop::RunUntilIdle() is not sufficient because the MessageLoop task // queue completely drains at some point between the send and the wait. @@ -163,9 +170,14 @@ void StartCollection() { ThreatDetails::StartCollection(); } + void SetShouldStopAfterRedirectCollection(bool should_stop) { + should_stop_after_redirect_collection_ = should_stop; + } + private: raw_ptr<base::RunLoop> run_loop_; size_t done_callback_count_; + bool should_stop_after_redirect_collection_ = false; }; class MockSafeBrowsingUIManager : public SafeBrowsingUIManager { @@ -1977,4 +1989,45 @@ VerifyResults(actual, expected); } +TEST_F(ThreatDetailsTest, CanCancelDuringCollection) { + content::WebContentsTester::For(web_contents()) + ->NavigateAndCommit(GURL(kLandingURL)); + + UnsafeResource resource; + InitResource(SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING, + ThreatSource::CLIENT_SIDE_DETECTION, true /* is_subresource */, + GURL(kThreatURL), &resource); + + auto report = std::make_unique<ThreatDetailsWrap>( + ui_manager_.get(), web_contents(), resource, test_shared_loader_factory_, + history_service(), user_population_callback(), + referrer_chain_provider_.get()); + report->StartCollection(); + + SimulateFillCache(kThreatURL); + + // The cache collection starts after the IPC from the DOM is fired. + std::vector<mojom::ThreatDOMDetailsNodePtr> params; + report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(), + main_rfh()->GetGlobalId(), + std::move(params)); + + // Let the cache callbacks complete. + base::RunLoop().RunUntilIdle(); + + // Let the cache collection start + { + base::RunLoop run_loop; + report->SetShouldStopAfterRedirectCollection(true); + report->SetRunLoopToQuit(&run_loop); + report->FinishCollection(/*did_proceed=*/true, /*num_visits=*/-1); + run_loop.Run(); + } + + // Cancel the collection + report.reset(); + + base::RunLoop().RunUntilIdle(); +} + } // namespace safe_browsing
diff --git a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.cc b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.cc index 910c82c9..9daf07c 100644 --- a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.cc +++ b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.cc
@@ -36,10 +36,10 @@ void RebootNotificationController::MaybeShowPendingRebootNotification( const base::Time& reboot_time, - ButtonClickCallback reboot_callback) const { + base::RepeatingClosure reboot_callback) { if (!ShouldNotifyUser()) return; - + notification_callback_ = std::move(reboot_callback); std::u16string reboot_title = l10n_util::GetStringUTF16(IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE); std::u16string reboot_message = @@ -53,7 +53,9 @@ l10n_util::GetStringUTF16(IDS_POLICY_REBOOT_BUTTON)); scoped_refptr<message_center::NotificationDelegate> delegate = base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( - std::move(reboot_callback)); + base::BindRepeating( + &RebootNotificationController::HandleNotificationClick, + weak_ptr_factory_.GetWeakPtr())); ShowNotification(kPendingRebootNotificationId, reboot_title, reboot_message, notification_data, delegate); @@ -74,6 +76,22 @@ reboot_time, parent, std::move(reboot_callback)); } +void RebootNotificationController::CloseRebootNotification() const { + if (!ShouldNotifyUser()) + return; + NotificationDisplayService* notification_display_service = + NotificationDisplayService::GetForProfile( + ProfileManager::GetActiveUserProfile()); + notification_display_service->Close(NotificationHandler::Type::TRANSIENT, + kPendingRebootNotificationId); +} + +void RebootNotificationController::CloseRebootDialog() { + if (scheduled_reboot_dialog_) { + scheduled_reboot_dialog_.reset(); + } +} + void RebootNotificationController::ShowNotification( const std::string& id, const std::u16string& title, @@ -103,4 +121,13 @@ return (user_manager::UserManager::IsInitialized() && user_manager::UserManager::Get()->IsUserLoggedIn() && !user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()); +} + +void RebootNotificationController::HandleNotificationClick( + absl::optional<int> button_index) const { + // Only request restart when the button is clicked, i.e. ignore the clicks + // on the body of the notification. + if (!button_index) + return; + notification_callback_.Run(); } \ No newline at end of file
diff --git a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.h b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.h index 4292b16..7afcf26 100644 --- a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.h +++ b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.h
@@ -8,8 +8,11 @@ #include <memory> #include <string> +#include "base/callback.h" #include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/ui/ash/device_scheduled_reboot/scheduled_reboot_dialog.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" @@ -17,9 +20,6 @@ class Time; } -using ButtonClickCallback = - message_center::HandleNotificationClickDelegate::ButtonClickCallback; - // This class is responsible for creating and managing notifications about the // reboot when DeviceScheduledRebootPolicy is set. class RebootNotificationController { @@ -34,13 +34,17 @@ // in progress. void MaybeShowPendingRebootNotification( const base::Time& reboot_time, - ButtonClickCallback reboot_callback) const; + base::RepeatingClosure reboot_callback); // Only show dialog if the user is in session and kiosk session is not // in progress. void MaybeShowPendingRebootDialog(const base::Time& reboot_time, base::OnceClosure reboot_callback); + void CloseRebootNotification() const; + + void CloseRebootDialog(); + protected: // Only notify in-session users that are not running in kiosk mode. virtual bool ShouldNotifyUser() const; @@ -53,8 +57,15 @@ const message_center::RichNotificationData& data, scoped_refptr<message_center::NotificationDelegate> delegate) const; + // Button click callback. + void HandleNotificationClick(absl::optional<int> button_index) const; + // Dialog notifying the user about the pending reboot. std::unique_ptr<ScheduledRebootDialog> scheduled_reboot_dialog_; + + // Callback to run on notification button click. + base::RepeatingClosure notification_callback_; + base::WeakPtrFactory<RebootNotificationController> weak_ptr_factory_{this}; }; #endif // CHROME_BROWSER_UI_ASH_DEVICE_SCHEDULED_REBOOT_REBOOT_NOTIFICATION_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_browsertest.cc b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_browsertest.cc index 02c91066..3c7259f 100644 --- a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_browsertest.cc +++ b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_browsertest.cc
@@ -37,6 +37,8 @@ notification_controller_.MaybeShowPendingRebootDialog(deadline, base::DoNothing()); } + // DialogBrowserTest: + void DismissUi() override { notification_controller_.CloseRebootDialog(); } private: RebootNotificationControllerForTest notification_controller_;
diff --git a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_unittest.cc b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_unittest.cc index e4d3783a..afa35bd 100644 --- a/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_unittest.cc +++ b/chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller_unittest.cc
@@ -47,6 +47,13 @@ 0, // second 0 // millisecond }; + +class ClickCounter { + public: + void ButtonClickCallback() { ++clicks; } + int clicks = 0; + base::WeakPtrFactory<ClickCounter> weak_ptr_factory_{this}; +}; } // namespace class RebootNotificationControllerTest : public testing::Test { @@ -107,6 +114,7 @@ ash::FakeChromeUserManager* fake_user_manager_ = nullptr; std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_; + RebootNotificationController notification_controller_; }; TEST_F(RebootNotificationControllerTest, UserSessionShowsNotification) { @@ -117,14 +125,13 @@ base::Time::FromLocalExploded(kRebootTime2022Feb2At1520, &reboot_time)); // User is not logged in. Don't show notification. - RebootNotificationController notification_controller; - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_EQ(absl::nullopt, GetNotification()); // Log in user and show notification. LoginFakeUser(account_id); - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_NE(absl::nullopt, GetNotification()); EXPECT_EQ( @@ -142,15 +149,14 @@ base::Time::FromLocalExploded(kRebootTime2023May15At1115, &reboot_time2)); // User is not logged in. Don't show notification. - RebootNotificationController notification_controller; - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time1, base::NullCallback()); EXPECT_EQ(absl::nullopt, GetNotification()); EXPECT_EQ(GetTransientNotificationCount(), 0); // Log in user and show notification. LoginFakeUser(account_id); - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time1, base::NullCallback()); EXPECT_NE(absl::nullopt, GetNotification()); EXPECT_EQ( @@ -159,7 +165,7 @@ EXPECT_EQ(GetTransientNotificationCount(), 1); // Change reboot time. Close old notification and show new one. - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time2, base::NullCallback()); EXPECT_NE(absl::nullopt, GetNotification()); EXPECT_EQ(GetNotification()->message(), @@ -176,14 +182,13 @@ base::Time::FromLocalExploded(kRebootTime2022Feb2At1520, &reboot_time)); // User is not logged in. Don't show notification. - RebootNotificationController notification_controller; - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_EQ(absl::nullopt, GetNotification()); // Log in user and show notification. LoginFakeUser(account_id); - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_NE(absl::nullopt, GetNotification()); EXPECT_EQ( @@ -200,14 +205,55 @@ base::Time::FromUTCExploded(kRebootTime2022Feb2At1520, &reboot_time)); // User is not logged in. Don't show notification. - RebootNotificationController notification_controller; - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_EQ(absl::nullopt, GetNotification()); // Start kiosk session. Don't show notification. LoginFakeUser(account_id); - notification_controller.MaybeShowPendingRebootNotification( + notification_controller_.MaybeShowPendingRebootNotification( reboot_time, base::NullCallback()); EXPECT_EQ(absl::nullopt, GetNotification()); } + +TEST_F(RebootNotificationControllerTest, CloseNotification) { + AccountId account_id = AccountId::FromUserEmailGaiaId(kEmailId, kGaiaId); + CreateFakeUser(account_id); + base::Time reboot_time; + ASSERT_TRUE( + base::Time::FromLocalExploded(kRebootTime2022Feb2At1520, &reboot_time)); + + // Log in user and show notification. + LoginFakeUser(account_id); + notification_controller_.MaybeShowPendingRebootNotification( + reboot_time, base::NullCallback()); + EXPECT_NE(absl::nullopt, GetNotification()); + EXPECT_EQ(GetTransientNotificationCount(), 1); + + // Explicitly close notification. + notification_controller_.CloseRebootNotification(); + EXPECT_EQ(absl::nullopt, GetNotification()); + EXPECT_EQ(GetTransientNotificationCount(), 0); +} + +TEST_F(RebootNotificationControllerTest, HandleNotificationClick) { + AccountId account_id = AccountId::FromUserEmailGaiaId(kEmailId, kGaiaId); + CreateFakeUser(account_id); + base::Time reboot_time; + ASSERT_TRUE( + base::Time::FromLocalExploded(kRebootTime2022Feb2At1520, &reboot_time)); + + // Log in user and show notification. + LoginFakeUser(account_id); + ClickCounter counter; + notification_controller_.MaybeShowPendingRebootNotification( + reboot_time, base::BindRepeating(&ClickCounter::ButtonClickCallback, + counter.weak_ptr_factory_.GetWeakPtr())); + auto notification = GetNotification().value(); + // Click on notification and do nothing. + notification.delegate()->Click(absl::nullopt, absl::nullopt); + EXPECT_EQ(counter.clicks, 0); + // Click on notification button and run callback. + notification.delegate()->Click(0, absl::nullopt); + EXPECT_EQ(counter.clicks, 1); +} \ No newline at end of file
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc index db43d8c..49c24295 100644 --- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc +++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
@@ -81,7 +81,7 @@ } // namespace // static -void apps::UninstallDialog::UiBase::Create( +views::Widget* apps::UninstallDialog::UiBase::Create( Profile* profile, apps::mojom::AppType app_type, const std::string& app_id, @@ -89,11 +89,12 @@ gfx::ImageSkia image, gfx::NativeWindow parent_window, apps::UninstallDialog* uninstall_dialog) { - constrained_window::CreateBrowserModalDialogViews( + views::Widget* widget = constrained_window::CreateBrowserModalDialogViews( (new AppUninstallDialogView(profile, app_type, app_id, app_name, image, uninstall_dialog)), - parent_window) - ->Show(); + parent_window); + widget->Show(); + return widget; } AppUninstallDialogView::AppUninstallDialogView(
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc index bbfbf74..254434e5 100644 --- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc
@@ -33,6 +33,7 @@ #include "content/public/test/test_navigation_observer.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/views/widget/any_widget_observer.h" class AppUninstallDialogViewBrowserTest : public DialogBrowserTest { public: @@ -207,6 +208,50 @@ } IN_PROC_BROWSER_TEST_F(WebAppsUninstallDialogViewBrowserTest, + ExistingDialogFocus) { + CreateApp(); + + auto* app_service_proxy = + apps::AppServiceProxyFactory::GetForProfile(browser()->profile()); + ASSERT_TRUE(app_service_proxy); + + // First call to uninstall should return true in callback for successful. + { + base::RunLoop run_loop; + app_service_proxy->UninstallForTesting( + app_id_, nullptr, base::BindLambdaForTesting([&](bool dialog_opened) { + EXPECT_TRUE(dialog_opened); + run_loop.Quit(); + })); + run_loop.Run(); + } + + views::Widget* first_widget = ActiveView()->GetWidget(); + first_widget->Hide(); + EXPECT_FALSE(first_widget->IsVisible()); + + // Second call should be unsuccessful. + { + base::RunLoop run_loop; + + // The shown widget should be the one opened in the first call to uninstall. + views::AnyWidgetObserver observer(views::test::AnyWidgetTestPasskey{}); + observer.set_shown_callback( + base::BindLambdaForTesting([&](views::Widget* widget) { + EXPECT_EQ(first_widget, widget); + EXPECT_TRUE(first_widget->IsVisible()); + })); + app_service_proxy->UninstallForTesting( + app_id_, nullptr, base::BindLambdaForTesting([&](bool dialog_opened) { + EXPECT_FALSE(dialog_opened); + run_loop.Quit(); + })); + + run_loop.Run(); + } +} + +IN_PROC_BROWSER_TEST_F(WebAppsUninstallDialogViewBrowserTest, PreventDuplicateUninstallDialogs) { CreateApp();
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index bf5f279..1da07dc8 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -1362,7 +1362,7 @@ &family_link_allowed); params.SetBoolKey("familyLinkAllowed", family_link_allowed); - CallJS("login.GaiaSigninScreen.showAllowlistCheckFailedError", true, params); + CallJS("login.GaiaSigninScreen.showAllowlistCheckFailedError", params); } void GaiaScreenHandler::LoadAuthExtension(bool force) {
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc index 2afa80c..5db32715 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc
@@ -11,19 +11,21 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/permission.h" #include "components/services/app_service/public/cpp/types_util.h" -#include "components/services/app_service/public/mojom/types.mojom.h" namespace chromeos { namespace settings { namespace { app_notification::mojom::AppPtr CreateAppPtr(const apps::AppUpdate& update) { - apps::mojom::PermissionPtr permission_copy; + apps::PermissionPtr permission_copy; for (const auto& permission : update.Permissions()) { if (permission->permission_type == apps::mojom::PermissionType::kNotifications) { - permission_copy = permission->Clone(); + permission_copy = apps::ConvertMojomPermissionToPermission(permission); break; } } @@ -32,7 +34,9 @@ app->id = update.AppId(); app->title = update.Name(); app->notification_permission = std::move(permission_copy); - app->readiness = update.Readiness(); + app->readiness = + mojo::EnumTraits<app_notification::mojom::Readiness, apps::Readiness>:: + ToMojom(apps::ConvertMojomReadinessToReadiness(update.Readiness())); return app; } @@ -103,8 +107,9 @@ void AppNotificationHandler::SetNotificationPermission( const std::string& app_id, - apps::mojom::PermissionPtr permission) { - app_service_proxy_->SetPermission(app_id, std::move(permission)); + apps::PermissionPtr permission) { + app_service_proxy_->SetPermission( + app_id, apps::ConvertPermissionToMojomPermission(permission)); } void AppNotificationHandler::GetApps(GetAppsCallback callback) {
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.h b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.h index c2632e6..ab6f4840 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.h +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.h
@@ -41,9 +41,8 @@ // settings::mojom::AppNotificationHandler: void SetQuietMode(bool in_quiet_mode) override; - void SetNotificationPermission( - const std::string& app_id, - apps::mojom::PermissionPtr permission) override; + void SetNotificationPermission(const std::string& app_id, + apps::PermissionPtr permission) override; void GetApps(GetAppsCallback callback) override; void GetQuietMode(GetQuietModeCallback callback) override;
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler_unittest.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler_unittest.cc index 6337c09..4a48dce 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler_unittest.cc
@@ -15,7 +15,8 @@ #include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom.h" #include "chrome/test/base/testing_profile.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" -#include "components/services/app_service/public/mojom/types.mojom.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/permission.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" @@ -209,7 +210,7 @@ EXPECT_EQ("arcAppWithNotifications", observer()->recently_updated_app()->id); EXPECT_TRUE(observer() ->recently_updated_app() - ->notification_permission->value->get_bool_value()); + ->notification_permission->value->bool_value.value()); CreateAndStoreFakeApp("webAppWithNotifications", apps::mojom::AppType::kWeb, apps::mojom::PermissionType::kNotifications, @@ -220,7 +221,7 @@ EXPECT_EQ("webAppWithNotifications", observer()->recently_updated_app()->id); EXPECT_TRUE(observer() ->recently_updated_app() - ->notification_permission->value->get_bool_value()); + ->notification_permission->value->bool_value.value()); CreateAndStoreFakeApp("arcAppWithCamera", apps::mojom::AppType::kArc, apps::mojom::PermissionType::kCamera); @@ -250,7 +251,7 @@ EXPECT_EQ("arcAppWithNotifications", observer()->recently_updated_app()->id); EXPECT_FALSE(observer() ->recently_updated_app() - ->notification_permission->value->get_bool_value()); + ->notification_permission->value->bool_value.value()); CreateAndStoreFakeApp("webAppWithNotifications", apps::mojom::AppType::kWeb, apps::mojom::PermissionType::kNotifications, @@ -261,7 +262,7 @@ EXPECT_EQ("webAppWithNotifications", observer()->recently_updated_app()->id); EXPECT_FALSE(observer() ->recently_updated_app() - ->notification_permission->value->get_bool_value()); + ->notification_permission->value->bool_value.value()); } } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/BUILD.gn b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/BUILD.gn index d58f83e1..c7bacea 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/BUILD.gn +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/BUILD.gn
@@ -14,4 +14,36 @@ "//components/services/app_service/public/mojom", "//mojo/public/mojom/base", ] + + cpp_typemaps = [ + { + types = [ + { + mojom = "chromeos.settings.app_notification.mojom.Permission" + cpp = "::apps::PermissionPtr" + move_only = true + }, + ] + traits_headers = [ + "//chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h", + "//components/services/app_service/public/cpp/app_types.h", + "//components/services/app_service/public/cpp/permission.h", + ] + traits_sources = [ "//chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc" ] + traits_public_deps = + [ "//components/services/app_service/public/cpp:app_types" ] + }, + ] +} + +source_set("test_support") { + testonly = true + + deps = [ + ":mojom", + "//base/test:test_support", + "//chrome/test:test_support", + "//mojo/public/cpp/test_support:test_utils", + "//testing/gtest", + ] }
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/OWNERS b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/OWNERS index 20352ec..11550d5 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/OWNERS +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/OWNERS
@@ -3,4 +3,7 @@ hsuregan@chromium.org per-file *.mojom=set noparent -per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file +per-file *.mojom=file://ipc/SECURITY_OWNERS + +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom index 1646039..29345ec 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom
@@ -4,7 +4,48 @@ module chromeos.settings.app_notification.mojom; -import "components/services/app_service/public/mojom/types.mojom"; +// Whether an app is ready to launch, i.e. installed. +enum Readiness { + kUnknown = 0, + kReady, // Installed and launchable. + kDisabledByBlocklist, // Disabled by SafeBrowsing. + kDisabledByPolicy, // Disabled by admin policy. + kDisabledByUser, // Disabled by explicit user action. + kTerminated, // Renderer process crashed. + kUninstalledByUser, + kRemoved, + kUninstalledByMigration, +}; + +// The types of permission. +enum PermissionType { + kUnknown = 0, + kCamera = 1, + kLocation = 2, + kMicrophone = 3, + kNotifications = 4, + kContacts = 5, + kStorage = 6, + kPrinting = 7, +}; + +enum TriState { + kAllow, + kBlock, + kAsk, +}; + +union PermissionValue { + bool bool_value; + TriState tristate_value; +}; + +struct Permission { + PermissionType permission_type; + PermissionValue value; + // If the permission is managed by an enterprise policy. + bool is_managed; +}; // Implementation of App // Contains the app's id, title, and only the notification permission, as this @@ -19,10 +60,10 @@ string? title; // Whether an app is ready to launch, i.e. installed. - apps.mojom.Readiness readiness; + Readiness readiness; // Contains the current permission state of the App's notification. - apps.mojom.Permission notification_permission; + Permission notification_permission; }; // Browser interface. @@ -36,7 +77,7 @@ AddObserver(pending_remote<AppNotificationsObserver> observer); // Updates the permission of the specified app (via app_id). - SetNotificationPermission(string app_id, apps.mojom.Permission permission); + SetNotificationPermission(string app_id, Permission permission); // Get the list of installed apps. GetApps() => (array<App> apps);
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc new file mode 100644 index 0000000..8a4fecad --- /dev/null +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.cc
@@ -0,0 +1,196 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h" + +#include <utility> + +namespace mojo { + +Readiness EnumTraits<Readiness, apps::Readiness>::ToMojom( + apps::Readiness input) { + switch (input) { + case apps::Readiness::kUnknown: + return Readiness::kUnknown; + case apps::Readiness::kReady: + return Readiness::kReady; + case apps::Readiness::kDisabledByBlocklist: + return Readiness::kDisabledByBlocklist; + case apps::Readiness::kDisabledByPolicy: + return Readiness::kDisabledByPolicy; + case apps::Readiness::kDisabledByUser: + return Readiness::kDisabledByUser; + case apps::Readiness::kTerminated: + return Readiness::kTerminated; + case apps::Readiness::kUninstalledByUser: + return Readiness::kUninstalledByUser; + case apps::Readiness::kRemoved: + return Readiness::kRemoved; + case apps::Readiness::kUninstalledByMigration: + return Readiness::kUninstalledByMigration; + } +} + +bool EnumTraits<Readiness, apps::Readiness>::FromMojom( + Readiness input, + apps::Readiness* output) { + switch (input) { + case Readiness::kUnknown: + *output = apps::Readiness::kUnknown; + return true; + case Readiness::kReady: + *output = apps::Readiness::kReady; + return true; + case Readiness::kDisabledByBlocklist: + *output = apps::Readiness::kDisabledByBlocklist; + return true; + case Readiness::kDisabledByPolicy: + *output = apps::Readiness::kDisabledByPolicy; + return true; + case Readiness::kDisabledByUser: + *output = apps::Readiness::kDisabledByUser; + return true; + case Readiness::kTerminated: + *output = apps::Readiness::kTerminated; + return true; + case Readiness::kUninstalledByUser: + *output = apps::Readiness::kUninstalledByUser; + return true; + case Readiness::kRemoved: + *output = apps::Readiness::kRemoved; + return true; + case Readiness::kUninstalledByMigration: + *output = apps::Readiness::kUninstalledByMigration; + return true; + } +} + +bool StructTraits<PermissionDataView, apps::PermissionPtr>::Read( + PermissionDataView data, + apps::PermissionPtr* out) { + apps::PermissionType permission_type; + if (!data.ReadPermissionType(&permission_type)) + return false; + + apps::PermissionValuePtr value; + if (!data.ReadValue(&value)) + return false; + + *out = std::make_unique<apps::Permission>(permission_type, std::move(value), + data.is_managed()); + return true; +} + +PermissionType EnumTraits<PermissionType, apps::PermissionType>::ToMojom( + apps::PermissionType input) { + switch (input) { + case apps::PermissionType::kUnknown: + return PermissionType::kUnknown; + case apps::PermissionType::kCamera: + return PermissionType::kCamera; + case apps::PermissionType::kLocation: + return PermissionType::kLocation; + case apps::PermissionType::kMicrophone: + return PermissionType::kMicrophone; + case apps::PermissionType::kNotifications: + return PermissionType::kNotifications; + case apps::PermissionType::kContacts: + return PermissionType::kContacts; + case apps::PermissionType::kStorage: + return PermissionType::kStorage; + case apps::PermissionType::kPrinting: + return PermissionType::kPrinting; + } +} + +bool EnumTraits<PermissionType, apps::PermissionType>::FromMojom( + PermissionType input, + apps::PermissionType* output) { + switch (input) { + case PermissionType::kUnknown: + *output = apps::PermissionType::kUnknown; + return true; + case PermissionType::kCamera: + *output = apps::PermissionType::kCamera; + return true; + case PermissionType::kLocation: + *output = apps::PermissionType::kLocation; + return true; + case PermissionType::kMicrophone: + *output = apps::PermissionType::kMicrophone; + return true; + case PermissionType::kNotifications: + *output = apps::PermissionType::kNotifications; + return true; + case PermissionType::kContacts: + *output = apps::PermissionType::kContacts; + return true; + case PermissionType::kStorage: + *output = apps::PermissionType::kStorage; + return true; + case PermissionType::kPrinting: + *output = apps::PermissionType::kPrinting; + return true; + } +} + +TriState EnumTraits<TriState, apps::TriState>::ToMojom(apps::TriState input) { + switch (input) { + case apps::TriState::kAllow: + return TriState::kAllow; + case apps::TriState::kBlock: + return TriState::kBlock; + case apps::TriState::kAsk: + return TriState::kAsk; + } +} + +bool EnumTraits<TriState, apps::TriState>::FromMojom(TriState input, + apps::TriState* output) { + switch (input) { + case TriState::kAllow: + *output = apps::TriState::kAllow; + return true; + case TriState::kBlock: + *output = apps::TriState::kBlock; + return true; + case TriState::kAsk: + *output = apps::TriState::kAsk; + return true; + } +} + +PermissionValueDataView::Tag +UnionTraits<PermissionValueDataView, apps::PermissionValuePtr>::GetTag( + const apps::PermissionValuePtr& r) { + if (r->bool_value.has_value()) { + return PermissionValueDataView::Tag::BOOL_VALUE; + } else if (r->tristate_value.has_value()) { + return PermissionValueDataView::Tag::TRISTATE_VALUE; + } + NOTREACHED(); + return PermissionValueDataView::Tag::BOOL_VALUE; +} + +bool UnionTraits<PermissionValueDataView, apps::PermissionValuePtr>::Read( + PermissionValueDataView data, + apps::PermissionValuePtr* out) { + switch (data.tag()) { + case PermissionValueDataView::Tag::BOOL_VALUE: { + *out = std::make_unique<apps::PermissionValue>(data.bool_value()); + return true; + } + case PermissionValueDataView::Tag::TRISTATE_VALUE: { + apps::TriState tristate_value; + if (!data.ReadTristateValue(&tristate_value)) + return false; + *out = std::make_unique<apps::PermissionValue>(tristate_value); + return true; + } + } + NOTREACHED(); + return false; +} + +} // namespace mojo
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h new file mode 100644 index 0000000..24714f7 --- /dev/null +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h
@@ -0,0 +1,91 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_APPS_PAGE_MOJOM_APP_TYPE_MOJOM_TRAITS_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_APPS_PAGE_MOJOM_APP_TYPE_MOJOM_TRAITS_H_ + +#include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/permission.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace mojo { + +namespace { + +using Readiness = chromeos::settings::app_notification::mojom::Readiness; +using PermissionDataView = + chromeos::settings::app_notification::mojom::PermissionDataView; +using PermissionType = + chromeos::settings::app_notification::mojom::PermissionType; +using TriState = chromeos::settings::app_notification::mojom::TriState; +using PermissionValueDataView = + chromeos::settings::app_notification::mojom::PermissionValueDataView; + +} // namespace + +template <> +struct EnumTraits<Readiness, apps::Readiness> { + static Readiness ToMojom(apps::Readiness input); + static bool FromMojom(Readiness input, apps::Readiness* output); +}; + +template <> +struct StructTraits<PermissionDataView, apps::PermissionPtr> { + static apps::PermissionType permission_type(const apps::PermissionPtr& r) { + return r->permission_type; + } + + static const apps::PermissionValuePtr& value(const apps::PermissionPtr& r) { + return r->value; + } + + static bool is_managed(const apps::PermissionPtr& r) { return r->is_managed; } + + static bool Read(PermissionDataView, apps::PermissionPtr* out); +}; + +template <> +struct CloneTraits<apps::PermissionPtr, false> { + static apps::PermissionPtr Clone(const apps::PermissionPtr& input) { + return input->Clone(); + } +}; + +template <> +struct EnumTraits<PermissionType, apps::PermissionType> { + static PermissionType ToMojom(apps::PermissionType input); + static bool FromMojom(PermissionType input, apps::PermissionType* output); +}; + +template <> +struct EnumTraits<TriState, apps::TriState> { + static TriState ToMojom(apps::TriState input); + static bool FromMojom(TriState input, apps::TriState* output); +}; + +template <> +struct UnionTraits<PermissionValueDataView, apps::PermissionValuePtr> { + static PermissionValueDataView::Tag GetTag(const apps::PermissionValuePtr& r); + + static bool IsNull(const apps::PermissionValuePtr& r) { + return !r->bool_value.has_value() && !r->tristate_value.has_value(); + } + + static void SetToNull(apps::PermissionValuePtr* out) { out->reset(); } + + static bool bool_value(const apps::PermissionValuePtr& r) { + return r->bool_value.value(); + } + + static apps::TriState tristate_value(const apps::PermissionValuePtr& r) { + return r->tristate_value.value(); + } + + static bool Read(PermissionValueDataView data, apps::PermissionValuePtr* out); +}; + +} // namespace mojo + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_ASH_OS_APPS_PAGE_MOJOM_APP_TYPE_MOJOM_TRAITS_H_
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc new file mode 100644 index 0000000..63dddef --- /dev/null +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits_unittest.cc
@@ -0,0 +1,131 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <utility> + +#include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_notification_handler.mojom.h" +#include "chrome/browser/ui/webui/settings/ash/os_apps_page/mojom/app_type_mojom_traits.h" +#include "components/services/app_service/public/cpp/app_types.h" +#include "components/services/app_service/public/cpp/permission.h" +#include "mojo/public/cpp/test_support/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Test that serialization and deserialization works with updating readiness. +TEST(AppTypeMojomTraitsTest, RoundTripReadiness) { + static constexpr apps::Readiness kTestReadiness[] = { + apps::Readiness::kUnknown, + apps::Readiness::kReady, + apps::Readiness::kDisabledByBlocklist, + apps::Readiness::kDisabledByPolicy, + apps::Readiness::kDisabledByUser, + apps::Readiness::kTerminated, + apps::Readiness::kUninstalledByUser, + apps::Readiness::kRemoved, + apps::Readiness::kUninstalledByMigration}; + + for (auto readiness_in : kTestReadiness) { + apps::Readiness readiness_out; + + chromeos::settings::app_notification::mojom::Readiness + serialized_readiness = mojo::EnumTraits< + chromeos::settings::app_notification::mojom::Readiness, + apps::Readiness>::ToMojom(readiness_in); + ASSERT_TRUE(( + mojo::EnumTraits<chromeos::settings::app_notification::mojom::Readiness, + apps::Readiness>::FromMojom(serialized_readiness, + &readiness_out))); + EXPECT_EQ(readiness_in, readiness_out); + } +} + +TEST(AppTypeMojomTraitsTest, RoundTripPermissions) { + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kUnknown, + std::make_unique<apps::PermissionValue>(true), + /*is_managed=*/false); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kCamera, + std::make_unique<apps::PermissionValue>(true), + /*is_managed=*/true); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kLocation, + std::make_unique<apps::PermissionValue>(apps::TriState::kAllow), + /*is_managed=*/false); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kMicrophone, + std::make_unique<apps::PermissionValue>(apps::TriState::kBlock), + /*is_managed=*/true); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kNotifications, + std::make_unique<apps::PermissionValue>(apps::TriState::kAsk), + /*is_managed=*/false); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kContacts, + std::make_unique<apps::PermissionValue>(apps::TriState::kAllow), + /*is_managed=*/true); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kStorage, + std::make_unique<apps::PermissionValue>(apps::TriState::kBlock), + /*is_managed=*/false); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } + { + auto permission = std::make_unique<apps::Permission>( + apps::PermissionType::kPrinting, + std::make_unique<apps::PermissionValue>(apps::TriState::kBlock), + /*is_managed=*/false); + apps::PermissionPtr output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize< + chromeos::settings::app_notification::mojom::Permission>( + permission, output)); + EXPECT_EQ(*permission, *output); + } +}
diff --git a/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc b/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc index 12d3071..c7e8cf753 100644 --- a/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/privacy_sandbox_handler_unittest.cc
@@ -150,7 +150,7 @@ content::TestWebUI* web_ui() { return web_ui_.get(); } PrivacySandboxHandler* handler() { return handler_.get(); } TestingProfile* profile() { return &profile_; } - PrivacySandboxSettings* privacy_sandbox_settings() { + privacy_sandbox::PrivacySandboxSettings* privacy_sandbox_settings() { return PrivacySandboxSettingsFactory::GetForProfile(profile()); }
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 36bb5bd4..6e65ed4 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -275,6 +275,10 @@ "enablePasswordNotes", base::FeatureList::IsEnabled(password_manager::features::kPasswordNotes)); + html_source->AddBoolean( + "enableSendPasswords", + base::FeatureList::IsEnabled(password_manager::features::kSendPasswords)); + #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS) html_source->AddBoolean("enableDesktopRestructuredLanguageSettings", base::FeatureList::IsEnabled(
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 50c452d2..46bc525 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1645574159-4f68b0ac4c0ad4f9971762f66286704eaa122288.profdata +chrome-linux-main-1645617234-edce5eead33c3da0cd365f8afd5609c9c0a116a4.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index b3b0e11b..f5c5422 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1645574159-9b0952a0e6f8425b04314d4ce625a5b4c219dcfc.profdata +chrome-mac-arm-main-1645617234-f1d8894b1e23955fd37ea585b43a081ff82a5c0f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index dabfd4c5..29e17c1 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1645574159-84ac20ae2b3921896fbf677a762cbe6c60e5d3d8.profdata +chrome-mac-main-1645595566-c3d1942eba7792b1af68e744864b2f418a87b3b5.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 139f86d2..3cd3b3b47 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1645574159-895357cd8bedc9dc31ba86d30478d3731468f622.profdata +chrome-win32-main-1645606721-838006e01d1447b87930ec35d524bd3f5806c21b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 7bb2d0a6..f7b24dec 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1645574159-8ba46068808193f24883e0c5d0b484d8961428e9.profdata +chrome-win64-main-1645606721-f0295952acd787de1e9d9ee8ddbc3c1c957cec11.profdata
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/fake_help_content_provider_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/fake_help_content_provider_test.js index 1d1db393..9b94ef7e 100644 --- a/chrome/test/data/webui/chromeos/os_feedback_ui/fake_help_content_provider_test.js +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/fake_help_content_provider_test.js
@@ -25,21 +25,21 @@ * Test that the fake help content provider returns the non-empty list which * was set explicitly. */ - test('getHelpContents', () => { + test('getHelpContents', async () => { provider.setFakeSearchResponse(fakeSearchResponse); - return provider.getHelpContents(fakeSearchRequest).then((response) => { - assertDeepEquals(fakeHelpContentList, response.response.results); - assertEquals( - fakeSearchResponse.totalResults, response.response.totalResults); - }); + const response = await provider.getHelpContents(fakeSearchRequest); + + assertDeepEquals(fakeHelpContentList, response.response.results); + assertEquals( + fakeSearchResponse.totalResults, response.response.totalResults); }); /** * Test that the fake help content provider returns the empty list which was * set explicitly. */ - test('getHelpContentsEmpty', () => { + test('getHelpContentsEmpty', async () => { /** @type {!HelpContentList} */ const expectedList = []; @@ -48,13 +48,13 @@ results: expectedList, totalResults: 0, }; - provider.setFakeSearchResponse(emptyResponse); - return provider.getHelpContents(fakeSearchRequest).then((response) => { - assertDeepEquals(expectedList, response.response.results); - assertEquals(emptyResponse.totalResults, response.response.totalResults); - assertEquals( - mojoString16ToString(fakeSearchRequest.query), provider.lastQuery); - }); + + const response = await provider.getHelpContents(fakeSearchRequest); + + assertDeepEquals(expectedList, response.response.results); + assertEquals(emptyResponse.totalResults, response.response.totalResults); + assertEquals( + mojoString16ToString(fakeSearchRequest.query), provider.lastQuery); }); }
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/help_content_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/help_content_test.js index a9e94b34..0935859c 100644 --- a/chrome/test/data/webui/chromeos/os_feedback_ui/help_content_test.js +++ b/chrome/test/data/webui/chromeos/os_feedback_ui/help_content_test.js
@@ -46,49 +46,47 @@ } /** Test that expected html elements are in the element. */ - test('HelpContentLoaded', () => { - return initializeHelpContentElement(fakeHelpContentList).then(() => { - // Verify the title is in the helpContentElement. - const title = getElement('#helpContentLabel'); - assertTrue(!!title); - assertEquals('Suggested help content:', title.textContent); + test('HelpContentLoaded', async () => { + await initializeHelpContentElement(fakeHelpContentList); - // Verify the help content is populated with correct number of items. - assertEquals(5, getElement('dom-repeat').items.length); - const helpLinks = - helpContentElement.shadowRoot.querySelectorAll('.help-item a'); - assertEquals(5, helpLinks.length); + // Verify the title is in the helpContentElement. + const title = getElement('#helpContentLabel'); + assertTrue(!!title); + assertEquals('Suggested help content:', title.textContent); - // Verify the help links are displayed in order with correct title and - // url. - assertEquals('Fix connection problems', helpLinks[0].innerText); - assertEquals( - 'https://support.google.com/chromebook/?q=6318213', - helpLinks[0].href); + // Verify the help content is populated with correct number of items. + assertEquals(5, getElement('dom-repeat').items.length); + const helpLinks = + helpContentElement.shadowRoot.querySelectorAll('.help-item a'); + assertEquals(5, helpLinks.length); - assertEquals( - 'Why won\'t my wireless mouse with a USB piece wor...?', - helpLinks[1].innerText); - assertEquals( - 'https://support.google.com/chromebook/?q=123920509', - helpLinks[1].href); + // Verify the help links are displayed in order with correct title and + // url. + assertEquals('Fix connection problems', helpLinks[0].innerText); + assertEquals( + 'https://support.google.com/chromebook/?q=6318213', helpLinks[0].href); - assertEquals('Wifi Issues - only on Chromebooks', helpLinks[2].innerText); - assertEquals( - 'https://support.google.com/chromebook/?q=114174470', - helpLinks[2].href); + assertEquals( + 'Why won\'t my wireless mouse with a USB piece wor...?', + helpLinks[1].innerText); + assertEquals( + 'https://support.google.com/chromebook/?q=123920509', + helpLinks[1].href); - assertEquals('Network Connectivity Fault', helpLinks[3].innerText); - assertEquals( - 'https://support.google.com/chromebook/?q=131459420', - helpLinks[3].href); + assertEquals('Wifi Issues - only on Chromebooks', helpLinks[2].innerText); + assertEquals( + 'https://support.google.com/chromebook/?q=114174470', + helpLinks[2].href); - assertEquals( - 'Connected to WiFi but can\'t connect to the internet', - helpLinks[4].innerText); - assertEquals( - 'https://support.google.com/chromebook/?q=22864239', - helpLinks[4].href); - }); + assertEquals('Network Connectivity Fault', helpLinks[3].innerText); + assertEquals( + 'https://support.google.com/chromebook/?q=131459420', + helpLinks[3].href); + + assertEquals( + 'Connected to WiFi but can\'t connect to the internet', + helpLinks[4].innerText); + assertEquals( + 'https://support.google.com/chromebook/?q=22864239', helpLinks[4].href); }); -} \ No newline at end of file +}
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_choose_wipe_device_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_choose_wipe_device_page_test.js index 7edc04c84..ebe8576 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_choose_wipe_device_page_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_choose_wipe_device_page_test.js
@@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; +import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js'; +import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js'; import {OnboardingChooseWipeDevicePage} from 'chrome://shimless-rma/onboarding_choose_wipe_device_page.js'; +import {ShimlessRma} from 'chrome://shimless-rma/shimless_rma.js'; import {assertFalse, assertTrue} from '../../chai_assert.js'; import {flushTasks} from '../../test_util.js'; @@ -11,6 +15,14 @@ /** @type {?OnboardingChooseWipeDevicePage} */ let component = null; + /** @type {?FakeShimlessRmaService} */ + let service = null; + + suiteSetup(() => { + service = new FakeShimlessRmaService(); + setShimlessRmaServiceForTesting(service); + }); + setup(() => { document.body.innerHTML = ''; }); @@ -18,6 +30,7 @@ teardown(() => { component.remove(); component = null; + service.reset(); }); /** @@ -39,4 +52,44 @@ assertTrue(!!component); }); + + test('ChooseWipeDevicePageSelectWipeDevice', async () => { + const resolver = new PromiseResolver(); + await initializeChooseWipeDevicePage(); + + let shouldWipeDevice = false; + service.setWipeDevice = (wipeDevice) => { + shouldWipeDevice = wipeDevice; + return resolver.promise; + }; + + const wipeDeviceOption = + component.shadowRoot.querySelector('cr-radio-button[name=wipeDevice]'); + wipeDeviceOption.click(); + assertTrue(wipeDeviceOption.checked); + + component.onNextButtonClick(); + await resolver; + assertTrue(shouldWipeDevice); + }); + + test('ChooseWipeDevicePageSelectPreserveData', async () => { + const resolver = new PromiseResolver(); + await initializeChooseWipeDevicePage(); + + let shouldWipeDevice = true; + service.setWipeDevice = (wipeDevice) => { + shouldWipeDevice = wipeDevice; + return resolver.promise; + }; + + const wipeDeviceOption = component.shadowRoot.querySelector( + 'cr-radio-button[name=preserveData]'); + wipeDeviceOption.click(); + assertTrue(wipeDeviceOption.checked); + + component.onNextButtonClick(); + await resolver; + assertFalse(shouldWipeDevice); + }); }
diff --git a/chrome/test/data/webui/history/BUILD.gn b/chrome/test/data/webui/history/BUILD.gn index 776fca3..6e0ea7a 100644 --- a/chrome/test/data/webui/history/BUILD.gn +++ b/chrome/test/data/webui/history/BUILD.gn
@@ -17,9 +17,9 @@ "history_overflow_menu_test.ts", "history_routing_test.ts", "history_routing_with_query_param_test.ts", - "history_supervised_user_test.js", + "history_supervised_user_test.ts", "history_synced_device_manager_focus_test.js", - "history_synced_tabs_test.js", + "history_synced_tabs_test.ts", "history_toolbar_focus_test.ts", "history_toolbar_test.ts", "link_click_test.ts",
diff --git a/chrome/test/data/webui/history/history_supervised_user_test.js b/chrome/test/data/webui/history/history_supervised_user_test.js deleted file mode 100644 index c0900ed..0000000 --- a/chrome/test/data/webui/history/history_supervised_user_test.js +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {BrowserServiceImpl, ensureLazyLoaded} from 'chrome://history/history.js'; -import {flushTasks} from 'chrome://webui-test/test_util.js'; - -import {TestBrowserService} from './test_browser_service.js'; -import {createHistoryEntry, createHistoryInfo} from './test_util.js'; - -suite('history-list supervised-user', function() { - let app; - let historyList; - let toolbar; - let testService; - const TEST_HISTORY_RESULTS = - [createHistoryEntry('2016-03-15', 'https://www.google.com')]; - - setup(function() { - document.body.innerHTML = ''; - testService = new TestBrowserService(); - BrowserServiceImpl.setInstance(testService); - - testService.setQueryResult({ - info: createHistoryInfo(), - value: TEST_HISTORY_RESULTS, - }); - app = document.createElement('history-app'); - document.body.appendChild(app); - - historyList = app.$.history; - toolbar = app.$.toolbar; - return Promise.all([ - testService.whenCalled('queryHistory'), - ensureLazyLoaded(), - ]); - }); - - test('checkboxes disabled for supervised user', function() { - return flushTasks().then(function() { - const items = historyList.shadowRoot.querySelectorAll('history-item'); - - items[0].$['checkbox'].click(); - - assertFalse(items[0].selected); - }); - }); - - test('deletion disabled for supervised user', function() { - // Make sure that removeVisits is not being called. - historyList.historyData_[0].selected = true; - toolbar.deleteSelectedItems(); - assertEquals(0, testService.getCallCount('removeVisits')); - }); - - test('remove history menu button disabled', function() { - const listContainer = app.$['history']; - listContainer.$.sharedMenu.get(); - assertTrue( - listContainer.shadowRoot.querySelector('#menuRemoveButton').hidden); - }); -});
diff --git a/chrome/test/data/webui/history/history_supervised_user_test.ts b/chrome/test/data/webui/history/history_supervised_user_test.ts new file mode 100644 index 0000000..cf5f1db --- /dev/null +++ b/chrome/test/data/webui/history/history_supervised_user_test.ts
@@ -0,0 +1,78 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {BrowserServiceImpl, ensureLazyLoaded, HistoryAppElement, HistoryEntry, HistoryListElement, HistoryToolbarElement} from 'chrome://history/history.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {eventToPromise, flushTasks} from 'chrome://webui-test/test_util.js'; + +import {TestBrowserService} from './test_browser_service.js'; +import {createHistoryEntry, createHistoryInfo} from './test_util.js'; + +suite('history-list supervised-user', function() { + let app: HistoryAppElement; + let historyList: HistoryListElement; + let toolbar: HistoryToolbarElement; + let testService: TestBrowserService; + const TEST_HISTORY_RESULTS: HistoryEntry[] = + [createHistoryEntry('2016-03-15', 'https://www.google.com')]; + + setup(function() { + document.body.innerHTML = ''; + testService = new TestBrowserService(); + BrowserServiceImpl.setInstance(testService); + + testService.setQueryResult({ + info: createHistoryInfo(), + value: TEST_HISTORY_RESULTS, + }); + app = document.createElement('history-app'); + document.body.appendChild(app); + + historyList = app.$.history; + toolbar = app.$.toolbar; + return Promise.all([ + testService.whenCalled('queryHistory'), + ensureLazyLoaded(), + ]); + }); + + test('checkboxes disabled for supervised user', function() { + return flushTasks().then(function() { + const items = historyList.shadowRoot!.querySelectorAll('history-item'); + + items[0]!.$.checkbox.click(); + + assertFalse(items[0]!.selected); + }); + }); + + test('deletion disabled for supervised user', function() { + return flushTasks() + .then(function() { + const whenChecked = + eventToPromise('history-checkbox-select', historyList); + // Manually dispatch the event since the checkboxes are disabled due + // to the test configuration. + historyList.shadowRoot!.querySelector('history-item')!.dispatchEvent( + new CustomEvent('history-checkbox-select', { + bubbles: true, + composed: true, + detail: {index: 0, shiftKey: false} + })); + return whenChecked; + }) + .then(() => { + toolbar.deleteSelectedItems(); + // Make sure that removeVisits is not being called. + assertEquals(0, testService.getCallCount('removeVisits')); + }); + }); + + test('remove history menu button disabled', function() { + historyList.$.sharedMenu.get(); + assertTrue( + historyList.shadowRoot!.querySelector<HTMLElement>( + '#menuRemoveButton')!.hidden); + }); +});
diff --git a/chrome/test/data/webui/history/history_synced_tabs_test.js b/chrome/test/data/webui/history/history_synced_tabs_test.ts similarity index 68% rename from chrome/test/data/webui/history/history_synced_tabs_test.js rename to chrome/test/data/webui/history/history_synced_tabs_test.ts index 4c0748a..cab0207 100644 --- a/chrome/test/data/webui/history/history_synced_tabs_test.js +++ b/chrome/test/data/webui/history/history_synced_tabs_test.ts
@@ -2,34 +2,39 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {BrowserServiceImpl, ensureLazyLoaded} from 'chrome://history/history.js'; +import {BrowserServiceImpl, ensureLazyLoaded, ForeignSession, HistorySyncedDeviceCardElement, HistorySyncedDeviceManagerElement} from 'chrome://history/history.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks, waitBeforeNextRender} from 'chrome://webui-test/test_util.js'; import {TestBrowserService} from './test_browser_service.js'; -import {createSession, createWindow, polymerSelectAll} from './test_util.js'; +import {createSession, createWindow} from './test_util.js'; -function getCards(manager) { - return polymerSelectAll(manager, 'history-synced-device-card'); +function getCards(manager: HistorySyncedDeviceManagerElement): + NodeListOf<HistorySyncedDeviceCardElement> { + return manager.shadowRoot!.querySelectorAll('history-synced-device-card'); } -function numWindowSeparators(card) { - return polymerSelectAll(card, ':not([hidden]).window-separator').length; +function numWindowSeparators(card: HistorySyncedDeviceCardElement): number { + return card.shadowRoot!.querySelectorAll(':not([hidden]).window-separator') + .length; } -function assertNoSyncedTabsMessageShown(manager, stringID) { +function assertNoSyncedTabsMessageShown( + manager: HistorySyncedDeviceManagerElement, stringID: string) { assertFalse(manager.$['no-synced-tabs'].hidden); const message = loadTimeData.getString(stringID); - assertNotEquals(-1, manager.$['no-synced-tabs'].textContent.indexOf(message)); + assertNotEquals( + -1, manager.$['no-synced-tabs'].textContent!.indexOf(message)); } suite('<history-synced-device-manager>', function() { - let element; - let testService; + let element: HistorySyncedDeviceManagerElement; + let testService: TestBrowserService; - const setForeignSessions = function(sessions) { + function setForeignSessions(sessions: Array<ForeignSession>) { element.sessionList = sessions; - }; + } setup(function() { document.body.innerHTML = ''; @@ -45,30 +50,31 @@ // the same order in tests, in order to catch regressions like // https://crbug.com/915641. element.searchTerm = ''; - element.signInState = true; + element.configureSignInForTest( + {signInState: true, signInAllowed: true, guestSession: false}); document.body.appendChild(element); }); }); test('single card, single window', function() { - const sessionList = [createSession( + const sessionList: Array<ForeignSession> = [createSession( 'Nexus 5', [createWindow(['http://www.google.com', 'http://example.com'])])]; setForeignSessions(sessionList); return flushTasks().then(function() { const card = - element.shadowRoot.querySelector('history-synced-device-card'); + element.shadowRoot!.querySelector('history-synced-device-card')!; assertEquals( 'http://www.google.com', - card.shadowRoot.querySelectorAll('.website-title')[0] - .textContent.trim()); + card.shadowRoot!.querySelectorAll<HTMLElement>( + '.website-title')[0]!.textContent!.trim()); assertEquals(2, card.tabs.length); }); }); test('two cards, multiple windows', function() { - const sessionList = [ + const sessionList: Array<ForeignSession> = [ createSession( 'Nexus 5', [createWindow(['http://www.google.com', 'http://example.com'])]), @@ -86,8 +92,8 @@ assertEquals(2, cards.length); // Ensure separators between windows are added appropriately. - assertEquals(0, numWindowSeparators(cards[0])); - assertEquals(1, numWindowSeparators(cards[1])); + assertEquals(0, numWindowSeparators(cards[0]!)); + assertEquals(1, numWindowSeparators(cards[1]!)); }); }); @@ -120,19 +126,19 @@ assertEquals(2, cards.length); // There are now 2 windows in the first device. - assertEquals(1, numWindowSeparators(cards[0])); + assertEquals(1, numWindowSeparators(cards[0]!)); // Check that the actual link changes. assertEquals( 'http://crbug.com/new', - cards[0] - .shadowRoot.querySelectorAll('.website-title')[1] - .textContent.trim()); + cards[0]!.shadowRoot! + .querySelectorAll<HTMLElement>( + '.website-title')[1]!.textContent!.trim()); }); }); test('two cards, multiple windows, search', function() { - const sessionList = [ + const sessionList: Array<ForeignSession> = [ createSession( 'Nexus 5', [createWindow(['http://www.google.com', 'http://example.com'])]), @@ -152,8 +158,8 @@ assertEquals(2, cards.length); // Ensure separators between windows are added appropriately. - assertEquals(0, numWindowSeparators(cards[0])); - assertEquals(2, numWindowSeparators(cards[1])); + assertEquals(0, numWindowSeparators(cards[0]!)); + assertEquals(2, numWindowSeparators(cards[1]!)); element.searchTerm = 'g'; return flushTasks(); @@ -161,21 +167,21 @@ .then(function() { const cards = getCards(element); - assertEquals(0, numWindowSeparators(cards[0])); - assertEquals(1, cards[0].tabs.length); - assertEquals('http://www.google.com', cards[0].tabs[0].title); - assertEquals(1, numWindowSeparators(cards[1])); - assertEquals(3, cards[1].tabs.length); - assertEquals('http://www.gmail.com', cards[1].tabs[0].title); - assertEquals('http://www.gmail.com', cards[1].tabs[1].title); - assertEquals('http://bagssl.com', cards[1].tabs[2].title); + assertEquals(0, numWindowSeparators(cards[0]!)); + assertEquals(1, cards[0]!.tabs.length); + assertEquals('http://www.google.com', cards[0]!.tabs[0]!.title); + assertEquals(1, numWindowSeparators(cards[1]!)); + assertEquals(3, cards[1]!.tabs.length); + assertEquals('http://www.gmail.com', cards[1]!.tabs[0]!.title); + assertEquals('http://www.gmail.com', cards[1]!.tabs[1]!.title); + assertEquals('http://bagssl.com', cards[1]!.tabs[2]!.title); // Ensure the title text is rendered during searches. assertEquals( 'http://www.google.com', - cards[0] - .shadowRoot.querySelectorAll('.website-title')[0] - .textContent.trim()); + cards[0]!.shadowRoot! + .querySelectorAll<HTMLElement>( + '.website-title')[0]!.textContent!.trim()); element.searchTerm = 'Sans'; return flushTasks(); @@ -188,7 +194,7 @@ }); test('delete a session', function() { - const sessionList = [ + const sessionList: Array<ForeignSession> = [ createSession('Nexus 5', [createWindow(['http://www.example.com'])]), createSession('Pixel C', [createWindow(['http://www.badssl.com'])]), ]; @@ -200,30 +206,31 @@ const cards = getCards(element); assertEquals(2, cards.length); - cards[0].$['menu-button'].click(); + cards[0]!.$['menu-button'].click(); return flushTasks(); }) .then(function() { - element.shadowRoot.querySelector('#menuDeleteButton').click(); + element.shadowRoot!.querySelector<HTMLElement>( + '#menuDeleteButton')!.click(); return testService.whenCalled('deleteForeignSession'); }) .then(args => { assertEquals('Nexus 5', args); // Simulate deleting the first device. - setForeignSessions([sessionList[1]]); + setForeignSessions([sessionList[1]!]); return flushTasks(); }) .then(function() { const cards = getCards(element); assertEquals(1, cards.length); - assertEquals('http://www.badssl.com', cards[0].tabs[0].title); + assertEquals('http://www.badssl.com', cards[0]!.tabs[0]!.title); }); }); test('delete a collapsed session', function() { - const sessionList = [ + const sessionList: Array<ForeignSession> = [ createSession('Nexus 5', [createWindow(['http://www.example.com'])]), createSession('Pixel C', [createWindow(['http://www.badssl.com'])]), ]; @@ -232,16 +239,16 @@ return flushTasks() .then(function() { const cards = getCards(element); - cards[0].$['card-heading'].click(); - assertFalse(cards[0].opened); + cards[0]!.$['card-heading'].click(); + assertFalse(cards[0]!.opened); // Simulate deleting the first device. - setForeignSessions([sessionList[1]]); + setForeignSessions([sessionList[1]!]); return flushTasks(); }) .then(function() { const cards = getCards(element); - assertTrue(cards[0].opened); + assertTrue(cards[0]!.opened); }); }); @@ -251,7 +258,7 @@ return flushTasks() .then(function() { const cards = getCards(element); - const anchor = cards[0].root.querySelector('a'); + const anchor = cards[0]!.shadowRoot!.querySelector('a')!; anchor.click(); return testService.whenCalled('openForeignSessionTab'); }) @@ -272,17 +279,19 @@ return flushTasks().then(function() { const cards = getCards(element); - cards[0].$['menu-button'].click(); - assertTrue(element.$.menu.getIfExists().open); + cards[0]!.$['menu-button'].click(); + assertTrue(element.$.menu.getIfExists()!.open); }); }); test('show sign in promo', function() { - element.signInState = false; + element.configureSignInForTest( + {signInState: false, signInAllowed: true, guestSession: false}); return flushTasks() .then(function() { assertFalse(element.$['sign-in-guide'].hidden); - element.signInState = true; + element.configureSignInForTest( + {signInState: true, signInAllowed: true, guestSession: false}); return flushTasks(); }) .then(function() { @@ -292,8 +301,9 @@ test('no synced tabs message', function() { // When user is not logged in, there is no synced tabs. - element.signInState = false; - element.syncedDevices_ = []; + element.configureSignInForTest( + {signInState: false, signInAllowed: true, guestSession: false}); + element.clearSyncedDevicesForTest(); return flushTasks() .then(function() { assertTrue(element.$['no-synced-tabs'].hidden); @@ -301,7 +311,8 @@ const cards = getCards(element); assertEquals(0, cards.length); - element.signInState = true; + element.configureSignInForTest( + {signInState: true, signInAllowed: true, guestSession: false}); return flushTasks(); }) @@ -309,7 +320,7 @@ // When user signs in, first show loading message. assertNoSyncedTabsMessageShown(element, 'loading'); - const sessionList = []; + const sessionList: Array<ForeignSession> = []; setForeignSessions(sessionList); return flushTasks(); }) @@ -319,7 +330,7 @@ // If no synced tabs are fetched, show 'no synced tabs'. assertNoSyncedTabsMessageShown(element, 'noSyncedResults'); - const sessionList = [createSession( + const sessionList: Array<ForeignSession> = [createSession( 'Nexus 5', [createWindow(['http://www.google.com', 'http://example.com'])])]; setForeignSessions(sessionList); @@ -332,7 +343,8 @@ // If there are any synced tabs, hide the 'no synced tabs' message. assertTrue(element.$['no-synced-tabs'].hidden); - element.signInState = false; + element.configureSignInForTest( + {signInState: false, signInAllowed: true, guestSession: false}); return flushTasks(); }) .then(function() { @@ -342,22 +354,22 @@ }); test('hide sign in promo in guest mode', function() { - element.signInState = false; - element.guestSession_ = true; + element.configureSignInForTest( + {signInState: false, signInAllowed: true, guestSession: true}); return flushTasks().then(function() { assertTrue(element.$['sign-in-guide'].hidden); }); }); test('hide sign-in promo if sign-in is disabled', async function() { - element.signInState = false; - element.signInAllowed_ = false; + element.configureSignInForTest( + {signInState: false, signInAllowed: false, guestSession: false}); await flushTasks(); assertTrue(element.$['sign-in-guide'].hidden); }); test('no synced tabs message displays on load', function() { - element.syncedDevices_ = []; + element.clearSyncedDevicesForTest(); // Should show no synced tabs message on initial load. Regression test for // https://crbug.com/915641. return Promise.all([flushTasks(), waitBeforeNextRender(element)])
diff --git a/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts b/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts index 8a6fc3fa..3de837d 100644 --- a/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts +++ b/chrome/test/data/webui/tab_search/tab_search_app_focus_test.ts
@@ -5,11 +5,11 @@ import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; import {InfiniteList, ProfileData, TabSearchApiProxyImpl, TabSearchAppElement, TabSearchItem} from 'chrome://tab-search.top-chrome/tab_search.js'; -import {assertEquals, assertGT, assertNotEquals} from 'chrome://webui-test/chai_assert.js'; +import {assertEquals, assertGT, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/test_util.js'; -import {createProfileData, generateSampleDataFromSiteNames, sampleSiteNames} from './tab_search_test_data.js'; -import {assertTabItemAndNeighborsInViewBounds, disableAnimationBehavior, initLoadTimeDataWithDefaults} from './tab_search_test_helper.js'; +import {createProfileData, generateSampleDataFromSiteNames, generateSampleRecentlyClosedTabs, generateSampleTabsFromSiteNames, sampleSiteNames, sampleToken} from './tab_search_test_data.js'; +import {assertTabItemAndNeighborsInViewBounds, assertTabItemInViewBounds, disableAnimationBehavior, getStylePropertyPixelValue, initLoadTimeDataWithDefaults} from './tab_search_test_helper.js'; import {TestTabSearchApiProxy} from './test_tab_search_api_proxy.js'; suite('TabSearchAppFocusTest', () => { @@ -39,6 +39,10 @@ return tabSearchApp.$.tabsList.querySelectorAll('tab-search-item'); } + function queryListTitle(): NodeListOf<HTMLElement> { + return tabSearchApp.$.tabsList.querySelectorAll('.list-section-title'); + } + test('KeyNavigation', async () => { await setupTest(createProfileData()); @@ -158,4 +162,46 @@ await flushTasks(); assertEquals(searchInput, getDeepActiveElement()); }); + + test('Section item visible on recently closed section expand', async () => { + // A list height that encompasses two title items, and four open tab items, + // thus ensuring that on adding a recently closed item to the list, it will + // be outside the visible boundaries. + const tabItemHeight = + getStylePropertyPixelValue(tabSearchApp, '--mwb-item-height'); + const titleItemHeight = getStylePropertyPixelValue( + tabSearchApp, '--mwb-list-section-title-height'); + const windowHeight = (titleItemHeight * 2) + (4 * tabItemHeight); + + await setupTest(createProfileData({ + windows: [{ + active: true, + height: windowHeight, + tabs: generateSampleTabsFromSiteNames(sampleSiteNames(4)) + }], + recentlyClosedTabs: generateSampleRecentlyClosedTabs( + 'Sample Tab', 1, sampleToken(0n, 1n)), + recentlyClosedSectionExpanded: false, + })); + + const recentlyClosedTitleItem = queryListTitle()[1]; + assertTrue(!!recentlyClosedTitleItem); + + const recentlyClosedTitleExpandButton = + recentlyClosedTitleItem!.querySelector('cr-expand-button'); + assertTrue(!!recentlyClosedTitleExpandButton); + + // Expand the `Recently Closed` section. + recentlyClosedTitleExpandButton!.click(); + + await waitAfterNextRender(tabSearchApp); + const tabsDiv = tabSearchApp.$.tabsList; + // Assert that the tabs are in a overflowing state. + assertGT(tabsDiv.scrollHeight, tabsDiv.clientHeight); + + // Assert the first recently closed item is in view bounds. + const tabItems = + tabSearchApp.$.tabsList.querySelectorAll('tab-search-item'); + assertTabItemInViewBounds(tabsDiv, tabItems[4]!); + }); });
diff --git a/chrome/test/data/webui/tab_search/tab_search_test_helper.ts b/chrome/test/data/webui/tab_search/tab_search_test_helper.ts index f650e3d..ffd3448 100644 --- a/chrome/test/data/webui/tab_search/tab_search_test_helper.ts +++ b/chrome/test/data/webui/tab_search/tab_search_test_helper.ts
@@ -66,3 +66,13 @@ }, loadTimeOverriddenData)); } + +/** + * Returns a style property number value that needs to be determined from the + * computed style of an HTML element. + */ +export function getStylePropertyPixelValue( + element: HTMLElement, name: string): number { + const pxValue = getComputedStyle(element).getPropertyValue(name); + return Number.parseInt(pxValue.trim().slice(0, -2), 10); +}
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn index 66972c7..b5d18dd 100644 --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn
@@ -134,6 +134,10 @@ ] } + if (is_linux || is_chromeos) { + deps += [ "//components/services/screen_ai" ] + } + if (enable_extensions) { deps += [ "//chrome/common/extensions/api",
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS index c425b93..0ba4d051 100644 --- a/chrome/utility/DEPS +++ b/chrome/utility/DEPS
@@ -44,6 +44,7 @@ "+components/services/patch", "+components/services/print_compositor", "+components/services/quarantine", + "+components/services/screen_ai", "+components/services/unzip", "+components/webapps/services/web_app_origin_association", "+content/public/child",
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc index 1cd1291..22828b8 100644 --- a/chrome/utility/services.cc +++ b/chrome/utility/services.cc
@@ -28,6 +28,10 @@ #include "mojo/public/cpp/bindings/service_factory.h" #include "printing/buildflags/buildflags.h" +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#include "components/services/screen_ai/screen_ai_service_impl.h" +#endif + #if BUILDFLAG(IS_WIN) #include "chrome/services/util_win/processor_metrics.h" #include "chrome/services/util_win/public/mojom/util_read_icon.mojom.h" @@ -209,6 +213,13 @@ } #endif // !BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +auto RunScreenAIService( + mojo::PendingReceiver<screen_ai::mojom::ScreenAIService> receiver) { + return std::make_unique<screen_ai::ScreenAIService>(std::move(receiver)); +} +#endif + #if BUILDFLAG(ENABLE_PRINTING) && BUILDFLAG(IS_CHROMEOS_ASH) auto RunCupsIppParser( mojo::PendingReceiver<ipp_parser::mojom::IppParser> receiver) { @@ -363,6 +374,11 @@ services.Add(RunSpeechRecognitionService); #endif +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + if (base::FeatureList::IsEnabled(features::kScreenAI)) + services.Add(RunScreenAIService); +#endif + #if BUILDFLAG(IS_WIN) services.Add(RunProcessorMetrics); services.Add(RunQuarantineService);
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc index ad8da5b..d8735a9 100644 --- a/components/autofill/core/browser/payments/payments_client.cc +++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -1145,7 +1145,7 @@ callback) { IssueRequest(std::make_unique<GetDetailsForEnrollmentRequest>( request_details, std::move(callback)), - /*authenticate=*/false); + /*authenticate=*/true); } void PaymentsClient::UpdateVirtualCardEnrollment(
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc index 6ffca778..2816353c 100644 --- a/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -1980,7 +1980,7 @@ request_details, base::BindOnce(&PaymentsClientTest::OnDidGetVirtualCardEnrollmentDetails, weak_ptr_factory_.GetWeakPtr())); - + IssueOAuthToken(); // Ensures the request contains the correct fields. EXPECT_TRUE(!GetUploadData().empty()); EXPECT_TRUE(GetUploadData().find("language_code") != std::string::npos);
diff --git a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h index 789bef10..652d080 100644 --- a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h +++ b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
@@ -52,6 +52,13 @@ autofill_client_ = autofill_client; } + void SetVirtualCardEnrollmentFieldsLoadedCallback( + VirtualCardEnrollmentFieldsLoadedCallback + virtual_card_enrollment_fields_loaded_callback) { + virtual_card_enrollment_fields_loaded_callback_ = + std::move(virtual_card_enrollment_fields_loaded_callback); + } + bool AutofillClientIsPresent() { return autofill_client_ != nullptr; } // VirtualCardEnrollmentManager:
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc index 45af9762..ec19952 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -53,12 +53,15 @@ const CreditCard& credit_card, VirtualCardEnrollmentSource virtual_card_enrollment_source, const raw_ptr<PrefService> user_prefs, - RiskAssessmentFunction risk_assessment_function) { + RiskAssessmentFunction risk_assessment_function, + VirtualCardEnrollmentFieldsLoadedCallback + virtual_card_enrollment_fields_loaded_callback) { Reset(); DCHECK_NE(virtual_card_enrollment_source, VirtualCardEnrollmentSource::kNone); state_.virtual_card_enrollment_fields.credit_card = credit_card; risk_assessment_function_ = std::move(risk_assessment_function); - + virtual_card_enrollment_fields_loaded_callback_ = + std::move(virtual_card_enrollment_fields_loaded_callback); // The |card_art_image| might not be synced yet from the sync server which // will result in a nullptr. This situation can occur in the upstream flow. If // it is not synced, GetCreditCardArtImageForUrl() will send a fetch request @@ -89,6 +92,28 @@ } } +void VirtualCardEnrollmentManager::Enroll() { + LogUpdateVirtualCardEnrollmentRequestAttempt( + state_.virtual_card_enrollment_fields.virtual_card_enrollment_source, + VirtualCardEnrollmentRequestType::kEnroll); + payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails + request_details; + request_details.virtual_card_enrollment_source = + state_.virtual_card_enrollment_fields.virtual_card_enrollment_source; + request_details.virtual_card_enrollment_request_type = + VirtualCardEnrollmentRequestType::kEnroll; + request_details.billing_customer_number = + payments::GetBillingCustomerId(personal_data_manager_); + request_details.vcn_context_token = state_.vcn_context_token; + + payments_client_->UpdateVirtualCardEnrollment( + request_details, + base::BindOnce(&VirtualCardEnrollmentManager:: + OnDidGetUpdateVirtualCardEnrollmentResponse, + weak_ptr_factory_.GetWeakPtr(), + VirtualCardEnrollmentRequestType::kEnroll)); +} + void VirtualCardEnrollmentManager::Unenroll(int64_t instrument_id) { LogUpdateVirtualCardEnrollmentRequestAttempt( VirtualCardEnrollmentSource::kSettingsPage, @@ -271,33 +296,15 @@ if (autofill_client_) { ShowVirtualCardEnrollBubble(); } else { - // TODO(crbug.com/1281695): Run the callback that is passed from the Clank - // settings page here to display the Virtual Card Enroll Dialog. + // If the `autofill_client_` is not present, it means that the request is + // from Android settings page, thus run the callback with the + // `virtual_card_enrollment_fields_`, which would show the enrollment + // dialog. + std::move(virtual_card_enrollment_fields_loaded_callback_) + .Run(&state_.virtual_card_enrollment_fields); } } -void VirtualCardEnrollmentManager::Enroll() { - LogUpdateVirtualCardEnrollmentRequestAttempt( - state_.virtual_card_enrollment_fields.virtual_card_enrollment_source, - VirtualCardEnrollmentRequestType::kEnroll); - payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails - request_details; - request_details.virtual_card_enrollment_source = - state_.virtual_card_enrollment_fields.virtual_card_enrollment_source; - request_details.virtual_card_enrollment_request_type = - VirtualCardEnrollmentRequestType::kEnroll; - request_details.billing_customer_number = - payments::GetBillingCustomerId(personal_data_manager_); - request_details.vcn_context_token = state_.vcn_context_token; - - payments_client_->UpdateVirtualCardEnrollment( - request_details, - base::BindOnce(&VirtualCardEnrollmentManager:: - OnDidGetUpdateVirtualCardEnrollmentResponse, - weak_ptr_factory_.GetWeakPtr(), - VirtualCardEnrollmentRequestType::kEnroll)); -} - void VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled() { Reset(); }
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h index 829104350..7c4635e2 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -99,6 +99,9 @@ const raw_ptr<content::WebContents> web_contents, gfx::Rect window_bounds)>; + using VirtualCardEnrollmentFieldsLoadedCallback = base::OnceCallback<void( + VirtualCardEnrollmentFields* virtual_card_enrollment_fields)>; + // Starting point for the VCN enroll flow. The fields in |credit_card| will // be used throughout the flow, such as for request fields as well as credit // card specific fields for the bubble to display. @@ -108,22 +111,32 @@ void OfferVirtualCardEnroll( const CreditCard& credit_card, VirtualCardEnrollmentSource virtual_card_enrollment_source, - // |user_prefs| will be populated if we are in the clank settings page, + // |user_prefs| will be populated if we are in the Android settings page, // to then be used for loading risk data. Otherwise it will always be // nullptr, and we should load risk data through |autofill_client_| as we // have access to web contents. const raw_ptr<PrefService> user_prefs = nullptr, - // Callback that will be run in the Clank settings page use cases. It will - // take in a |callback|, |obfuscated_gaia_id|, and |user_prefs| that will - // end up being passed into the overloaded risk_util::LoadRiskData() call - // that does not require web contents. - RiskAssessmentFunction risk_assessment_function = base::DoNothing()); + // Callback that will be run in the Android settings page use cases. It + // will take in a |callback|, |obfuscated_gaia_id|, and |user_prefs| that + // will end up being passed into the overloaded risk_util::LoadRiskData() + // call that does not require web contents. + RiskAssessmentFunction risk_assessment_function = base::DoNothing(), + // Callback that be run once the `state_.virtual_card_enrollment_fields_` + // is loaded from the server response. The callback would trigger the + // enrollment dialog in the Settings page on Android. + VirtualCardEnrollmentFieldsLoadedCallback = base::DoNothing()); // Updates |avatar_animation_complete| to true if the user is beginning the // upstream enrollment flow. This is a prerequisite to showing the enrollment // bubble. void OnCardSavedAnimationComplete(); + // Uses |payments_client_| to send the enroll request. |state_|'s + // |vcn_context_token_|, which should be set when we receive the + // GetDetailsForEnrollResponse, is used in the + // UpdateVirtualCardEnrollmentRequest to enroll the correct card. + void Enroll(); + // Unenrolls the card mapped to the given |instrument_id|. void Unenroll(int64_t instrument_id); @@ -191,6 +204,12 @@ // VirtualCardEnrollmentBubbleController needs to display the correct bubble. virtual void ShowVirtualCardEnrollBubble(); + // Callback triggered after the VirtualCardEnrollmentFields are loaded from + // the server response. Note: This is only called when the `autofill_client_` + // is not available. + VirtualCardEnrollmentFieldsLoadedCallback + virtual_card_enrollment_fields_loaded_callback_; + private: // Called once the risk data is loaded. The |risk_data| will be used with // |state_|'s |virtual_card_enrollment_fields|'s |credit_card|'s @@ -217,12 +236,6 @@ const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails& response); - // Uses |payments_client_| to send the enroll request. |state_|'s - // |vcn_context_token_|, which should be set when we receive the - // GetDetailsForEnrollResponse, is used in the - // UpdateVirtualCardEnrollmentRequest to enroll the correct card. - void Enroll(); - // Cancels the entire Virtual Card Enrollment process. void OnVirtualCardEnrollmentBubbleCancelled();
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc index 4c84252..cc20c808 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -4,7 +4,9 @@ #include <string> +#include "base/callback.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/data_model/credit_card.h" @@ -22,6 +24,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/image/image_unittest_util.h" +using testing::_; + namespace autofill { namespace { @@ -238,7 +242,13 @@ VirtualCardEnrollmentSource::kSettingsPage; virtual_card_enrollment_manager_->SetAutofillClient(nullptr); - + base::MockCallback<TestVirtualCardEnrollmentManager:: + VirtualCardEnrollmentFieldsLoadedCallback> + virtual_card_enrollment_fields_loadaed_callback; + virtual_card_enrollment_manager_ + ->SetVirtualCardEnrollmentFieldsLoadedCallback( + virtual_card_enrollment_fields_loadaed_callback.Get()); + EXPECT_CALL(virtual_card_enrollment_fields_loadaed_callback, Run(_)); virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse( AutofillClient::PaymentsRpcResult::kSuccess, response);
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc index 245aaf8..ca614c8 100644 --- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc +++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -363,7 +363,7 @@ UserData* user_data, UserModel* user_model, const CollectUserDataOptions& options, - const CollectUserDataProto::UserDataProto& proto_data) { + const GetUserDataResponseProto& proto_data) { if (!user_data->selected_phone_number()) { return; } @@ -1331,7 +1331,7 @@ } void CollectUserDataAction::UpdateUserDataFromProto( - const CollectUserDataProto::UserDataProto& proto_data, + const GetUserDataResponseProto& proto_data, UserData* user_data) { DCHECK(user_data != nullptr);
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.h b/components/autofill_assistant/browser/actions/collect_user_data_action.h index 5979d90..eddfd0d 100644 --- a/components/autofill_assistant/browser/actions/collect_user_data_action.h +++ b/components/autofill_assistant/browser/actions/collect_user_data_action.h
@@ -103,9 +103,8 @@ void WriteProcessedAction(UserData* user_data, const UserModel* user_model); void UpdateProfileAndCardUse(UserData* user_data); - void UpdateUserDataFromProto( - const CollectUserDataProto::UserDataProto& proto_data, - UserData* user_data); + void UpdateUserDataFromProto(const GetUserDataResponseProto& proto_data, + UserData* user_data); // Update user data with the new state from personal data manager. void UpdatePersonalDataManagerProfiles( UserData* user_data,
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc index 3abc98e..c387bc1 100644 --- a/components/autofill_assistant/browser/protocol_utils.cc +++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -911,4 +911,20 @@ } } +// static +std::string ProtocolUtils::CreateGetUserDataRequest( + const CollectUserDataOptions& options) { + GetUserDataRequestProto request_proto; + request_proto.set_request_name(options.request_payer_name); + request_proto.set_request_email(options.request_payer_email); + request_proto.set_request_phone(options.request_phone_number_separately); + request_proto.set_request_addresses(options.request_shipping); + request_proto.set_request_payment_methods(options.request_payment_method); + + std::string serialized_request_proto; + bool success = request_proto.SerializeToString(&serialized_request_proto); + DCHECK(success); + return serialized_request_proto; +} + } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/protocol_utils.h b/components/autofill_assistant/browser/protocol_utils.h index f0c043d..51d737a 100644 --- a/components/autofill_assistant/browser/protocol_utils.h +++ b/components/autofill_assistant/browser/protocol_utils.h
@@ -16,6 +16,7 @@ #include "components/autofill_assistant/browser/script_parameters.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/trigger_scripts/trigger_script.h" +#include "components/autofill_assistant/browser/user_data.h" #include "third_party/abseil-cpp/absl/types/optional.h" class GURL; @@ -72,6 +73,10 @@ const ClientContextProto& client_context, const ScriptParameters& script_parameters); + // Create request to get user data. + static std::string CreateGetUserDataRequest( + const CollectUserDataOptions& options); + // Create an action from the |action|. static std::unique_ptr<Action> CreateAction(ActionDelegate* delegate, const ActionProto& action);
diff --git a/components/autofill_assistant/browser/protocol_utils_unittest.cc b/components/autofill_assistant/browser/protocol_utils_unittest.cc index 4c708edf..c8e75746 100644 --- a/components/autofill_assistant/browser/protocol_utils_unittest.cc +++ b/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -584,4 +584,22 @@ ASSERT_FALSE(ProtocolUtils::ParseFromString(11, "\xff\xff\xff", nullptr)); } +TEST_F(ProtocolUtilsTest, CreateGetUserDataRequest) { + CollectUserDataOptions options; + options.request_payer_name = true; + options.request_payer_email = true; + options.request_phone_number_separately = true; + options.request_shipping = true; + options.request_payment_method = true; + + GetUserDataRequestProto request; + EXPECT_TRUE(request.ParseFromString( + ProtocolUtils::CreateGetUserDataRequest(options))); + EXPECT_TRUE(request.request_name()); + EXPECT_TRUE(request.request_email()); + EXPECT_TRUE(request.request_phone()); + EXPECT_TRUE(request.request_addresses()); + EXPECT_TRUE(request.request_payment_methods()); +} + } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index 313e612..fafb430 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -220,6 +220,56 @@ repeated MatchInfoProto match_info = 1; } +// Request to get user data. +message GetUserDataRequestProto { + // For logging, to know which run this request has originated from. + optional uint64 run_id = 1; + + optional bool request_name = 2; + optional bool request_email = 3; + optional bool request_phone = 4; + optional bool request_addresses = 5; + optional bool request_payment_methods = 6; +} + +// Response with user data. +message GetUserDataResponseProto { + // The locale to be used when creating this data. This can have influence + // on the potential processing by Autofill. + optional string locale = 3; + + repeated ProfileProto available_contacts = 1; + // The identifier of the contact to select. If not specified, the client + // will use its own heuristics to select a default contact. + optional string selected_contact_identifier = 5; + + // Available phone numbers to select. + repeated PhoneNumberProto available_phone_numbers = 10; + // The identifier of the phone number to select. If not specified, + // the client will use its own heuristics to select a default payment + // instrument. + optional string selected_phone_number_identifier = 11; + + // Available (shipping) addresses to select. + repeated ProfileProto available_addresses = 4; + // The identifier of the shipping address to select. If not specified, the + // client will use its own heuristics to select a default shipping address. + optional string selected_shipping_address_identifier = 6; + // An opaque token to launch the GMS address editor for creating a new + // address. + optional bytes add_address_token = 8; + + // Available payment instruments to select. + repeated PaymentInstrumentProto available_payment_instruments = 2; + // The identifier of the payment instrument to select. If not specified, + // the client will use its own heuristics to select a default payment + // instrument. + optional string selected_payment_instrument_identifier = 7; + // An opaque token returned by the |GetInstrumentListResponse| to launch + // the GMS card editor to create a new credit card. + optional bytes add_payment_instrument_token = 9; +} + // Overlay image to be drawn on top of full overlays. message OverlayImageProto { // TODO(b/170202574): Remove legacy |image_url|. @@ -2594,38 +2644,9 @@ repeated RequiredDataPiece required_credit_card_data_piece = 35; repeated RequiredDataPiece required_billing_address_data_piece = 36; - message UserDataProto { - // Available contacts to select. - repeated ProfileProto available_contacts = 1; - // The identifier of the contact to select. If not specified, the client - // will use its own heuristics to select a default contact. - optional string selected_contact_identifier = 5; - - // Available (shipping) addresses to select. - repeated ProfileProto available_addresses = 4; - // The identifier of the shipping address to select. If not specified, the - // client will use its own heuristics to select a default shipping address. - optional string selected_shipping_address_identifier = 6; - - // Available payment instruments to select. - repeated PaymentInstrumentProto available_payment_instruments = 2; - // The identifier of the payment instrument to select. If not specified, - // the client will use its own heuristics to select a default payment - // instrument. - optional string selected_payment_instrument_identifier = 7; - - // Available phone numbers to select. - repeated PhoneNumberProto available_phone_numbers = 10; - // The identifier of the phone number to select. If not specified, - // the client will use its own heuristics to select a default payment - // instrument. - optional string selected_phone_number_identifier = 11; - - // The locale to be used when creating this data. This can have influence - // on the potential processing by Autofill. - optional string locale = 3; - } - optional UserDataProto user_data = 37; + // TODO(b/218838411): This way of getting data is about to be deprecated. It + // is left in place until the backend has been adapted. Reserve after. + optional GetUserDataResponseProto user_data = 37; reserved 7, 10, 14, 15, 17, 26; }
diff --git a/components/autofill_assistant/browser/service/java_service.cc b/components/autofill_assistant/browser/service/java_service.cc index 11376a8e..650b72ce 100644 --- a/components/autofill_assistant/browser/service/java_service.cc +++ b/components/autofill_assistant/browser/service/java_service.cc
@@ -87,4 +87,13 @@ std::move(callback).Run(net::HTTP_OK, response); } +void JavaService::GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) { + // TODO(b/218838411): Mock. + GetUserDataResponseProto response; + std::string serialized_response; + response.SerializeToString(&serialized_response); + std::move(callback).Run(net::HTTP_OK, serialized_response); +} + } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/java_service.h b/components/autofill_assistant/browser/service/java_service.h index eb1b4b0c..1d7e101 100644 --- a/components/autofill_assistant/browser/service/java_service.h +++ b/components/autofill_assistant/browser/service/java_service.h
@@ -12,6 +12,7 @@ #include "base/android/scoped_java_ref.h" #include "base/memory/weak_ptr.h" #include "components/autofill_assistant/browser/service/service.h" +#include "components/autofill_assistant/browser/user_data.h" #include "url/gurl.h" namespace autofill_assistant { @@ -54,6 +55,10 @@ const RoundtripTimingStats& timing_stats, ResponseCallback callback) override; + // Get user data. + void GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) override; + private: base::android::ScopedJavaGlobalRef<jobject> java_service_; };
diff --git a/components/autofill_assistant/browser/service/java_test_endpoint_service.cc b/components/autofill_assistant/browser/service/java_test_endpoint_service.cc index e0ad586..d0aab73 100644 --- a/components/autofill_assistant/browser/service/java_test_endpoint_service.cc +++ b/components/autofill_assistant/browser/service/java_test_endpoint_service.cc
@@ -118,4 +118,9 @@ timing_stats, std::move(callback)); } +void JavaTestEndpointService::GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) { + service_impl_->GetUserData(options, std::move(callback)); +} + } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/java_test_endpoint_service.h b/components/autofill_assistant/browser/service/java_test_endpoint_service.h index b6bf24d..e29fdedd 100644 --- a/components/autofill_assistant/browser/service/java_test_endpoint_service.h +++ b/components/autofill_assistant/browser/service/java_test_endpoint_service.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "components/autofill_assistant/browser/service/service.h" +#include "components/autofill_assistant/browser/user_data.h" namespace autofill_assistant { @@ -44,6 +45,9 @@ const RoundtripTimingStats& timing_stats, ResponseCallback callback) override; + void GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) override; + private: void OnGetScriptsForUrl(ResponseCallback callback, int http_status,
diff --git a/components/autofill_assistant/browser/service/mock_service.cc b/components/autofill_assistant/browser/service/mock_service.cc index a0bb4ba3..92da091 100644 --- a/components/autofill_assistant/browser/service/mock_service.cc +++ b/components/autofill_assistant/browser/service/mock_service.cc
@@ -15,6 +15,7 @@ /* request_sender = */ nullptr, /* script_server_url = */ GURL("http://fake"), /* action_server_url = */ GURL("http://fake"), + /* user_data_url = */ GURL("http://fake"), /* client_context = */ nullptr) {} MockService::~MockService() {}
diff --git a/components/autofill_assistant/browser/service/rpc_type.h b/components/autofill_assistant/browser/service/rpc_type.h index 17ad3fd..d23428a 100644 --- a/components/autofill_assistant/browser/service/rpc_type.h +++ b/components/autofill_assistant/browser/service/rpc_type.h
@@ -13,6 +13,7 @@ GET_TRIGGER_SCRIPTS, SUPPORTS_SCRIPT, GET_CAPABILITIES_BY_HASH_PREFIX, + GET_USER_DATA, }; }
diff --git a/components/autofill_assistant/browser/service/server_url_fetcher.cc b/components/autofill_assistant/browser/service/server_url_fetcher.cc index 0793a4ff..703be675a 100644 --- a/components/autofill_assistant/browser/service/server_url_fetcher.cc +++ b/components/autofill_assistant/browser/service/server_url_fetcher.cc
@@ -17,6 +17,7 @@ const char kActionEndpoint[] = "/v1/actions2"; const char kTriggersEndpoint[] = "/v1/triggers"; const char kCapabilitiesByHashEndpoint[] = "/v1/capabilitiesByHashPrefix2"; +const char kUserDataEndpoint[] = "/v1/userData"; } // namespace namespace autofill_assistant { @@ -59,9 +60,15 @@ } GURL ServerUrlFetcher::GetCapabilitiesByHashEndpoint() const { - GURL::Replacements trigger_replacements; - trigger_replacements.SetPathStr(kCapabilitiesByHashEndpoint); - return server_url_.ReplaceComponents(trigger_replacements); + GURL::Replacements capabilities_replacements; + capabilities_replacements.SetPathStr(kCapabilitiesByHashEndpoint); + return server_url_.ReplaceComponents(capabilities_replacements); +} + +GURL ServerUrlFetcher::GetUserDataEndpoint() const { + GURL::Replacements user_data_replacements; + user_data_replacements.SetPathStr(kUserDataEndpoint); + return server_url_.ReplaceComponents(user_data_replacements); } } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/server_url_fetcher.h b/components/autofill_assistant/browser/service/server_url_fetcher.h index b0aee70..5af784cd 100644 --- a/components/autofill_assistant/browser/service/server_url_fetcher.h +++ b/components/autofill_assistant/browser/service/server_url_fetcher.h
@@ -29,6 +29,8 @@ virtual GURL GetTriggerScriptsEndpoint() const; // Returns the endpoint to send the GetCapabilitiesByHashPrefix RPC to. virtual GURL GetCapabilitiesByHashEndpoint() const; + // Returns the endpoint to send the GetUserData RPC to. + virtual GURL GetUserDataEndpoint() const; private: GURL server_url_;
diff --git a/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc b/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc index ce78aeda..9443fe0 100644 --- a/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc +++ b/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
@@ -60,5 +60,11 @@ Eq(GURL("https://www.example.com/v1/capabilitiesByHashPrefix2"))); } +TEST(ServerUrlFetcherTest, GetUserDataEndpoint) { + EXPECT_THAT( + ServerUrlFetcher(GURL("https://www.example.com")).GetUserDataEndpoint(), + Eq(GURL("https://www.example.com/v1/userData"))); +} + } // namespace } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/service.h b/components/autofill_assistant/browser/service/service.h index 13773272..e3421214 100644 --- a/components/autofill_assistant/browser/service/service.h +++ b/components/autofill_assistant/browser/service/service.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "components/autofill_assistant/browser/service.pb.h" +#include "components/autofill_assistant/browser/user_data.h" #include "url/gurl.h" namespace autofill_assistant { @@ -50,6 +51,10 @@ virtual void SetScriptStoreConfig( const ScriptStoreConfig& script_store_config) {} + // Get user data. + virtual void GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) = 0; + protected: Service() = default; };
diff --git a/components/autofill_assistant/browser/service/service_impl.cc b/components/autofill_assistant/browser/service/service_impl.cc index 633a953..11337e82 100644 --- a/components/autofill_assistant/browser/service/service_impl.cc +++ b/components/autofill_assistant/browser/service/service_impl.cc
@@ -56,7 +56,7 @@ return std::make_unique<ServiceImpl>( client, std::move(request_sender), url_fetcher.GetSupportsScriptEndpoint(), - url_fetcher.GetNextActionsEndpoint(), + url_fetcher.GetNextActionsEndpoint(), url_fetcher.GetUserDataEndpoint(), std::make_unique<ClientContextImpl>(client)); } @@ -64,14 +64,17 @@ std::unique_ptr<ServiceRequestSender> request_sender, const GURL& script_server_url, const GURL& action_server_url, + const GURL& user_data_url, std::unique_ptr<ClientContext> client_context) : client_(client), request_sender_(std::move(request_sender)), script_server_url_(script_server_url), script_action_server_url_(action_server_url), + user_data_url_(user_data_url), client_context_(std::move(client_context)) { DCHECK(script_server_url.is_valid()); DCHECK(action_server_url.is_valid()); + DCHECK(user_data_url_.is_valid()); } ServiceImpl::~ServiceImpl() {} @@ -160,4 +163,11 @@ std::move(callback), RpcType::GET_ACTIONS); } +void ServiceImpl::GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) { + request_sender_->SendRequest(user_data_url_, + ProtocolUtils::CreateGetUserDataRequest(options), + std::move(callback), RpcType::GET_USER_DATA); +} + } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/service_impl.h b/components/autofill_assistant/browser/service/service_impl.h index 69a2c5b1..dd7116b 100644 --- a/components/autofill_assistant/browser/service/service_impl.h +++ b/components/autofill_assistant/browser/service/service_impl.h
@@ -51,6 +51,7 @@ std::unique_ptr<ServiceRequestSender> request_sender, const GURL& script_server_url, const GURL& action_server_url, + const GURL& user_data_url, std::unique_ptr<ClientContext> client_context); ServiceImpl(const ServiceImpl&) = delete; ServiceImpl& operator=(const ServiceImpl&) = delete; @@ -82,6 +83,9 @@ void SetScriptStoreConfig( const ScriptStoreConfig& script_store_config) override; + void GetUserData(const CollectUserDataOptions& options, + ResponseCallback callback) override; + private: void OnFetchPaymentsClientToken( const std::string& script_path, @@ -106,6 +110,7 @@ // The RPC endpoints to send requests to. GURL script_server_url_; GURL script_action_server_url_; + GURL user_data_url_; // The client context to send to the backend. std::unique_ptr<ClientContext> client_context_;
diff --git a/components/autofill_assistant/browser/service/service_impl_unittest.cc b/components/autofill_assistant/browser/service/service_impl_unittest.cc index 314d6ce..b21bf64 100644 --- a/components/autofill_assistant/browser/service/service_impl_unittest.cc +++ b/components/autofill_assistant/browser/service/service_impl_unittest.cc
@@ -29,6 +29,8 @@ const char kScriptServerUrl[] = "https://www.fake.backend.com/script_server"; const char kActionServerUrl[] = "https://www.fake.backend.com/action_server"; +const char kUserDataServerUrl[] = + "https://www.fake.backend.com/user_data_server"; // TODO(b/207744539): In all tests, check that protocol utils is called with // the correct parameters. @@ -44,7 +46,8 @@ service_ = std::make_unique<ServiceImpl>( &mock_client_, std::move(mock_request_sender), GURL(kScriptServerUrl), - GURL(kActionServerUrl), std::move(mock_client_context)); + GURL(kActionServerUrl), GURL(kUserDataServerUrl), + std::move(mock_client_context)); } ~ServiceImplTest() override = default; @@ -178,5 +181,16 @@ mock_response_callback_.Get()); } +TEST_F(ServiceImplTest, GetUserData) { + EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kUserDataServerUrl), _, + _, RpcType::GET_USER_DATA)) + .WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response"))); + EXPECT_CALL(mock_response_callback_, + Run(net::HTTP_OK, std::string("response"))); + + service_->GetUserData(CollectUserDataOptions(), + mock_response_callback_.Get()); +} + } // namespace } // namespace autofill_assistant
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.cc b/components/privacy_sandbox/privacy_sandbox_settings.cc index 4fce80b0..958d4c7 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings.cc
@@ -20,6 +20,8 @@ #include "url/gurl.h" #include "url/origin.h" +namespace privacy_sandbox { + namespace { bool IsCookiesClearOnExitEnabled(HostContentSettingsMap* map) { @@ -333,6 +335,10 @@ return IsPrivacySandboxEnabled(); } +bool PrivacySandboxSettings::IsPrivacySandboxRestricted() { + return delegate_->IsPrivacySandboxRestricted(); +} + void PrivacySandboxSettings::OnCookiesCleared() { SetFlocDataAccessibleFromNow(/*reset_calculate_timer=*/false); } @@ -369,3 +375,5 @@ cookie_settings, url, top_frame_origin ? top_frame_origin->GetURL() : GURL()); } + +} // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.h b/components/privacy_sandbox/privacy_sandbox_settings.h index 4d5e893..a0174ad 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.h +++ b/components/privacy_sandbox/privacy_sandbox_settings.h
@@ -25,6 +25,8 @@ class Origin; } +namespace privacy_sandbox { + // A service which acts as a intermediary between Privacy Sandbox APIs and the // preferences and content settings which define when they are allowed to be // accessed. Privacy Sandbox APIs, regardless of where they live (renderer, @@ -146,6 +148,10 @@ // appropriate context specific check. bool IsTrustTokensAllowed(); + // Returns whether the Privacy Sandbox is being restricted by the associated + // delegate. Forwards directly to the corresponding delegate function. + bool IsPrivacySandboxRestricted(); + // Called when there's a broad cookies clearing action. For example, this // should be called on "Clear browsing data", but shouldn't be called on the // Clear-Site-Data header, as it's restricted to a specific site. @@ -179,4 +185,6 @@ bool incognito_profile_; }; +} // namespace privacy_sandbox + #endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SETTINGS_H_
diff --git a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc index d88ea9f..f191a53d 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -20,6 +20,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/origin.h" +namespace privacy_sandbox { + class MockPrivacySandboxDelegate : public PrivacySandboxSettings::Delegate { public: void SetupDefaultResponse() { @@ -833,3 +835,5 @@ INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingsMockDelegateTestInstance, PrivacySandboxSettingsMockDelegateTest, testing::Bool()); + +} // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.h b/components/privacy_sandbox/privacy_sandbox_test_util.h index 1b5c692..6c32f8c 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util.h +++ b/components/privacy_sandbox/privacy_sandbox_test_util.h
@@ -19,7 +19,8 @@ namespace privacy_sandbox_test_util { -class MockPrivacySandboxObserver : public PrivacySandboxSettings::Observer { +class MockPrivacySandboxObserver + : public privacy_sandbox::PrivacySandboxSettings::Observer { public: MockPrivacySandboxObserver(); ~MockPrivacySandboxObserver();
diff --git a/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc b/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc index 82c56c2..f01b6ca 100644 --- a/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc +++ b/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
@@ -326,13 +326,13 @@ void SafeBrowsingNavigationObserver::SetNavigationSourceMainFrameUrl( content::NavigationHandle* navigation_handle, NavigationEvent* nav_event) { - if (navigation_handle->IsInMainFrame()) { + if (!navigation_handle->GetParentFrameOrOuterDocument()) { nav_event->source_main_frame_url = nav_event->source_url; } else { nav_event->source_main_frame_url = SafeBrowsingNavigationObserverManager::ClearURLRef( - navigation_handle->GetParentFrame() - ->GetMainFrame() + navigation_handle->GetParentFrameOrOuterDocument() + ->GetOutermostMainFrame() ->GetLastCommittedURL()); } }
diff --git a/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc b/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc index 07fc208..f864e1ad 100644 --- a/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc +++ b/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc
@@ -626,7 +626,8 @@ source_render_frame_host->GetLastCommittedURL()); nav_event->source_main_frame_url = SafeBrowsingNavigationObserverManager::ClearURLRef( - source_render_frame_host->GetMainFrame()->GetLastCommittedURL()); + source_render_frame_host->GetOutermostMainFrame() + ->GetLastCommittedURL()); } nav_event->source_tab_id = sessions::SessionTabHelper::IdForTab(source_web_contents);
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc index 3444ebd2..e252991 100644 --- a/components/safe_browsing/content/browser/threat_details.cc +++ b/components/safe_browsing/content/browser/threat_details.cc
@@ -401,11 +401,11 @@ did_proceed_(false), num_visits_(0), trim_to_ad_tags_(trim_to_ad_tags), - cache_collector_(new ThreatDetailsCacheCollector), + cache_collector_(std::make_unique<ThreatDetailsCacheCollector>()), done_callback_(std::move(done_callback)), all_done_expected_(false), is_all_done_(false) { - redirects_collector_ = new ThreatDetailsRedirectsCollector( + redirects_collector_ = std::make_unique<ThreatDetailsRedirectsCollector>( history_service ? history_service->AsWeakPtr() : base::WeakPtr<history::HistoryService>()); } @@ -420,9 +420,7 @@ all_done_expected_(false), is_all_done_(false) {} -ThreatDetails::~ThreatDetails() { - DCHECK_EQ(all_done_expected_, is_all_done_); -} +ThreatDetails::~ThreatDetails() = default; bool ThreatDetails::IsReportableUrl(const GURL& url) const { // TODO(panayiotis): also skip internal urls.
diff --git a/components/safe_browsing/content/browser/threat_details.h b/components/safe_browsing/content/browser/threat_details.h index f1f9b25..29932811d 100644 --- a/components/safe_browsing/content/browser/threat_details.h +++ b/components/safe_browsing/content/browser/threat_details.h
@@ -109,7 +109,8 @@ void OnCacheCollectionReady(); - void OnRedirectionCollectionReady(); + // Overridden during tests + virtual void OnRedirectionCollectionReady(); // WebContentsObserver implementation: void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; @@ -262,10 +263,10 @@ static ThreatDetailsFactory* factory_; // Used to collect details from the HTTP Cache. - scoped_refptr<ThreatDetailsCacheCollector> cache_collector_; + std::unique_ptr<ThreatDetailsCacheCollector> cache_collector_; // Used to collect redirect urls from the history service - scoped_refptr<ThreatDetailsRedirectsCollector> redirects_collector_; + std::unique_ptr<ThreatDetailsRedirectsCollector> redirects_collector_; // Callback to run when the report is finished. ThreatDetailsDoneCallback done_callback_; @@ -294,6 +295,7 @@ FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames); FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags); FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails); + FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, CanCancelDuringCollection); }; // Factory for creating ThreatDetails. Useful for tests.
diff --git a/components/safe_browsing/content/browser/threat_details_cache.cc b/components/safe_browsing/content/browser/threat_details_cache.cc index 8219b0be..1f0a5b14 100644 --- a/components/safe_browsing/content/browser/threat_details_cache.cc +++ b/components/safe_browsing/content/browser/threat_details_cache.cc
@@ -54,7 +54,8 @@ // Post a task in the message loop, so the callers don't need to // check if we call their callback immediately. content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this)); + FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, + weak_factory_.GetWeakPtr())); } bool ThreatDetailsCacheCollector::HasStarted() { @@ -120,6 +121,7 @@ current_load_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( url_loader_factory_.get(), base::BindOnce(&ThreatDetailsCacheCollector::OnURLLoaderComplete, + // This is safe because `current_load_` is owned by `this`. base::Unretained(this))); } @@ -229,7 +231,8 @@ // Create a task so we don't take over the UI thread for too long. content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this)); + FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, + weak_factory_.GetWeakPtr())); } void ThreatDetailsCacheCollector::AllDone(bool success) {
diff --git a/components/safe_browsing/content/browser/threat_details_cache.h b/components/safe_browsing/content/browser/threat_details_cache.h index 51cb5c7..b2ea679 100644 --- a/components/safe_browsing/content/browser/threat_details_cache.h +++ b/components/safe_browsing/content/browser/threat_details_cache.h
@@ -31,10 +31,10 @@ std::unique_ptr<ClientSafeBrowsingReportRequest::Resource>> ResourceMap; -class ThreatDetailsCacheCollector - : public base::RefCounted<ThreatDetailsCacheCollector> { +class ThreatDetailsCacheCollector { public: ThreatDetailsCacheCollector(); + ~ThreatDetailsCacheCollector(); // We use |request_context_getter|, we modify |resources| and // |result|, and we call |callback|, so they must all remain alive @@ -55,8 +55,6 @@ private: friend class base::RefCounted<ThreatDetailsCacheCollector>; - ~ThreatDetailsCacheCollector(); - // Points to the url for which we are fetching the HTTP cache entry or // redirect chain. ResourceMap::iterator resources_it_; @@ -80,6 +78,8 @@ // The current SimpleURLLoader. std::unique_ptr<network::SimpleURLLoader> current_load_; + base::WeakPtrFactory<ThreatDetailsCacheCollector> weak_factory_{this}; + // Returns the resource from resources_ that corresponds to |url| ClientSafeBrowsingReportRequest::Resource* GetResource(const GURL& url);
diff --git a/components/safe_browsing/content/browser/threat_details_history.cc b/components/safe_browsing/content/browser/threat_details_history.cc index 3a36327..c71d155 100644 --- a/components/safe_browsing/content/browser/threat_details_history.cc +++ b/components/safe_browsing/content/browser/threat_details_history.cc
@@ -42,8 +42,8 @@ content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, - base::BindOnce(&ThreatDetailsRedirectsCollector::StartGetRedirects, this, - urls)); + base::BindOnce(&ThreatDetailsRedirectsCollector::StartGetRedirects, + weak_factory_.GetWeakPtr(), urls)); } bool ThreatDetailsRedirectsCollector::HasStarted() const { @@ -79,7 +79,7 @@ history_service_->QueryRedirectsTo( url, base::BindOnce(&ThreatDetailsRedirectsCollector::OnGotQueryRedirectsTo, - base::Unretained(this), url), + weak_factory_.GetWeakPtr(), url), &request_tracker_); }
diff --git a/components/safe_browsing/content/browser/threat_details_history.h b/components/safe_browsing/content/browser/threat_details_history.h index bddeee8..670d1b5 100644 --- a/components/safe_browsing/content/browser/threat_details_history.h +++ b/components/safe_browsing/content/browser/threat_details_history.h
@@ -22,12 +22,11 @@ typedef std::vector<GURL> RedirectChain; -class ThreatDetailsRedirectsCollector - : public base::RefCounted<ThreatDetailsRedirectsCollector>, - public history::HistoryServiceObserver { +class ThreatDetailsRedirectsCollector : public history::HistoryServiceObserver { public: explicit ThreatDetailsRedirectsCollector( const base::WeakPtr<history::HistoryService>& history_service); + ~ThreatDetailsRedirectsCollector() override; ThreatDetailsRedirectsCollector(const ThreatDetailsRedirectsCollector&) = delete; @@ -52,8 +51,6 @@ private: friend class base::RefCounted<ThreatDetailsRedirectsCollector>; - ~ThreatDetailsRedirectsCollector() override; - void StartGetRedirects(const std::vector<GURL>& urls); void GetRedirects(const GURL& url); void OnGotQueryRedirectsTo(const GURL& url, @@ -82,6 +79,8 @@ base::ScopedObservation<history::HistoryService, history::HistoryServiceObserver> history_service_observation_{this}; + + base::WeakPtrFactory<ThreatDetailsRedirectsCollector> weak_factory_{this}; }; } // namespace safe_browsing
diff --git a/components/security_interstitials/BUILD.gn b/components/security_interstitials/BUILD.gn new file mode 100644 index 0000000..05c1389 --- /dev/null +++ b/components/security_interstitials/BUILD.gn
@@ -0,0 +1,14 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +assert(enable_js_type_check) + +group("closure_compile") { + deps = [ + "content/resources:closure_compile", + "core/common/resources:closure_compile", + ] +}
diff --git a/components/security_interstitials/content/resources/BUILD.gn b/components/security_interstitials/content/resources/BUILD.gn new file mode 100644 index 0000000..a812d35 --- /dev/null +++ b/components/security_interstitials/content/resources/BUILD.gn
@@ -0,0 +1,18 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +assert(enable_js_type_check) + +js_type_check("closure_compile") { + deps = [ ":connection_help" ] +} + +js_library("connection_help") { + deps = [ + "//ui/webui/resources/js:load_time_data.m", + "//ui/webui/resources/js:util.m", + ] +}
diff --git a/components/security_interstitials/content/resources/connection_help.html b/components/security_interstitials/content/resources/connection_help.html index e431a7c6..5bb01aa1 100644 --- a/components/security_interstitials/content/resources/connection_help.html +++ b/components/security_interstitials/content/resources/connection_help.html
@@ -8,12 +8,7 @@ <link rel="stylesheet" href="interstitial_core.css"> <link rel="stylesheet" href="interstitial_common.css"> <link rel="stylesheet" href="connection_help.css"> - <script src="chrome://resources/js/cr.js"></script> - <script src="chrome://resources/js/load_time_data.js"></script> - <script src="chrome://resources/js/assert.js"></script> - <script src="chrome://resources/js/util.js"></script> - <script src="strings.js"></script> - <script src="connection_help.js"></script> + <script type="module" src="connection_help.js"></script> </head> <body> <div class="interstitial-wrapper">
diff --git a/components/security_interstitials/content/resources/connection_help.js b/components/security_interstitials/content/resources/connection_help.js index fe42ea6a..8a6eba1 100644 --- a/components/security_interstitials/content/resources/connection_help.js +++ b/components/security_interstitials/content/resources/connection_help.js
@@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import './strings.m.js'; + +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {$} from 'chrome://resources/js/util.m.js'; + const HIDDEN_CLASS = 'hidden'; function setupEvents() {
diff --git a/components/services/screen_ai/BUILD.gn b/components/services/screen_ai/BUILD.gn new file mode 100644 index 0000000..b5fb37e --- /dev/null +++ b/components/services/screen_ai/BUILD.gn
@@ -0,0 +1,30 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("screen_ai") { + sources = [ + "screen_ai_service_impl.cc", + "screen_ai_service_impl.h", + ] + + public_deps = [ + "//base", + "//components/services/screen_ai/public/mojom", + "//mojo/public/cpp/bindings", + ] +} + +source_set("screen_ai_sandbox_hook") { + sources = [ + "sandbox/screen_ai_sandbox_hook_linux.cc", + "sandbox/screen_ai_sandbox_hook_linux.h", + ] + + deps = [ + "//base", + "//sandbox/linux:sandbox_services", + ] + + public_deps = [ "//sandbox/policy" ] +}
diff --git a/components/services/screen_ai/OWNERS b/components/services/screen_ai/OWNERS new file mode 100644 index 0000000..976b955 --- /dev/null +++ b/components/services/screen_ai/OWNERS
@@ -0,0 +1 @@ +file://ui/accessibility/OWNERS
diff --git a/components/services/screen_ai/README.md b/components/services/screen_ai/README.md new file mode 100644 index 0000000..a6ed810 --- /dev/null +++ b/components/services/screen_ai/README.md
@@ -0,0 +1,2 @@ +ScreenAIService provides an API to extract metadata from snapshots using a local +machine intelligence based module. \ No newline at end of file
diff --git a/components/services/screen_ai/public/cpp/BUILD.gn b/components/services/screen_ai/public/cpp/BUILD.gn new file mode 100644 index 0000000..fc9084b --- /dev/null +++ b/components/services/screen_ai/public/cpp/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("screen_ai_service_router_factory") { + sources = [ + "screen_ai_service_router.cc", + "screen_ai_service_router.h", + "screen_ai_service_router_factory.cc", + "screen_ai_service_router_factory.h", + ] + + deps = [ + "//components/keyed_service/content", + "//components/keyed_service/core", + "//components/services/screen_ai/public/mojom", + "//content/public/browser", + ] +}
diff --git a/components/services/screen_ai/public/cpp/DEPS b/components/services/screen_ai/public/cpp/DEPS new file mode 100644 index 0000000..794f22c --- /dev/null +++ b/components/services/screen_ai/public/cpp/DEPS
@@ -0,0 +1,5 @@ +include_rules = [ + "+content/public/browser", + "+components/keyed_service/core", + "+components/keyed_service/content" +]
diff --git a/components/services/screen_ai/public/cpp/screen_ai_service_router.cc b/components/services/screen_ai/public/cpp/screen_ai_service_router.cc new file mode 100644 index 0000000..7fa986b3 --- /dev/null +++ b/components/services/screen_ai/public/cpp/screen_ai_service_router.cc
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/services/screen_ai/public/cpp/screen_ai_service_router.h" + +#include "content/public/browser/service_process_host.h" + +namespace screen_ai { + +ScreenAIServiceRouter::ScreenAIServiceRouter() = default; +ScreenAIServiceRouter::~ScreenAIServiceRouter() = default; + +void ScreenAIServiceRouter::BindScreenAIAnnotator( + mojo::PendingReceiver<screen_ai::mojom::ScreenAIAnnotator> receiver) { + LaunchIfNotRunning(); + + if (screen_ai_service_.is_bound()) + screen_ai_service_->BindAnnotator(std::move(receiver)); +} + +void ScreenAIServiceRouter::LaunchIfNotRunning() { + if (screen_ai_service_.is_bound()) + return; + + content::ServiceProcessHost::Launch( + screen_ai_service_.BindNewPipeAndPassReceiver(), + content::ServiceProcessHost::Options() + .WithDisplayName("Screen AI Service") + .Pass()); +} + +} // namespace screen_ai
diff --git a/components/services/screen_ai/public/cpp/screen_ai_service_router.h b/components/services/screen_ai/public/cpp/screen_ai_service_router.h new file mode 100644 index 0000000..fa2ce427d --- /dev/null +++ b/components/services/screen_ai/public/cpp/screen_ai_service_router.h
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_H_ +#define COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_H_ + +#include "components/keyed_service/core/keyed_service.h" +#include "components/services/screen_ai/public/mojom/screen_ai_service.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace screen_ai { + +class ScreenAIServiceRouter : public KeyedService { + public: + ScreenAIServiceRouter(); + ScreenAIServiceRouter(const ScreenAIServiceRouter&) = delete; + ScreenAIServiceRouter& operator=(const ScreenAIServiceRouter&) = delete; + ~ScreenAIServiceRouter() override; + + void BindScreenAIAnnotator( + mojo::PendingReceiver<screen_ai::mojom::ScreenAIAnnotator> receiver); + + void LaunchIfNotRunning(); + + private: + mojo::Remote<mojom::ScreenAIService> screen_ai_service_; +}; + +} // namespace screen_ai + +#endif // COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_H_
diff --git a/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.cc b/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.cc new file mode 100644 index 0000000..cb51e699 --- /dev/null +++ b/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.cc
@@ -0,0 +1,41 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/services/screen_ai/public/cpp/screen_ai_service_router_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/services/screen_ai/public/cpp/screen_ai_service_router.h" +#include "content/public/browser/browser_context.h" + +// static +screen_ai::ScreenAIServiceRouter* +ScreenAIServiceRouterFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<screen_ai::ScreenAIServiceRouter*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ScreenAIServiceRouterFactory* ScreenAIServiceRouterFactory::GetInstance() { + static base::NoDestructor<ScreenAIServiceRouterFactory> instance; + return instance.get(); +} + +ScreenAIServiceRouterFactory::ScreenAIServiceRouterFactory() + : BrowserContextKeyedServiceFactory( + "ScreenAIService", + BrowserContextDependencyManager::GetInstance()) {} + +ScreenAIServiceRouterFactory::~ScreenAIServiceRouterFactory() = default; + +KeyedService* ScreenAIServiceRouterFactory::BuildServiceInstanceFor( + content::BrowserContext* /*context*/) const { + return new screen_ai::ScreenAIServiceRouter(); +} + +// Incognito profiles should use their own instance. +content::BrowserContext* ScreenAIServiceRouterFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return context; +}
diff --git a/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.h b/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.h new file mode 100644 index 0000000..e6a1d65 --- /dev/null +++ b/components/services/screen_ai/public/cpp/screen_ai_service_router_factory.h
@@ -0,0 +1,39 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_FACTORY_H_ +#define COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_FACTORY_H_ + +#include "base/no_destructor.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace content { +class BrowserContext; +} + +namespace screen_ai { +class ScreenAIServiceRouter; +} + +// Factory to get or create an instance of ScreenAIServiceRouter for a Profile. +class ScreenAIServiceRouterFactory : public BrowserContextKeyedServiceFactory { + public: + static screen_ai::ScreenAIServiceRouter* GetForBrowserContext( + content::BrowserContext* context); + + private: + friend class base::NoDestructor<ScreenAIServiceRouterFactory>; + static ScreenAIServiceRouterFactory* GetInstance(); + + ScreenAIServiceRouterFactory(); + ~ScreenAIServiceRouterFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +#endif // COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_SCREEN_AI_SERVICE_ROUTER_FACTORY_H_
diff --git a/components/services/screen_ai/public/mojom/BUILD.gn b/components/services/screen_ai/public/mojom/BUILD.gn new file mode 100644 index 0000000..38b74f03 --- /dev/null +++ b/components/services/screen_ai/public/mojom/BUILD.gn
@@ -0,0 +1,14 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojom") { + sources = [ "screen_ai_service.mojom" ] + + public_deps = [ + "//media/mojo/mojom", + "//sandbox/policy/mojom", + ] +}
diff --git a/components/services/screen_ai/public/mojom/OWNERS b/components/services/screen_ai/public/mojom/OWNERS new file mode 100644 index 0000000..61b5e28 --- /dev/null +++ b/components/services/screen_ai/public/mojom/OWNERS
@@ -0,0 +1,2 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/components/services/screen_ai/public/mojom/screen_ai_service.mojom b/components/services/screen_ai/public/mojom/screen_ai_service.mojom new file mode 100644 index 0000000..8c5c846 --- /dev/null +++ b/components/services/screen_ai/public/mojom/screen_ai_service.mojom
@@ -0,0 +1,86 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module screen_ai.mojom; + +import "sandbox/policy/mojom/sandbox.mojom"; +import "skia/public/mojom/bitmap.mojom"; +import "ui/gfx/geometry/mojom/geometry.mojom"; + +// The type of object that the Screen AI module has detected. +// This list is in sync with the following proto: +// google3/research/socrates/multimodal/visual_annotation/config/ +// labelmap_layout_extractor_v1.pbtxt +enum NodeType { + kImage = 1, + kPictogram = 2, + kButton = 3, + kText = 4, + kTextInput = 5, + kLabel = 6, + kMap = 7, + kCheckBox = 8, + kSwitch = 9, + kPageIndicator = 10, + kRadioButton = 11, + kSlider = 12, + kSpinner = 13, + kProgressBar = 14, + kAdvertisement = 15, + kDrawer = 16, + kNavigationBar = 17, + kToolbar = 18, + kListItem = 19, + kCardView = 20, + kContainer = 21, + kDatePicker = 22, + kNumberStepper = 23, + kKeyboard = 24 +}; + +// An object detected by the Screen AI library. +struct Node { + // Rectangle covering the detected object, with respect to the top-left of + // the image. + gfx.mojom.Rect rect; + + // Detected type of the object. + NodeType type; + + // Confidence level of detection, [0..1]. + float confidence; +}; + +// Indicates the result of image processing service. +enum ErrorType { + // No error. + kOK = 0, + + // Could not find the library. + kFailedLibraryNotFound = 1, + + // Library could not process image. + kFailedProcessingImage = 2, +}; + +// Main interface a client uses for Screen AI services. Each renderer has its +// own ScreenAIAnnotator and all ScreenAIAnnotators of one profile use one +// ScreenAIService. +// Requests are sent from renderers in AxScreenAIAnnotator class. +interface ScreenAIAnnotator { + // Receives a snapshot, schedules image processing, and returns the error + // type (if any) and an array of detected nodes. + Annotate(skia.mojom.BitmapN32 image) => + (ErrorType error, array<Node> nodes); +}; + + +// The service runs in a sandboxed process to run Screen AI service library. The +// library provides an image processing module to analyze snapshots of the +// browser and add more details to the accessibility tree. +[ServiceSandbox=sandbox.mojom.Sandbox.kScreenAI] +interface ScreenAIService { + // Binds a new annotator to the service. + BindAnnotator(pending_receiver<ScreenAIAnnotator> annotator); +};
diff --git a/components/services/screen_ai/sandbox/DEPS b/components/services/screen_ai/sandbox/DEPS new file mode 100644 index 0000000..e194a2d --- /dev/null +++ b/components/services/screen_ai/sandbox/DEPS
@@ -0,0 +1 @@ +include_rules = [ "+sandbox/linux", "+sandbox/policy/linux" ]
diff --git a/components/services/screen_ai/sandbox/OWNERS b/components/services/screen_ai/sandbox/OWNERS new file mode 100644 index 0000000..56bafd3e --- /dev/null +++ b/components/services/screen_ai/sandbox/OWNERS
@@ -0,0 +1,2 @@ +set noparent +file://sandbox/linux/OWNERS \ No newline at end of file
diff --git a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc new file mode 100644 index 0000000..8bd1ee6 --- /dev/null +++ b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
@@ -0,0 +1,48 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.h" + +#include <dlfcn.h> + +#include "base/files/file_util.h" +#include "sandbox/linux/syscall_broker/broker_command.h" +#include "sandbox/linux/syscall_broker/broker_file_permission.h" + +using sandbox::syscall_broker::BrokerFilePermission; +using sandbox::syscall_broker::MakeBrokerCommandSet; + +namespace screen_ai { + +bool ScreenAIPreSandboxHook(sandbox::policy::SandboxLinux::Options options) { + // TODO(https://crbug.com/1278249): Add a common getter function for the + // library file path. + const base::FilePath library_path = + base::FilePath(FILE_PATH_LITERAL("/")) + .Append(FILE_PATH_LITERAL("lib")) + .Append(FILE_PATH_LITERAL("libchrome_screen_ai.so")); + + void* screen_ai_library = dlopen(library_path.value().c_str(), + RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE); + // TODO(https://crbug.com/1278249): Consider handling differently when library + // is downloaded using component updater and feature is enabled by default. + if (!screen_ai_library) + VLOG(1) << dlerror(); + + auto* instance = sandbox::policy::SandboxLinux::GetInstance(); + + std::vector<BrokerFilePermission> permissions{ + BrokerFilePermission::ReadOnly("/dev/urandom"), + BrokerFilePermission::ReadOnly("/proc/meminfo")}; + + instance->StartBrokerProcess( + MakeBrokerCommandSet({sandbox::syscall_broker::COMMAND_ACCESS, + sandbox::syscall_broker::COMMAND_OPEN}), + permissions, sandbox::policy::SandboxLinux::PreSandboxHook(), options); + instance->EngageNamespaceSandboxIfPossible(); + + return true; +} + +} // namespace screen_ai
diff --git a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.h b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.h new file mode 100644 index 0000000..fbe695a --- /dev/null +++ b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.h
@@ -0,0 +1,18 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SERVICES_SCREEN_AI_SANDBOX_SCREEN_AI_SANDBOX_HOOK_LINUX_H_ +#define COMPONENTS_SERVICES_SCREEN_AI_SANDBOX_SCREEN_AI_SANDBOX_HOOK_LINUX_H_ + +#include "sandbox/policy/linux/sandbox_linux.h" + +namespace screen_ai { + +// Opens the chrome_screen_ai.lib binary and grants broker file permissions to +// the necessary files required by the binary. +bool ScreenAIPreSandboxHook(sandbox::policy::SandboxLinux::Options options); + +} // namespace screen_ai + +#endif // COMPONENTS_SERVICES_SCREEN_AI_SANDBOX_SCREEN_AI_SANDBOX_HOOK_LINUX_H_
diff --git a/components/services/screen_ai/screen_ai_service_impl.cc b/components/services/screen_ai/screen_ai_service_impl.cc new file mode 100644 index 0000000..fc105c1 --- /dev/null +++ b/components/services/screen_ai/screen_ai_service_impl.cc
@@ -0,0 +1,73 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/services/screen_ai/screen_ai_service_impl.h" + +namespace screen_ai { + +// static +base::FilePath ScreenAIService::GetLibraryPath() { + return base::FilePath(FILE_PATH_LITERAL("/")) + .Append(FILE_PATH_LITERAL("lib")) + .Append(FILE_PATH_LITERAL("libchrome_screen_ai.so")); +} + +ScreenAIService::ScreenAIService( + mojo::PendingReceiver<mojom::ScreenAIService> receiver) + : library_(GetLibraryPath()), + init_function_(reinterpret_cast<ScreenAIInitFunction>( + library_.GetFunctionPointer("Init"))), + annotator_function_(reinterpret_cast<ScreenAIAnnotateFunction>( + library_.GetFunctionPointer("Annotate"))), + receiver_(this, std::move(receiver)) { + if (!init_function_ || !init_function_()) { + VLOG(1) << "Screen AI library initialization failed."; + annotator_function_ = nullptr; + } +} + +ScreenAIService::~ScreenAIService() = default; + +void ScreenAIService::BindAnnotator( + mojo::PendingReceiver<mojom::ScreenAIAnnotator> annotator) { + screen_ai_annotators_.Add(this, std::move(annotator)); +} + +void ScreenAIService::Annotate(const SkBitmap& image, + AnnotationCallback callback) { + std::vector<mojom::NodePtr> nodes; + mojom::ErrorType error = mojom::ErrorType::kOK; + + if (annotator_function_) { + VLOG(2) << "Screen AI library starting to process " << image.width() << "x" + << image.height() << " snapshot."; + + std::string annotation_text; + // TODO(https://crbug.com/1278249): Consider adding a signature that + // verifies the data integrity and source. + // TODO(https://crbug.com/1278249): Consider replacing the input with a data + // item that includes data size. + if (annotator_function_( + static_cast<const unsigned char*>(image.getPixels()), image.width(), + image.height(), annotation_text)) { + VLOG(2) << "Screen AI library returned: " << annotation_text; + DecodeProto(annotation_text, nodes); + } else { + VLOG(1) << "Screen AI library could not process snapshot."; + error = mojom::ErrorType::kFailedProcessingImage; + } + } else { + error = mojom::ErrorType::kFailedLibraryNotFound; + } + + std::move(callback).Run(error, std::move(nodes)); +} + +// TODO(https://crbug.com/1278249): Implement! +bool ScreenAIService::DecodeProto(const std::string& proto_text, + std::vector<mojom::NodePtr>& annotations) { + return false; +} + +} // namespace screen_ai
diff --git a/components/services/screen_ai/screen_ai_service_impl.h b/components/services/screen_ai/screen_ai_service_impl.h new file mode 100644 index 0000000..382ff3d --- /dev/null +++ b/components/services/screen_ai/screen_ai_service_impl.h
@@ -0,0 +1,67 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SERVICES_SCREEN_AI_SCREEN_AI_SERVICE_IMPL_H_ +#define COMPONENTS_SERVICES_SCREEN_AI_SCREEN_AI_SERVICE_IMPL_H_ + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/scoped_native_library.h" +#include "components/services/screen_ai/public/mojom/screen_ai_service.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" + +namespace screen_ai { + +using AnnotationCallback = + base::OnceCallback<void(mojom::ErrorType, std::vector<mojom::NodePtr>)>; + +// Sends the snapshot to a local machine learning library to get annotations +// that can help in updating the accessibility tree. See more in: +// google3/chrome/chromeos/accessibility/machine_intelligence/ +// chrome_screen_ai/README.md +class ScreenAIService : public mojom::ScreenAIService, + public mojom::ScreenAIAnnotator { + public: + explicit ScreenAIService( + mojo::PendingReceiver<mojom::ScreenAIService> receiver); + ScreenAIService(const ScreenAIService&) = delete; + ScreenAIService& operator=(const ScreenAIService&) = delete; + ~ScreenAIService() override; + + static base::FilePath GetLibraryPath(); + + private: + base::ScopedNativeLibrary library_; + + // mojom::ScreenAIAnnotator + void Annotate(const SkBitmap& image, AnnotationCallback callback) override; + + // mojom::ScreenAIService + void BindAnnotator( + mojo::PendingReceiver<mojom::ScreenAIAnnotator> annotator) override; + + // Translates proto output form screen-ai library to vector of + // screen_ai::mojom::Node. + bool DecodeProto(const std::string& proto_text, + std::vector<mojom::NodePtr>& annotations); + + typedef bool (*ScreenAIInitFunction)(); + ScreenAIInitFunction init_function_; + + typedef bool (*ScreenAIAnnotateFunction)(const unsigned char* /*png_pixels*/, + int /*image_width*/, + int /*image_height*/, + std::string& /*annotation_text*/); + ScreenAIAnnotateFunction annotator_function_; + + mojo::Receiver<mojom::ScreenAIService> receiver_; + + // The set of receivers used to receive messages from the renderer clients. + mojo::ReceiverSet<mojom::ScreenAIAnnotator> screen_ai_annotators_; +}; + +} // namespace screen_ai + +#endif // COMPONENTS_SERVICES_SCREEN_AI_SCREEN_AI_SERVICE_IMPL_H_
diff --git a/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.cc b/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.cc index 7ee1cec..310f0a3 100644 --- a/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.cc +++ b/components/signin/internal/identity_manager/oauth_multilogin_token_fetcher.cc
@@ -103,8 +103,6 @@ if (error.IsTransientError() && retried_requests_.find(account_id) == retried_requests_.end()) { retried_requests_.insert(account_id); - UMA_HISTOGRAM_ENUMERATION("Signin.GetAccessTokenRetry", error.state(), - GoogleServiceAuthError::NUM_STATES); EraseRequest(request); // Fetching fresh access tokens requires network. signin_client_->DelayNetworkCall(
diff --git a/components/sync/model/processor_entity.cc b/components/sync/model/processor_entity.cc index 1d0bb3a..9bcc573 100644 --- a/components/sync/model/processor_entity.cc +++ b/components/sync/model/processor_entity.cc
@@ -90,12 +90,6 @@ data->creation_time = ProtoTimeToTime(metadata_.creation_time()); data->modification_time = ProtoTimeToTime(metadata_.modification_time()); - commit_data_.reset(); - CacheCommitData(std::move(data)); -} - -void ProcessorEntity::CacheCommitData(std::unique_ptr<EntityData> data) { - DCHECK(RequiresCommitData()); commit_data_ = std::move(data); DCHECK(HasCommitData()); }
diff --git a/components/sync/model/processor_entity.h b/components/sync/model/processor_entity.h index 3de0375..94952ad 100644 --- a/components/sync/model/processor_entity.h +++ b/components/sync/model/processor_entity.h
@@ -122,8 +122,6 @@ // and caches it in the instance. void SetCommitData(std::unique_ptr<EntityData> data); - void CacheCommitData(std::unique_ptr<EntityData> data); - // Check if the instance has cached commit data. bool HasCommitData() const;
diff --git a/content/browser/utility_process_sandbox_browsertest.cc b/content/browser/utility_process_sandbox_browsertest.cc index 59166a6..6107192 100644 --- a/content/browser/utility_process_sandbox_browsertest.cc +++ b/content/browser/utility_process_sandbox_browsertest.cc
@@ -141,6 +141,11 @@ EXPECT_EQ(sandbox_status, kExpectedPartialSandboxFlags); break; } +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + case Sandbox::kScreenAI: + // TODO(https://crbug.com/1278249): Add test. + break; +#endif case Sandbox::kGpu: case Sandbox::kRenderer:
diff --git a/content/browser/utility_sandbox_delegate.cc b/content/browser/utility_sandbox_delegate.cc index 7c0e15ae..d5703cf 100644 --- a/content/browser/utility_sandbox_delegate.cc +++ b/content/browser/utility_sandbox_delegate.cc
@@ -73,6 +73,9 @@ sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant || #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + sandbox_type_ == sandbox::mojom::Sandbox::kScreenAI || +#endif sandbox_type_ == sandbox::mojom::Sandbox::kAudio || sandbox_type_ == sandbox::mojom::Sandbox::kSpeechRecognition; DCHECK(supported_sandbox_type); @@ -115,6 +118,9 @@ #if BUILDFLAG(ENABLE_OOP_PRINTING) sandbox_type_ == sandbox::mojom::Sandbox::kPrintBackend || #endif +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + sandbox_type_ == sandbox::mojom::Sandbox::kScreenAI || +#endif sandbox_type_ == sandbox::mojom::Sandbox::kSpeechRecognition) { return GetUnsandboxedZygote(); }
diff --git a/content/browser/xr/service/browser_xr_runtime_impl.h b/content/browser/xr/service/browser_xr_runtime_impl.h index 5982ad2..69a44f0 100644 --- a/content/browser/xr/service/browser_xr_runtime_impl.h +++ b/content/browser/xr/service/browser_xr_runtime_impl.h
@@ -121,7 +121,7 @@ mojo::Remote<device::mojom::XRRuntime> runtime_; mojo::Remote<device::mojom::XRSessionController> immersive_session_controller_; - bool immersive_session_has_camera_access_; + bool immersive_session_has_camera_access_ = false; std::set<VRServiceImpl*> services_; device::mojom::VRDisplayInfoPtr display_info_;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 52babf62..f20d944 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -203,7 +203,11 @@ } if (is_linux || is_chromeos) { - sources += [ "renderer_main_platform_delegate_linux.cc" ] + sources += [ + "accessibility/ax_screen_ai_annotator.cc", + "accessibility/ax_screen_ai_annotator.h", + "renderer_main_platform_delegate_linux.cc", + ] } if (is_mac) { @@ -345,7 +349,11 @@ } if (is_linux || is_chromeos) { - deps += [ "//components/services/font/public/cpp" ] + deps += [ + "//components/services/font/public/cpp", + "//components/services/screen_ai", + "//ui/gfx/codec", + ] } if (is_fuchsia) {
diff --git a/content/renderer/DEPS b/content/renderer/DEPS index 87e50ab..798358f 100644 --- a/content/renderer/DEPS +++ b/content/renderer/DEPS
@@ -7,6 +7,7 @@ "+components/discardable_memory/client", "+components/metrics", "+components/metrics:single_sample_metrics", + "+components/services/screen_ai", "+components/url_formatter", "+components/viz/client", "+components/viz/common",
diff --git a/content/renderer/accessibility/ax_screen_ai_annotator.cc b/content/renderer/accessibility/ax_screen_ai_annotator.cc new file mode 100644 index 0000000..c4b7c824 --- /dev/null +++ b/content/renderer/accessibility/ax_screen_ai_annotator.cc
@@ -0,0 +1,108 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/accessibility/ax_screen_ai_annotator.h" + +#include "net/base/data_url.h" +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/public/web/web_ax_object.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/geometry/size.h" + +namespace { +bool GetImageFromWebAXObject(const blink::WebAXObject& object, + SkBitmap& bitmap) { + const std::string image_data_url = object.ImageDataUrl(gfx::Size()).Utf8(); + if (image_data_url.empty()) { + VLOG(1) << "Screen AI could not get image for " << object.ToString().Utf8(); + return false; + } + + std::string mimetype; + std::string charset; + std::string png_data; + + if (!net::DataURL::Parse(GURL(image_data_url), &mimetype, &charset, + &png_data)) { + VLOG(1) << "Screen AI could not parse image."; + return false; + } + + if (!gfx::PNGCodec::Decode( + reinterpret_cast<const unsigned char*>(png_data.data()), + png_data.size(), &bitmap)) { + VLOG(2) << "Screen AI could not decode image."; + return false; + } + + return true; +} +} // namespace + +namespace content { + +AXScreenAIAnnotator::AXScreenAIAnnotator( + RenderAccessibilityImpl* const render_accessibility, + mojo::PendingRemote<screen_ai::mojom::ScreenAIAnnotator> + screen_ai_annotator) + : render_accessibility_(render_accessibility), + screen_ai_annotator_(std::move(screen_ai_annotator)) {} + +AXScreenAIAnnotator::~AXScreenAIAnnotator() = default; + +bool AXScreenAIAnnotator::ShouldAnnotateObject( + const blink::WebAXObject& object) { + // TODO(https://crbug.com/1278249): Add snapshot archiving and comparison to + // prevent re-annotating an object unless its image is modified. + + // TODO(https://crbug.com/1278249): Update heuristic. + return object.Role() == ax::mojom::Role::kRootWebArea; +} + +bool AXScreenAIAnnotator::ApplyAnnotationsIfAvailable( + const blink::WebAXObject& src, + ui::AXNodeData& dst) { + const auto lookup = annotations_.find(src.AxID()); + if (lookup == annotations_.end()) + return false; + + // TODO(https://crbug.com/1278249): Apply annotations. + return true; +} + +void AXScreenAIAnnotator::MaybeRunScreenAI(const blink::WebAXObject& object) { + if (ShouldAnnotateObject(object)) { + SkBitmap bitmap; + if (!GetImageFromWebAXObject(object, bitmap)) + return; + + annotations_[object.AxID()] = std::vector<screen_ai::mojom::Node>(); + screen_ai_annotator_->Annotate( + bitmap, base::BindOnce(&AXScreenAIAnnotator::OnAnnotationReceived, + weak_ptr_factory_.GetWeakPtr(), object.AxID())); + } +} + +void AXScreenAIAnnotator::OnAnnotationReceived( + ui::AXNodeID ax_id, + screen_ai::mojom::ErrorType error_type, + std::vector<screen_ai::mojom::NodePtr> annotation) { + if (error_type != screen_ai::mojom::ErrorType::kOK) + return; + + // TODO(https://crbug.com/1278249): Perform required conversions on members of + // |annotation| and store them in |annotations_| + + // TODO(https://crbug.com/1278249): Apply received annotation on |object|. + // Depending on the data received from Screen AI library, we may decide to + // update the node here, or just add the data during serialization. + blink::WebAXObject object = blink::WebAXObject::FromWebDocumentByID( + render_accessibility_->GetMainDocument(), ax_id); + + render_accessibility_->MarkWebAXObjectDirty(object, true /* subtree */); +} + +} // namespace content \ No newline at end of file
diff --git a/content/renderer/accessibility/ax_screen_ai_annotator.h b/content/renderer/accessibility/ax_screen_ai_annotator.h new file mode 100644 index 0000000..6572a4d --- /dev/null +++ b/content/renderer/accessibility/ax_screen_ai_annotator.h
@@ -0,0 +1,63 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_ACCESSIBILITY_AX_SCREEN_AI_ANNOTATOR_H_ +#define CONTENT_RENDERER_ACCESSIBILITY_AX_SCREEN_AI_ANNOTATOR_H_ + +#include "base/memory/weak_ptr.h" +#include "components/services/screen_ai/public/mojom/screen_ai_service.mojom.h" +#include "content/renderer/accessibility/render_accessibility_impl.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace blink { +class WebAXObject; +} + +namespace ui { +struct AXNodeData; +} + +namespace content { + +class AXScreenAIAnnotator { + public: + AXScreenAIAnnotator(RenderAccessibilityImpl* const render_accessibility, + mojo::PendingRemote<screen_ai::mojom::ScreenAIAnnotator> + screen_ai_annotator); + ~AXScreenAIAnnotator(); + AXScreenAIAnnotator(const AXScreenAIAnnotator&) = delete; + AXScreenAIAnnotator& operator=(const AXScreenAIAnnotator&) = delete; + + // If |src| is already annotated, updates |dst| and returns true. Otherwise + // returns false. + bool ApplyAnnotationsIfAvailable(const blink::WebAXObject& src, + ui::AXNodeData& dst); + + // If validated by heuristics, |object|'s image is sent to ScreenAI service. + void MaybeRunScreenAI(const blink::WebAXObject& object); + + private: + // Heuristic based assessment if an object needs annotation. + bool ShouldAnnotateObject(const blink::WebAXObject& object); + + // Receives the annotation from ScreenAI service, stores them in + // |annotations_|, and marks the respective object dirty. + void OnAnnotationReceived(ui::AXNodeID ax_id, + screen_ai::mojom::ErrorType error_type, + std::vector<screen_ai::mojom::NodePtr> annotation); + + std::unordered_map<ui::AXNodeID, std::vector<screen_ai::mojom::Node>> + annotations_; + + // Weak, owns us. + RenderAccessibilityImpl* const render_accessibility_; + + mojo::Remote<screen_ai::mojom::ScreenAIAnnotator> screen_ai_annotator_; + + base::WeakPtrFactory<AXScreenAIAnnotator> weak_ptr_factory_{this}; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_ACCESSIBILITY_AX_SCREEN_AI_ANNOTATOR_H_
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index e693e63..7218fb79 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -49,6 +49,10 @@ #include "url/gurl.h" #include "url/url_constants.h" +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#include "content/renderer/accessibility/ax_screen_ai_annotator.h" +#endif + using base::ASCIIToUTF16; using base::UTF16ToUTF8; using blink::WebAXObject; @@ -587,6 +591,13 @@ element.GetAttribute("type").Utf8()); } } + +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + if (screen_ai_annotator_ && + !screen_ai_annotator_->ApplyAnnotationsIfAvailable(src, *dst)) { + screen_ai_annotator_->MaybeRunScreenAI(src); + } +#endif } blink::WebDocument BlinkAXTreeSource::GetMainDocument() const {
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h index 82a6cb4..cee34de 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.h +++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -24,6 +24,7 @@ namespace content { class AXImageAnnotator; +class AXScreenAIAnnotator; class BlinkAXTreeSource; class RenderFrameImpl; @@ -95,6 +96,12 @@ first_unlabeled_image_id_ = absl::nullopt; } + // The following method add or remove Screen AI annotator that is used to + // analyze the image of the nodes and provide additional metadata. + void set_screen_ai_annotator(AXScreenAIAnnotator* annotator) { + screen_ai_annotator_ = annotator; + } + // Query or update a set of IDs for which we should load inline text boxes. bool ShouldLoadInlineTextBoxes(const blink::WebAXObject& obj) const; void SetLoadInlineTextBoxesForId(int32_t id); @@ -190,6 +197,11 @@ // The class instance that retrieves and manages automatic labels for images. AXImageAnnotator* image_annotator_ = nullptr; + // The class instance that uses Screen AI library to analyze snapshots. + // |screen_ai_annotator_| belongs to RenderAccessibilityImpl which owns + // |BlinkAXTreeSource|. + AXScreenAIAnnotator* screen_ai_annotator_ = nullptr; + // Whether we should highlight annotation results visually on the page // for debugging. bool image_annotation_debugging_ = false;
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc index 7f8b7fe1..13e9647 100644 --- a/content/renderer/accessibility/render_accessibility_impl.cc +++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -26,6 +26,7 @@ #include "base/timer/elapsed_timer.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" +#include "content/public/common/content_features.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/accessibility/ax_action_target_factory.h" #include "content/renderer/accessibility/ax_image_annotator.h" @@ -52,6 +53,10 @@ #include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_tree_id.h" +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#include "content/renderer/accessibility/ax_screen_ai_annotator.h" +#endif + using blink::WebAXContext; using blink::WebAXObject; using blink::WebDocument; @@ -168,6 +173,10 @@ image_annotation_debugging_ = base::CommandLine::ForCurrentProcess()->HasSwitch( ::switches::kEnableExperimentalAccessibilityLabelsDebugging); + +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + StartOrStopScreenAIAnnotator(mode); +#endif } RenderAccessibilityImpl::~RenderAccessibilityImpl() = default; @@ -240,6 +249,9 @@ event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately; ScheduleSendPendingAccessibilityEvents(); } +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + StartOrStopScreenAIAnnotator(mode); +#endif } void RenderAccessibilityImpl::HitTest( @@ -1245,6 +1257,33 @@ } } +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +void RenderAccessibilityImpl::StartOrStopScreenAIAnnotator( + ui::AXMode new_mode) { + if (!base::FeatureList::IsEnabled(features::kScreenAI)) + return; + + if (new_mode.has_mode(ui::AXMode::kScreenReader) && + !ax_screen_ai_annotator_.get()) { + mojo::PendingRemote<screen_ai::mojom::ScreenAIAnnotator> + screen_ai_annotator; + render_frame_->GetBrowserInterfaceBroker()->GetInterface( + screen_ai_annotator.InitWithNewPipeAndPassReceiver()); + + ax_screen_ai_annotator_ = std::make_unique<AXScreenAIAnnotator>( + this, std::move(screen_ai_annotator)); + tree_source_->set_screen_ai_annotator(ax_screen_ai_annotator_.get()); + return; + } + + if (ax_screen_ai_annotator_.get() && + !new_mode.has_mode(ui::AXMode::kScreenReader)) { + tree_source_->set_screen_ai_annotator(nullptr); + ax_screen_ai_annotator_.reset(); + } +} +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + void RenderAccessibilityImpl::MarkAllAXObjectsDirty( ax::mojom::Role role, ax::mojom::Action event_from_action) {
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h index 61ce661..92cd85c 100644 --- a/content/renderer/accessibility/render_accessibility_impl.h +++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -50,6 +50,7 @@ namespace content { class AXImageAnnotator; +class AXScreenAIAnnotator; class RenderFrameImpl; class RenderAccessibilityManager; @@ -210,6 +211,14 @@ // any automatic annotations that might have been added before. void StartOrStopLabelingImages(ui::AXMode old_mode, ui::AXMode new_mode); +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + // If new mode includes screen reader, initializes Screen AI service + // connection that processes snapshots to get more metadata. + // If new mode does not includes screen reader and Screen AI is enabled, turns + // it off. + void StartOrStopScreenAIAnnotator(ui::AXMode new_mode); +#endif + // Marks all AXObjects with the given role in the current tree dirty. void MarkAllAXObjectsDirty(ax::mojom::Role role, ax::mojom::Action event_from_action); @@ -270,6 +279,11 @@ // Manages the automatic image annotations, if enabled. std::unique_ptr<AXImageAnnotator> ax_image_annotator_; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + // Manages the snapshot processing, if enabled. + std::unique_ptr<AXScreenAIAnnotator> ax_screen_ai_annotator_; +#endif + // Events from Blink are collected until they are ready to be // sent to the browser. std::vector<ui::AXEvent> pending_events_;
diff --git a/content/test/data/gpu/webcodecs/copyTo.html b/content/test/data/gpu/webcodecs/copyTo.html index 2a19e40..6b8af26 100644 --- a/content/test/data/gpu/webcodecs/copyTo.html +++ b/content/test/data/gpu/webcodecs/copyTo.html
@@ -100,5 +100,6 @@ } frame.close(); + source.close(); } </script> \ No newline at end of file
diff --git a/content/test/data/gpu/webcodecs/draw-image.html b/content/test/data/gpu/webcodecs/draw-image.html index eb56b00..77fb866 100644 --- a/content/test/data/gpu/webcodecs/draw-image.html +++ b/content/test/data/gpu/webcodecs/draw-image.html
@@ -50,6 +50,7 @@ frame.close(); await waitForNextFrame(); } + source.close(); } </script> </head>
diff --git a/content/test/data/gpu/webcodecs/encode-decode.html b/content/test/data/gpu/webcodecs/encode-decode.html index 5eb3354b..8ed6fb3 100644 --- a/content/test/data/gpu/webcodecs/encode-decode.html +++ b/content/test/data/gpu/webcodecs/encode-decode.html
@@ -91,6 +91,7 @@ await decoder.flush(); encoder.close(); decoder.close(); + source.close(); TEST.assert( frames_encoded == frames_to_encode,
diff --git a/content/test/data/gpu/webcodecs/encode.html b/content/test/data/gpu/webcodecs/encode.html index b4faf94..a20f760f 100644 --- a/content/test/data/gpu/webcodecs/encode.html +++ b/content/test/data/gpu/webcodecs/encode.html
@@ -18,12 +18,6 @@ const width = 640; const height = 480; const frames_in_one_pass = 15; - let source = await createFrameSource(arg.source_type, width, height); - if (!source) { - TEST.skip('Unsupported source: ' + arg.source_type); - return; - } - let errors = 0; let chunks = []; let decoder_configs = []; @@ -43,6 +37,12 @@ return; } + let source = await createFrameSource(arg.source_type, width, height); + if (!source) { + TEST.skip('Unsupported source: ' + arg.source_type); + return; + } + const init = { output(chunk, metadata) { if (metadata.decoderConfig) @@ -84,6 +84,7 @@ await encoder.flush(); encoder.close(); + source.close(); TEST.assert( decoder_configs.length >= 2,
diff --git a/content/test/data/gpu/webcodecs/encoding-modes.html b/content/test/data/gpu/webcodecs/encoding-modes.html index f8deda84..5f4f03d8 100644 --- a/content/test/data/gpu/webcodecs/encoding-modes.html +++ b/content/test/data/gpu/webcodecs/encoding-modes.html
@@ -13,11 +13,6 @@ const width = 640; const height = 480; const frames_in_one_pass = 15; - let source = await createFrameSource(arg.source_type, width, height); - if (!source) { - TEST.skip('Unsupported source: ' + arg.source_type); - return; - } let errors = 0; let chunks = []; @@ -40,6 +35,12 @@ return; } + let source = await createFrameSource(arg.source_type, width, height); + if (!source) { + TEST.skip('Unsupported source: ' + arg.source_type); + return; + } + const init = { output(chunk, metadata) { if (metadata.decoderConfig) @@ -65,6 +66,7 @@ await encoder.flush(); encoder.close(); + source.close(); TEST.assert( decoder_configs.length >= 1,
diff --git a/content/test/data/gpu/webcodecs/svc.html b/content/test/data/gpu/webcodecs/svc.html index 5d6c7ed..9508c5e 100644 --- a/content/test/data/gpu/webcodecs/svc.html +++ b/content/test/data/gpu/webcodecs/svc.html
@@ -95,6 +95,7 @@ await decoder.flush(); encoder.close(); decoder.close(); + source.close(); TEST.assert( frames_encoded == frames_to_encode,
diff --git a/content/test/data/gpu/webcodecs/tex-image-2d.html b/content/test/data/gpu/webcodecs/tex-image-2d.html index 64c1e4d..699ccbe 100644 --- a/content/test/data/gpu/webcodecs/tex-image-2d.html +++ b/content/test/data/gpu/webcodecs/tex-image-2d.html
@@ -112,6 +112,7 @@ frame.close(); await waitForNextFrame(); } + source.close(); } </script> </head>
diff --git a/content/test/data/gpu/webcodecs/webcodecs_common.js b/content/test/data/gpu/webcodecs/webcodecs_common.js index 4a9c593..6096c19 100644 --- a/content/test/data/gpu/webcodecs/webcodecs_common.js +++ b/content/test/data/gpu/webcodecs/webcodecs_common.js
@@ -175,6 +175,8 @@ async getNextFrame() { return null; } + + close() {} } // Source of video frames coming from taking snapshots of a canvas. @@ -214,6 +216,11 @@ const frame = result.value; return frame; } + + close() { + if (this.reader) + this.reader.cancel(); + } } class ArrayBufferSource extends FrameSource { @@ -293,6 +300,11 @@ return next.promise; } + + close() { + if (this.decoder) + this.decoder.close(); + } } function createCanvasCaptureSource(width, height) { @@ -367,7 +379,15 @@ encoder.encode(frame, {keyFrame: false}); frame.close(); } - await encoder.flush(); + try { + await encoder.flush(); + encoder.close(); + canvasSource.close(); + } catch (e) { + errors++; + TEST.log(e); + } + if (errors > 0) return null;
diff --git a/content/test/gpu/gpu_tests/webcodecs_integration_test.py b/content/test/gpu/gpu_tests/webcodecs_integration_test.py index 05469b6f..c44cd0f 100644 --- a/content/test/gpu/gpu_tests/webcodecs_integration_test.py +++ b/content/test/gpu/gpu_tests/webcodecs_integration_test.py
@@ -68,7 +68,8 @@ for acc in accelerations: for bitrate_mode in ['constant', 'variable']: for latency_mode in ['realtime', 'quality']: - args = ('offscreen', codec, acc, bitrate_mode, latency_mode) + source_type = 'offscreen' + args = (source_type, codec, acc, bitrate_mode, latency_mode) yield ('WebCodecs_EncodingModes_%s_%s_%s_%s_%s' % args, 'encoding-modes.html', ({ 'source_type': source_type,
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn index fe84145..3182033 100644 --- a/content/utility/BUILD.gn +++ b/content/utility/BUILD.gn
@@ -112,6 +112,7 @@ if (is_linux || is_chromeos) { deps += [ + "//components/services/screen_ai:screen_ai_sandbox_hook", "//content/utility/speech:speech_recognition_sandbox_hook", "//services/network:network_sandbox_hook", ]
diff --git a/content/utility/DEPS b/content/utility/DEPS index 81ecc04..0bde0a1 100644 --- a/content/utility/DEPS +++ b/content/utility/DEPS
@@ -17,6 +17,7 @@ "+services/service_manager", "+services/shape_detection", "+services/tracing", + "+components/services/screen_ai", "+services/video_capture", "+services/viz", "+sandbox/win/src",
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc index dd6a232..57206009 100644 --- a/content/utility/utility_main.cc +++ b/content/utility/utility_main.cc
@@ -33,6 +33,7 @@ #include "third_party/icu/source/i18n/unicode/timezone.h" #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#include "components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.h" #include "content/utility/speech/speech_recognition_sandbox_hook_linux.h" #if BUILDFLAG(ENABLE_PRINTING) #include "printing/sandbox/print_backend_sandbox_hook_linux.h" @@ -158,6 +159,9 @@ pre_sandbox_hook = base::BindOnce(&speech::SpeechRecognitionPreSandboxHook); break; + case sandbox::mojom::Sandbox::kScreenAI: + pre_sandbox_hook = base::BindOnce(&screen_ai::ScreenAIPreSandboxHook); + break; #if BUILDFLAG(IS_CHROMEOS_ASH) case sandbox::mojom::Sandbox::kHardwareVideoDecoding: pre_sandbox_hook =
diff --git a/google_apis/google_api_keys_unittest.cc b/google_apis/google_api_keys_unittest.cc index 0b335aa5..fc92bc1 100644 --- a/google_apis/google_api_keys_unittest.cc +++ b/google_apis/google_api_keys_unittest.cc
@@ -26,9 +26,10 @@ // unit_tests, and the Android builders complain about multiply // defined symbols (likely they don't do name decoration as well as // the Mac and Linux linkers). Therefore these tests are only built -// and run on Mac and Linux, which should provide plenty of coverage +// and run on Mac, Linux and Fuchsia, which should provide plenty of coverage // since there are no platform-specific bits in this code. -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) || \ + BUILDFLAG(IS_FUCHSIA) // We need to include everything included by google_api_keys.cc once // at global scope so that things like STL and classes from base don't @@ -587,3 +588,4 @@ } #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) + // || BUILDFLAG(IS_FUCHSIA)
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index d221d1c..effb4eb1 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -202,6 +202,7 @@ "//ios/chrome/app/application_delegate:app_state_header", "//ios/chrome/browser", "//ios/chrome/browser/policy", + "//ios/chrome/browser/ui/first_run:utils", "//ios/chrome/browser/ui/main:scene_state_header", ] }
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm index 0a8d4a3..64d69ee 100644 --- a/ios/chrome/app/application_delegate/app_state.mm +++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -230,7 +230,8 @@ } // Return YES if the First Run UI is showing. - return self.initStage == InitStageFirstRun && + return (self.initStage == InitStageFirstRun || + self.initStage == InitStageEnterprise) && self.startupInformation.isFirstRun; }
diff --git a/ios/chrome/app/enterprise_app_agent.mm b/ios/chrome/app/enterprise_app_agent.mm index 571a487..825d451 100644 --- a/ios/chrome/app/enterprise_app_agent.mm +++ b/ios/chrome/app/enterprise_app_agent.mm
@@ -16,6 +16,7 @@ #include "ios/chrome/browser/policy/chrome_browser_cloud_management_controller_ios.h" #import "ios/chrome/browser/policy/chrome_browser_cloud_management_controller_observer_bridge.h" #import "ios/chrome/browser/policy/cloud_policy_client_observer_bridge.h" +#import "ios/chrome/browser/ui/first_run/first_run_util.h" #import "ios/chrome/browser/ui/main/scene_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -191,7 +192,7 @@ machineLevelUserCloudPolicyManager = self.policyConnector->machine_level_user_cloud_policy_manager(); - return !tests_hook::DisableFirstRun() && + return ShouldPresentFirstRunExperience() && self.policyConnector->chrome_browser_cloud_management_controller() ->IsEnabled() && machineLevelUserCloudPolicyManager &&
diff --git a/ios/chrome/browser/web_state_list/BUILD.gn b/ios/chrome/browser/web_state_list/BUILD.gn index cccf25c..481aa1d 100644 --- a/ios/chrome/browser/web_state_list/BUILD.gn +++ b/ios/chrome/browser/web_state_list/BUILD.gn
@@ -53,6 +53,7 @@ "//ios/web", "//ios/web/public/session", ] + public_deps = [ "//third_party/abseil-cpp:absl" ] frameworks = [ "Foundation.framework" ] configs += [ "//build/config/compiler:enable_arc" ] }
diff --git a/ios/chrome/browser/web_state_list/web_state_list_order_controller.mm b/ios/chrome/browser/web_state_list/web_state_list_order_controller.mm index cf60802..a08af5b 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_order_controller.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_order_controller.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/web_state_list/web_state_list_order_controller.h" #include <cstdint> +#include <set> #include "base/check_op.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" @@ -15,6 +16,45 @@ #error "This file requires ARC support." #endif +namespace { + +// Find the index of next non-removed WebState opened by |web_state|. It +// may return WebStateList::kInvalidIndex if there is no such indexes. +int FindIndexOfNextNonRemovedWebStateOpenedBy( + const WebStateListRemovingIndexes& removing_indexes, + const WebStateList& web_state_list, + const web::WebState* web_state, + int starting_index) { + std::set<int> children; + for (;;) { + const int child_index = web_state_list.GetIndexOfNextWebStateOpenedBy( + web_state, starting_index, false); + + // The active WebState has no child, fall back to the next heuristic. + if (child_index == WebStateList::kInvalidIndex) + break; + + // All children are going to be removed, fallback to the next heuristic. + if (children.find(child_index) != children.end()) + break; + + // Found a child that is not removed, select it as the next active + // WebState. + const int child_index_after_removal = + removing_indexes.IndexAfterRemoval(child_index); + + if (child_index_after_removal != WebStateList::kInvalidIndex) + return child_index_after_removal; + + children.insert(child_index); + starting_index = child_index; + } + + return WebStateList::kInvalidIndex; +} + +} // anonymous namespace + WebStateListOrderController::WebStateListOrderController( const WebStateList& web_state_list) : web_state_list_(web_state_list) {} @@ -69,9 +109,9 @@ // the new active element. Prefer childs located after the active element, // but this may end up selecting an element before it. const int child_index_after_removal = - removing_indexes.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, web_state_list_.GetWebStateAt(active_index), - active_index); + FindIndexOfNextNonRemovedWebStateOpenedBy( + removing_indexes, web_state_list_, + web_state_list_.GetWebStateAt(active_index), active_index); if (child_index_after_removal != WebStateList::kInvalidIndex) return child_index_after_removal; @@ -82,8 +122,8 @@ // to be the new active element. Prefer siblings located after the active // element, but this may end up selecting an element before it. const int sibling_index_after_removal = - removing_indexes.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener.opener, active_index); + FindIndexOfNextNonRemovedWebStateOpenedBy( + removing_indexes, web_state_list_, opener.opener, active_index); if (sibling_index_after_removal != WebStateList::kInvalidIndex) return sibling_index_after_removal;
diff --git a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h index 1819104..d80aaad 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h +++ b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h
@@ -8,6 +8,8 @@ #include <initializer_list> #include <vector> +#include "third_party/abseil-cpp/absl/types/variant.h" + class WebStateList; namespace web { @@ -32,7 +34,7 @@ ~WebStateListRemovingIndexes(); // Returns the number of WebState that will be closed. - int count() const { return static_cast<int>(indexes_.size()); } + int count() const; // Returns whether index is present in the list of indexes to close. bool Contains(int index) const; @@ -41,15 +43,15 @@ // scheduled to be removed, will return WebStateList::kInvalidIndex. int IndexAfterRemoval(int index) const; - // Find the index of next non-removed WebState opened by |web_state|. It - // may return WebStateList::kInvalidIndex if there is no such indexes. - int FindIndexOfNextNonRemovedWebStateOpenedBy( - const WebStateList& web_state_list, - const web::WebState* web_state, - int starting_index); + // Represents an empty WebStateListRemovingIndexes. + struct Empty {}; + + // Alias for the variant storing the indexes to remove. Using a variant + // allow not allocating for the common case of removing one element. + using Storage = absl::variant<Empty, int, std::vector<int>>; private: - std::vector<int> indexes_; + Storage removing_; }; #endif // IOS_CHROME_BROWSER_WEB_STATE_LIST_WEB_STATE_LIST_REMOVING_INDEXES_H_
diff --git a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.mm b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.mm index 4677871..d687958 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes.mm
@@ -5,25 +5,115 @@ #import "ios/chrome/browser/web_state_list/web_state_list_removing_indexes.h" #include <algorithm> -#include <set> #import "ios/chrome/browser/web_state_list/web_state_list.h" -#import "ios/chrome/browser/web_state_list/web_state_opener.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +namespace { + +// Constructs a WebStateListRemovingIndexes::Storage from a +// std::vector<int>, sorting it and removing duplicates. +WebStateListRemovingIndexes::Storage StorageFromVector( + std::vector<int> indexes) { + std::sort(indexes.begin(), indexes.end()); + indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end()); + + if (indexes.empty()) + return WebStateListRemovingIndexes::Empty{}; + + if (indexes.size() == 1) + return indexes[0]; + + return indexes; +} + +// Constructs a WebStateListRemovingIndexes::Storage from a +// std::initializer_list<int>. +WebStateListRemovingIndexes::Storage StorageFromInitializerList( + std::initializer_list<int> indexes) { + if (indexes.size() == 0) + return WebStateListRemovingIndexes::Empty{}; + + if (indexes.size() == 1) + return *indexes.begin(); + + // Use the vector overload. + return StorageFromVector(std::vector<int>(std::move(indexes))); +} + +// Visitor implementing WebStateListRemovingIndexes::count(). +struct CountVisitor { + using Empty = WebStateListRemovingIndexes::Empty; + + int operator()(const Empty&) const { return 0; } + + int operator()(const int& index) const { return 1; } + + int operator()(const std::vector<int>& indexes) const { + return static_cast<int>(indexes.size()); + } +}; + +// Visitor implementing WebStateListRemovingIndexes::Contains(int). +struct ContainsVisitor { + using Empty = WebStateListRemovingIndexes::Empty; + + explicit ContainsVisitor(int index) : index_(index) {} + + bool operator()(const Empty&) const { return false; } + + bool operator()(const int& index) const { return index_ == index; } + + bool operator()(const std::vector<int>& indexes) const { + return std::binary_search(indexes.begin(), indexes.end(), index_); + } + + const int index_; +}; + +// Visitor implementing WebStateListRemovingIndexes::IndexAfterRemoval(int). +struct IndexAfterRemovalVisitor { + using Empty = WebStateListRemovingIndexes::Empty; + + explicit IndexAfterRemovalVisitor(int index) : index_(index) {} + + int operator()(const Empty&) const { return index_; } + + int operator()(const int& index) const { + if (index_ == index) + return WebStateList::kInvalidIndex; + + if (index_ > index) + return index_ - 1; + + return index_; + } + + int operator()(const std::vector<int>& indexes) const { + const auto lower_bound = + std::lower_bound(indexes.begin(), indexes.end(), index_); + + if (lower_bound == indexes.end() || *lower_bound != index_) + return index_ - std::distance(indexes.begin(), lower_bound); + + return WebStateList::kInvalidIndex; + } + + const int index_; +}; + +} // anonymous namespace + WebStateListRemovingIndexes::WebStateListRemovingIndexes( std::vector<int> indexes) - : indexes_(std::move(indexes)) { - std::sort(indexes_.begin(), indexes_.end()); - indexes_.erase(std::unique(indexes_.begin(), indexes_.end()), indexes_.end()); -} + : removing_(StorageFromVector(std::move(indexes))) {} WebStateListRemovingIndexes::WebStateListRemovingIndexes( std::initializer_list<int> indexes) - : WebStateListRemovingIndexes(std::vector<int>(indexes)) {} + : removing_(StorageFromInitializerList(std::move(indexes))) {} WebStateListRemovingIndexes::WebStateListRemovingIndexes( const WebStateListRemovingIndexes&) = default; @@ -39,47 +129,14 @@ WebStateListRemovingIndexes::~WebStateListRemovingIndexes() = default; +int WebStateListRemovingIndexes::count() const { + return absl::visit(CountVisitor(), removing_); +} + bool WebStateListRemovingIndexes::Contains(int index) const { - return std::binary_search(indexes_.begin(), indexes_.end(), index); + return absl::visit(ContainsVisitor(index), removing_); } int WebStateListRemovingIndexes::IndexAfterRemoval(int index) const { - const auto lower_bound = - std::lower_bound(indexes_.begin(), indexes_.end(), index); - - if (lower_bound == indexes_.end() || *lower_bound != index) - return index - std::distance(indexes_.begin(), lower_bound); - - // The index is scheduled for removal. - return WebStateList::kInvalidIndex; -} - -int WebStateListRemovingIndexes::FindIndexOfNextNonRemovedWebStateOpenedBy( - const WebStateList& web_state_list, - const web::WebState* web_state, - int starting_index) { - std::set<int> children; - for (;;) { - const int child_index = web_state_list.GetIndexOfNextWebStateOpenedBy( - web_state, starting_index, false); - - // The active WebState has no child, fall back to the next heuristic. - if (child_index == WebStateList::kInvalidIndex) - break; - - // All children are going to be removed, fallback to the next heuristic. - if (children.find(child_index) != children.end()) - break; - - // Found a child that is not removed, select it as the next active - // WebState. - const int child_index_after_removal = IndexAfterRemoval(child_index); - if (child_index_after_removal != WebStateList::kInvalidIndex) - return child_index_after_removal; - - children.insert(child_index); - starting_index = child_index; - } - - return WebStateList::kInvalidIndex; + return absl::visit(IndexAfterRemovalVisitor(index), removing_); }
diff --git a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes_unittest.mm b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes_unittest.mm index 136d233..4dbe4f9 100644 --- a/ios/chrome/browser/web_state_list/web_state_list_removing_indexes_unittest.mm +++ b/ios/chrome/browser/web_state_list/web_state_list_removing_indexes_unittest.mm
@@ -63,11 +63,43 @@ EXPECT_EQ(WebStateListRemovingIndexes({}).count(), 0); EXPECT_EQ(WebStateListRemovingIndexes({1}).count(), 1); EXPECT_EQ(WebStateListRemovingIndexes({1, 1}).count(), 1); + EXPECT_EQ(WebStateListRemovingIndexes({1, 2}).count(), 2); + EXPECT_EQ(WebStateListRemovingIndexes({2, 1, 2, 1}).count(), 2); } // Tests that WebStateListRemovingIndexes correctly returns the correct -// updated value when asked for index once tabs have been removed. -TEST_F(WebStateListRemovingIndexesTest, IndexAfterRemoval) { +// updated value when asked for index if no tabs are removed. +TEST_F(WebStateListRemovingIndexesTest, IndexAfterRemovalEmpty) { + WebStateListRemovingIndexes removing_indexes({}); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(0), 0); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(1), 1); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(2), 2); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(3), 3); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(4), 4); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(5), 5); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(6), 6); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(7), 7); // no removal before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(8), 8); // no removal before +} + +// Tests that WebStateListRemovingIndexes correctly returns the correct +// updated value when asked for index if one tab is removed. +TEST_F(WebStateListRemovingIndexesTest, IndexAfterRemovalOneTab) { + WebStateListRemovingIndexes removing_indexes({4}); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(0), 0); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(1), 1); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(2), 2); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(3), 3); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(4), WebStateList::kInvalidIndex); + EXPECT_EQ(removing_indexes.IndexAfterRemoval(5), 4); // one removals before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(6), 5); // one removals before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(7), 6); // one removals before + EXPECT_EQ(removing_indexes.IndexAfterRemoval(8), 7); // one removals before +} + +// Tests that WebStateListRemovingIndexes correctly returns the correct +// updated value when asked for index if multiple tabs have been removed. +TEST_F(WebStateListRemovingIndexesTest, IndexAfterRemovalMultipleTabs) { WebStateListRemovingIndexes removing_indexes({1, 3, 7}); EXPECT_EQ(removing_indexes.IndexAfterRemoval(0), 0); // no removal before EXPECT_EQ(removing_indexes.IndexAfterRemoval(1), WebStateList::kInvalidIndex); @@ -79,75 +111,3 @@ EXPECT_EQ(removing_indexes.IndexAfterRemoval(7), WebStateList::kInvalidIndex); EXPECT_EQ(removing_indexes.IndexAfterRemoval(8), 5); // three removals before } - -// Tests that WebStateListRemovingIndexes correctly find a child index after -// removal. -TEST_F(WebStateListRemovingIndexesTest, - FindIndexOfNextNonRemovedWebStateOpenedBy) { - // Create a WebStateList with 6 WebStates, 5 of them children of the - // WebState at index 2 (so the WebState at index 2 has two children - // before itself and three children after). - web::WebState* opener = InsertNewWebState(0, WebStateOpener()); - InsertNewWebState(0, WebStateOpener(opener)); - InsertNewWebState(0, WebStateOpener(opener)); - InsertNewWebState(3, WebStateOpener(opener)); - InsertNewWebState(4, WebStateOpener(opener)); - InsertNewWebState(5, WebStateOpener(opener)); - - // If no indexes are removed, FindIndexOfNextNonRemovedWebStateOpenedBy() - // should behave as GetIndexOfNextWebStateOpenedBy(). - WebStateListRemovingIndexes removing_no_children({}); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 2), - 3); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 3), - 4); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 4), - 5); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 5), - 0); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 0), - 1); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 1), - 3); - EXPECT_EQ(removing_no_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, web_state_list_.GetWebStateAt(0), 0), - WebStateList::kInvalidIndex); - - // If some child are removed, FindIndexOfNextNonRemovedWebStateOpenedBy() - // correctly skips them. - WebStateListRemovingIndexes removing_some_children({1, 3}); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 2), - 2); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 3), - 2); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 4), - 3); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 5), - 0); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 0), - 2); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 1), - 2); - EXPECT_EQ(removing_some_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, web_state_list_.GetWebStateAt(0), 0), - WebStateList::kInvalidIndex); - - // If some child are removed, FindIndexOfNextNonRemovedWebStateOpenedBy() - // correctly reports there is no possible index. - WebStateListRemovingIndexes removing_all_children({0, 1, 3, 4, 5}); - EXPECT_EQ(removing_all_children.FindIndexOfNextNonRemovedWebStateOpenedBy( - web_state_list_, opener, 2), - WebStateList::kInvalidIndex); -}
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index fb03eb0..41f4046 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -49ddad3a398cfc43d83250608d149e6dc3d59680 \ No newline at end of file +2b8e506504799f30cc8f2d1711fd836332c93cc9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 7e1d84a..c8ad181 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -d3352e27b5c67a0e5c04ba01001282d5581065dc \ No newline at end of file +21c3e988c0d2b80ee8ae6ed7df4a1b69300372c5 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index dda4b3b..b38f0ab 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e623d33bcc8a5dd1114675945f000c9e1510914e \ No newline at end of file +7feebe295ab656b03330cff8a9e3814d2c6daff6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 0a6cb96..62c950b7 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -2d2489b63b5b7f88e7426e846a3b2dd00efd7853 \ No newline at end of file +531d8eae58162f78991db60373da7b7d7d31f680 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index d498de1..e232b20 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -19ab26ff503f81c71cfb5fca8babaad044cea1fa \ No newline at end of file +3c1ba500ed12019a5cc362238449823d4a5e13f8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 6ff1621..e9e870af3 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -6adc817dd79c2ceaa10b049d24379e98240b0693 \ No newline at end of file +d53868e633dad1a790228a2efa4c61b0d7507398 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index fac15f3..4f1515a 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -4bcd8f7e9bb9055936fb7e317983b4db20d0b9e2 \ No newline at end of file +799e048bb2d0549f7c11015ff19db71fbfdde4f7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 2a6c62b7..de4468b 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -adcea63ec37ade93a9e1fd87a8c296ab3f905ccb \ No newline at end of file +0d2884566b27fb8d7ba1b6376d05247f58f1819e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index d07ec66..fb27462 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -11bb5b5dc64bee4a8722a6ba68356898e71f04a1 \ No newline at end of file +0d65a7e4c4d05bb98c37d5eae3c2f051534900d7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 569c153c..00e1feac 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -63e99800a977f2445d3b08483c6025d6592adc5f \ No newline at end of file +79b1716dadb6802f0963892b4c74af4d61873eac \ No newline at end of file
diff --git a/media/base/audio_processing.h b/media/base/audio_processing.h index ca80199..95fda4b1 100644 --- a/media/base/audio_processing.h +++ b/media/base/audio_processing.h
@@ -9,6 +9,7 @@ #include "build/build_config.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -89,6 +90,13 @@ std::string ToString() const; }; +// This struct contains audio processing metrics that are reported by the audio +// service. +struct MEDIA_EXPORT AudioProcessingStats { + absl::optional<double> echo_return_loss; + absl::optional<double> echo_return_loss_enhancement; +}; + } // namespace media #endif // MEDIA_BASE_AUDIO_PROCESSING_H_
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc index 8dc31033..6587b22 100644 --- a/media/capture/video/chromeos/camera_device_delegate.cc +++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -280,10 +280,10 @@ CameraDeviceDelegate::CameraDeviceDelegate( VideoCaptureDeviceDescriptor device_descriptor, - scoped_refptr<CameraHalDelegate> camera_hal_delegate, + CameraHalDelegate* camera_hal_delegate, scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) : device_descriptor_(device_descriptor), - camera_hal_delegate_(std::move(camera_hal_delegate)), + camera_hal_delegate_(camera_hal_delegate), ipc_task_runner_(std::move(ipc_task_runner)) {} CameraDeviceDelegate::~CameraDeviceDelegate() = default;
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h index 4b1708d8..4d495ae3 100644 --- a/media/capture/video/chromeos/camera_device_delegate.h +++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -119,7 +119,7 @@ CameraDeviceDelegate( VideoCaptureDeviceDescriptor device_descriptor, - scoped_refptr<CameraHalDelegate> camera_hal_delegate, + CameraHalDelegate* camera_hal_delegate, scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner); CameraDeviceDelegate(const CameraDeviceDelegate&) = delete; @@ -248,7 +248,7 @@ // Current configured resolution of BLOB stream. gfx::Size current_blob_resolution_; - const scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + CameraHalDelegate* camera_hal_delegate_; // Map client type to video capture parameter. base::flat_map<ClientType, VideoCaptureParams> chrome_capture_params_;
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc index c481f80..4f8d6be 100644 --- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -146,9 +146,10 @@ &mock_gpu_memory_buffer_manager_); hal_delegate_thread_.Start(); camera_hal_delegate_ = - new CameraHalDelegate(hal_delegate_thread_.task_runner()); - auto get_camera_info = base::BindRepeating( - &CameraHalDelegate::GetCameraInfoFromDeviceId, camera_hal_delegate_); + std::make_unique<CameraHalDelegate>(hal_delegate_thread_.task_runner()); + auto get_camera_info = + base::BindRepeating(&CameraHalDelegate::GetCameraInfoFromDeviceId, + base::Unretained(camera_hal_delegate_.get())); camera_hal_delegate_->SetCameraModule( mock_camera_module_.GetPendingRemote()); } @@ -175,7 +176,7 @@ device_delegate_thread_.Start(); camera_device_delegate_ = std::make_unique<CameraDeviceDelegate>( - devices_info[0].descriptor, camera_hal_delegate_, + devices_info[0].descriptor, camera_hal_delegate_.get(), device_delegate_thread_.task_runner()); } @@ -516,7 +517,7 @@ protected: base::test::TaskEnvironment task_environment_; - scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + std::unique_ptr<CameraHalDelegate> camera_hal_delegate_; std::unique_ptr<CameraDeviceDelegate> camera_device_delegate_; testing::StrictMock<unittest_internal::MockCameraModule> mock_camera_module_;
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc index ef67081e..50a22a94 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -42,12 +42,11 @@ public: LocalCameraClientObserver() = delete; - explicit LocalCameraClientObserver( - scoped_refptr<CameraHalDelegate> camera_hal_delegate, - cros::mojom::CameraClientType type, - base::UnguessableToken auth_token) + explicit LocalCameraClientObserver(CameraHalDelegate* camera_hal_delegate, + cros::mojom::CameraClientType type, + base::UnguessableToken auth_token) : CameraClientObserver(type, std::move(auth_token)), - camera_hal_delegate_(std::move(camera_hal_delegate)) {} + camera_hal_delegate_(camera_hal_delegate) {} LocalCameraClientObserver(const LocalCameraClientObserver&) = delete; LocalCameraClientObserver& operator=(const LocalCameraClientObserver&) = @@ -59,7 +58,7 @@ } private: - scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + CameraHalDelegate* camera_hal_delegate_; }; // chromeos::system::StatisticsProvider::IsRunningOnVM() is not available in @@ -148,17 +147,19 @@ DETACH_FROM_SEQUENCE(sequence_checker_); } -CameraHalDelegate::~CameraHalDelegate() = default; +CameraHalDelegate::~CameraHalDelegate() {} bool CameraHalDelegate::RegisterCameraClient() { auto* dispatcher = CameraHalDispatcherImpl::GetInstance(); auto type = cros::mojom::CameraClientType::CHROME; + auto client_observer = std::make_unique<LocalCameraClientObserver>( + this, type, dispatcher->GetTokenForTrustedClient(type)); dispatcher->AddClientObserver( - std::make_unique<LocalCameraClientObserver>( - this, type, dispatcher->GetTokenForTrustedClient(type)), + client_observer.get(), base::BindOnce(&CameraHalDelegate::OnRegisteredCameraHalClient, base::Unretained(this))); camera_hal_client_registered_.Wait(); + local_client_observers_.emplace_back(std::move(client_observer)); return authenticated_; } @@ -176,14 +177,24 @@ void CameraHalDelegate::SetCameraModule( mojo::PendingRemote<cros::mojom::CameraModule> camera_module) { ipc_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&CameraHalDelegate::SetCameraModuleOnIpcThread, - this, std::move(camera_module))); + FROM_HERE, + base::BindOnce(&CameraHalDelegate::SetCameraModuleOnIpcThread, + base::Unretained(this), std::move(camera_module))); } void CameraHalDelegate::Reset() { ipc_task_runner_->PostTask( FROM_HERE, - base::BindOnce(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, this)); + base::BindOnce(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, + base::Unretained(this))); + + std::vector<CameraClientObserver*> observers; + for (auto& client_observer : local_client_observers_) { + observers.emplace_back(client_observer.get()); + } + auto* dispatcher = CameraHalDispatcherImpl::GetInstance(); + dispatcher->RemoveClientObservers(observers); + local_client_observers_.clear(); } std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice( @@ -490,7 +501,8 @@ camera_module_has_been_set_.Wait(); ipc_task_runner_->PostTask( FROM_HERE, - base::BindOnce(&CameraHalDelegate::OpenDeviceOnIpcThread, this, camera_id, + base::BindOnce(&CameraHalDelegate::OpenDeviceOnIpcThread, + base::Unretained(this), camera_id, std::move(device_ops_receiver), std::move(callback))); } @@ -533,8 +545,9 @@ } if (camera_module.is_valid()) { camera_module_.Bind(std::move(camera_module)); - camera_module_.set_disconnect_handler(base::BindOnce( - &CameraHalDelegate::ResetMojoInterfaceOnIpcThread, this)); + camera_module_.set_disconnect_handler( + base::BindOnce(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, + base::Unretained(this))); } camera_module_has_been_set_.Signal(); } @@ -568,7 +581,7 @@ ipc_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread, - this)); + base::Unretained(this))); if (!builtin_camera_info_updated_.TimedWait(kEventWaitTimeoutSecs)) { LOG(ERROR) << "Timed out getting camera info"; return false; @@ -578,8 +591,9 @@ void CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread() { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - camera_module_->GetNumberOfCameras(base::BindOnce( - &CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread, this)); + camera_module_->GetNumberOfCameras( + base::BindOnce(&CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread, + base::Unretained(this))); } void CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras) { @@ -598,11 +612,13 @@ // functions are called. camera_module_->SetCallbacksAssociated( camera_module_callbacks_.BindNewEndpointAndPassRemote(), - base::BindOnce(&CameraHalDelegate::OnSetCallbacksOnIpcThread, this)); + base::BindOnce(&CameraHalDelegate::OnSetCallbacksOnIpcThread, + base::Unretained(this))); camera_module_->GetVendorTagOps( vendor_tag_ops_delegate_.MakeReceiver(), - base::BindOnce(&CameraHalDelegate::OnGotVendorTagOpsOnIpcThread, this)); + base::BindOnce(&CameraHalDelegate::OnGotVendorTagOpsOnIpcThread, + base::Unretained(this))); } void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) { @@ -625,8 +641,8 @@ for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) { GetCameraInfoOnIpcThread( camera_id, - base::BindOnce(&CameraHalDelegate::OnGotCameraInfoOnIpcThread, this, - camera_id)); + base::BindOnce(&CameraHalDelegate::OnGotCameraInfoOnIpcThread, + base::Unretained(this), camera_id)); } } @@ -717,8 +733,8 @@ } GetCameraInfoOnIpcThread( camera_id, - base::BindOnce(&CameraHalDelegate::OnGotCameraInfoOnIpcThread, this, - camera_id)); + base::BindOnce(&CameraHalDelegate::OnGotCameraInfoOnIpcThread, + base::Unretained(this), camera_id)); } else { LOG(WARNING) << "Ignore duplicated camera_id = " << camera_id; }
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h index 58c7b0f..e0c5ef1a 100644 --- a/media/capture/video/chromeos/camera_hal_delegate.h +++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -15,6 +15,7 @@ #include "base/synchronization/waitable_event.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/thread.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "media/capture/video/chromeos/mojom/camera3.mojom.h" #include "media/capture/video/chromeos/mojom/camera_common.mojom.h" #include "media/capture/video/chromeos/vendor_tag_ops_delegate.h" @@ -35,18 +36,21 @@ // process on Chrome OS to access the module-level camera functionalities such // as camera device info look-up and opening camera devices. // -// CameraHalDelegate is refcounted because VideoCaptureDeviceFactoryChromeOS and -// CameraDeviceDelegate both need to reference CameraHalDelegate, and -// VideoCaptureDeviceFactoryChromeOS may be destroyed while CameraDeviceDelegate -// is still alive. +// CameraHalDelegate is owned by VideoCaptureDeviceFactoryChromeOS. +// VideoCaptureDeviceChromeOSDelegate and CameraDeviceDelegate have +// CameraHalDelegate's raw pointer. +// When VideoCaptureDeviceFactoryChromeOS destroys, +// CameraHalDelegate destroys VideoCaptureDeviceChromeOSDelegate and +// VideoCaptureDeviceChromeOSDelegate destroys CameraDeviceDelegate. class CAPTURE_EXPORT CameraHalDelegate final - : public base::RefCountedThreadSafe<CameraHalDelegate>, - public cros::mojom::CameraModuleCallbacks { + : public cros::mojom::CameraModuleCallbacks { public: // All the Mojo IPC operations happen on |ipc_task_runner|. explicit CameraHalDelegate( scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner); + ~CameraHalDelegate() final; + CameraHalDelegate(const CameraHalDelegate&) = delete; CameraHalDelegate& operator=(const CameraHalDelegate&) = delete; @@ -98,10 +102,6 @@ void DisableAllVirtualDevices(); private: - friend class base::RefCountedThreadSafe<CameraHalDelegate>; - - ~CameraHalDelegate() final; - void OnRegisteredCameraHalClient(int32_t result); void GetSupportedFormats(const cros::mojom::CameraInfoPtr& camera_info, @@ -224,6 +224,8 @@ // A map from camera id to corresponding delegate instance. base::flat_map<int, std::unique_ptr<VideoCaptureDeviceChromeOSDelegate>> vcd_delegate_map_; + + std::vector<std::unique_ptr<CameraClientObserver>> local_client_observers_; }; } // namespace media
diff --git a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc index e0a740f..f9efb92c 100644 --- a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc +++ b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc
@@ -48,7 +48,7 @@ &mock_gpu_memory_buffer_manager_); hal_delegate_thread_.Start(); camera_hal_delegate_ = - new CameraHalDelegate(hal_delegate_thread_.task_runner()); + std::make_unique<CameraHalDelegate>(hal_delegate_thread_.task_runner()); camera_hal_delegate_->SetCameraModule( mock_camera_module_.GetPendingRemote()); } @@ -65,7 +65,7 @@ protected: base::test::TaskEnvironment task_environment_; - scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + std::unique_ptr<CameraHalDelegate> camera_hal_delegate_; testing::StrictMock<unittest_internal::MockCameraModule> mock_camera_module_; testing::StrictMock<unittest_internal::MockVendorTagOps> mock_vendor_tag_ops_; unittest_internal::MockGpuMemoryBufferManager mock_gpu_memory_buffer_manager_;
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc index aef8354f..3a3ca47 100644 --- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -265,8 +265,7 @@ jda_factory_ = std::move(jda_factory); jea_factory_ = std::move(jea_factory); - base::WaitableEvent started(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent started; // It's important we generate tokens before creating the socket, because once // it is available, everyone connecting to socket would start fetching // tokens. @@ -292,15 +291,15 @@ } void CameraHalDispatcherImpl::AddClientObserver( - std::unique_ptr<CameraClientObserver> observer, + CameraClientObserver* observer, base::OnceCallback<void(int32_t)> result_callback) { // If |proxy_thread_| fails to start in Start() then CameraHalDelegate will // not be created, and this function will not be called. DCHECK(proxy_thread_.IsRunning()); - proxy_thread_.task_runner()->PostTask( + proxy_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImpl::AddClientObserverOnProxyThread, - base::Unretained(this), std::move(observer), + base::Unretained(this), observer, std::move(result_callback))); } @@ -366,7 +365,7 @@ CameraHalDispatcherImpl::~CameraHalDispatcherImpl() { VLOG(1) << "Stopping CameraHalDispatcherImpl..."; if (proxy_thread_.IsRunning()) { - proxy_thread_.task_runner()->PostTask( + proxy_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImpl::StopOnProxyThread, base::Unretained(this))); proxy_thread_.Stop(); @@ -410,8 +409,8 @@ // Set up the Mojo channels for clients which registered before the server // registers. - for (auto& client_observer : client_observers_) { - EstablishMojoChannel(client_observer.get()); + for (auto* client_observer : client_observers_) { + EstablishMojoChannel(client_observer); } } @@ -669,12 +668,12 @@ client_observer->client().set_disconnect_handler(base::BindOnce( &CameraHalDispatcherImpl::OnCameraHalClientConnectionError, base::Unretained(this), base::Unretained(client_observer.get()))); - AddClientObserverOnProxyThread(std::move(client_observer), - std::move(callback)); + AddClientObserverOnProxyThread(client_observer.get(), std::move(callback)); + mojo_client_observers_[client_observer.get()] = std::move(client_observer); } void CameraHalDispatcherImpl::AddClientObserverOnProxyThread( - std::unique_ptr<CameraClientObserver> observer, + CameraClientObserver* observer, base::OnceCallback<void(int32_t)> result_callback) { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); if (!observer->Authenticate(&token_manager_)) { @@ -683,9 +682,9 @@ return; } if (camera_hal_server_) { - EstablishMojoChannel(observer.get()); + EstablishMojoChannel(observer); } - client_observers_.insert(std::move(observer)); + client_observers_.insert(observer); std::move(result_callback).Run(0); CAMERA_LOG(EVENT) << "Camera HAL client registered"; } @@ -739,6 +738,17 @@ void CameraHalDispatcherImpl::OnCameraHalClientConnectionError( CameraClientObserver* client_observer) { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + CleanupClientOnProxyThread(client_observer); + if (mojo_client_observers_.find(client_observer) != + mojo_client_observers_.end()) { + mojo_client_observers_[client_observer].reset(); + mojo_client_observers_.erase(client_observer); + } +} + +void CameraHalDispatcherImpl::CleanupClientOnProxyThread( + CameraClientObserver* client_observer) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); base::AutoLock lock(opened_camera_id_map_lock_); auto camera_client_type = client_observer->GetType(); auto opened_it = opened_camera_id_map_.find(camera_client_type); @@ -761,6 +771,31 @@ } } +void CameraHalDispatcherImpl::RemoveClientObserversOnProxyThread( + std::vector<CameraClientObserver*> client_observers, + base::WaitableEvent* removed) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + for (auto* client_observer : client_observers) { + CleanupClientOnProxyThread(client_observer); + } + removed->Signal(); +} + +void CameraHalDispatcherImpl::RemoveClientObservers( + std::vector<CameraClientObserver*> client_observers) { + if (client_observers.empty()) + return; + DCHECK(proxy_thread_.IsRunning()); + base::WaitableEvent removed; + proxy_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &CameraHalDispatcherImpl::RemoveClientObserversOnProxyThread, + base::Unretained(this), client_observers, + base::Unretained(&removed))); + removed.Wait(); +} + void CameraHalDispatcherImpl::RegisterSensorClientWithTokenOnUIThread( mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, const base::UnguessableToken& auth_token, @@ -801,6 +836,7 @@ } // Close |cancel_pipe_| to quit the loop in WaitForIncomingConnection. cancel_pipe_.reset(); + mojo_client_observers_.clear(); client_observers_.clear(); camera_hal_server_callbacks_.reset(); camera_hal_server_.reset();
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h index f86e523..1dc7339c 100644 --- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h +++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -27,7 +27,6 @@ #include "media/capture/capture_export.h" #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" #include "media/capture/video/chromeos/token_manager.h" -#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" #include "media/capture/video/video_capture_device_factory.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -46,6 +45,8 @@ using MojoJpegEncodeAcceleratorFactoryCB = base::RepeatingCallback<void( mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator>)>; +using MojoMjpegDecodeAcceleratorFactoryCB = base::RepeatingCallback<void( + mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>)>; class CAPTURE_EXPORT CameraClientObserver { public: @@ -118,8 +119,8 @@ // establish direct Mojo connections between the CameraHalServer and the // CameraHalClients. // -// For general documentation about the CameraHalDispater Mojo interface see the -// comments in mojo/cros_camera_service.mojom. +// For general documentation about the CameraHalDispatcher Mojo interface see +// the comments in mojo/cros_camera_service.mojom. // // On ChromeOS the video capture service must run in the browser process, // because parts of the code depend on global objects that are only available in @@ -139,7 +140,7 @@ bool Start(MojoMjpegDecodeAcceleratorFactoryCB jda_factory, MojoJpegEncodeAcceleratorFactoryCB jea_factory); - void AddClientObserver(std::unique_ptr<CameraClientObserver> observer, + void AddClientObserver(CameraClientObserver* observer, base::OnceCallback<void(int32_t)> result_callback); bool IsStarted(); @@ -152,6 +153,11 @@ // being destroyed. void RemoveActiveClientObserver(CameraActiveClientObserver* observer); + // Removes the observers after a call by the subject and returns after + // the observers are removed. + void RemoveClientObservers( + std::vector<CameraClientObserver*> client_observers); + // Adds an observer to get notified when the camera privacy switch status // changed. Please note that for some devices, the signal will only be // detectable when the camera is currently on due to hardware limitations. @@ -231,7 +237,7 @@ RegisterClientWithTokenCallback callback); void AddClientObserverOnProxyThread( - std::unique_ptr<CameraClientObserver> observer, + CameraClientObserver* observer, base::OnceCallback<void(int32_t)> result_callback); void EstablishMojoChannel(CameraClientObserver* client_observer); @@ -243,6 +249,12 @@ void OnCameraHalServerConnectionError(); void OnCameraHalClientConnectionError(CameraClientObserver* client); + // Cleans up everything about the observer + void CleanupClientOnProxyThread(CameraClientObserver* client_observer); + void RemoveClientObserversOnProxyThread( + std::vector<CameraClientObserver*> client_observers, + base::WaitableEvent* removed); + void RegisterSensorClientWithTokenOnUIThread( mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, const base::UnguessableToken& auth_token, @@ -272,8 +284,7 @@ camera_hal_server_callbacks_; FailedCameraHalServerCallbacks failed_camera_hal_server_callbacks_; - std::set<std::unique_ptr<CameraClientObserver>, base::UniquePtrComparator> - client_observers_; + std::set<CameraClientObserver*> client_observers_; MojoMjpegDecodeAcceleratorFactoryCB jda_factory_; @@ -295,6 +306,9 @@ scoped_refptr<base::ObserverListThreadSafe<CameraPrivacySwitchObserver>> privacy_switch_observers_; + std::map<CameraClientObserver*, std::unique_ptr<CameraClientObserver>> + mojo_client_observers_; + base::WeakPtrFactory<CameraHalDispatcherImpl> weak_factory_{this}; };
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc index 137afb9f..6ae67e43 100644 --- a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc +++ b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
@@ -106,10 +106,10 @@ VideoCaptureDeviceChromeOSDelegate::VideoCaptureDeviceChromeOSDelegate( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, const VideoCaptureDeviceDescriptor& device_descriptor, - scoped_refptr<CameraHalDelegate> camera_hal_delegate, + CameraHalDelegate* camera_hal_delegate, base::OnceClosure cleanup_callback) : device_descriptor_(device_descriptor), - camera_hal_delegate_(std::move(camera_hal_delegate)), + camera_hal_delegate_(camera_hal_delegate), capture_task_runner_(base::ThreadTaskRunnerHandle::Get()), camera_device_ipc_thread_(std::string("CameraDeviceIpcThread") + device_descriptor.device_id),
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h index 02d2c3d..a0225c0 100644 --- a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h +++ b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.h
@@ -38,7 +38,7 @@ VideoCaptureDeviceChromeOSDelegate( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, const VideoCaptureDeviceDescriptor& device_descriptor, - scoped_refptr<CameraHalDelegate> camera_hal_delegate, + CameraHalDelegate* camera_hal_delegate, base::OnceClosure cleanup_callback); VideoCaptureDeviceChromeOSDelegate( @@ -76,7 +76,7 @@ // A reference to the CameraHalDelegate instance in the VCD factory. This is // used by AllocateAndStart to query camera info and create the camera device. - const scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + CameraHalDelegate* camera_hal_delegate_; // A reference to the thread that all the VideoCaptureDevice interface methods // are expected to be called on.
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc index c340d37..08ba87d 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -34,6 +34,7 @@ camera_hal_delegate_->Reset(); camera_hal_ipc_thread_.Stop(); + camera_hal_delegate_.reset(); } VideoCaptureErrorOrDevice VideoCaptureDeviceFactoryChromeOS::CreateDevice( @@ -88,7 +89,7 @@ } camera_hal_delegate_ = - new CameraHalDelegate(camera_hal_ipc_thread_.task_runner()); + std::make_unique<CameraHalDelegate>(camera_hal_ipc_thread_.task_runner()); if (!camera_hal_delegate_->RegisterCameraClient()) { LOG(ERROR) << "Failed to register camera client"; return false;
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h index 00e1543..5fad611 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
@@ -56,7 +56,7 @@ // created on the thread on which Init is called. All the Mojo communication // that |camera_hal_delegate_| issues and receives must be sequenced through // |camera_hal_ipc_thread_|. - scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + std::unique_ptr<CameraHalDelegate> camera_hal_delegate_; bool initialized_;
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc index b89fd7e..45e7a285 100644 --- a/media/capture/video/win/video_capture_device_mf_win.cc +++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -1121,6 +1121,8 @@ // event. For the lack of any other events indicating success, we have to wait // for the first video frame to arrive before sending our |OnStarted| event to // |client_|. + // We still need to wait for MF_CAPTURE_ENGINE_PREVIEW_STARTED event to ensure + // that we won't call StopPreview before the preview is started. has_sent_on_started_to_client_ = false; hr = engine_->StartPreview(); if (FAILED(hr)) { @@ -1129,11 +1131,14 @@ return; } + hr = WaitOnCaptureEvent(MF_CAPTURE_ENGINE_PREVIEW_STARTED); + if (SUCCEEDED(hr)) { + is_started_ = true; + } + selected_video_capability_ = std::make_unique<CapabilityWin>(best_match_video_capability); - is_started_ = true; - base::UmaHistogramEnumeration( "Media.VideoCapture.Win.Device.InternalPixelFormat", best_match_video_capability.source_pixel_format, @@ -1152,8 +1157,12 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::AutoLock lock(lock_); - if (is_started_ && engine_) - engine_->StopPreview(); + if (is_started_ && engine_) { + HRESULT hr = engine_->StopPreview(); + if (SUCCEEDED(hr)) { + WaitOnCaptureEvent(MF_CAPTURE_ENGINE_PREVIEW_STOPPED); + } + } is_started_ = false; client_.reset(); @@ -1738,16 +1747,22 @@ media_event->GetStatus(&hr); media_event->GetExtendedType(&capture_event_guid); - // TODO(http://crbug.com/1093521): Add cases for Start - // MF_CAPTURE_ENGINE_PREVIEW_STARTED and MF_CAPTURE_ENGINE_PREVIEW_STOPPED // When MF_CAPTURE_ENGINE_ERROR is returned the captureengine object is no // longer valid. if (capture_event_guid == MF_CAPTURE_ENGINE_ERROR || FAILED(hr)) { + last_error_hr_ = hr; capture_error_.Signal(); // There should always be a valid error hr = SUCCEEDED(hr) ? E_UNEXPECTED : hr; - } else if (capture_event_guid == MF_CAPTURE_ENGINE_INITIALIZED) { - capture_initialize_.Signal(); + } else { + if (capture_event_guid == MF_CAPTURE_ENGINE_INITIALIZED) { + capture_initialize_.Signal(); + } else if (capture_event_guid == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) { + capture_stopped_.Signal(); + } else if (capture_event_guid == MF_CAPTURE_ENGINE_PREVIEW_STARTED) { + capture_started_.Signal(); + } + return; } // Lock is taken after events are signalled, because if the capture @@ -1824,10 +1839,12 @@ HRESULT hr = S_OK; HANDLE events[] = {nullptr, capture_error_.handle()}; - // TODO(http://crbug.com/1093521): Add cases for Start - // MF_CAPTURE_ENGINE_PREVIEW_STARTED and MF_CAPTURE_ENGINE_PREVIEW_STOPPED if (capture_event_guid == MF_CAPTURE_ENGINE_INITIALIZED) { events[0] = capture_initialize_.handle(); + } else if (capture_event_guid == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) { + events[0] = capture_stopped_.handle(); + } else if (capture_event_guid == MF_CAPTURE_ENGINE_PREVIEW_STARTED) { + events[0] = capture_started_.handle(); } else { // no registered event handle for the event requested hr = E_NOTIMPL; @@ -1845,7 +1862,10 @@ LogError(FROM_HERE, hr); break; default: - hr = E_UNEXPECTED; + hr = last_error_hr_; + if (SUCCEEDED(hr)) { + hr = MF_E_UNEXPECTED; + } LogError(FROM_HERE, hr); break; }
diff --git a/media/capture/video/win/video_capture_device_mf_win.h b/media/capture/video/win/video_capture_device_mf_win.h index b788812d..1c2ec4e 100644 --- a/media/capture/video/win/video_capture_device_mf_win.h +++ b/media/capture/video/win/video_capture_device_mf_win.h
@@ -181,6 +181,9 @@ base::queue<TakePhotoCallback> video_stream_take_photo_callbacks_; base::WaitableEvent capture_initialize_; base::WaitableEvent capture_error_; + base::WaitableEvent capture_stopped_; + base::WaitableEvent capture_started_; + HRESULT last_error_hr_ = S_OK; scoped_refptr<DXGIDeviceManager> dxgi_device_manager_; absl::optional<int> camera_rotation_; VideoCaptureParams params_;
diff --git a/media/capture/video/win/video_capture_device_mf_win_unittest.cc b/media/capture/video/win/video_capture_device_mf_win_unittest.cc index 1c0eefb..99b2e57d 100644 --- a/media/capture/video/win/video_capture_device_mf_win_unittest.cc +++ b/media/capture/video/win/video_capture_device_mf_win_unittest.cc
@@ -568,6 +568,7 @@ IFACEMETHODIMP StartPreview(void) override { OnStartPreview(); + FireCaptureEvent(MF_CAPTURE_ENGINE_PREVIEW_STARTED, S_OK); return S_OK; } @@ -575,6 +576,7 @@ IFACEMETHODIMP StopPreview(void) override { OnStopPreview(); + FireCaptureEvent(MF_CAPTURE_ENGINE_PREVIEW_STOPPED, S_OK); return S_OK; }
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc index ac4cca3..7cd58a2 100644 --- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc +++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -990,7 +990,8 @@ return MF_E_INVALID_STREAM_DATA; } - if (gmb->GetType() == gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE) { + if (gmb->GetType() == gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE && + dxgi_device_manager_ != nullptr) { return PopulateInputSampleBufferGpu(std::move(frame)); } @@ -1087,6 +1088,7 @@ DCHECK(frame->HasGpuMemoryBuffer()); DCHECK_EQ(frame->GetGpuMemoryBuffer()->GetType(), gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE); + DCHECK(dxgi_device_manager_); gfx::GpuMemoryBufferHandle buffer_handle = frame->GetGpuMemoryBuffer()->CloneHandle();
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn index dbac61f9..648df0e 100644 --- a/media/mojo/mojom/BUILD.gn +++ b/media/mojo/mojom/BUILD.gn
@@ -167,6 +167,10 @@ mojom = "media.mojom.AudioProcessingSettings" cpp = "::media::AudioProcessingSettings" }, + { + mojom = "media.mojom.AudioProcessingStats" + cpp = "::media::AudioProcessingStats" + }, ] traits_headers = [ "audio_processing_mojom_traits.h" ] traits_sources = [ "audio_processing_mojom_traits.cc" ]
diff --git a/media/mojo/mojom/audio_processing.mojom b/media/mojo/mojom/audio_processing.mojom index ca7756e..b5ede7e8 100644 --- a/media/mojo/mojom/audio_processing.mojom +++ b/media/mojo/mojom/audio_processing.mojom
@@ -4,7 +4,19 @@ module media.mojom; -import "mojo/public/mojom/base/file.mojom"; +// Stats from software audio processing in the audio service. Are passed upon +// request from the renderer, see AudioProcessorControls::GetStats() in this +// file. +struct AudioProcessingStats { + + // TODO(https://crbug.com/657632): Numeric values cannot be optional, so add + // flags for each of them. + bool has_echo_return_loss; + double echo_return_loss; + + bool has_echo_return_loss_enhancement; + double echo_return_loss_enhancement; +}; // Settings for the software audio processing performed in the audio service. // The settings are determined in the renderer from media constraints passed by @@ -23,10 +35,23 @@ }; // This interface is hosted in the audio service and called from the renderer. -// It's only used when the audio processing is performed in the audio service. +// It is only used when the audio processing is performed in the audio service. interface AudioProcessorControls { - // TODO(crbug.com/1284652): Add methods once this interface is plumbed through - // all layers. + + // Request the latest stats from the audio processor. At the farthest level, + // this is triggered by calls from JavaScript, through some levels of + // indirection. (See: https://www.w3.org/TR/webrtc-stats/). Since there are no + // guarantees in the standard about the rate at which stats change, it is + // reasonable to let multiple user-facing calls result in just one call to + // this function. + GetStats() => (AudioProcessingStats stats); + + // Sets a preferred number of capture audio channels. This allows the audio + // processor to avoid unnecessary computational load when the number of input + // audio channels exceeds what is used by the input consumers. + // Values less than 1 and greater than the input stream capacity are adjusted + // to the nearest valid number. + SetPreferredNumCaptureChannels(int32 num_preferred_channels); }; struct AudioProcessingConfig {
diff --git a/media/mojo/mojom/audio_processing_mojom_traits.cc b/media/mojo/mojom/audio_processing_mojom_traits.cc index 2f4a860..62d57ac1 100644 --- a/media/mojo/mojom/audio_processing_mojom_traits.cc +++ b/media/mojo/mojom/audio_processing_mojom_traits.cc
@@ -5,6 +5,22 @@ #include "media/mojo/mojom/audio_processing_mojom_traits.h" namespace mojo { +namespace { +// Deserializes has_field and field into a absl::optional. +#define DESERIALIZE_INTO_OPT(field) \ + if (input.has_##field()) \ + out_stats->field = input.field() +} // namespace + +// static +bool StructTraits<media::mojom::AudioProcessingStatsDataView, + media::AudioProcessingStats>:: + Read(media::mojom::AudioProcessingStatsDataView input, + media::AudioProcessingStats* out_stats) { + DESERIALIZE_INTO_OPT(echo_return_loss); + DESERIALIZE_INTO_OPT(echo_return_loss_enhancement); + return true; +} // static bool StructTraits<media::mojom::AudioProcessingSettingsDataView,
diff --git a/media/mojo/mojom/audio_processing_mojom_traits.h b/media/mojo/mojom/audio_processing_mojom_traits.h index 8f42535..6bd436f4 100644 --- a/media/mojo/mojom/audio_processing_mojom_traits.h +++ b/media/mojo/mojom/audio_processing_mojom_traits.h
@@ -5,12 +5,37 @@ #define MEDIA_MOJO_MOJOM_AUDIO_PROCESSING_MOJOM_TRAITS_H_ #include "media/base/audio_processing.h" + #include "media/mojo/mojom/audio_processing.mojom.h" #include "mojo/public/cpp/bindings/struct_traits.h" namespace mojo { template <> +struct StructTraits<media::mojom::AudioProcessingStatsDataView, + media::AudioProcessingStats> { + public: + static bool has_echo_return_loss(const media::AudioProcessingStats& input) { + return input.echo_return_loss.has_value(); + } + static double echo_return_loss(const media::AudioProcessingStats& input) { + return input.echo_return_loss.value_or(0.0); + } + + static bool has_echo_return_loss_enhancement( + const media::AudioProcessingStats& input) { + return input.echo_return_loss_enhancement.has_value(); + } + static double echo_return_loss_enhancement( + const media::AudioProcessingStats& input) { + return input.echo_return_loss_enhancement.value_or(0.0); + } + + static bool Read(media::mojom::AudioProcessingStatsDataView input, + media::AudioProcessingStats* out_stats); +}; + +template <> struct StructTraits<media::mojom::AudioProcessingSettingsDataView, media::AudioProcessingSettings> { public:
diff --git a/media/mojo/mojom/audio_processing_mojom_traits_unittest.cc b/media/mojo/mojom/audio_processing_mojom_traits_unittest.cc index 0e10cf1..c95c6330 100644 --- a/media/mojo/mojom/audio_processing_mojom_traits_unittest.cc +++ b/media/mojo/mojom/audio_processing_mojom_traits_unittest.cc
@@ -11,21 +11,7 @@ namespace media { -namespace { - -class AudioProcessingMojomTraitsTest : public testing::Test { - public: - AudioProcessingMojomTraitsTest() = default; - - AudioProcessingMojomTraitsTest(const AudioProcessingMojomTraitsTest&) = - delete; - AudioProcessingMojomTraitsTest& operator=( - const AudioProcessingMojomTraitsTest&) = delete; -}; - -} // namespace - -TEST_F(AudioProcessingMojomTraitsTest, AudioProcessingSettings) { +TEST(AudioProcessingMojomTraitsTest, AudioProcessingSettings) { AudioProcessingSettings settings_in; AudioProcessingSettings settings_out; @@ -54,4 +40,29 @@ EXPECT_EQ(settings_in, settings_out); } +TEST(AudioProcessingMojomTraitsTest, AudioProcessingStats) { + AudioProcessingStats stats_in; + AudioProcessingStats stats_out; + + mojo::test::SerializeAndDeserialize<media::mojom::AudioProcessingStats>( + stats_in, stats_out); + + EXPECT_EQ(stats_in.echo_return_loss, stats_out.echo_return_loss); + EXPECT_EQ(stats_in.echo_return_loss_enhancement, + stats_out.echo_return_loss_enhancement); + + // Set all fields to non-default values. + ASSERT_FALSE(stats_in.echo_return_loss); + ASSERT_FALSE(stats_in.echo_return_loss_enhancement); + stats_in.echo_return_loss = 1.0; + stats_in.echo_return_loss_enhancement = 2.0; + + mojo::test::SerializeAndDeserialize<media::mojom::AudioProcessingStats>( + stats_in, stats_out); + + EXPECT_EQ(stats_in.echo_return_loss, stats_out.echo_return_loss); + EXPECT_EQ(stats_in.echo_return_loss_enhancement, + stats_out.echo_return_loss_enhancement); +} + } // namespace media
diff --git a/media/mojo/mojom/video_frame_metadata_mojom_traits.h b/media/mojo/mojom/video_frame_metadata_mojom_traits.h index 16a24aaa..b87508d 100644 --- a/media/mojo/mojom/video_frame_metadata_mojom_traits.h +++ b/media/mojo/mojom/video_frame_metadata_mojom_traits.h
@@ -160,6 +160,8 @@ media::VideoFrameMetadata* output); }; +#undef GENERATE_OPT_SERIALIZATION + } // namespace mojo #endif // MEDIA_MOJO_MOJOM_VIDEO_FRAME_METADATA_MOJOM_TRAITS_H_
diff --git a/media/webrtc/audio_processor.cc b/media/webrtc/audio_processor.cc index c1456671..338f704 100644 --- a/media/webrtc/audio_processor.cc +++ b/media/webrtc/audio_processor.cc
@@ -380,7 +380,8 @@ } webrtc::AudioProcessingStats AudioProcessor::GetStats() { - DCHECK(webrtc_audio_processing_); + if (!webrtc_audio_processing_) + return {}; return webrtc_audio_processing_->GetStatistics(); }
diff --git a/media/webrtc/audio_processor.h b/media/webrtc/audio_processor.h index 4e60844..572ca95 100644 --- a/media/webrtc/audio_processor.h +++ b/media/webrtc/audio_processor.h
@@ -123,8 +123,7 @@ // Stops any ongoing aecdump. void OnStopDump(); - // Returns statistics from the WebRTC audio processing module. Requires that - // WebRTC audio processing is enabled. + // Returns any available statistics from the WebRTC audio processing module. // May be called on any thread. webrtc::AudioProcessingStats GetStats();
diff --git a/mojo/core/data_pipe_consumer_dispatcher.cc b/mojo/core/data_pipe_consumer_dispatcher.cc index 4e76209..05b95c54 100644 --- a/mojo/core/data_pipe_consumer_dispatcher.cc +++ b/mojo/core/data_pipe_consumer_dispatcher.cc
@@ -14,6 +14,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/numerics/checked_math.h" #include "base/trace_event/trace_event.h" #include "mojo/core/core.h" #include "mojo/core/data_pipe_control_message.h" @@ -583,8 +584,10 @@ TRACE_EVENT0("ipc", "DataPipeConsumerDispatcher received DATA_WAS_WRITTEN"); - if (static_cast<size_t>(bytes_available_) + m->num_bytes > - options_.capacity_num_bytes) { + uint32_t new_bytes_available; + if (!base::CheckAdd(bytes_available_, m->num_bytes) + .AssignIfValid(&new_bytes_available) || + new_bytes_available > options_.capacity_num_bytes) { DLOG(ERROR) << "Producer claims to have written too many bytes."; peer_closed_ = true; break; @@ -594,7 +597,7 @@ << m->num_bytes << " bytes were written. [control_port=" << control_port_.name() << "]"; - bytes_available_ += m->num_bytes; + bytes_available_ = new_bytes_available; } } while (message_event); }
diff --git a/mojo/core/data_pipe_producer_dispatcher.cc b/mojo/core/data_pipe_producer_dispatcher.cc index 65f7261..f4281d9 100644 --- a/mojo/core/data_pipe_producer_dispatcher.cc +++ b/mojo/core/data_pipe_producer_dispatcher.cc
@@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/numerics/checked_math.h" #include "base/trace_event/trace_event.h" #include "mojo/core/configuration.h" #include "mojo/core/core.h" @@ -530,8 +531,10 @@ TRACE_EVENT0("ipc", "DataPipeProducerDispatcher received DATA_WAS_READ"); - if (static_cast<size_t>(available_capacity_) + m->num_bytes > - options_.capacity_num_bytes) { + uint32_t new_available_capacity; + if (!base::CheckAdd(available_capacity_, m->num_bytes) + .AssignIfValid(&new_available_capacity) || + new_available_capacity > options_.capacity_num_bytes) { DLOG(ERROR) << "Consumer claims to have read too many bytes."; break; } @@ -541,7 +544,7 @@ << " bytes were read. [control_port=" << control_port_.name() << "]"; - available_capacity_ += m->num_bytes; + available_capacity_ = new_available_capacity; } } while (message_event); }
diff --git a/sandbox/policy/BUILD.gn b/sandbox/policy/BUILD.gn index b412c8d..ec6a1ab 100644 --- a/sandbox/policy/BUILD.gn +++ b/sandbox/policy/BUILD.gn
@@ -59,6 +59,8 @@ "linux/bpf_print_compositor_policy_linux.h", "linux/bpf_renderer_policy_linux.cc", "linux/bpf_renderer_policy_linux.h", + "linux/bpf_screen_ai_policy_linux.cc", + "linux/bpf_screen_ai_policy_linux.h", "linux/bpf_service_policy_linux.cc", "linux/bpf_service_policy_linux.h", "linux/bpf_speech_recognition_policy_linux.cc",
diff --git a/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc b/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc new file mode 100644 index 0000000..d10fb1a2 --- /dev/null +++ b/sandbox/policy/linux/bpf_screen_ai_policy_linux.cc
@@ -0,0 +1,47 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/policy/linux/bpf_screen_ai_policy_linux.h" + +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" +#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" +#include "sandbox/linux/system_headers/linux_syscalls.h" +#include "sandbox/policy/linux/sandbox_linux.h" + +using sandbox::bpf_dsl::Allow; +using sandbox::bpf_dsl::Arg; +using sandbox::bpf_dsl::Error; +using sandbox::bpf_dsl::If; +using sandbox::bpf_dsl::ResultExpr; + +namespace sandbox::policy { + +ScreenAIProcessPolicy::ScreenAIProcessPolicy() = default; +ScreenAIProcessPolicy::~ScreenAIProcessPolicy() = default; + +ResultExpr ScreenAIProcessPolicy::EvaluateSyscall( + int system_call_number) const { + auto* sandbox_linux = SandboxLinux::GetInstance(); + if (sandbox_linux->ShouldBrokerHandleSyscall(system_call_number)) + return sandbox_linux->HandleViaBroker(system_call_number); + + switch (system_call_number) { + case __NR_getitimer: + case __NR_setitimer: { + const Arg<int> which(0); + return If(which == ITIMER_PROF, Allow()).Else(Error(EPERM)); + } + case __NR_get_mempolicy: { + const Arg<unsigned long> which(4); + return If(which == 0, Allow()).Else(Error(EPERM)); + } + case __NR_sched_getaffinity: + return RestrictSchedTarget(GetPolicyPid(), system_call_number); + + default: + return BPFBasePolicy::EvaluateSyscall(system_call_number); + } +} + +} // namespace sandbox::policy
diff --git a/sandbox/policy/linux/bpf_screen_ai_policy_linux.h b/sandbox/policy/linux/bpf_screen_ai_policy_linux.h new file mode 100644 index 0000000..c9df6f2 --- /dev/null +++ b/sandbox/policy/linux/bpf_screen_ai_policy_linux.h
@@ -0,0 +1,29 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_POLICY_LINUX_BPF_SCREEN_AI_POLICY_LINUX_H_ +#define SANDBOX_POLICY_LINUX_BPF_SCREEN_AI_POLICY_LINUX_H_ + +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" +#include "sandbox/policy/linux/bpf_base_policy_linux.h" + +namespace sandbox::policy { + +// The process policy for the sandboxed utility process that loads the Screen AI +// on-device library. +class SANDBOX_POLICY_EXPORT ScreenAIProcessPolicy : public BPFBasePolicy { + public: + ScreenAIProcessPolicy(); + + ScreenAIProcessPolicy(const ScreenAIProcessPolicy&) = delete; + ScreenAIProcessPolicy& operator=(const ScreenAIProcessPolicy&) = delete; + + ~ScreenAIProcessPolicy() override; + + bpf_dsl::ResultExpr EvaluateSyscall(int system_call_number) const override; +}; + +} // namespace sandbox::policy + +#endif // SANDBOX_POLICY_LINUX_BPF_SCREEN_AI_POLICY_LINUX_H_
diff --git a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc index 62c4551f..11819b5 100644 --- a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc +++ b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
@@ -48,6 +48,7 @@ #include "sandbox/policy/linux/bpf_print_backend_policy_linux.h" #include "sandbox/policy/linux/bpf_print_compositor_policy_linux.h" #include "sandbox/policy/linux/bpf_renderer_policy_linux.h" +#include "sandbox/policy/linux/bpf_screen_ai_policy_linux.h" #include "sandbox/policy/linux/bpf_service_policy_linux.h" #include "sandbox/policy/linux/bpf_speech_recognition_policy_linux.h" #include "sandbox/policy/linux/bpf_utility_policy_linux.h" @@ -190,6 +191,8 @@ return std::make_unique<ServiceProcessPolicy>(); case sandbox::mojom::Sandbox::kSpeechRecognition: return std::make_unique<SpeechRecognitionProcessPolicy>(); + case sandbox::mojom::Sandbox::kScreenAI: + return std::make_unique<ScreenAIProcessPolicy>(); #if BUILDFLAG(IS_CHROMEOS_ASH) case sandbox::mojom::Sandbox::kHardwareVideoDecoding: // TODO(b/195769334): we're using the GPU process sandbox policy for now @@ -259,6 +262,7 @@ case sandbox::mojom::Sandbox::kLibassistant: #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) #endif // BUILDFLAG(IS_CHROMEOS_ASH) + case sandbox::mojom::Sandbox::kScreenAI: case sandbox::mojom::Sandbox::kAudio: case sandbox::mojom::Sandbox::kService: case sandbox::mojom::Sandbox::kServiceWithJit:
diff --git a/sandbox/policy/mojom/BUILD.gn b/sandbox/policy/mojom/BUILD.gn index ebff0901..c914dba7 100644 --- a/sandbox/policy/mojom/BUILD.gn +++ b/sandbox/policy/mojom/BUILD.gn
@@ -19,7 +19,10 @@ enabled_features += [ "enable_plugins" ] } if (is_linux || is_chromeos) { - enabled_features += [ "has_zygote" ] + enabled_features += [ + "has_zygote", + "is_linux_or_chromeos", + ] } if (enable_cros_libassistant) { enabled_features += [ "enable_cros_libassistant" ]
diff --git a/sandbox/policy/mojom/sandbox.mojom b/sandbox/policy/mojom/sandbox.mojom index 916ead93..b4079d9 100644 --- a/sandbox/policy/mojom/sandbox.mojom +++ b/sandbox/policy/mojom/sandbox.mojom
@@ -59,6 +59,10 @@ // Like kUtility but allows loading of speech recognition libraries. kSpeechRecognition, + // Like kUtility but allows loading of screen AI library. + [EnableIf=is_linux_or_chromeos] + kScreenAI, + // The PPAPI plugin process. [EnableIf=enable_plugins] kPpapi,
diff --git a/sandbox/policy/sandbox_type.cc b/sandbox/policy/sandbox_type.cc index 944e9ba..7d457bf 100644 --- a/sandbox/policy/sandbox_type.cc +++ b/sandbox/policy/sandbox_type.cc
@@ -72,6 +72,7 @@ #endif // // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) case Sandbox::kZygoteIntermediateSandbox: + case Sandbox::kScreenAI: #endif case Sandbox::kSpeechRecognition: return false; @@ -144,6 +145,9 @@ #if BUILDFLAG(IS_MAC) case Sandbox::kMirroring: #endif // BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + case Sandbox::kScreenAI: +#endif case Sandbox::kSpeechRecognition: DCHECK(command_line->GetSwitchValueASCII(switches::kProcessType) == switches::kUtilityProcess); @@ -257,6 +261,10 @@ return switches::kServiceSandboxWithJit; case Sandbox::kSpeechRecognition: return switches::kSpeechRecognitionSandbox; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + case Sandbox::kScreenAI: + return switches::kScreenAISandbox; +#endif #if BUILDFLAG(IS_WIN) case Sandbox::kXrCompositing: return switches::kXrCompositingSandbox; @@ -355,6 +363,10 @@ return Sandbox::kAudio; if (sandbox_string == switches::kSpeechRecognitionSandbox) return Sandbox::kSpeechRecognition; +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + if (sandbox_string == switches::kScreenAISandbox) + return Sandbox::kScreenAI; +#endif #if BUILDFLAG(IS_FUCHSIA) if (sandbox_string == switches::kVideoCaptureSandbox) return Sandbox::kVideoCapture;
diff --git a/sandbox/policy/switches.cc b/sandbox/policy/switches.cc index 4ad0ff3..6b20a9564 100644 --- a/sandbox/policy/switches.cc +++ b/sandbox/policy/switches.cc
@@ -36,6 +36,7 @@ const char kAudioSandbox[] = "audio"; const char kServiceSandbox[] = "service"; const char kServiceSandboxWithJit[] = "service_with_jit"; +const char kScreenAISandbox[] = "screen_ai"; const char kSpeechRecognitionSandbox[] = "speech_recognition"; const char kVideoCaptureSandbox[] = "video_capture";
diff --git a/sandbox/policy/switches.h b/sandbox/policy/switches.h index d07e692..4586cb2 100644 --- a/sandbox/policy/switches.h +++ b/sandbox/policy/switches.h
@@ -37,6 +37,7 @@ SANDBOX_POLICY_EXPORT extern const char kAudioSandbox[]; SANDBOX_POLICY_EXPORT extern const char kServiceSandbox[]; SANDBOX_POLICY_EXPORT extern const char kServiceSandboxWithJit[]; +SANDBOX_POLICY_EXPORT extern const char kScreenAISandbox[]; SANDBOX_POLICY_EXPORT extern const char kSpeechRecognitionSandbox[]; SANDBOX_POLICY_EXPORT extern const char kVideoCaptureSandbox[];
diff --git a/services/audio/audio_processor_handler.cc b/services/audio/audio_processor_handler.cc index 488b6456..669e7502 100644 --- a/services/audio/audio_processor_handler.cc +++ b/services/audio/audio_processor_handler.cc
@@ -4,16 +4,27 @@ #include "services/audio/audio_processor_handler.h" +#include "base/cxx17_backports.h" #include "base/trace_event/trace_event.h" #include "media/base/audio_bus.h" +#include "media/base/audio_parameters.h" namespace audio { AudioProcessorHandler::AudioProcessorHandler( const media::AudioProcessingSettings& settings, + const media::AudioParameters& audio_format, + LogCallback log_callback, + DeliverProcessedAudioCallback deliver_processed_audio_callback, mojo::PendingReceiver<media::mojom::AudioProcessorControls> controls_receiver) - : receiver_(this, std::move(controls_receiver)) { + : audio_processor_(std::make_unique<media::AudioProcessor>( + std::move(deliver_processed_audio_callback), + std::move(log_callback), + settings, + /*input_format=*/audio_format, + /*output_format=*/audio_format)), + receiver_(this, std::move(controls_receiver)) { DCHECK(settings.NeedAudioModification()); } @@ -21,11 +32,46 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); } +void AudioProcessorHandler::ProcessCapturedAudio( + const media::AudioBus& audio_source, + base::TimeTicks audio_capture_time, + double volume, + bool key_pressed) { + const int num_preferred_channels = + num_preferred_channels_.load(std::memory_order_acquire); + audio_processor_->ProcessCapturedAudio(audio_source, audio_capture_time, + num_preferred_channels, volume, + key_pressed); +} + void AudioProcessorHandler::OnPlayoutData(const media::AudioBus& audio_bus, int sample_rate, base::TimeDelta delay) { TRACE_EVENT2("audio", "AudioProcessorHandler::OnPlayoutData", " this ", static_cast<void*>(this), "delay", delay.InMillisecondsF()); - // TODO(https://crbug.com/1215061): Forward playout data to audio processor. + // TODO(https://crbug.com/1292037): Ensure that the buffer size is supported, + // either through interface guarantees or rebuffering. + CHECK_EQ(audio_bus.frames(), sample_rate / 100); + audio_processor_->OnPlayoutData(audio_bus, sample_rate, delay); +} + +void AudioProcessorHandler::GetStats(GetStatsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); + media::AudioProcessingStats stats; + const webrtc::AudioProcessingStats processor_stats = + audio_processor_->GetStats(); + stats.echo_return_loss = processor_stats.echo_return_loss; + stats.echo_return_loss_enhancement = + processor_stats.echo_return_loss_enhancement; + std::move(callback).Run(stats); +} + +void AudioProcessorHandler::SetPreferredNumCaptureChannels( + int32_t num_preferred_channels) { + DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); + num_preferred_channels = base::clamp( + num_preferred_channels, 1, audio_processor_->OutputFormat().channels()); + num_preferred_channels_.store(num_preferred_channels, + std::memory_order_release); } } // namespace audio
diff --git a/services/audio/audio_processor_handler.h b/services/audio/audio_processor_handler.h index 7d9a146d..1dd53ce 100644 --- a/services/audio/audio_processor_handler.h +++ b/services/audio/audio_processor_handler.h
@@ -5,44 +5,111 @@ #ifndef SERVICES_AUDIO_AUDIO_PROCESSOR_HANDLER_H_ #define SERVICES_AUDIO_AUDIO_PROCESSOR_HANDLER_H_ +#include <atomic> + #include "base/sequence_checker.h" #include "media/base/audio_processing.h" #include "media/mojo/mojom/audio_processing.mojom.h" +#include "media/webrtc/audio_processor.h" #include "mojo/public/cpp/bindings/receiver.h" #include "services/audio/reference_output.h" namespace media { class AudioBus; +class AudioParameters; } // namespace media namespace audio { -// Encapsulates audio processing effects in the audio process. -// TODO(https://crbug.com/1215061): Create and manage a media::AudioProcessor. -// TODO(https://crbug.com/1284652): Add methods to AudioProcessorControls and -// implement them. -// This class is currently a no-op implementation of ReferenceOutput::Listener. +// Encapsulates audio processing effects in the audio process, using a +// media::AudioProcessor. Forwards capture audio, playout audio, and +// AudioProcessorControls calls to the processor. +// +// The class can be operated on by three different sequences: +// - An owning sequence, which performs construction, destruction, getting +// stats, and similar control flow. +// - A capture thread, which calls ProcessCapturedAudio(). +// - A playout thread, which calls OnPlayoutData(). +// +// All functions should be called on the owning thread, unless otherwise +// specified. It is the responsibility of the owner to ensure that the playout +// thread and capture thread stop calling into the AudioProcessorHandler before +// destruction. class AudioProcessorHandler final : public ReferenceOutput::Listener, public media::mojom::AudioProcessorControls { public: + using DeliverProcessedAudioCallback = + media::AudioProcessor::DeliverProcessedAudioCallback; + + using LogCallback = base::RepeatingCallback<void(base::StringPiece)>; + + // |settings| specifies which audio processing effects to apply. Some effect + // must be required, i.e. the AudioProcessorHandler may only be created if + // |settings.NeedAudioModification()| is true. + // |audio_format| specifies the audio format, both before and after + // processing. If |settings|.NeedWebrtcAudioProcessing(), then + // |audio_format|.frames_per_buffer() must specify 10 ms. + // TODO(https://crbug.com/1298056): Support different input vs output format + // to avoid unnecessary resampling. + // |log_callback| is used for logging messages on the owning sequence. + // |deliver_processed_audio_callback| is used to deliver processed audio + // provided to ProcessCapturedAudio(). + // |controls_receiver| calls are received by the AudioProcessorHandler. explicit AudioProcessorHandler( const media::AudioProcessingSettings& settings, + const media::AudioParameters& audio_format, + LogCallback log_callback, + DeliverProcessedAudioCallback deliver_processed_audio_callback, mojo::PendingReceiver<media::mojom::AudioProcessorControls> controls_receiver); AudioProcessorHandler(const AudioProcessorHandler&) = delete; AudioProcessorHandler& operator=(const AudioProcessorHandler&) = delete; ~AudioProcessorHandler() final; + // Processes and delivers capture audio. + // See media::AudioProcessor::ProcessCapturedAudio for API details. + // Called on the capture thread. + void ProcessCapturedAudio(const media::AudioBus& audio_source, + base::TimeTicks audio_capture_time, + double volume, + bool key_pressed); + private: + // Used in the mojom::AudioProcessorControls implementation. + using GetStatsCallback = + base::OnceCallback<void(const media::AudioProcessingStats& stats)>; + // ReferenceOutput::Listener implementation. + // Called on the playout thread. + // TODO(https://crbug.com/1292037): Currently needs 10 ms of audio per call, + // but this is not guaranteed in the interface. void OnPlayoutData(const media::AudioBus& audio_bus, int sample_rate, base::TimeDelta delay) final; + // mojom::AudioProcessorControls implementation. + void GetStats(GetStatsCallback callback) final; + void SetPreferredNumCaptureChannels(int32_t num_preferred_channels) final; + SEQUENCE_CHECKER(owning_sequence_); - mojo::Receiver<media::mojom::AudioProcessorControls> receiver_; + // The audio processor is accessed on all threads (OS capture thread, OS + // playout thread, owning sequence) and created / destroyed on the owning + // sequence. + const std::unique_ptr<media::AudioProcessor> audio_processor_; + + mojo::Receiver<media::mojom::AudioProcessorControls> receiver_ + GUARDED_BY_CONTEXT(owning_sequence_); + + // The number of channels preferred by consumers of the captured audio. + // Initially, consumers are assumed to use mono audio in order to 1) avoid + // unnecessary computational load and 2) preserve the historical default. + // Written from the owning thread in SetPreferredNumCaptureChannels and read + // from the real-time capture thread in ProcessCapturedAudio. + // We use an atomic instead of a lock in order to avoid blocking on the + // real-time thread. + std::atomic<int32_t> num_preferred_channels_ = 1; }; } // namespace audio
diff --git a/services/audio/input_controller.cc b/services/audio/input_controller.cc index be1037e1..e05e0d08 100644 --- a/services/audio/input_controller.cc +++ b/services/audio/input_controller.cc
@@ -220,7 +220,7 @@ weak_this_ = weak_ptr_factory_.GetWeakPtr(); #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION) - MaybeSetUpAudioProcessing(std::move(processing_config), + MaybeSetUpAudioProcessing(std::move(processing_config), params, device_output_listener); #endif @@ -233,6 +233,7 @@ #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION) void InputController::MaybeSetUpAudioProcessing( media::mojom::AudioProcessingConfigPtr processing_config, + const media::AudioParameters& params, DeviceOutputListener* device_output_listener) { if (!device_output_listener) return; @@ -245,8 +246,14 @@ ReferenceOutput::Listener* output_listener = nullptr; if (processing_config && processing_config->settings.NeedAudioModification()) { + // Unretained() is safe, since |this| and |event_handler_| outlive + // |audio_processor_handler_|. audio_processor_handler_ = std::make_unique<AudioProcessorHandler>( - processing_config->settings, + processing_config->settings, params, + base::BindRepeating(&EventHandler::OnLog, + base::Unretained(event_handler_)), + base::BindRepeating(&InputController::DeliverProcessedAudio, + base::Unretained(this)), std::move(processing_config->controls_receiver)); if (processing_config->settings.NeedPlayoutReference()) output_listener = audio_processor_handler_.get(); @@ -296,6 +303,7 @@ // Create the InputController object and ensure that it runs on // the audio-manager thread. + // Using `new` to access a non-public constructor. std::unique_ptr<InputController> controller = base::WrapUnique(new InputController( event_handler, sync_writer, user_input_monitor, activity_monitor, @@ -725,7 +733,15 @@ base::TimeTicks capture_time, double volume) { const bool key_pressed = CheckForKeyboardInput(); - sync_writer_->Write(source, volume, key_pressed, capture_time); +#if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION) + if (audio_processor_handler_) { + audio_processor_handler_->ProcessCapturedAudio(*source, capture_time, + volume, key_pressed); + } else +#endif + { + sync_writer_->Write(source, volume, key_pressed, capture_time); + } float average_power_dbfs; int mic_volume_percent; @@ -740,6 +756,22 @@ } } +#if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION) +void InputController::DeliverProcessedAudio(const media::AudioBus& audio_bus, + base::TimeTicks audio_capture_time, + absl::optional<double> new_volume) { + // When processing is performed in the audio service, the consumer is not + // expected to use the input volume and keypress information. + sync_writer_->Write(&audio_bus, /*volume=*/1.0, + /*key_pressed=*/false, audio_capture_time); + if (new_volume) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&InputController::SetVolume, weak_this_, *new_volume)); + } +} +#endif + // static InputController::StreamType InputController::ParamsToStreamType( const media::AudioParameters& params) {
diff --git a/services/audio/input_controller.h b/services/audio/input_controller.h index 222c714..eecd5184 100644 --- a/services/audio/input_controller.h +++ b/services/audio/input_controller.h
@@ -264,7 +264,13 @@ // processing components. void MaybeSetUpAudioProcessing( media::mojom::AudioProcessingConfigPtr processing_config, + const media::AudioParameters& params, DeviceOutputListener* device_output_listener); + + // Used as a callback for |audio_processor_handler_|. + void DeliverProcessedAudio(const media::AudioBus& audio_bus, + base::TimeTicks audio_capture_time, + absl::optional<double> new_volume); #endif static StreamType ParamsToStreamType(const media::AudioParameters& params);
diff --git a/services/audio/input_controller_unittest.cc b/services/audio/input_controller_unittest.cc index 3a809f5..65b9a2f 100644 --- a/services/audio/input_controller_unittest.cc +++ b/services/audio/input_controller_unittest.cc
@@ -24,11 +24,11 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using base::WaitableEvent; using ::testing::_; using ::testing::AtLeast; using ::testing::Exactly; using ::testing::InvokeWithoutArgs; +using ::testing::NiceMock; using ::testing::NotNull; using ::testing::StrictMock; @@ -40,8 +40,6 @@ const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; const int kSamplesPerPacket = kSampleRate / 100; -const double kMaxVolume = 1.0; - // InputController will poll once every second, so wait at most a bit // more than that for the callbacks. constexpr base::TimeDelta kOnMutePollInterval = base::Milliseconds(1000); @@ -94,26 +92,6 @@ MOCK_METHOD0(OnInputStreamInactive, void()); }; -class MockAudioInputStream : public media::AudioInputStream { - public: - MockAudioInputStream() {} - ~MockAudioInputStream() override {} - - void Start(AudioInputCallback*) override {} - void Stop() override {} - void Close() override {} - double GetMaxVolume() override { return kMaxVolume; } - double GetVolume() override { return 0; } - bool SetAutomaticGainControl(bool) override { return false; } - bool GetAutomaticGainControl() override { return false; } - bool IsMuted() override { return false; } - void SetOutputDeviceForAec(const std::string&) override {} - - MOCK_METHOD0(Open, media::AudioInputStream::OpenOutcome()); - MOCK_METHOD1(SetVolume, void(double)); -}; - -// Parameter: use audio processing. template <base::test::TaskEnvironment::TimeSource TimeSource = base::test::TaskEnvironment::TimeSource::MOCK_TIME> class TimeSourceInputControllerTest : public ::testing::Test { @@ -157,8 +135,6 @@ MockUserInputMonitor user_input_monitor_; StrictMock<MockInputStreamActivityMonitor> mock_stream_activity_monitor_; media::AudioParameters params_; - MockAudioInputStream stream_; - base::test::ScopedFeatureList audio_processing_feature_; }; using SystemTimeInputControllerTest = TimeSourceInputControllerTest< @@ -245,9 +221,6 @@ // Test that InputController sends OnMute callbacks properly. TEST_F(InputControllerTest, TestOnmutedCallbackInitiallyUnmuted) { - WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - EXPECT_CALL(event_handler_, OnCreated(false)); EXPECT_CALL(sync_writer_, Close()); @@ -270,9 +243,6 @@ } TEST_F(InputControllerTest, TestOnmutedCallbackInitiallyMuted) { - WaitableEvent callback_event(WaitableEvent::ResetPolicy::AUTOMATIC, - WaitableEvent::InitialState::NOT_SIGNALED); - EXPECT_CALL(event_handler_, OnCreated(true)); EXPECT_CALL(sync_writer_, Close()); @@ -301,44 +271,69 @@ MOCK_METHOD1(StopListening, void(ReferenceOutput::Listener*)); }; -class InputControllerTestWithDeviceListener : public InputControllerTest { +template <base::test::TaskEnvironment::TimeSource TimeSource = + base::test::TaskEnvironment::TimeSource::MOCK_TIME> +class TimeSourceInputControllerTestWithDeviceListener + : public TimeSourceInputControllerTest<TimeSource> { protected: void CreateAudioController() final { - controller_ = InputController::Create( - audio_manager_.get(), &event_handler_, &sync_writer_, - &user_input_monitor_, &mock_stream_activity_monitor_, - &device_output_listener_, std::move(processing_config_), params_, - media::AudioDeviceDescription::kDefaultDeviceId, false); + // Must use |this| to access template base class members: + // https://stackoverflow.com/q/4643074 + this->controller_ = InputController::Create( + this->audio_manager_.get(), &this->event_handler_, &this->sync_writer_, + &this->user_input_monitor_, &this->mock_stream_activity_monitor_, + &this->device_output_listener_, std::move(processing_config_), + this->params_, media::AudioDeviceDescription::kDefaultDeviceId, false); } - void SetupProcessingConfig(bool force_need_audio_modification) { - media::AudioProcessingSettings settings; - if (force_need_audio_modification) { - settings.echo_cancellation = true; - } else { - settings.echo_cancellation = false; - settings.noise_suppression = false; - settings.transient_noise_suppression = false; - settings.automatic_gain_control = false; - settings.experimental_automatic_gain_control = false; - settings.high_pass_filter = false; - settings.multi_channel_capture_processing = false; - settings.stereo_mirroring = false; - settings.force_apm_creation = false; - } + enum class AudioProcessingType { + // No effects, audio does not need to be modified. + kNone, + // Effects that modify audio but do not require a playout reference signal. + kWithoutPlayoutReference, + // Effects that require a playout reference signal. + kWithPlayoutReference + }; + void SetupProcessingConfig(AudioProcessingType audio_processing_type) { + media::AudioProcessingSettings settings; + settings.echo_cancellation = false; + settings.noise_suppression = false; + settings.transient_noise_suppression = false; + settings.automatic_gain_control = false; + settings.experimental_automatic_gain_control = false; + settings.high_pass_filter = false; + settings.multi_channel_capture_processing = false; + settings.stereo_mirroring = false; + settings.force_apm_creation = false; + switch (audio_processing_type) { + case AudioProcessingType::kNone: + break; + case AudioProcessingType::kWithoutPlayoutReference: + settings.noise_suppression = true; + break; + case AudioProcessingType::kWithPlayoutReference: + settings.echo_cancellation = true; + break; + } processing_config_ = media::mojom::AudioProcessingConfig::New( remote_controls_.BindNewPipeAndPassReceiver(), settings); } - MockDeviceOutputListener device_output_listener_; + NiceMock<MockDeviceOutputListener> device_output_listener_; media::mojom::AudioProcessingConfigPtr processing_config_; mojo::Remote<media::mojom::AudioProcessorControls> remote_controls_; }; +using SystemTimeInputControllerTestWithDeviceListener = + TimeSourceInputControllerTestWithDeviceListener< + base::test::TaskEnvironment::TimeSource::SYSTEM_TIME>; +using InputControllerTestWithDeviceListener = + TimeSourceInputControllerTestWithDeviceListener<>; + TEST_F(InputControllerTestWithDeviceListener, - CreateWithAudioProcessingConfig_EchoCancellation) { - SetupProcessingConfig(/*force_need_audio_modification=*/true); + CreateWithAudioProcessingConfig_WithSomeEffectsEnabled) { + SetupProcessingConfig(AudioProcessingType::kWithoutPlayoutReference); CreateAudioController(); @@ -358,8 +353,8 @@ } TEST_F(InputControllerTestWithDeviceListener, - CreateWithAudioProcessingConfig_WithoutEchoCancellation) { - SetupProcessingConfig(/*force_need_audio_modification=*/false); + CreateWithAudioProcessingConfig_WithoutEnablingEffects) { + SetupProcessingConfig(AudioProcessingType::kNone); CreateAudioController(); @@ -378,6 +373,26 @@ controller_->Close(); } +TEST_F( + InputControllerTestWithDeviceListener, + CreateWithAudioProcessingConfig_DoesNotListenForPlayoutReferenceIfNotRequired) { + const std::string kOutputDeviceId = "0x123"; + EXPECT_CALL(mock_stream_activity_monitor_, OnInputStreamActive()).Times(1); + EXPECT_CALL(mock_stream_activity_monitor_, OnInputStreamInactive()).Times(1); + + EXPECT_CALL(device_output_listener_, StartListening(_, _)).Times(0); + EXPECT_CALL(device_output_listener_, StopListening(_)).Times(0); + + SetupProcessingConfig(AudioProcessingType::kWithoutPlayoutReference); + CreateAudioController(); + + ASSERT_TRUE(controller_.get()); + + controller_->Record(); + controller_->SetOutputDeviceForAec(kOutputDeviceId); + controller_->Close(); +} + TEST_F(InputControllerTestWithDeviceListener, RecordBeforeSetOutputForAec) { const std::string kOutputDeviceId = "0x123"; EXPECT_CALL(mock_stream_activity_monitor_, OnInputStreamActive()).Times(1); @@ -439,6 +454,44 @@ controller_->SetOutputDeviceForAec(kOtherOutputDeviceId); controller_->Close(); } + +// Test a normal call sequence of create, record and close when audio processing +// is enabled. +// Note: Must use system time as MOCK_TIME does not support the threads created +// by the FakeAudioInputStream. The callbacks to sync_writer_.Write() are on +// that thread, and thus we must use SYSTEM_TIME. +TEST_F(SystemTimeInputControllerTestWithDeviceListener, CreateRecordAndClose) { + EXPECT_CALL(event_handler_, OnCreated(_)); + EXPECT_CALL(mock_stream_activity_monitor_, OnInputStreamActive()).Times(1); + EXPECT_CALL(mock_stream_activity_monitor_, OnInputStreamInactive()).Times(1); + SetupProcessingConfig(AudioProcessingType::kWithPlayoutReference); + CreateAudioController(); + ASSERT_TRUE(controller_.get()); + + base::RunLoop loop; + + { + // Wait for Write() to be called ten times. + testing::InSequence s; + EXPECT_CALL(user_input_monitor_, EnableKeyPressMonitoring()); + EXPECT_CALL(sync_writer_, Write(NotNull(), _, _, _)).Times(Exactly(9)); + EXPECT_CALL(sync_writer_, Write(NotNull(), _, _, _)) + .Times(AtLeast(1)) + .WillOnce(InvokeWithoutArgs([&]() { loop.Quit(); })); + } + controller_->Record(); + loop.Run(); + + testing::Mock::VerifyAndClearExpectations(&user_input_monitor_); + testing::Mock::VerifyAndClearExpectations(&sync_writer_); + + EXPECT_CALL(sync_writer_, Close()); + EXPECT_CALL(user_input_monitor_, DisableKeyPressMonitoring()); + controller_->Close(); + + task_environment_.RunUntilIdle(); +} + #endif // BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION) } // namespace audio
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index c312da06..531bdf7 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -5460,7 +5460,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -5724,7 +5724,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 8ce3bdc..665edcd 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -42606,7 +42606,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -42870,7 +42870,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -43138,7 +43138,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -43402,7 +43402,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -43741,7 +43741,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -44005,7 +44005,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -44344,7 +44344,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -44608,7 +44608,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M100", - "revision": "version:100.0.4896.8" + "revision": "version:100.0.4896.9" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index f7b87011..c3bfc5f 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -387,7 +387,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.8', + 'revision': 'version:100.0.4896.9', } ], }, @@ -459,7 +459,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.8', + 'revision': 'version:100.0.4896.9', } ], }, @@ -531,7 +531,7 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M100', - 'revision': 'version:100.0.4896.8', + 'revision': 'version:100.0.4896.9', } ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index c543556..aa99077 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3515,7 +3515,7 @@ { "name": "Enabled", "enable_features": [ - "IOSTabGridSearch" + "TabsSearch" ] } ]
diff --git a/third_party/abseil-cpp/BUILD.gn b/third_party/abseil-cpp/BUILD.gn index ebe250f..a3f2f62a 100644 --- a/third_party/abseil-cpp/BUILD.gn +++ b/third_party/abseil-cpp/BUILD.gn
@@ -188,14 +188,15 @@ "absl/container:inlined_vector_test", "absl/container:node_slot_policy_test", "absl/container:sample_element_size_test", - "absl/hash:low_level_hash_test", "absl/hash:hash_test", + "absl/hash:low_level_hash_test", "absl/memory:memory_test", "absl/meta:type_traits_test", "absl/profiling:exponential_biased_test", "absl/profiling:periodic_sampler_test", "absl/status:statusor_test", "absl/strings:ascii_test", + "absl/strings:cord_data_edge_test", "absl/strings:cord_rep_btree_navigator_test", "absl/strings:cord_rep_btree_reader_test", "absl/strings:cord_rep_btree_test",
diff --git a/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third_party/abseil-cpp/CMake/AbseilDll.cmake index 14ce9d186f..0becc7a 100644 --- a/third_party/abseil-cpp/CMake/AbseilDll.cmake +++ b/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -204,6 +204,7 @@ "strings/internal/charconv_bigint.h" "strings/internal/charconv_parse.cc" "strings/internal/charconv_parse.h" + "strings/internal/cord_data_edge.h" "strings/internal/cord_internal.cc" "strings/internal/cord_internal.h" "strings/internal/cord_rep_btree.cc"
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium index 726a602..1b47c85 100644 --- a/third_party/abseil-cpp/README.chromium +++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@ License: Apache 2.0 License File: LICENSE Version: 0 -Revision: c2ef7033380a3d8661fee76465097422170fb653 +Revision: 7f850b3167fb38e6b4a9ce1824e6fabd733b5d62 Security Critical: yes Description:
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc index 3ff343d..ddccd59 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc +++ b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
@@ -323,6 +323,7 @@ const ptrdiff_t relocation, char *out, int out_size, char *tmp_buf, int tmp_buf_size); + const char *GetUncachedSymbol(const void *pc); enum { SYMBOL_BUF_SIZE = 3072, @@ -1333,13 +1334,7 @@ // they are called here as well. // To keep stack consumption low, we would like this function to not // get inlined. -const char *Symbolizer::GetSymbol(const void *const pc) { - const char *entry = FindSymbolInCache(pc); - if (entry != nullptr) { - return entry; - } - symbol_buf_[0] = '\0'; - +const char *Symbolizer::GetUncachedSymbol(const void *pc) { ObjFile *const obj = FindObjFile(pc, 1); ptrdiff_t relocation = 0; int fd = -1; @@ -1427,6 +1422,42 @@ return InsertSymbolInCache(pc, symbol_buf_); } +const char *Symbolizer::GetSymbol(const void *pc) { + const char *entry = FindSymbolInCache(pc); + if (entry != nullptr) { + return entry; + } + symbol_buf_[0] = '\0'; + +#ifdef __hppa__ + { + // In some contexts (e.g., return addresses), PA-RISC uses the lowest two + // bits of the address to indicate the privilege level. Clear those bits + // before trying to symbolize. + const auto pc_bits = reinterpret_cast<uintptr_t>(pc); + const auto address = pc_bits & ~0x3; + entry = GetUncachedSymbol(reinterpret_cast<const void *>(address)); + if (entry != nullptr) { + return entry; + } + + // In some contexts, PA-RISC also uses bit 1 of the address to indicate that + // this is a cross-DSO function pointer. Such function pointers actually + // point to a procedure label, a struct whose first 32-bit (pointer) element + // actually points to the function text. With no symbol found for this + // address so far, try interpreting it as a cross-DSO function pointer and + // see how that goes. + if (pc_bits & 0x2) { + return GetUncachedSymbol(*reinterpret_cast<const void *const *>(address)); + } + + return nullptr; + } +#else + return GetUncachedSymbol(pc); +#endif +} + bool RemoveAllSymbolDecorators(void) { if (!g_decorators_mu.TryLock()) { // Someone else is using decorators. Get out.
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc index c710a3da8..a62fa35 100644 --- a/third_party/abseil-cpp/absl/debugging/symbolize_test.cc +++ b/third_party/abseil-cpp/absl/debugging/symbolize_test.cc
@@ -392,12 +392,14 @@ DummySymbolDecorator, &c_message), 0); - char *address = reinterpret_cast<char *>(1); - EXPECT_STREQ("abc", TrySymbolize(address++)); + // Use addresses 4 and 8 here to ensure that we always use valid addresses + // even on systems that require instructions to be 32-bit aligned. + char *address = reinterpret_cast<char *>(4); + EXPECT_STREQ("abc", TrySymbolize(address)); EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b)); - EXPECT_STREQ("ac", TrySymbolize(address++)); + EXPECT_STREQ("ac", TrySymbolize(address + 4)); // Cleanup: remove all remaining decorators so other stack traces don't // get mystery "ac" decoration.
diff --git a/third_party/abseil-cpp/absl/random/zipf_distribution.h b/third_party/abseil-cpp/absl/random/zipf_distribution.h index ed4038f1..03497b1b 100644 --- a/third_party/abseil-cpp/absl/random/zipf_distribution.h +++ b/third_party/abseil-cpp/absl/random/zipf_distribution.h
@@ -30,7 +30,7 @@ ABSL_NAMESPACE_BEGIN // absl::zipf_distribution produces random integer-values in the range [0, k], -// distributed according to the discrete probability function: +// distributed according to the unnormalized discrete probability function: // // P(x) = (v + x) ^ -q //
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel index 129affec..5f122ee9 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.bazel +++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -276,6 +276,7 @@ "internal/cord_rep_ring.cc", ], hdrs = [ + "internal/cord_data_edge.h", "internal/cord_internal.h", "internal/cord_rep_btree.h", "internal/cord_rep_btree_navigator.h", @@ -308,6 +309,21 @@ ) cc_test( + name = "cord_data_edge_test", + size = "small", + srcs = ["internal/cord_data_edge_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":cord_internal", + ":cord_rep_test_util", + ":strings", + "//absl/base:config", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( name = "cord_rep_btree_test", size = "medium", srcs = ["internal/cord_rep_btree_test.cc"],
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.gn b/third_party/abseil-cpp/absl/strings/BUILD.gn index e9d69f1..799027f 100644 --- a/third_party/abseil-cpp/absl/strings/BUILD.gn +++ b/third_party/abseil-cpp/absl/strings/BUILD.gn
@@ -128,6 +128,7 @@ "internal/cord_rep_ring.cc", ] public = [ + "internal/cord_data_edge.h", "internal/cord_internal.h", "internal/cord_rep_btree.h", "internal/cord_rep_btree_navigator.h", @@ -156,6 +157,19 @@ ] } +absl_source_set("cord_data_edge_test") { + testonly = true + sources = [ "internal/cord_data_edge_test.cc" ] + deps = [ + ":cord_internal", + ":cord_rep_test_util", + ":strings", + "//third_party/abseil-cpp/absl/base:config", + "//third_party/googletest:gmock", + "//third_party/googletest:gtest", + ] +} + absl_source_set("cord_rep_btree_test") { testonly = true sources = [ "internal/cord_rep_btree_test.cc" ]
diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt index f31eef4..5d418c8 100644 --- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt +++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -554,6 +554,7 @@ NAME cord_internal HDRS + "internal/cord_data_edge.h" "internal/cord_internal.h" "internal/cord_rep_btree.h" "internal/cord_rep_btree_navigator.h" @@ -934,6 +935,23 @@ absl_cc_test( NAME + cord_data_edge_test + SRCS + "internal/cord_data_edge_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::config + absl::cord_internal + absl::cord_rep_test_util + absl::core_headers + absl::strings + GTest::gmock_main +) + +absl_cc_test( + NAME cord_rep_btree_test SRCS "internal/cord_rep_btree_test.cc"
diff --git a/third_party/abseil-cpp/absl/strings/cord.cc b/third_party/abseil-cpp/absl/strings/cord.cc index 4ee722da..6547c2d 100644 --- a/third_party/abseil-cpp/absl/strings/cord.cc +++ b/third_party/abseil-cpp/absl/strings/cord.cc
@@ -35,6 +35,7 @@ #include "absl/container/fixed_array.h" #include "absl/container/inlined_vector.h" #include "absl/strings/escaping.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" @@ -1094,35 +1095,6 @@ } } -Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() { - auto& stack_of_right_children = stack_of_right_children_; - if (stack_of_right_children.empty()) { - assert(!current_chunk_.empty()); // Called on invalid iterator. - // We have reached the end of the Cord. - return *this; - } - - // Process the next node on the stack. - CordRep* node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - - assert(node->IsExternal() || node->IsFlat()); - assert(length != 0); - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset, length); - current_leaf_ = node; - return *this; -} - Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); @@ -1165,135 +1137,38 @@ return subcord; } - auto& stack_of_right_children = stack_of_right_children_; - if (n < current_chunk_.size()) { - // Range to read is a proper subrange of the current chunk. - assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); - const char* data = subnode->IsExternal() ? subnode->external()->base - : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, n); - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - RemoveChunkPrefix(n); - return subcord; - } - - // Range to read begins with a proper subrange of the current chunk. - assert(!current_chunk_.empty()); + // Short circuit if reading the entire data edge. assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); - if (current_chunk_.size() < subnode->length) { - const char* data = subnode->IsExternal() ? subnode->external()->base - : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, - current_chunk_.size()); - } - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - - // Process the next node(s) on the stack, reading whole subtrees depending on - // their length and how many bytes we are advancing. - CordRep* node = nullptr; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - if (node->length > n) break; - // TODO(qrczak): This might unnecessarily recreate existing concat nodes. - // Avoiding that would need pretty complicated logic (instead of - // current_leaf, keep current_subtree_ which points to the highest node - // such that the current leaf can be found on the path of left children - // starting from current_subtree_; delay creating subnode while node is - // below current_subtree_; find the proper node along the path of left - // children starting from current_subtree_ if this loop exits while staying - // below current_subtree_; etc.; alternatively, push parents instead of - // right children on the stack). - subnode = Concat(subnode, CordRep::Ref(node)); - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); + if (n == current_leaf_->length) { + bytes_remaining_ = 0; + current_chunk_ = {}; + CordRep* tree = CordRep::Ref(current_leaf_); + subcord.contents_.EmplaceTree(VerifyTree(tree), method); return subcord; } - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } + // From this point on, we need a partial substring node. + // Get pointer to the underlying flat or external data payload and + // compute data pointer and offset into current flat or external. + CordRep* payload = current_leaf_->IsSubstring() + ? current_leaf_->substring()->child + : current_leaf_; + const char* data = payload->IsExternal() ? payload->external()->base + : payload->flat()->Data(); + const size_t offset = current_chunk_.data() - data; - // Range to read ends with a proper (possibly empty) subrange of the current - // chunk. - assert(node->IsExternal() || node->IsFlat()); - assert(length > n); - if (n > 0) { - subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n)); - } - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; + CordRepSubstring* tree = new CordRepSubstring(); + tree->tag = cord_internal::SUBSTRING; + tree->length = n; + tree->start = offset; + tree->child = CordRep::Ref(payload); + + subcord.contents_.EmplaceTree(VerifyTree(tree), method); bytes_remaining_ -= n; - subcord.contents_.EmplaceTree(VerifyTree(subnode), method); + current_chunk_.remove_prefix(n); return subcord; } -void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { - assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); - assert(n >= current_chunk_.size()); // This should only be called when - // iterating to a new node. - - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - - if (stack_of_right_children_.empty()) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } - - // Process the next node(s) on the stack, skipping whole subtrees depending on - // their length and how many bytes we are advancing. - CordRep* node = nullptr; - auto& stack_of_right_children = stack_of_right_children_; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); - if (node->length > n) break; - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - - assert(node->IsExternal() || node->IsFlat()); - assert(length > n); - const char* data = - node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; - bytes_remaining_ -= n; -} - char Cord::operator[](size_t i) const { ABSL_HARDENING_ASSERT(i < size()); size_t offset = i;
diff --git a/third_party/abseil-cpp/absl/strings/cord.h b/third_party/abseil-cpp/absl/strings/cord.h index 7f34ef48..081b631 100644 --- a/third_party/abseil-cpp/absl/strings/cord.h +++ b/third_party/abseil-cpp/absl/strings/cord.h
@@ -80,6 +80,7 @@ #include "absl/functional/function_ref.h" #include "absl/meta/type_traits.h" #include "absl/strings/cord_analysis.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_reader.h" @@ -388,12 +389,6 @@ using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; - // Stack of right children of concat nodes that we have to visit. - // Keep this at the end of the structure to avoid cache-thrashing. - // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for - // the inlined vector size (47 exists for backward compatibility). - using Stack = absl::InlinedVector<absl::cord_internal::CordRep*, 47>; - // Constructs a `begin()` iterator from `tree`. `tree` must not be null. explicit ChunkIterator(cord_internal::CordRep* tree); @@ -409,17 +404,10 @@ Cord AdvanceAndReadBytes(size_t n); void AdvanceBytes(size_t n); - // Stack specific operator++ - ChunkIterator& AdvanceStack(); - // Btree specific operator++ ChunkIterator& AdvanceBtree(); void AdvanceBytesBtree(size_t n); - // Iterates `n` bytes, where `n` is expected to be greater than or equal to - // `current_chunk_.size()`. - void AdvanceBytesSlowPath(size_t n); - // A view into bytes of the current `CordRep`. It may only be a view to a // suffix of bytes if this is being used by `CharIterator`. absl::string_view current_chunk_; @@ -432,9 +420,6 @@ // Cord reader for cord btrees. Empty if not traversing a btree. CordRepBtreeReader btree_reader_; - - // See 'Stack' alias definition. - Stack stack_of_right_children_; }; // Cord::ChunkIterator::chunk_begin() @@ -725,7 +710,8 @@ // be used by spelling absl::strings_internal::MakeStringConstant, which is // also an internal API. template <typename T> - explicit constexpr Cord(strings_internal::StringConstant<T>); + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr Cord(strings_internal::StringConstant<T>); private: using CordRep = absl::cord_internal::CordRep; @@ -1321,25 +1307,24 @@ tree = cord_internal::SkipCrcNode(tree); if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); - return; + } else { + current_leaf_ = tree; + current_chunk_ = cord_internal::EdgeData(tree); } - - stack_of_right_children_.push_back(tree); - operator++(); } -inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) - : bytes_remaining_(tree->length) { +inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) { + bytes_remaining_ = tree->length; InitTree(tree); } -inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) - : bytes_remaining_(cord->size()) { - if (cord->contents_.is_tree()) { - InitTree(cord->contents_.as_tree()); +inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) { + if (CordRep* tree = cord->contents_.tree()) { + bytes_remaining_ = tree->length; + InitTree(tree); } else { - current_chunk_ = - absl::string_view(cord->contents_.data(), bytes_remaining_); + bytes_remaining_ = cord->contents_.inline_size(); + current_chunk_ = {cord->contents_.data(), bytes_remaining_}; } } @@ -1369,8 +1354,11 @@ assert(bytes_remaining_ >= current_chunk_.size()); bytes_remaining_ -= current_chunk_.size(); if (bytes_remaining_ > 0) { - return btree_reader_ ? AdvanceBtree() : AdvanceStack(); - } else { + if (btree_reader_) { + return AdvanceBtree(); + } else { + assert(!current_chunk_.empty()); // Called on invalid iterator. + } current_chunk_ = {}; } return *this; @@ -1411,7 +1399,11 @@ if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { RemoveChunkPrefix(n); } else if (n != 0) { - btree_reader_ ? AdvanceBytesBtree(n) : AdvanceBytesSlowPath(n); + if (btree_reader_) { + AdvanceBytesBtree(n); + } else { + bytes_remaining_ = 0; + } } }
diff --git a/third_party/abseil-cpp/absl/strings/cord_analysis.cc b/third_party/abseil-cpp/absl/strings/cord_analysis.cc index 3fa15b01..73d3c4e6 100644 --- a/third_party/abseil-cpp/absl/strings/cord_analysis.cc +++ b/third_party/abseil-cpp/absl/strings/cord_analysis.cc
@@ -12,13 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/strings/cord_analysis.h" + #include <cstddef> #include <cstdint> #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/container/inlined_vector.h" -#include "absl/strings/cord_analysis.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" @@ -98,16 +100,6 @@ } }; -// Returns true if the provided rep is a valid data edge. -bool IsDataEdge(const CordRep* rep) { - // The fast path is that `rep` is an EXTERNAL or FLAT node, making the below - // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL - // check in the slow path the SUBSTRING check to optimize for the hot path. - if (rep->tag == EXTERNAL || rep->tag >= FLAT) return true; - if (rep->tag == SUBSTRING) rep = rep->substring()->child; - return rep->tag == EXTERNAL || rep->tag >= FLAT; -} - // Computes the estimated memory size of the provided data edge. // External reps are assumed 'heap allocated at their exact size'. template <Mode mode>
diff --git a/third_party/abseil-cpp/absl/strings/cord_test.cc b/third_party/abseil-cpp/absl/strings/cord_test.cc index c26e506d..9dcc4ce5 100644 --- a/third_party/abseil-cpp/absl/strings/cord_test.cc +++ b/third_party/abseil-cpp/absl/strings/cord_test.cc
@@ -1866,6 +1866,78 @@ VerifyChunkIterator(subcords, 128); } + +TEST_P(CordTest, AdvanceAndReadOnDataEdge) { + RandomEngine rng(GTEST_FLAG_GET(random_seed)); + const std::string data = RandomLowercaseString(&rng, 2000); + for (bool as_flat : {true, false}) { + SCOPED_TRACE(as_flat ? "Flat" : "External"); + + absl::Cord cord = + as_flat ? absl::Cord(data) + : absl::MakeCordFromExternal(data, [](absl::string_view) {}); + auto it = cord.Chars().begin(); +#if !defined(NDEBUG) || ABSL_OPTION_HARDENED + EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*"); +#endif + + it = cord.Chars().begin(); + absl::Cord frag = cord.AdvanceAndRead(&it, 2000); + EXPECT_EQ(frag, data); + EXPECT_TRUE(it == cord.Chars().end()); + + it = cord.Chars().begin(); + frag = cord.AdvanceAndRead(&it, 200); + EXPECT_EQ(frag, data.substr(0, 200)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 1500); + EXPECT_EQ(frag, data.substr(200, 1500)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 300); + EXPECT_EQ(frag, data.substr(1700, 300)); + EXPECT_TRUE(it == cord.Chars().end()); + } +} + +TEST_P(CordTest, AdvanceAndReadOnSubstringDataEdge) { + RandomEngine rng(GTEST_FLAG_GET(random_seed)); + const std::string data = RandomLowercaseString(&rng, 2500); + for (bool as_flat : {true, false}) { + SCOPED_TRACE(as_flat ? "Flat" : "External"); + + absl::Cord cord = + as_flat ? absl::Cord(data) + : absl::MakeCordFromExternal(data, [](absl::string_view) {}); + cord = cord.Subcord(200, 2000); + const std::string substr = data.substr(200, 2000); + + auto it = cord.Chars().begin(); +#if !defined(NDEBUG) || ABSL_OPTION_HARDENED + EXPECT_DEATH_IF_SUPPORTED(cord.AdvanceAndRead(&it, 2001), ".*"); +#endif + + it = cord.Chars().begin(); + absl::Cord frag = cord.AdvanceAndRead(&it, 2000); + EXPECT_EQ(frag, substr); + EXPECT_TRUE(it == cord.Chars().end()); + + it = cord.Chars().begin(); + frag = cord.AdvanceAndRead(&it, 200); + EXPECT_EQ(frag, substr.substr(0, 200)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 1500); + EXPECT_EQ(frag, substr.substr(200, 1500)); + EXPECT_FALSE(it == cord.Chars().end()); + + frag = cord.AdvanceAndRead(&it, 300); + EXPECT_EQ(frag, substr.substr(1700, 300)); + EXPECT_TRUE(it == cord.Chars().end()); + } +} + TEST_P(CordTest, CharIteratorTraits) { static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value, "");
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_data_edge.h b/third_party/abseil-cpp/absl/strings/internal/cord_data_edge.h new file mode 100644 index 0000000..e18b33e --- /dev/null +++ b/third_party/abseil-cpp/absl/strings/internal/cord_data_edge.h
@@ -0,0 +1,63 @@ +// Copyright 2022 The Abseil Authors +// +// 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 +// +// https://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. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ +#define ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_ + +#include <cassert> +#include <cstddef> + +#include "absl/base/config.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_flat.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// Returns true if the provided rep is a FLAT, EXTERNAL or a SUBSTRING node +// holding a FLAT or EXTERNAL child rep. Requires `rep != nullptr`. +inline bool IsDataEdge(const CordRep* edge) { + assert(edge != nullptr); + + // The fast path is that `edge` is an EXTERNAL or FLAT node, making the below + // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL + // check in the slow path of the SUBSTRING check to optimize for the hot path. + if (edge->tag == EXTERNAL || edge->tag >= FLAT) return true; + if (edge->tag == SUBSTRING) edge = edge->substring()->child; + return edge->tag == EXTERNAL || edge->tag >= FLAT; +} + +// Returns the `absl::string_view` data reference for the provided data edge. +// Requires 'IsDataEdge(edge) == true`. +inline absl::string_view EdgeData(const CordRep* edge) { + assert(IsDataEdge(edge)); + + size_t offset = 0; + const size_t length = edge->length; + if (edge->IsSubstring()) { + offset = edge->substring()->start; + edge = edge->substring()->child; + } + return edge->tag >= FLAT + ? absl::string_view{edge->flat()->Data() + offset, length} + : absl::string_view{edge->external()->base + offset, length}; +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_DATA_EDGE_H_
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_data_edge_test.cc b/third_party/abseil-cpp/absl/strings/internal/cord_data_edge_test.cc new file mode 100644 index 0000000..8fce3bc --- /dev/null +++ b/third_party/abseil-cpp/absl/strings/internal/cord_data_edge_test.cc
@@ -0,0 +1,130 @@ +// Copyright 2022 The Abseil Authors +// +// 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 +// +// https://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. + +#include "absl/strings/internal/cord_data_edge.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_test_util.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { +namespace { + +using ::absl::cordrep_testing::MakeExternal; +using ::absl::cordrep_testing::MakeFlat; +using ::absl::cordrep_testing::MakeSubstring; + +TEST(CordDataEdgeTest, IsDataEdgeOnFlat) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + EXPECT_TRUE(IsDataEdge(rep)); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnExternal) { + CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ..."); + EXPECT_TRUE(IsDataEdge(rep)); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfFlat) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_TRUE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnSubstringOfExternal) { + CordRep* rep = MakeExternal("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_TRUE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnBtree) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRepBtree* tree = CordRepBtree::New(rep); + EXPECT_FALSE(IsDataEdge(tree)); + CordRep::Unref(tree); +} + +TEST(CordDataEdgeTest, IsDataEdgeOnBadSubstr) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep)); + EXPECT_FALSE(IsDataEdge(substr)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, EdgeDataOnFlat) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeFlat(value); + EXPECT_EQ(EdgeData(rep), value); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, EdgeDataOnExternal) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeExternal(value); + EXPECT_EQ(EdgeData(rep), value); + CordRep::Unref(rep); +} + +TEST(CordDataEdgeTest, EdgeDataOnSubstringOfFlat) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeFlat(value); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_EQ(EdgeData(substr), value.substr(1, 20)); + CordRep::Unref(substr); +} + +TEST(CordDataEdgeTest, EdgeDataOnSubstringOfExternal) { + absl::string_view value = "Lorem ipsum dolor sit amet, consectetur ..."; + CordRep* rep = MakeExternal(value); + CordRep* substr = MakeSubstring(1, 20, rep); + EXPECT_EQ(EdgeData(substr), value.substr(1, 20)); + CordRep::Unref(substr); +} + +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) + +TEST(CordDataEdgeTest, IsDataEdgeOnNullPtr) { + EXPECT_DEATH(IsDataEdge(nullptr), ".*"); +} + +TEST(CordDataEdgeTest, EdgeDataOnNullPtr) { + EXPECT_DEATH(EdgeData(nullptr), ".*"); +} + +TEST(CordDataEdgeTest, EdgeDataOnBtree) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRepBtree* tree = CordRepBtree::New(rep); + EXPECT_DEATH(EdgeData(tree), ".*"); + CordRep::Unref(tree); +} + +TEST(CordDataEdgeTest, EdgeDataOnBadSubstr) { + CordRep* rep = MakeFlat("Lorem ipsum dolor sit amet, consectetur ..."); + CordRep* substr = MakeSubstring(1, 18, MakeSubstring(1, 20, rep)); + EXPECT_DEATH(EdgeData(substr), ".*"); + CordRep::Unref(substr); +} + +#endif // GTEST_HAS_DEATH_TEST && !NDEBUG + +} // namespace +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace absl
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc index 3ebd9f6..2b592b47 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc
@@ -22,6 +22,7 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_consume.h" #include "absl/strings/internal/cord_rep_flat.h" @@ -69,7 +70,7 @@ // indentation and prefix / labels keeps us within roughly 80-100 wide. constexpr size_t kMaxDataLength = 60; stream << ", data = \"" - << CordRepBtree::EdgeData(r).substr(0, kMaxDataLength) + << EdgeData(r).substr(0, kMaxDataLength) << (r->length > kMaxDataLength ? "\"..." : "\""); } stream << '\n'; @@ -150,7 +151,7 @@ CordRep* ResizeEdge(CordRep* edge, size_t length, bool is_mutable) { assert(length > 0); assert(length <= edge->length); - assert(CordRepBtree::IsDataEdge(edge)); + assert(IsDataEdge(edge)); if (length >= edge->length) return edge; if (is_mutable && (edge->tag >= FLAT || edge->tag == SUBSTRING)) { @@ -207,7 +208,7 @@ // Deletes a leaf node data edge. Requires `IsDataEdge(rep)`. void DeleteLeafEdge(CordRep* rep) { - assert(CordRepBtree::IsDataEdge(rep)); + assert(IsDataEdge(rep)); if (rep->tag >= FLAT) { CordRepFlat::Delete(rep->flat()); } else if (rep->tag == EXTERNAL) {
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.h b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.h index df5c994..0e78e12 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.h +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.h
@@ -22,6 +22,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/string_view.h" @@ -310,13 +311,6 @@ // Requires this instance to be a leaf node, and `index` to be valid index. inline absl::string_view Data(size_t index) const; - static const char* EdgeDataPtr(const CordRep* r); - static absl::string_view EdgeData(const CordRep* r); - - // Returns true if the provided rep is a FLAT, EXTERNAL or a SUBSTRING node - // holding a FLAT or EXTERNAL child rep. - static bool IsDataEdge(const CordRep* rep); - // Diagnostics: returns true if `tree` is valid and internally consistent. // If `shallow` is false, then the provided top level node and all child nodes // below it are recursively checked. If `shallow` is true, only the provided @@ -631,34 +625,11 @@ return {edges_ + begin, static_cast<size_t>(end - begin)}; } -inline const char* CordRepBtree::EdgeDataPtr(const CordRep* r) { - assert(IsDataEdge(r)); - size_t offset = 0; - if (r->tag == SUBSTRING) { - offset = r->substring()->start; - r = r->substring()->child; - } - return (r->tag >= FLAT ? r->flat()->Data() : r->external()->base) + offset; -} - -inline absl::string_view CordRepBtree::EdgeData(const CordRep* r) { - return absl::string_view(EdgeDataPtr(r), r->length); -} - inline absl::string_view CordRepBtree::Data(size_t index) const { assert(height() == 0); return EdgeData(Edge(index)); } -inline bool CordRepBtree::IsDataEdge(const CordRep* rep) { - // The fast path is that `rep` is an EXTERNAL or FLAT node, making the below - // if a single, well predicted branch. We then repeat the FLAT or EXTERNAL - // check in the slow path the SUBSTRING check to optimize for the hot path. - if (rep->tag == EXTERNAL || rep->tag >= FLAT) return true; - if (rep->tag == SUBSTRING) rep = rep->substring()->child; - return rep->tag == EXTERNAL || rep->tag >= FLAT; -} - inline CordRepBtree* CordRepBtree::New(int height) { CordRepBtree* tree = new CordRepBtree; tree->length = 0;
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc index 19afbe90..9b896a3d 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc
@@ -16,6 +16,7 @@ #include <cassert> +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" @@ -39,7 +40,7 @@ assert(n <= rep->length); assert(offset < rep->length); assert(offset <= rep->length - n); - assert(CordRepBtree::IsDataEdge(rep)); + assert(IsDataEdge(rep)); if (n == 0) return nullptr; if (n == rep->length) return CordRep::Ref(rep);
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc index 5dc7696..0d0e8601 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc
@@ -17,6 +17,7 @@ #include <cassert> #include "absl/base/config.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_navigator.h" @@ -44,7 +45,7 @@ // can directly return the substring into the current data edge as the next // chunk. We can easily establish from the above code that `navigator_.Next()` // has not been called as that requires `chunk_size` to be zero. - if (n < chunk_size) return CordRepBtree::EdgeData(edge).substr(result.n); + if (n < chunk_size) return EdgeData(edge).substr(result.n); // The amount of data taken from the last edge is `chunk_size` and `result.n` // contains the offset into the current edge trailing the read data (which can @@ -60,7 +61,7 @@ // We did not read all data, return remaining data from current edge. edge = navigator_.Current(); remaining_ -= consumed_by_read + edge->length; - return CordRepBtree::EdgeData(edge).substr(result.n); + return EdgeData(edge).substr(result.n); } } // namespace cord_internal
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h index 7aa79dbf..8db8f8d 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h
@@ -18,6 +18,7 @@ #include <cassert> #include "absl/base/config.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_navigator.h" @@ -167,7 +168,7 @@ assert(tree != nullptr); const CordRep* edge = navigator_.InitFirst(tree); remaining_ = tree->length - edge->length; - return CordRepBtree::EdgeData(edge); + return EdgeData(edge); } inline absl::string_view CordRepBtreeReader::Next() { @@ -175,7 +176,7 @@ const CordRep* edge = navigator_.Next(); assert(edge != nullptr); remaining_ -= edge->length; - return CordRepBtree::EdgeData(edge); + return EdgeData(edge); } inline absl::string_view CordRepBtreeReader::Skip(size_t skip) { @@ -190,7 +191,7 @@ // The combined length of all edges skipped before `pos.edge` is `skip - // pos.offset`, all of which are 'consumed', as well as the current edge. remaining_ -= skip - pos.offset + pos.edge->length; - return CordRepBtree::EdgeData(pos.edge).substr(pos.offset); + return EdgeData(pos.edge).substr(pos.offset); } inline absl::string_view CordRepBtreeReader::Seek(size_t offset) { @@ -199,7 +200,7 @@ remaining_ = 0; return {}; } - absl::string_view chunk = CordRepBtree::EdgeData(pos.edge).substr(pos.offset); + absl::string_view chunk = EdgeData(pos.edge).substr(pos.offset); remaining_ = length() - offset - chunk.length(); return chunk; }
diff --git a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc index 1d56b252..51b90db 100644 --- a/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc +++ b/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc
@@ -25,6 +25,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/cleanup/cleanup.h" +#include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_test_util.h" #include "absl/strings/str_cat.h" @@ -323,30 +324,26 @@ CordRep* substr2 = MakeSubstring(1, 6, CordRep::Ref(external)); CordRep* bad_substr = MakeSubstring(1, 2, CordRep::Ref(substr1)); - EXPECT_TRUE(CordRepBtree::IsDataEdge(flat)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(flat), - TypedEq<const void*>(flat->Data())); - EXPECT_THAT(CordRepBtree::EdgeData(flat), Eq("Hello world")); + EXPECT_TRUE(IsDataEdge(flat)); + EXPECT_THAT(EdgeData(flat).data(), TypedEq<const void*>(flat->Data())); + EXPECT_THAT(EdgeData(flat), Eq("Hello world")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(external)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(external), - TypedEq<const void*>(external->base)); - EXPECT_THAT(CordRepBtree::EdgeData(external), Eq("Hello external")); + EXPECT_TRUE(IsDataEdge(external)); + EXPECT_THAT(EdgeData(external).data(), TypedEq<const void*>(external->base)); + EXPECT_THAT(EdgeData(external), Eq("Hello external")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(substr1)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(substr1), - TypedEq<const void*>(flat->Data() + 1)); - EXPECT_THAT(CordRepBtree::EdgeData(substr1), Eq("ello w")); + EXPECT_TRUE(IsDataEdge(substr1)); + EXPECT_THAT(EdgeData(substr1).data(), TypedEq<const void*>(flat->Data() + 1)); + EXPECT_THAT(EdgeData(substr1), Eq("ello w")); - EXPECT_TRUE(CordRepBtree::IsDataEdge(substr2)); - EXPECT_THAT(CordRepBtree::EdgeDataPtr(substr2), + EXPECT_TRUE(IsDataEdge(substr2)); + EXPECT_THAT(EdgeData(substr2).data(), TypedEq<const void*>(external->base + 1)); - EXPECT_THAT(CordRepBtree::EdgeData(substr2), Eq("ello e")); + EXPECT_THAT(EdgeData(substr2), Eq("ello e")); - EXPECT_FALSE(CordRepBtree::IsDataEdge(bad_substr)); + EXPECT_FALSE(IsDataEdge(bad_substr)); #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) - EXPECT_DEATH(CordRepBtree::EdgeData(bad_substr), ".*"); - EXPECT_DEATH(CordRepBtree::EdgeDataPtr(bad_substr), ".*"); + EXPECT_DEATH(EdgeData(bad_substr), ".*"); #endif CordRep::Unref(bad_substr);
diff --git a/third_party/abseil-cpp/ci/linux_docker_containers.sh b/third_party/abseil-cpp/ci/linux_docker_containers.sh index 37be53104..0e05564f 100644 --- a/third_party/abseil-cpp/ci/linux_docker_containers.sh +++ b/third_party/abseil-cpp/ci/linux_docker_containers.sh
@@ -16,6 +16,6 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220113" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220113" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20210617"
diff --git a/third_party/abseil-cpp/symbols_arm64_dbg.def b/third_party/abseil-cpp/symbols_arm64_dbg.def index 6d30a35..c096197 100644 --- a/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/third_party/abseil-cpp/symbols_arm64_dbg.def
@@ -280,12 +280,10 @@ ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AEAAIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AEAAIXZ ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z - ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBack@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUSubRange@2@$$QEAU32@@Z ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z - ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBackSlow@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUSubRange@2@$$QEAU32@@Z @@ -607,7 +605,6 @@ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ??$emplace_back@AEAVstring_view@absl@@AEBV12@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAVstring_view@5@AEBV65@AEA_K@Z ??$emplace_back@AEBQEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@AEBQEAU231@@Z - ??$emplace_back@AEBQEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@AEBQEAU231@@Z ??$emplace_back@PEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@$$QEAPEAU231@@Z ??$emplace_back@UPayload@status_internal@absl@@@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QEAAAEAUPayload@status_internal@1@$$QEAU231@@Z ??$emplace_back@USubRange@absl@@@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAAEAUSubRange@1@$$QEAU21@@Z @@ -1148,7 +1145,6 @@ ??1?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAA@XZ ??1?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@QEAA@XZ ??1BadStatusOrAccess@absl@@UEAA@XZ - ??1ChunkIterator@Cord@absl@@QEAA@XZ ??1CondVar@absl@@QEAA@XZ ??1Cord@absl@@QEAA@XZ ??1CordzHandle@cord_internal@absl@@MEAA@XZ @@ -1478,8 +1474,6 @@ ?AdvanceBtree@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?AdvanceBytes@ChunkIterator@Cord@absl@@AEAAX_K@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?Align@adl_barrier@internal_layout@container_internal@absl@@YA_K_K0@Z ?AlignBegin@CordRepBtree@cord_internal@absl@@AEAAXXZ ?AlignEnd@CordRepBtree@cord_internal@absl@@AEAAXXZ @@ -1702,8 +1696,7 @@ ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z ?Edge@CordRepBtree@cord_internal@absl@@QEBAPEAUCordRep@23@W4EdgeType@123@@Z ?Edge@CordRepBtree@cord_internal@absl@@QEBAPEAUCordRep@23@_K@Z - ?EdgeData@CordRepBtree@cord_internal@absl@@SA?AVstring_view@3@PEBUCordRep@23@@Z - ?EdgeDataPtr@CordRepBtree@cord_internal@absl@@SAPEBDPEBUCordRep@23@@Z + ?EdgeData@cord_internal@absl@@YA?AVstring_view@2@PEBUCordRep@12@@Z ?Edges@CordRepBtree@cord_internal@absl@@QEBA?AV?$Span@QEAUCordRep@cord_internal@absl@@@3@XZ ?Edges@CordRepBtree@cord_internal@absl@@QEBA?AV?$Span@QEAUCordRep@cord_internal@absl@@@3@_K0@Z ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z @@ -1997,7 +1990,7 @@ ?IsCancelled@absl@@YA_NAEBVStatus@1@@Z ?IsCooperative@SpinLock@base_internal@absl@@CA_NW4SchedulingMode@23@@Z ?IsCrc@CordRep@cord_internal@absl@@QEBA_NXZ - ?IsDataEdge@CordRepBtree@cord_internal@absl@@SA_NPEBUCordRep@23@@Z + ?IsDataEdge@cord_internal@absl@@YA_NPEBUCordRep@12@@Z ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsEmpty@Queue@CordzHandle@cord_internal@absl@@QEBA_NXZ @@ -3268,7 +3261,6 @@ ?probe@container_internal@absl@@YA?AV?$probe_seq@$07@12@PEBW4ctrl_t@12@_K1@Z ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAXAEBQEAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAX$$QEAPEAUCordRep@cord_internal@2@@Z - ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAXAEBQEAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QEAAX$$QEAUPayload@status_internal@2@@Z ?push_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAX$$QEAUSubRange@2@@Z ?push_back@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z
diff --git a/third_party/abseil-cpp/symbols_arm64_rel.def b/third_party/abseil-cpp/symbols_arm64_rel.def index 530ad452..36d84e6 100644 --- a/third_party/abseil-cpp/symbols_arm64_rel.def +++ b/third_party/abseil-cpp/symbols_arm64_rel.def
@@ -42,11 +42,9 @@ ??$Dispatch@_N@FormatArgImpl@str_format_internal@absl@@CA_NTData@012@VFormatConversionSpecImpl@12@PEAX@Z ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AEAAIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AEAAIXZ - ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBack@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUSubRange@2@$$QEAU32@@Z - ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBackSlow@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUSubRange@2@$$QEAU32@@Z @@ -127,6 +125,7 @@ ??0ByAnyChar@absl@@QEAA@Vstring_view@1@@Z ??0ByLength@absl@@QEAA@_J@Z ??0ByString@absl@@QEAA@Vstring_view@1@@Z + ??0ChunkIterator@Cord@absl@@AEAA@PEAUCordRep@cord_internal@2@@Z ??0ChunkIterator@Cord@absl@@AEAA@PEBV12@@Z ??0Condition@absl@@AEAA@XZ ??0Condition@absl@@QEAA@P6A_NPEAX@Z0@Z @@ -231,8 +230,6 @@ ?AddressIsReadable@debugging_internal@absl@@YA_NPEBX@Z ?AdvanceAndReadBytes@ChunkIterator@Cord@absl@@AEAA?AV23@_K@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?Allocate@?$MallocAdapter@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@$0A@@inlined_vector_internal@absl@@SA?AU?$Allocation@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@23@AEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@_K@Z ?Allocate@?$MallocAdapter@V?$allocator@UPayload@status_internal@absl@@@__1@std@@$0A@@inlined_vector_internal@absl@@SA?AU?$Allocation@V?$allocator@UPayload@status_internal@absl@@@__1@std@@@23@AEAV?$allocator@UPayload@status_internal@absl@@@__1@std@@_K@Z @@ -407,6 +404,7 @@ ?Find@ByChar@absl@@QEBA?AVstring_view@2@V32@_K@Z ?Find@ByLength@absl@@QEBA?AVstring_view@2@V32@_K@Z ?Find@ByString@absl@@QEBA?AVstring_view@2@V32@_K@Z + ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AVstring_view@3@XZ ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z ?FindSlow@CordRepRing@cord_internal@absl@@AEBA?AUPosition@123@I_K@Z ?FindTailSlow@CordRepRing@cord_internal@absl@@AEBA?AUPosition@123@I_K@Z
diff --git a/third_party/abseil-cpp/symbols_x64_dbg.def b/third_party/abseil-cpp/symbols_x64_dbg.def index 6e31257..1a6b6dc 100644 --- a/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/third_party/abseil-cpp/symbols_x64_dbg.def
@@ -280,12 +280,10 @@ ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AEAAIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AEAAIXZ ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z - ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBack@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUSubRange@2@$$QEAU32@@Z ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z - ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBackSlow@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUSubRange@2@$$QEAU32@@Z @@ -611,7 +609,6 @@ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAXXZ ??$emplace_back@AEAVstring_view@absl@@AEBV12@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAVstring_view@5@AEBV65@AEA_K@Z ??$emplace_back@AEBQEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@AEBQEAU231@@Z - ??$emplace_back@AEBQEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@AEBQEAU231@@Z ??$emplace_back@PEAUCordRep@cord_internal@absl@@@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAAEAPEAUCordRep@cord_internal@1@$$QEAPEAU231@@Z ??$emplace_back@UPayload@status_internal@absl@@@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QEAAAEAUPayload@status_internal@1@$$QEAU231@@Z ??$emplace_back@USubRange@absl@@@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAAEAUSubRange@1@$$QEAU21@@Z @@ -1151,7 +1148,6 @@ ??1?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QEAA@XZ ??1?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@QEAA@XZ ??1BadStatusOrAccess@absl@@UEAA@XZ - ??1ChunkIterator@Cord@absl@@QEAA@XZ ??1CondVar@absl@@QEAA@XZ ??1Cord@absl@@QEAA@XZ ??1CordzHandle@cord_internal@absl@@MEAA@XZ @@ -1481,8 +1477,6 @@ ?AdvanceBtree@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?AdvanceBytes@ChunkIterator@Cord@absl@@AEAAX_K@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?Align@adl_barrier@internal_layout@container_internal@absl@@YA_K_K0@Z ?AlignBegin@CordRepBtree@cord_internal@absl@@AEAAXXZ ?AlignEnd@CordRepBtree@cord_internal@absl@@AEAAXXZ @@ -1705,8 +1699,7 @@ ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z ?Edge@CordRepBtree@cord_internal@absl@@QEBAPEAUCordRep@23@W4EdgeType@123@@Z ?Edge@CordRepBtree@cord_internal@absl@@QEBAPEAUCordRep@23@_K@Z - ?EdgeData@CordRepBtree@cord_internal@absl@@SA?AVstring_view@3@PEBUCordRep@23@@Z - ?EdgeDataPtr@CordRepBtree@cord_internal@absl@@SAPEBDPEBUCordRep@23@@Z + ?EdgeData@cord_internal@absl@@YA?AVstring_view@2@PEBUCordRep@12@@Z ?Edges@CordRepBtree@cord_internal@absl@@QEBA?AV?$Span@QEAUCordRep@cord_internal@absl@@@3@XZ ?Edges@CordRepBtree@cord_internal@absl@@QEBA?AV?$Span@QEAUCordRep@cord_internal@absl@@@3@_K0@Z ?EmplaceTree@InlineRep@Cord@absl@@QEAAXPEAUCordRep@cord_internal@3@AEBVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z @@ -1999,7 +1992,7 @@ ?IsCancelled@absl@@YA_NAEBVStatus@1@@Z ?IsCooperative@SpinLock@base_internal@absl@@CA_NW4SchedulingMode@23@@Z ?IsCrc@CordRep@cord_internal@absl@@QEBA_NXZ - ?IsDataEdge@CordRepBtree@cord_internal@absl@@SA_NPEBUCordRep@23@@Z + ?IsDataEdge@cord_internal@absl@@YA_NPEBUCordRep@12@@Z ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsEmpty@Queue@CordzHandle@cord_internal@absl@@QEBA_NXZ @@ -3267,7 +3260,6 @@ ?probe@container_internal@absl@@YA?AV?$probe_seq@$0BA@@12@PEBW4ctrl_t@12@_K1@Z ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAXAEBQEAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAX$$QEAPEAUCordRep@cord_internal@2@@Z - ?push_back@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QEAAXAEBQEAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QEAAX$$QEAUPayload@status_internal@2@@Z ?push_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QEAAX$$QEAUSubRange@2@@Z ?push_back@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__1@std@@@__1@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel.def b/third_party/abseil-cpp/symbols_x64_rel.def index 1959e143..12a8bd5 100644 --- a/third_party/abseil-cpp/symbols_x64_rel.def +++ b/third_party/abseil-cpp/symbols_x64_rel.def
@@ -42,11 +42,9 @@ ??$Dispatch@_N@FormatArgImpl@str_format_internal@absl@@CA_NTData@012@VFormatConversionSpecImpl@12@PEAX@Z ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AEAAIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AEAAIXZ - ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBack@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUSubRange@2@$$QEAU32@@Z - ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBackSlow@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUSubRange@2@$$QEAU32@@Z @@ -198,7 +196,6 @@ ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@XZ ??Bint128@absl@@QEBANXZ - ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??Gdetail@cctz@time_internal@absl@@YA?AV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@0123@V40123@_J@Z ??Gdetail@cctz@time_internal@absl@@YA?AV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@V40123@_J@Z ??Hdetail@cctz@time_internal@absl@@YA?AV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@0123@V40123@_J@Z @@ -206,6 +203,8 @@ ??Kabsl@@YA?AVuint128@0@V10@0@Z ??Labsl@@YA?AVint128@0@V10@0@Z ??Labsl@@YA?AVuint128@0@V10@0@Z + ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHAEBV23@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAVstring_view@3@@Z + ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHVstring_view@3@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV43@@Z ??R?$RandenPool@E@random_internal@absl@@QEAAEXZ ??R?$RandenPool@G@random_internal@absl@@QEAAGXZ ??R?$RandenPool@I@random_internal@absl@@QEAAIXZ @@ -233,8 +232,6 @@ ?AddressIsReadable@debugging_internal@absl@@YA_NPEBX@Z ?AdvanceAndReadBytes@ChunkIterator@Cord@absl@@AEAA?AV23@_K@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlreadyExistsError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Append@?$AppendUninitializedTraits@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@X@strings_internal@absl@@SAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@_K@Z @@ -305,7 +302,6 @@ ?Compare@Cord@absl@@QEBAHVstring_view@2@@Z ?CompareImpl@Cord@absl@@AEBAHAEBV12@@Z ?CompareSlowPath@Cord@absl@@AEBAHAEBV12@_K1@Z - ?CompareSlowPath@Cord@absl@@AEBAHVstring_view@2@_K1@Z ?Consume@cord_internal@absl@@YAXPEAUCordRep@12@V?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@2@@Z ?ConsumeBeginTo@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAV123@_K1@Z ?ConsumeUnboundConversion@str_format_internal@absl@@YAPEBDPEBD0PEAUUnboundConversion@12@PEAH@Z
diff --git a/third_party/abseil-cpp/symbols_x64_rel_asan.def b/third_party/abseil-cpp/symbols_x64_rel_asan.def index f8dbd50..d912375 100644 --- a/third_party/abseil-cpp/symbols_x64_rel_asan.def +++ b/third_party/abseil-cpp/symbols_x64_rel_asan.def
@@ -41,11 +41,9 @@ ??$Dispatch@_N@FormatArgImpl@str_format_internal@absl@@CA_NTData@012@VFormatConversionSpecImpl@12@PEAX@Z ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AEAAIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AEAAIXZ - ??$EmplaceBack@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBack@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QEAAAEAUSubRange@2@$$QEAU32@@Z - ??$EmplaceBackSlow@AEBQEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@AEBQEAU342@@Z ??$EmplaceBackSlow@PEAUCordRep@cord_internal@absl@@@?$Storage@PEAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PEAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAPEAUCordRep@cord_internal@2@$$QEAPEAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AEAAAEAUSubRange@2@$$QEAU32@@Z @@ -238,8 +236,6 @@ ?AddressIsReadable@debugging_internal@absl@@YA_NPEBX@Z ?AdvanceAndReadBytes@ChunkIterator@Cord@absl@@AEAA?AV23@_K@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AEAAX_K@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AEAAAEAV123@XZ ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlreadyExistsError@absl@@YA?AVStatus@1@Vstring_view@1@@Z ?Append@?$AppendUninitializedTraits@V?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@X@strings_internal@absl@@SAXPEAV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@_K@Z @@ -310,7 +306,6 @@ ?Compare@Cord@absl@@QEBAHVstring_view@2@@Z ?CompareImpl@Cord@absl@@AEBAHAEBV12@@Z ?CompareSlowPath@Cord@absl@@AEBAHAEBV12@_K1@Z - ?CompareSlowPath@Cord@absl@@AEBAHVstring_view@2@_K1@Z ?Consume@cord_internal@absl@@YAXPEAUCordRep@12@V?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@2@@Z ?ConsumeBeginTo@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAV123@_K1@Z ?ConsumeUnboundConversion@str_format_internal@absl@@YAPEBDPEBD0PEAUUnboundConversion@12@PEAH@Z @@ -410,6 +405,7 @@ ?Find@ByChar@absl@@QEBA?AVstring_view@2@V32@_K@Z ?Find@ByLength@absl@@QEBA?AVstring_view@2@V32@_K@Z ?Find@ByString@absl@@QEBA?AVstring_view@2@V32@_K@Z + ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AVstring_view@3@XZ ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z ?FindSlow@CordRepRing@cord_internal@absl@@AEBA?AUPosition@123@I_K@Z ?FindTailSlow@CordRepRing@cord_internal@absl@@AEBA?AUPosition@123@I_K@Z
diff --git a/third_party/abseil-cpp/symbols_x86_dbg.def b/third_party/abseil-cpp/symbols_x86_dbg.def index 64ebcb7..11fac5c 100644 --- a/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/third_party/abseil-cpp/symbols_x86_dbg.def
@@ -280,12 +280,10 @@ ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AAEIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AAEIXZ ??$EmplaceBack@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z - ??$EmplaceBack@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z ??$EmplaceBack@PAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAPAUCordRep@cord_internal@2@$$QAPAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAUPayload@status_internal@2@$$QAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAUSubRange@2@$$QAU32@@Z ??$EmplaceBackSlow@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z - ??$EmplaceBackSlow@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z ??$EmplaceBackSlow@PAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAPAUCordRep@cord_internal@2@$$QAPAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAUPayload@status_internal@2@$$QAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAUSubRange@2@$$QAU32@@Z @@ -607,7 +605,6 @@ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEXXZ ??$emplace_back@AAVstring_view@absl@@ABV12@AAI@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QAEAAUViableSubstitution@strings_internal@absl@@AAVstring_view@5@ABV65@AAI@Z ??$emplace_back@ABQAUCordRep@cord_internal@absl@@@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEAAPAUCordRep@cord_internal@1@ABQAU231@@Z - ??$emplace_back@ABQAUCordRep@cord_internal@absl@@@?$InlinedVector@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEAAPAUCordRep@cord_internal@1@ABQAU231@@Z ??$emplace_back@PAUCordRep@cord_internal@absl@@@?$InlinedVector@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEAAPAUCordRep@cord_internal@1@$$QAPAU231@@Z ??$emplace_back@UPayload@status_internal@absl@@@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QAEAAUPayload@status_internal@1@$$QAU231@@Z ??$emplace_back@USubRange@absl@@@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QAEAAUSubRange@1@$$QAU21@@Z @@ -1146,7 +1143,6 @@ ??1?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__1@std@@@__1@std@@QAE@XZ ??1?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__1@std@@@__1@std@@QAE@XZ ??1BadStatusOrAccess@absl@@UAE@XZ - ??1ChunkIterator@Cord@absl@@QAE@XZ ??1CondVar@absl@@QAE@XZ ??1Cord@absl@@QAE@XZ ??1CordzHandle@cord_internal@absl@@MAE@XZ @@ -1476,8 +1472,6 @@ ?AdvanceBtree@ChunkIterator@Cord@absl@@AAEAAV123@XZ ?AdvanceBytes@ChunkIterator@Cord@absl@@AAEXI@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AAEXI@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AAEXI@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AAEAAV123@XZ ?Align@adl_barrier@internal_layout@container_internal@absl@@YAIII@Z ?AlignBegin@CordRepBtree@cord_internal@absl@@AAEXXZ ?AlignEnd@CordRepBtree@cord_internal@absl@@AAEXXZ @@ -1700,8 +1694,7 @@ ?DurationFromTimeval@absl@@YA?AVDuration@1@Utimeval@@@Z ?Edge@CordRepBtree@cord_internal@absl@@QBEPAUCordRep@23@I@Z ?Edge@CordRepBtree@cord_internal@absl@@QBEPAUCordRep@23@W4EdgeType@123@@Z - ?EdgeData@CordRepBtree@cord_internal@absl@@SA?AVstring_view@3@PBUCordRep@23@@Z - ?EdgeDataPtr@CordRepBtree@cord_internal@absl@@SAPBDPBUCordRep@23@@Z + ?EdgeData@cord_internal@absl@@YA?AVstring_view@2@PBUCordRep@12@@Z ?Edges@CordRepBtree@cord_internal@absl@@QBE?AV?$Span@QAUCordRep@cord_internal@absl@@@3@II@Z ?Edges@CordRepBtree@cord_internal@absl@@QBE?AV?$Span@QAUCordRep@cord_internal@absl@@@3@XZ ?EmplaceTree@InlineRep@Cord@absl@@QAEXPAUCordRep@cord_internal@3@ABVInlineData@53@W4MethodIdentifier@CordzUpdateTracker@53@@Z @@ -1994,7 +1987,7 @@ ?IsCancelled@absl@@YA_NABVStatus@1@@Z ?IsCooperative@SpinLock@base_internal@absl@@CA_NW4SchedulingMode@23@@Z ?IsCrc@CordRep@cord_internal@absl@@QBE_NXZ - ?IsDataEdge@CordRepBtree@cord_internal@absl@@SA_NPBUCordRep@23@@Z + ?IsDataEdge@cord_internal@absl@@YA_NPBUCordRep@12@@Z ?IsDataLoss@absl@@YA_NABVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NABVStatus@1@@Z ?IsEmpty@Queue@CordzHandle@cord_internal@absl@@QBE_NXZ @@ -3262,7 +3255,6 @@ ?probe@container_internal@absl@@YA?AV?$probe_seq@$0BA@@12@PBW4ctrl_t@12@II@Z ?push_back@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEXABQAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEX$$QAPAUCordRep@cord_internal@2@@Z - ?push_back@?$InlinedVector@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@absl@@QAEXABQAUCordRep@cord_internal@2@@Z ?push_back@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@absl@@QAEX$$QAUPayload@status_internal@2@@Z ?push_back@?$InlinedVector@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@absl@@QAEX$$QAUSubRange@2@@Z ?push_back@?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@AAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__1@std@@@__1@std@@QAEX$$QAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z
diff --git a/third_party/abseil-cpp/symbols_x86_rel.def b/third_party/abseil-cpp/symbols_x86_rel.def index 6b72311..58a8867 100644 --- a/third_party/abseil-cpp/symbols_x86_rel.def +++ b/third_party/abseil-cpp/symbols_x86_rel.def
@@ -42,11 +42,9 @@ ??$Dispatch@_N@FormatArgImpl@str_format_internal@absl@@CA_NTData@012@VFormatConversionSpecImpl@12@PAX@Z ??$DivMod@$09@?$BigUnsigned@$03@strings_internal@absl@@AAEIXZ ??$DivMod@$09@?$BigUnsigned@$0FE@@strings_internal@absl@@AAEIXZ - ??$EmplaceBack@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z ??$EmplaceBack@PAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAPAUCordRep@cord_internal@2@$$QAPAU342@@Z ??$EmplaceBack@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAUPayload@status_internal@2@$$QAU342@@Z ??$EmplaceBack@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@QAEAAUSubRange@2@$$QAU32@@Z - ??$EmplaceBackSlow@ABQAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAPAUCordRep@cord_internal@2@ABQAU342@@Z ??$EmplaceBackSlow@PAUCordRep@cord_internal@absl@@@?$Storage@PAUCordRep@cord_internal@absl@@$0CP@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAPAUCordRep@cord_internal@2@$$QAPAU342@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAUPayload@status_internal@2@$$QAU342@@Z ??$EmplaceBackSlow@USubRange@absl@@@?$Storage@USubRange@absl@@$0CP@V?$allocator@USubRange@absl@@@__1@std@@@inlined_vector_internal@absl@@AAEAAUSubRange@2@$$QAU32@@Z @@ -196,7 +194,6 @@ ??ACord@absl@@QBEDI@Z ??BCord@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__1@std@@V?$allocator@D@23@@__1@std@@XZ ??Bint128@absl@@QBENXZ - ??EChunkIterator@Cord@absl@@QAEAAV012@XZ ??Gdetail@cctz@time_internal@absl@@YA?AV?$civil_time@Uday_tag@detail@cctz@time_internal@absl@@@0123@V40123@_J@Z ??Gdetail@cctz@time_internal@absl@@YA?AV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@V40123@_J@Z ??Kabsl@@YA?AVint128@0@V10@0@Z @@ -230,8 +227,6 @@ ?AddressIsReadable@debugging_internal@absl@@YA_NPBX@Z ?AdvanceAndReadBytes@ChunkIterator@Cord@absl@@AAE?AV23@I@Z ?AdvanceBytesBtree@ChunkIterator@Cord@absl@@AAEXI@Z - ?AdvanceBytesSlowPath@ChunkIterator@Cord@absl@@AAEXI@Z - ?AdvanceStack@ChunkIterator@Cord@absl@@AAEAAV123@XZ ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPAXIPAUArena@123@@Z ?Allocate@?$MallocAdapter@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@$0A@@inlined_vector_internal@absl@@SA?AU?$Allocation@V?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@@23@AAV?$allocator@PAUCordRep@cord_internal@absl@@@__1@std@@I@Z ?Allocate@?$MallocAdapter@V?$allocator@UPayload@status_internal@absl@@@__1@std@@$0A@@inlined_vector_internal@absl@@SA?AU?$Allocation@V?$allocator@UPayload@status_internal@absl@@@__1@std@@@23@AAV?$allocator@UPayload@status_internal@absl@@@__1@std@@I@Z
diff --git a/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidation.html b/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidation.html new file mode 100644 index 0000000..6ec486b --- /dev/null +++ b/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidation.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../resources/runner.js"></script> +<style> + div { color: grey } + .a:has(~ .b .c) { color: green } +</style> +</head> +<body> +<div id=container><div class=a></div></div> +<script> + +function addChildren(element, numChildren, idPrefix) +{ + for (var i = 0; i < numChildren; i++) { + var child = document.createElement("div"); + child.id = idPrefix + i; + element.appendChild(child); + } +} + +function makeTree(element, depth, fanOut, idPrefix) +{ + if (depth <= 0) + return; + addChildren(element, fanOut, idPrefix); + for (var child = element.firstChild; child.nextSibling; child = child.nextSibling) { + makeTree(child, depth - 1, fanOut, child.id); + } + if (child) + makeTree(child, depth - 1, fanOut, child.id); +} + +for (var i = 0; i < 32; i++) { + var child = document.createElement("div"); + child.id = "child" + i; + child.classList.add("b"); + container.appendChild(child); + makeTree(child, 6, 2, child.id + "_") +} + +container.offsetHeight; // force recalc style + +var runFunction = function() +{ + child0_0.classList.toggle("c"); + container.offsetHeight; // force recalc style + document.querySelectorAll(".a").forEach(function(e) { + child0_0.classList.toggle("c"); + container.offsetHeight; // force recalc style + + child31_111111.classList.toggle("c"); + container.offsetHeight; // force recalc style + child31_111111.classList.toggle("c"); + container.offsetHeight; // force recalc style +} + +PerfTestRunner.measureRunsPerSecond({ + description: "Measures performance of the '.a:has(~ .b .c)' invalidation with a single subject element.", + run: runFunction +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidationAllSubjects.html b/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidationAllSubjects.html new file mode 100644 index 0000000..a4c9364d --- /dev/null +++ b/third_party/blink/perf_tests/css/HasSiblingDescendantInvalidationAllSubjects.html
@@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../resources/runner.js"></script> +<style> + div { color: grey } + .a:has(~ .b .c) { color: green } +</style> +</head> +<body> +<div id=container></div></div> +<script> + +function makeTree(element, depth, children) { + if (depth <= 0) { + var child = document.createElement("div"); + child.id = 'sibling_descendant'; + element.appendChild(child); + return; + } + + for (var i = 0; i < children - 1; i++) { + var child = document.createElement("div"); + child.classList.add("a"); + child.id = 'subject_' + depth + '_' + i; + element.appendChild(child); + } + var child = document.createElement("div"); + child.classList.add("b"); + element.appendChild(child); + makeTree(child, depth - 1, children); +} + +makeTree(container, 10, 10); +container.offsetHeight; // force recalc style + +var runFunction = function() +{ + sibling_descendant.classList.toggle("c"); + container.offsetHeight; // force recalc style + sibling_descendant.classList.toggle("c"); + container.offsetHeight; // force recalc style +} + +PerfTestRunner.measureRunsPerSecond({ + description: "Measures performance of the '.a:has(~ .b .c)' invalidation with all subject elements.", + run: runFunction +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/perf_tests/css/HasSiblingInvalidation.html b/third_party/blink/perf_tests/css/HasSiblingInvalidation.html new file mode 100644 index 0000000..1a44f2fb --- /dev/null +++ b/third_party/blink/perf_tests/css/HasSiblingInvalidation.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../resources/runner.js"></script> +<style> + div { color: grey } + .a:has(~ .b) { color: green } +</style> +</head> +<body> +<div id=container><div class=a></div></div> +<script> + +function makeTree(siblings) { + for (var i = 0; i < siblings; i++) { + var child = document.createElement("div"); + child.id = "child" + i; + container.appendChild(child); + } +} + +makeTree(2048); +container.offsetHeight; // force recalc style + +var runFunction = function() +{ + child0.classList.toggle("b"); + container.offsetHeight; // force recalc style + child0.classList.toggle("b"); + container.offsetHeight; // force recalc style + + child2047.classList.toggle("b"); + container.offsetHeight; // force recalc style + child2047.classList.toggle("b"); + container.offsetHeight; // force recalc style +} + +PerfTestRunner.measureRunsPerSecond({ + description: "Measures performance of the '.a:has(~ .b)' invalidation with a single subject element.", + run: runFunction +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/perf_tests/css/HasSiblingInvalidationAllSubjects.html b/third_party/blink/perf_tests/css/HasSiblingInvalidationAllSubjects.html new file mode 100644 index 0000000..154f559 --- /dev/null +++ b/third_party/blink/perf_tests/css/HasSiblingInvalidationAllSubjects.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../resources/runner.js"></script> +<style> + div { color: grey } + .a:has(~ .b) { color: green } +</style> +</head> +<body> +<div id=container><div class=a></div></div> +<script> + +function makeTree(siblings) { + for (var i = 0; i < siblings; i++) { + var child = document.createElement("div"); + child.classList.add("a"); + child.id = "child" + i; + container.appendChild(child); + } +} + +makeTree(100); +container.offsetHeight; // force recalc style + +var runFunction = function() +{ + child0.classList.toggle("b"); + container.offsetHeight; // force recalc style + child0.classList.toggle("b"); + container.offsetHeight; // force recalc style + + child99.classList.toggle("b"); + container.offsetHeight; // force recalc style + child99.classList.toggle("b"); + container.offsetHeight; // force recalc style +} + +PerfTestRunner.measureRunsPerSecond({ + description: "Measures performance of the '.a:has(~ .b)' invalidation with all subject elements.", + run: runFunction +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/renderer/core/css/affected_by_pseudo_test.cc b/third_party/blink/renderer/core/css/affected_by_pseudo_test.cc index f597a21..98425b9 100644 --- a/third_party/blink/renderer/core/css/affected_by_pseudo_test.cc +++ b/third_party/blink/renderer/core/css/affected_by_pseudo_test.cc
@@ -26,6 +26,18 @@ void SetHtmlInnerHTML(const char* html_content); void CheckElementsForFocus(ElementResult expected[], unsigned expected_count) const; + + enum AffectedByFlagName { + kAffectedBySubjectHas, + kAffectedByNonSubjectHas, + kAncestorsOrAncestorSiblingsAffectedByHas, + kSiblingsAffectedByHas, + kAffectedByPseudoInSubjectHas, + kAncestorsAffectedByHoverInSubjectHas + }; + void CheckAffectedByFlagsForHas( + const char* element_id, + std::map<AffectedByFlagName, bool> expected) const; }; void AffectedByPseudoTest::SetHtmlInnerHTML(const char* html_content) { @@ -51,6 +63,55 @@ DCHECK_EQ(i, expected_count); } +void AffectedByPseudoTest::CheckAffectedByFlagsForHas( + const char* element_id, + std::map<AffectedByFlagName, bool> expected) const { + bool actual; + const char* flag_name = nullptr; + for (auto iter : expected) { + switch (iter.first) { + case kAffectedBySubjectHas: + actual = GetElementById(element_id) + ->GetComputedStyle() + ->AffectedBySubjectHas(); + flag_name = "AffectedBySubjectHas"; + break; + case kAffectedByNonSubjectHas: + actual = GetElementById(element_id)->AffectedByNonSubjectHas(); + flag_name = "AffectedByNonSubjectHas"; + break; + case kAncestorsOrAncestorSiblingsAffectedByHas: + actual = GetElementById(element_id) + ->AncestorsOrAncestorSiblingsAffectedByHas(); + flag_name = "AncestorsOrAncestorSiblingsAffectedByHas"; + break; + case kSiblingsAffectedByHas: + actual = GetElementById(element_id)->SiblingsAffectedByHas(); + flag_name = "SiblingsAffectedByHas"; + break; + case kAffectedByPseudoInSubjectHas: + actual = GetElementById(element_id) + ->GetComputedStyle() + ->AffectedByPseudoInSubjectHas(); + flag_name = "AffectedByPseudoInSubjectHas"; + break; + case kAncestorsAffectedByHoverInSubjectHas: + actual = GetElementById(element_id) + ->GetComputedStyle() + ->AncestorsAffectedByHoverInSubjectHas(); + flag_name = "AncestorsAffectedByHoverInSubjectHas"; + break; + } + DCHECK(flag_name); + if (iter.second == actual) + continue; + + ADD_FAILURE() << "#" << element_id << " : " << flag_name << " should be " + << (iter.second ? "true" : "false") << " but " + << (actual ? "true" : "false"); + } +} + // ":focus div" will mark ascendants of all divs with // childrenOrSiblingsAffectedByFocus. TEST_F(AffectedByPseudoTest, FocusedAscendant) { @@ -328,7 +389,8 @@ EXPECT_FALSE(GetElementById("div1")->GetComputedStyle()->AffectedByHover()); } -TEST_F(AffectedByPseudoTest, AffectedByHasAndAncestorsAffectedByHas) { +TEST_F(AffectedByPseudoTest, + AffectedBySubjectHasAndAncestorsOrAncestorSiblingsAffectedByHas) { SetHtmlInnerHTML(R"HTML( <style>.a:has(.b) { background-color: lime; }</style> <div id=div1> @@ -348,36 +410,36 @@ )HTML"); UpdateAllLifecyclePhasesForTest(); - EXPECT_FALSE( - GetElementById("div1")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div1")->AncestorsAffectedByHas()); - EXPECT_TRUE( - GetElementById("div2")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div2")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div3")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_TRUE(GetElementById("div3")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div4")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_TRUE(GetElementById("div4")->AncestorsAffectedByHas()); - EXPECT_TRUE( - GetElementById("div5")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div6")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div7")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_TRUE(GetElementById("div7")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div8")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div8")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div9")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div9")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div10")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div10")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div8", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div10", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); unsigned start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div10")->setAttribute(html_names::kClassAttr, "b"); @@ -410,15 +472,15 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_TRUE( - GetElementById("div5")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_FALSE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div6")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_TRUE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE( - GetElementById("div7")->GetComputedStyle()->AffectedBySubjectHas()); - EXPECT_TRUE(GetElementById("div7")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); } TEST_F(AffectedByPseudoTest, @@ -450,78 +512,42 @@ )HTML"); UpdateAllLifecyclePhasesForTest(); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div2") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_TRUE(GetElementById("div5") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div5") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div6") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div6") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div7") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div7") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_TRUE(GetElementById("div8") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div8") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div9") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div9") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div10") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div10") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div11") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div11") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div12") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div12") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div13") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div13") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); + CheckAffectedByFlagsForHas("div2", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div13", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); unsigned start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div3")->SetHovered(true); @@ -546,24 +572,15 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(3U, element_count); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div3") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div4") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); + CheckAffectedByFlagsForHas("div2", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div3")->setAttribute(html_names::kClassAttr, "b"); @@ -571,24 +588,15 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div3") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div4") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); + CheckAffectedByFlagsForHas("div2", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div3")->SetHovered(true); @@ -612,24 +620,15 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div3") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_TRUE(GetElementById("div4") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); + CheckAffectedByFlagsForHas("div2", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, true}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div4")->setAttribute(html_names::kClassAttr, ""); @@ -637,24 +636,15 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(3U, element_count); - EXPECT_TRUE(GetElementById("div2") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div2") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div3") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AffectedByPseudoInSubjectHas()); - EXPECT_FALSE(GetElementById("div4") - ->GetComputedStyle() - ->AncestorsAffectedByHoverInSubjectHas()); + CheckAffectedByFlagsForHas("div2", + {{kAffectedByPseudoInSubjectHas, true}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedByPseudoInSubjectHas, false}, + {kAncestorsAffectedByHoverInSubjectHas, false}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div6")->SetHovered(true); @@ -706,7 +696,7 @@ } TEST_F(AffectedByPseudoTest, - AffectedByNonSubjectHasHasAndAncestorsAffectedByHas) { + AffectedByNonSubjectHasHasAndAncestorsOrAncestorSiblingsAffectedByHas) { SetHtmlInnerHTML(R"HTML( <style>.a:has(.b) .c { background-color: lime; }</style> <div id=div1> @@ -723,20 +713,27 @@ )HTML"); UpdateAllLifecyclePhasesForTest(); - EXPECT_FALSE(GetElementById("div1")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div1")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div2")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div2")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div3")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div3")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div4")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div4")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div5")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div6")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div7")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div7")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); unsigned start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div7")->setAttribute(html_names::kClassAttr, "c"); @@ -745,20 +742,27 @@ GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_FALSE(GetElementById("div1")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div1")->AncestorsAffectedByHas()); - EXPECT_TRUE(GetElementById("div2")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div2")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div3")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div3")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div4")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div4")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div5")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div6")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div7")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div7")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div6")->setAttribute(html_names::kClassAttr, ""); @@ -766,20 +770,27 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_FALSE(GetElementById("div1")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div1")->AncestorsAffectedByHas()); - EXPECT_TRUE(GetElementById("div2")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div2")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div3")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div3")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div4")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div4")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div5")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div6")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div7")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div7")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); start_count = GetStyleEngine().StyleForElementCount(); GetElementById("div5")->setAttribute(html_names::kClassAttr, "b"); @@ -787,20 +798,1509 @@ element_count = GetStyleEngine().StyleForElementCount() - start_count; ASSERT_EQ(1U, element_count); - EXPECT_FALSE(GetElementById("div1")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div1")->AncestorsAffectedByHas()); - EXPECT_TRUE(GetElementById("div2")->AffectedByNonSubjectHas()); - EXPECT_FALSE(GetElementById("div2")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div3")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div3")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div4")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div4")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div5")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div5")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div6")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div6")->AncestorsAffectedByHas()); - EXPECT_FALSE(GetElementById("div7")->AffectedByNonSubjectHas()); - EXPECT_TRUE(GetElementById("div7")->AncestorsAffectedByHas()); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}}); +} + +TEST_F(AffectedByPseudoTest, + AffectedByNonSubjectHasHasAndSiblingsAffectedByHas) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b) .c { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4></div> + <div id=div5 class='b'></div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div3")->setAttribute(html_names::kClassAttr, "c"); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + + start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div5")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + element_count = GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase1) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(.b ~ .c) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + <div id=div4> + <div id=div5></div> + <div id=div6 class='b'></div> + <div id=div7></div> + <div id=div8 class='c'></div> + <div id=div9></div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div8")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase2) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4> + <div id=div5></div> + </div> + <div id=div6 class='b'> + <div id=div7></div> + <div id=div8> + <div id=div9></div> + <div id=div10 class='c'></div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div6")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase3) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(.b ~ .c .d) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + <div id=div4> + <div id=div5></div> + <div id=div6 class='b'></div> + <div id=div7></div> + <div id=div8 class='c'> + <div id=div9></div> + <div id=div10> + <div id=div11></div> + <div id=div12 class='d'></div> + </div> + </div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div11", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div8")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div3", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div4", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase4) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c ~ .d .e) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4> + <div id=div5></div> + </div> + <div id=div6 class='b'> + <div id=div7></div> + <div id=div8> + <div id=div9></div> + <div id=div10 class='c'></div> + <div id=div11></div> + <div id=div12 class='d'> + <div id=div13></div> + <div id=div14 class='e'></div> + </div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div13", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div14", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div6")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div13", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div14", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase5) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'></div> + <div id=div3></div> + <div id=div4 class='b'> + <div id=div5 class='a'></div> + <div id=div6></div> + <div id=div7 class='b'> + <div id=div8 class='a'></div> + <div id=div9></div> + <div id=div10 class='b'> + <div id=div11 class='c'></div> + </div> + <div id=div12></div> + </div> + <div id=div13></div> + </div> + <div id=div14></div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div8", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div13", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div14", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase6) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c) { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'></div> + <div id=div3></div> + <div id=div4 class='b'> + <div id=div5 class='a'></div> + <div id=div6></div> + <div id=div7 class='b'> + <div id=div8 class='a'></div> + <div id=div9></div> + <div id=div10 class='b'> + <div id=div11></div> + </div> + <div id=div12></div> + </div> + <div id=div13></div> + </div> + <div id=div14></div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div13", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div14", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); +} + +TEST_F(AffectedByPseudoTest, AffectedBySubjectHasComplexCase7) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(+ .b .c) { background-color: lime; }</style> + <div id=div1> + <div id=div2></div> + <div id=div3 class='a'></div> + <div id=div4 class='b'> + <div id=div5></div> + <div id=div6 class='a'></div> + <div id=div7 class='b'> + <div id=div8></div> + <div id=div9 class='a'></div> + <div id=div10 class='b'> + <div id=div11></div> + </div> + <div id=div12></div> + </div> + <div id=div13></div> + </div> + <div id=div14></div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div7", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, true}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div10", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div11", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div12", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div13", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div14", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedByNonSubjectHasComplexCase1) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c) .d { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4> + <div id=div5> + <div id=div6></div> + </div> + </div> + <div id=div7 class='b'> + <div id=div8> + <div id=div9 class='c'></div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div8", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div3")->setAttribute(html_names::kClassAttr, "d"); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div9")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + element_count = GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedByNonSubjectHasComplexCase2) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b .c) ~ .d { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4> + <div id=div5> + <div id=div6></div> + </div> + </div> + <div id=div7 class='b'> + <div id=div8> + <div id=div9 class='c'></div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div8", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div4")->setAttribute(html_names::kClassAttr, "d"); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + + start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div9")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + element_count = GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); +} + +TEST_F(AffectedByPseudoTest, AffectedByNonSubjectHasComplexCase3) { + SetHtmlInnerHTML(R"HTML( + <style>.a:has(~ .b > .c > .d) ~ .e { background-color: lime; }</style> + <div id=div1> + <div id=div2 class='a'> + <div id=div3></div> + </div> + <div id=div4> + <div id=div5> + <div id=div6></div> + </div> + </div> + <div id=div7 class='b'> + <div id=div8 class='c'> + <div id=div9 class='d'> + <div id=div10></div> + </div> + </div> + </div> + </div> + )HTML"); + + UpdateAllLifecyclePhasesForTest(); + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div8", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div9", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div10", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + + unsigned start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div4")->setAttribute(html_names::kClassAttr, "e"); + UpdateAllLifecyclePhasesForTest(); + unsigned element_count = + GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas( + "div5", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div6", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div10", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + + start_count = GetStyleEngine().StyleForElementCount(); + GetElementById("div8")->setAttribute(html_names::kClassAttr, ""); + UpdateAllLifecyclePhasesForTest(); + element_count = GetStyleEngine().StyleForElementCount() - start_count; + ASSERT_EQ(1U, element_count); + + CheckAffectedByFlagsForHas( + "div1", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div2", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, true}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div3", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div4", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div5", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div6", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div7", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, true}}); + CheckAffectedByFlagsForHas("div8", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas("div9", + {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, true}, + {kSiblingsAffectedByHas, false}}); + CheckAffectedByFlagsForHas( + "div10", {{kAffectedBySubjectHas, false}, + {kAffectedByNonSubjectHas, false}, + {kAncestorsOrAncestorSiblingsAffectedByHas, false}, + {kSiblingsAffectedByHas, false}}); } } // namespace blink
diff --git a/third_party/blink/renderer/core/css/cascade_layer.h b/third_party/blink/renderer/core/css/cascade_layer.h index c65c7857..0d8e599 100644 --- a/third_party/blink/renderer/core/css/cascade_layer.h +++ b/third_party/blink/renderer/core/css/cascade_layer.h
@@ -26,6 +26,11 @@ return direct_sub_layers_; } + // Getting or setting the order of a layer is only valid for canonical cascade + // layers i.e. the unique layer representation for a particular tree scope. + const absl::optional<unsigned> GetOrder() const { return order_; } + void SetOrder(unsigned order) { order_ = order; } + CascadeLayer* GetOrAddSubLayer(const StyleRuleBase::LayerName& name); void Trace(blink::Visitor*) const; @@ -40,6 +45,7 @@ CascadeLayer* FindDirectSubLayer(const AtomicString&) const; void ComputeLayerOrderInternal(unsigned* next); + absl::optional<unsigned> order_; AtomicString name_; HeapVector<Member<CascadeLayer>> direct_sub_layers_; };
diff --git a/third_party/blink/renderer/core/css/cascade_layer_map.cc b/third_party/blink/renderer/core/css/cascade_layer_map.cc index 62e0cc1..03b12d4e 100644 --- a/third_party/blink/renderer/core/css/cascade_layer_map.cc +++ b/third_party/blink/renderer/core/css/cascade_layer_map.cc
@@ -32,12 +32,10 @@ } } -void ComputeLayerOrder(const CascadeLayer& layer, - unsigned& next, - LayerOrderMap& layer_order_map) { +void ComputeLayerOrder(CascadeLayer& layer, unsigned& next) { for (const auto& sub_layer : layer.GetDirectSubLayers()) - ComputeLayerOrder(*sub_layer, next, layer_order_map); - layer_order_map.insert(&layer, next++); + ComputeLayerOrder(*sub_layer, next); + layer.SetOrder(next++); } } // namespace @@ -55,15 +53,14 @@ } unsigned next = 0; - LayerOrderMap canonical_layer_order_map; - ComputeLayerOrder(*canonical_root_layer, next, canonical_layer_order_map); + ComputeLayerOrder(*canonical_root_layer, next); - canonical_layer_order_map.Set(canonical_root_layer, kImplicitOuterLayerOrder); + canonical_root_layer->SetOrder(kImplicitOuterLayerOrder); for (const auto& iter : canonical_layer_map) { const CascadeLayer* layer_from_sheet = iter.key; const CascadeLayer* canonical_layer = iter.value; - unsigned layer_order = canonical_layer_order_map.at(canonical_layer); + unsigned layer_order = canonical_layer->GetOrder().value(); layer_order_map_.insert(layer_from_sheet, layer_order); #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/css/has_argument_match_context.cc b/third_party/blink/renderer/core/css/has_argument_match_context.cc index 74fdb6d..e20afe2 100644 --- a/third_party/blink/renderer/core/css/has_argument_match_context.cc +++ b/third_party/blink/renderer/core/css/has_argument_match_context.cc
@@ -29,6 +29,9 @@ CSSSelector::RelationType relation = CSSSelector::kSubSelector; depth_limit_ = 0; adjacent_distance_limit_ = 0; + bool contains_child_or_descendant_combinator = false; + bool sibling_combinator_at_leftmost = false; + // The explicit ':scope' in ':has' argument selector is not considered // for getting the depth and adjacent distance. // TODO(blee@igalia.com) Need to clarify the :scope dependency in relative @@ -43,6 +46,11 @@ leftmost_relation_ = relation; [[fallthrough]]; case CSSSelector::kDescendant: + if (sibling_combinator_at_leftmost) { + sibling_combinator_at_leftmost = false; + sibling_combinator_between_child_or_descendant_combinator_ = true; + } + contains_child_or_descendant_combinator = true; depth_limit_ = kInfiniteDepth; adjacent_distance_limit_ = 0; break; @@ -51,6 +59,11 @@ leftmost_relation_ = relation; [[fallthrough]]; case CSSSelector::kChild: + if (sibling_combinator_at_leftmost) { + sibling_combinator_at_leftmost = false; + sibling_combinator_between_child_or_descendant_combinator_ = true; + } + contains_child_or_descendant_combinator = true; if (DepthFixed()) { depth_limit_++; adjacent_distance_limit_ = 0; @@ -61,6 +74,10 @@ leftmost_relation_ = relation; [[fallthrough]]; case CSSSelector::kDirectAdjacent: + if (contains_child_or_descendant_combinator) + sibling_combinator_at_leftmost = true; + else + sibling_combinator_at_rightmost_ = true; if (AdjacentDistanceFixed()) adjacent_distance_limit_++; break; @@ -69,6 +86,10 @@ leftmost_relation_ = relation; [[fallthrough]]; case CSSSelector::kIndirectAdjacent: + if (contains_child_or_descendant_combinator) + sibling_combinator_at_leftmost = true; + else + sibling_combinator_at_rightmost_ = true; adjacent_distance_limit_ = kInfiniteAdjacentDistance; break; @@ -166,4 +187,56 @@ DCHECK(current_); } +AffectedByHasIterator::AffectedByHasIterator( + HasArgumentSubtreeIterator& iterator_at_matched) + : iterator_at_matched_(iterator_at_matched), + depth_(iterator_at_matched_.Depth()), + current_(iterator_at_matched_.CurrentElement()) { + DCHECK_GE(depth_, 0); +} + +bool AffectedByHasIterator::NeedsTraverseSiblings() { + // When the current element is at the same depth of the subselector-matched + // element, we can determine whether the sibling traversal is needed or not + // by checking whether the rightmost combinator is an adjacent combinator. + // When the current element is not at the same depth of the subselector- + // matched element, we can determine whether the sibling traversal is needed + // or not by checking whether an adjacent combinator is between child or + // descendant combinator. + DCHECK_LE(depth_, iterator_at_matched_.Depth()); + return iterator_at_matched_.Depth() == depth_ + ? iterator_at_matched_.Context().SiblingCombinatorAtRightmost() + : iterator_at_matched_.Context() + .SiblingCombinatorBetweenChildOrDescendantCombinator(); +} + +bool AffectedByHasIterator::AtEnd() const { + DCHECK_GE(iterator_at_matched_.Depth(), 0); + return current_ == iterator_at_matched_.ScopeElement(); +} + +void AffectedByHasIterator::operator++() { + DCHECK(current_); + DCHECK_GE(iterator_at_matched_.Depth(), 0); + + if (depth_ == 0) { + current_ = Traversal<Element>::PreviousSibling(*current_); + DCHECK(current_); + return; + } + + Element* previous = nullptr; + if (NeedsTraverseSiblings() && + (previous = Traversal<Element>::PreviousSibling(*current_))) { + current_ = previous; + DCHECK(current_); + return; + } + + DCHECK_GT(depth_, 0); + depth_--; + current_ = current_->parentElement(); + DCHECK(current_); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/css/has_argument_match_context.h b/third_party/blink/renderer/core/css/has_argument_match_context.h index 0d7d2cf..5ec9e41 100644 --- a/third_party/blink/renderer/core/css/has_argument_match_context.h +++ b/third_party/blink/renderer/core/css/has_argument_match_context.h
@@ -27,6 +27,13 @@ return leftmost_relation_; } + inline bool SiblingCombinatorAtRightmost() const { + return sibling_combinator_at_rightmost_; + } + inline bool SiblingCombinatorBetweenChildOrDescendantCombinator() const { + return sibling_combinator_between_child_or_descendant_combinator_; + } + private: const static int kInfiniteDepth = std::numeric_limits<int>::max(); const static int kInfiniteAdjacentDistance = std::numeric_limits<int>::max(); @@ -151,6 +158,11 @@ CSSSelector::RelationType leftmost_relation_; int adjacent_distance_limit_; int depth_limit_; + + // Indicates the selector's combinator information which can be used for + // sibling traversal after subselector matched. + bool sibling_combinator_at_rightmost_{false}; + bool sibling_combinator_between_child_or_descendant_combinator_{false}; }; // Subtree traversal iterator class for ':has' argument matching. To @@ -202,8 +214,11 @@ Element* CurrentElement() const { return current_; } bool AtEnd() const { return !current_; } bool AtFixedDepth() const { return depth_ == context_.DepthLimit(); } + bool UnderDepthLimit() const { return depth_ <= context_.DepthLimit(); } bool AtSiblingOfHasScope() const { return depth_ == 0; } - int Depth() const { return depth_; } + inline int Depth() const { return depth_; } + inline Element* ScopeElement() const { return has_scope_element_; } + inline const HasArgumentMatchContext& Context() const { return context_; } private: inline Element* LastWithin(Element*); @@ -215,6 +230,30 @@ Element* traversal_end_{nullptr}; }; +// Iterator class to traverse siblings, ancestors and ancestor siblings of the +// HasArgumentSubtreeIterator's current element until reach to the scope +// element. +// This iterator is used to set the 'AncestorsOrAncestorSiblingsAffectedByHas' +// or 'SiblingsAffectedByHas' flags of those elements before returning early +// from the ':has()' argument subtree traversal. +class AffectedByHasIterator { + STACK_ALLOCATED(); + + public: + explicit AffectedByHasIterator(HasArgumentSubtreeIterator&); + void operator++(); + Element* CurrentElement() const { return current_; } + bool AtEnd() const; + bool AtSiblingOfHasScope() const { return depth_ == 0; } + + private: + inline bool NeedsTraverseSiblings(); + + const HasArgumentSubtreeIterator& iterator_at_matched_; + int depth_; + Element* current_; +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_HAS_ARGUMENT_MATCH_CONTEXT_H_
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc index b3d3d04d..f36d925 100644 --- a/third_party/blink/renderer/core/css/selector_checker.cc +++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -655,12 +655,70 @@ return true; } +namespace { + +Element* TraverseToParent(Element* element) { + return element->parentElement(); +} + +Element* TraverseToPreviousSibling(Element* element) { + return ElementTraversal::PreviousSibling(*element); +} + +inline bool CacheMatchedElementsAndReturnMatchedResultForIndirectRelation( + Element* has_scope_element, + HeapVector<Member<Element>>& has_argument_leftmost_compound_matches, + ElementHasMatchedMap& map, + Element* (*next)(Element*)) { + bool selector_matched = false; + for (auto leftmost : has_argument_leftmost_compound_matches) { + for (Element* has_matched_element = next(leftmost); has_matched_element; + has_matched_element = next(has_matched_element)) { + if (has_matched_element == has_scope_element) + selector_matched = true; + auto cache_result = map.insert(has_matched_element, true); + if (cache_result.is_new_entry) + continue; + if (cache_result.stored_value->value) + break; + cache_result.stored_value->value = true; + } + } + return selector_matched; +} + +inline bool CacheMatchedElementsAndReturnMatchedResultForDirectRelation( + Element* has_scope_element, + HeapVector<Member<Element>>& has_argument_leftmost_compound_matches, + ElementHasMatchedMap& map, + Element* (*next)(Element*)) { + bool selector_matched = false; + for (auto leftmost : has_argument_leftmost_compound_matches) { + if (Element* has_matched_element = next(leftmost)) { + map.Set(has_matched_element, true); + if (has_matched_element == has_scope_element) + selector_matched = true; + } + } + return selector_matched; +} + +inline void SetAffectedByHasFlag(Element* element, + bool is_sibling_of_has_scope) { + if (is_sibling_of_has_scope) + element->SetSiblingsAffectedByHas(); + else + element->SetAncestorsOrAncestorSiblingsAffectedByHas(); +} + +} // namespace + bool SelectorChecker::CheckPseudoHas(const SelectorCheckingContext& context, MatchResult& result) const { - Document& document = context.element->GetDocument(); + Element* has_scope_element = context.element; + Document& document = has_scope_element->GetDocument(); DCHECK(document.GetHasMatchedCacheScope()); - Element* element = context.element; - SelectorCheckingContext sub_context(element); + SelectorCheckingContext sub_context(has_scope_element); // TODO(blee@igalia.com) Need to clarify the :scope dependency in relative // selector definition. // - spec : https://www.w3.org/TR/selectors-4/#relative @@ -676,6 +734,9 @@ selector; selector = CSSSelectorList::Next(*selector)) { ElementHasMatchedMap& map = HasMatchedCacheScope::GetCacheForSelector(&document, selector); + HasArgumentMatchContext has_argument_match_context(selector); + CSSSelector::RelationType leftmost_relation = + has_argument_match_context.LeftmostRelation(); // Get the cache item of matching ':has(<selector>)' on the element // to skip argument matching on the subtree elements @@ -684,8 +745,38 @@ // move to the next argument selector. // - Otherwise, mark the element as checked but not matched. { // Limit the the AddResult scope to prevent SECURITY_DCHECK - auto cache_result = map.insert(element, false); // Mark as checked + auto cache_result = + map.insert(has_scope_element, false); // Mark as checked if (!cache_result.is_new_entry) { // Was already marked as checked + + // The SiblingsAffectedByHas flag is set only when an element is a + // sibling of the :has() scope element during the subselector matching. + // But during the matching, the matching status of some elements are + // cached and those element cannot be a sibling of the :has() scope + // element in case that the subselector starts with adjacent combinator. + // 1. MatchSelector() gives some possibly matched elements, and those + // are cached as matched. + // 2. If an element is not matched, then it is cached as not matched. + // We need to set missing SiblingAffectedByHas flags for the cached + // elements before returning early. + switch (leftmost_relation) { + case CSSSelector::kRelativeDirectAdjacent: + if (Element* next_sibling = + ElementTraversal::NextSibling(*has_scope_element)) + next_sibling->SetSiblingsAffectedByHas(); + break; + case CSSSelector::kRelativeIndirectAdjacent: + for (Element* next_sibling = + ElementTraversal::NextSibling(*has_scope_element); + next_sibling && !next_sibling->SiblingsAffectedByHas(); + next_sibling = ElementTraversal::NextSibling(*next_sibling)) { + next_sibling->SetSiblingsAffectedByHas(); + } + break; + default: + break; + } + if (cache_result.stored_value->value) // Was already marked as matched return true; continue; @@ -693,7 +784,6 @@ } sub_context.selector = selector; - HasArgumentMatchContext has_argument_match_context(selector); bool depth_fixed = has_argument_match_context.DepthFixed(); @@ -735,24 +825,38 @@ // - csswg issue : https://github.com/w3c/csswg-drafts/issues/6399 if (!depth_fixed) { sub_context.relative_leftmost_element = - &element->GetTreeScope().RootNode(); + &has_scope_element->GetTreeScope().RootNode(); } else if (has_argument_match_context.AdjacentDistanceFixed()) { - if (ContainerNode* parent_node = element->parentNode()) { + if (ContainerNode* parent_node = has_scope_element->parentNode()) { sub_context.relative_leftmost_element = Traversal<Element>::FirstChild(*parent_node); } else { - sub_context.relative_leftmost_element = element; + sub_context.relative_leftmost_element = has_scope_element; } } else { - sub_context.relative_leftmost_element = element; + sub_context.relative_leftmost_element = has_scope_element; } bool selector_matched = false; - for (HasArgumentSubtreeIterator iterator(*element, + for (HasArgumentSubtreeIterator iterator(*has_scope_element, has_argument_match_context); !iterator.AtEnd(); ++iterator) { - if (depth_fixed && !iterator.AtFixedDepth()) + if (depth_fixed && !iterator.AtFixedDepth()) { + // We can skip subselector matching on some elements at a certain depth + // when the subselector doesn't have descendant combinator. (e.g. For + // the style rule '.a:has(> .b > .c) {}', we don't need to match the + // subselector '> .b > .c' on the child of '.a' or the great-grand-child + // of '.a'.) + // But this can break the upward tree walk because the 'affected-by' + // flags of the skipped elements will not set. + // To prevent this, marks the flags of skipped elements if those are + // under the depth limit. + if (iterator.UnderDepthLimit()) { + SetAffectedByHasFlag(iterator.CurrentElement(), + iterator.AtSiblingOfHasScope()); + } continue; + } sub_context.element = iterator.CurrentElement(); HeapVector<Member<Element>> has_argument_leftmost_compound_matches; MatchResult sub_result; @@ -761,54 +865,30 @@ MatchSelector(sub_context, sub_result); - switch (has_argument_match_context.LeftmostRelation()) { + switch (leftmost_relation) { case CSSSelector::kRelativeDescendant: - map.insert(iterator.CurrentElement(), false); // Mark as checked - if (!has_argument_leftmost_compound_matches.IsEmpty()) { - sub_context.element = - has_argument_leftmost_compound_matches.front(); - for (sub_context.element = ParentElement(sub_context); - sub_context.element; - sub_context.element = ParentElement(sub_context)) { - map.Set(sub_context.element, true); // Mark as matched - if (sub_context.element == element) - selector_matched = true; - } - } + selector_matched = + CacheMatchedElementsAndReturnMatchedResultForIndirectRelation( + has_scope_element, has_argument_leftmost_compound_matches, + map, TraverseToParent); break; case CSSSelector::kRelativeChild: - for (auto leftmost : has_argument_leftmost_compound_matches) { - Element* parent = leftmost->parentElement(); - map.Set(parent, true); // Mark as matched - if (parent == element) - selector_matched = true; - } + selector_matched = + CacheMatchedElementsAndReturnMatchedResultForDirectRelation( + has_scope_element, has_argument_leftmost_compound_matches, + map, TraverseToParent); break; case CSSSelector::kRelativeDirectAdjacent: - if (!depth_fixed && !iterator.AtSiblingOfHasScope()) - map.insert(iterator.CurrentElement(), false); // Mark as checked - for (auto leftmost : has_argument_leftmost_compound_matches) { - if (Element* sibling = - Traversal<Element>::PreviousSibling(*leftmost)) { - map.Set(sibling, true); // Mark as matched - if (sibling == element) - selector_matched = true; - } - } + selector_matched = + CacheMatchedElementsAndReturnMatchedResultForDirectRelation( + has_scope_element, has_argument_leftmost_compound_matches, + map, TraverseToPreviousSibling); break; case CSSSelector::kRelativeIndirectAdjacent: - if (!depth_fixed) - map.insert(iterator.CurrentElement(), false); // Mark as checked - for (auto leftmost : has_argument_leftmost_compound_matches) { - for (Element* sibling = - Traversal<Element>::PreviousSibling(*leftmost); - sibling; - sibling = Traversal<Element>::PreviousSibling(*sibling)) { - map.Set(sibling, true); // Mark as matched - if (sibling == element) - selector_matched = true; - } - } + selector_matched = + CacheMatchedElementsAndReturnMatchedResultForIndirectRelation( + has_scope_element, has_argument_leftmost_compound_matches, + map, TraverseToPreviousSibling); break; default: NOTREACHED(); @@ -816,37 +896,36 @@ } if (selector_matched) { - // Need to walk up ancestors to set 'AncestorsAffectedByHas' flag so - // that the StyleEngine can walk up to find the elements affected by - // subject or non-subject :has(). + // Need to walk up to set 'AncestorsOrAncestorSiblingsAffectedByHas' + // or 'SiblingsAffectedByHas' flag so that the StyleEngine can walk up + // to find the elements affected by subject or non-subject :has(). // // StyleEngine tries to find elements affected by :has() by walking up - // ancestors of a mutated element only when an element marked as - // 'AncestorsAffectedByHas'. If an ancestor of the mutated element - // is not 'AncestorsAffectedByHas' element, then StyleEngine will stop - // the upward tree walk at the element. + // siblings or ancestors a mutated element only when an element has the + // flags set. If an element doesn't have those flags set, then the + // StyleEngine will stop the upward tree walk at the element. // // HasArgumentSubtreeIterator traverses the sub-tree in the reversed // DOM tree walk order for preventing O(n^2) matching problem of // multiple elements affected by :has(). Due to this traversal order, - // this early returning can break the upward tree walk. To prevent the - // problem, marks all ancestors as 'AncestorsAffectedByHas' before - // returning. + // this early returning can break the upward tree walk. // - // Similar to the DynamicRestyleFlags in the ContainerNode, this flag + // To prevent the problem, walks up until reach to the scope element + // and marks elements as 'AncestorsOrAncestorSiblingsAffectedByHas' or + // 'SiblingsAffectedByHas' before returning. + // + // Similar to the DynamicRestyleFlags in the ContainerNode, these flags // will never be reset. - // - // TODO(blee@igalia.com) Need to traverse to siblings and siblings of - // ancestors to support sibling combinator and complex selector in - // :has() argument. - for (Element* parent = iterator.CurrentElement(); - parent && parent != element; parent = parent->parentElement()) { - parent->SetAncestorsAffectedByHas(); + for (AffectedByHasIterator affected_by_has_iterator(iterator); + !affected_by_has_iterator.AtEnd(); ++affected_by_has_iterator) { + SetAffectedByHasFlag(affected_by_has_iterator.CurrentElement(), + affected_by_has_iterator.AtSiblingOfHasScope()); } return true; - } else { - iterator.CurrentElement()->SetAncestorsAffectedByHas(); } + + SetAffectedByHasFlag(iterator.CurrentElement(), + iterator.AtSiblingOfHasScope()); } } return false;
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc index 8d5cff51..60f9c0d 100644 --- a/third_party/blink/renderer/core/css/style_engine.cc +++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -941,12 +941,39 @@ return element.parentNode()->GetStyleChangeType() == kSubtreeStyleChange; } -void StyleEngine::InvalidateAncestorsAffectedByHasInternal( - Element* element, +namespace { + +bool PossiblyAffectingHasState(Element& element) { + return element.AncestorsOrAncestorSiblingsAffectedByHas() || + element.SiblingsAffectedByHas(); +} + +inline Element* SelfOrPreviousSibling(Node* node) { + if (!node) + return nullptr; + if (Element* element = DynamicTo<Element>(node)) + return element; + return ElementTraversal::PreviousSibling(*node); +} + +} // namespace + +void StyleEngine::InvalidateAncestorsOrSiblingsAffectedByHasInternal( + Element* parent, + Element* previous_sibling, bool for_pseudo_change) { const RuleFeatureSet& features = GetRuleFeatureSet(); + bool traverse_ancestors = false; + bool traverse_siblings = false; + Element* element = previous_sibling ? previous_sibling : parent; + + DCHECK(element); + while (element) { + traverse_ancestors |= element->AncestorsOrAncestorSiblingsAffectedByHas(); + traverse_siblings = element->SiblingsAffectedByHas(); + const ComputedStyle* style = element->GetComputedStyle(); if (style && style->AffectedBySubjectHas() && @@ -970,23 +997,56 @@ *element); } - // Stop walk up when the 'AncestorsAffectedByHas' flag is false. - if (!element->AncestorsAffectedByHas()) + if (traverse_siblings) { + previous_sibling = ElementTraversal::PreviousSibling(*element); + if (previous_sibling) { + element = previous_sibling; + continue; + } + } + + if (!traverse_ancestors) return; element = element->parentElement(); + traverse_ancestors = false; } } -void StyleEngine::InvalidateAncestorsAffectedByHasForPseudoChange( - Element* element) { - InvalidateAncestorsAffectedByHasInternal(element, - true /* for_pseudo_change */); +void StyleEngine::InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + Element& changed_element) { + InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + changed_element.AncestorsOrAncestorSiblingsAffectedByHas() + ? changed_element.parentElement() + : nullptr, + changed_element.SiblingsAffectedByHas() + ? ElementTraversal::PreviousSibling(changed_element) + : nullptr); } -void StyleEngine::InvalidateAncestorsAffectedByHas(Element* element) { - InvalidateAncestorsAffectedByHasInternal(element, - false /* for_pseudo_change */); +void StyleEngine::InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + Element* parent, + Element* previous_sibling) { + InvalidateAncestorsOrSiblingsAffectedByHasInternal( + parent, previous_sibling, true /* for_pseudo_change */); +} + +void StyleEngine::InvalidateAncestorsOrSiblingsAffectedByHas( + Element& changed_element) { + InvalidateAncestorsOrSiblingsAffectedByHas( + changed_element.AncestorsOrAncestorSiblingsAffectedByHas() + ? changed_element.parentElement() + : nullptr, + changed_element.SiblingsAffectedByHas() + ? ElementTraversal::PreviousSibling(changed_element) + : nullptr); +} + +void StyleEngine::InvalidateAncestorsOrSiblingsAffectedByHas( + Element* parent, + Element* previous_sibling) { + InvalidateAncestorsOrSiblingsAffectedByHasInternal( + parent, previous_sibling, false /* for_pseudo_change */); } void StyleEngine::ClassChangedForElement( @@ -998,11 +1058,11 @@ const RuleFeatureSet& features = GetRuleFeatureSet(); if (RuntimeEnabledFeatures::CSSPseudoHasEnabled() && - element.AncestorsAffectedByHas()) { + PossiblyAffectingHasState(element)) { unsigned changed_size = changed_classes.size(); for (unsigned i = 0; i < changed_size; ++i) { if (features.NeedsHasInvalidationForClass(changed_classes[i])) { - InvalidateAncestorsAffectedByHas(element.parentElement()); + InvalidateAncestorsOrSiblingsAffectedByHas(element); break; } } @@ -1035,7 +1095,7 @@ bool needs_schedule_invalidation = !IsSubtreeAndSiblingsStyleDirty(element); bool possibly_affecting_has_state = RuntimeEnabledFeatures::CSSPseudoHasEnabled() && - element.AncestorsAffectedByHas(); + PossiblyAffectingHasState(element); if (!needs_schedule_invalidation && !possibly_affecting_has_state) return; @@ -1094,7 +1154,7 @@ } if (affecting_has_state) - InvalidateAncestorsAffectedByHas(element.parentElement()); + InvalidateAncestorsOrSiblingsAffectedByHas(element); } namespace { @@ -1124,9 +1184,9 @@ const RuleFeatureSet& features = GetRuleFeatureSet(); if (RuntimeEnabledFeatures::CSSPseudoHasEnabled() && - element.AncestorsAffectedByHas()) { + PossiblyAffectingHasState(element)) { if (features.NeedsHasInvalidationForAttribute(attribute_name)) - InvalidateAncestorsAffectedByHas(element.parentElement()); + InvalidateAncestorsOrSiblingsAffectedByHas(element); } if (IsSubtreeAndSiblingsStyleDirty(element)) @@ -1155,10 +1215,10 @@ const RuleFeatureSet& features = GetRuleFeatureSet(); if (RuntimeEnabledFeatures::CSSPseudoHasEnabled() && - element.AncestorsAffectedByHas()) { + PossiblyAffectingHasState(element)) { if ((!old_id.IsEmpty() && features.NeedsHasInvalidationForId(old_id)) || (!new_id.IsEmpty() && features.NeedsHasInvalidationForId(new_id))) { - InvalidateAncestorsAffectedByHas(element.parentElement()); + InvalidateAncestorsOrSiblingsAffectedByHas(element); } } @@ -1188,9 +1248,9 @@ const RuleFeatureSet& features = GetRuleFeatureSet(); if (invalidate_ancestors && RuntimeEnabledFeatures::CSSPseudoHasEnabled() && - element.AncestorsAffectedByHas()) { + PossiblyAffectingHasState(element)) { if (features.NeedsHasInvalidationForPseudoClass(pseudo_type)) - InvalidateAncestorsAffectedByHasForPseudoChange(element.parentElement()); + InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange(element); } if (!invalidate_descendants_or_siblings || @@ -1401,7 +1461,9 @@ *document_); } -void StyleEngine::ElementInsertedOrRemoved(Element* parent, Element& element) { +void StyleEngine::ElementInsertedOrRemoved(Element* parent, + Node* node_before_change, + Element& element) { if (!RuntimeEnabledFeatures::CSSPseudoHasEnabled() || !parent) return; @@ -1410,13 +1472,17 @@ const RuleFeatureSet& features = GetRuleFeatureSet(); - if (features.NeedsHasInvalidationForElement(element)) - InvalidateAncestorsAffectedByHas(parent); - else if (features.NeedsHasInvalidationForPseudoStateChange()) - InvalidateAncestorsAffectedByHasForPseudoChange(parent); + if (features.NeedsHasInvalidationForElement(element)) { + InvalidateAncestorsOrSiblingsAffectedByHas( + parent, SelfOrPreviousSibling(node_before_change)); + } else if (features.NeedsHasInvalidationForPseudoStateChange()) { + InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + parent, SelfOrPreviousSibling(node_before_change)); + } } void StyleEngine::SubtreeInsertedOrRemoved(Element* parent, + Node* node_before_change, Element& subtree_root) { if (!RuntimeEnabledFeatures::CSSPseudoHasEnabled() || !parent) return; @@ -1428,13 +1494,16 @@ for (Element& element : ElementTraversal::InclusiveDescendantsOf(subtree_root)) { if (features.NeedsHasInvalidationForElement(element)) { - InvalidateAncestorsAffectedByHas(parent); + InvalidateAncestorsOrSiblingsAffectedByHas( + parent, SelfOrPreviousSibling(node_before_change)); return; } } - if (features.NeedsHasInvalidationForPseudoStateChange()) - InvalidateAncestorsAffectedByHasForPseudoChange(parent); + if (features.NeedsHasInvalidationForPseudoStateChange()) { + InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + parent, SelfOrPreviousSibling(node_before_change)); + } } void StyleEngine::InvalidateStyle() {
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h index 98c678e..bdf0eed 100644 --- a/third_party/blink/renderer/core/css/style_engine.h +++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -390,8 +390,12 @@ InvalidationScope = kInvalidateCurrentScope); void ScheduleCustomElementInvalidations(HashSet<AtomicString> tag_names); - void ElementInsertedOrRemoved(Element* parent, Element& element); - void SubtreeInsertedOrRemoved(Element* parent, Element& subtree_root); + void ElementInsertedOrRemoved(Element* parent, + Node* node_before_change, + Element& element); + void SubtreeInsertedOrRemoved(Element* parent, + Node* node_before_change, + Element& subtree_root); void NodeWillBeRemoved(Node&); void ChildrenRemoved(ContainerNode& parent); @@ -695,11 +699,20 @@ // container. void RebuildFieldSetContainer(HTMLFieldSetElement& fieldset); - // Walk-up to invalidate elements affected by :has() state change - void InvalidateAncestorsAffectedByHasInternal(Element*, - bool for_pseudo_change); - void InvalidateAncestorsAffectedByHas(Element*); - void InvalidateAncestorsAffectedByHasForPseudoChange(Element*); + // Invalidate ancestors or siblings affected by :has() state change + void InvalidateAncestorsOrSiblingsAffectedByHasInternal( + Element* parent, + Element* previous_sibling, + bool for_pseudo_change); + inline void InvalidateAncestorsOrSiblingsAffectedByHas( + Element& changed_element); + void InvalidateAncestorsOrSiblingsAffectedByHas(Element* parent, + Element* previous_sibling); + inline void InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + Element& changed_element); + void InvalidateAncestorsOrSiblingsAffectedByHasForPseudoChange( + Element* parent, + Element* previous_sibling); Member<Document> document_;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index d3fd7d0..2e3c712 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -4200,8 +4200,8 @@ : kSiblingElementInserted, changed_element, change.sibling_before_change, change.sibling_after_change); - GetDocument().GetStyleEngine().SubtreeInsertedOrRemoved(this, - *changed_element); + GetDocument().GetStyleEngine().SubtreeInsertedOrRemoved( + this, change.sibling_before_change, *changed_element); } if (ShadowRoot* shadow_root = GetShadowRoot()) @@ -4214,7 +4214,7 @@ CheckForSiblingStyleChanges(kFinishedParsingChildren, nullptr, lastChild(), nullptr); GetDocument().GetStyleEngine().ElementInsertedOrRemoved(parentElement(), - *this); + lastChild(), *this); } AttrNodeList* Element::GetAttrNodeList() { @@ -4846,14 +4846,24 @@ EnsureElementRareData().SetAffectedByNonSubjectHas(); } -bool Element::AncestorsAffectedByHas() const { +bool Element::AncestorsOrAncestorSiblingsAffectedByHas() const { if (HasRareData()) - return GetElementRareData()->AncestorsAffectedByHas(); + return GetElementRareData()->AncestorsOrAncestorSiblingsAffectedByHas(); return false; } -void Element::SetAncestorsAffectedByHas() { - EnsureElementRareData().SetAncestorsAffectedByHas(); +void Element::SetAncestorsOrAncestorSiblingsAffectedByHas() { + EnsureElementRareData().SetAncestorsOrAncestorSiblingsAffectedByHas(); +} + +bool Element::SiblingsAffectedByHas() const { + if (HasRareData()) + return GetElementRareData()->SiblingsAffectedByHas(); + return false; +} + +void Element::SetSiblingsAffectedByHas() { + EnsureElementRareData().SetSiblingsAffectedByHas(); } bool Element::UpdateForceLegacyLayout(const ComputedStyle& new_style,
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index 306b771..69c5026 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -1042,8 +1042,10 @@ bool AffectedByNonSubjectHas() const; void SetAffectedByNonSubjectHas(); - bool AncestorsAffectedByHas() const; - void SetAncestorsAffectedByHas(); + bool AncestorsOrAncestorSiblingsAffectedByHas() const; + void SetAncestorsOrAncestorSiblingsAffectedByHas(); + bool SiblingsAffectedByHas() const; + void SetSiblingsAffectedByHas(); void SaveIntrinsicSize(ResizeObserverSize* size); const ResizeObserverSize* LastIntrinsicSize() const;
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.cc b/third_party/blink/renderer/core/dom/element_rare_data.cc index d59074f10..d577ad79 100644 --- a/third_party/blink/renderer/core/dom/element_rare_data.cc +++ b/third_party/blink/renderer/core/dom/element_rare_data.cc
@@ -57,7 +57,8 @@ has_undo_stack_(false), scrollbar_pseudo_element_styles_depend_on_font_metrics_(false), affected_by_non_subject_has_(false), - ancestors_affected_by_has_(false) { + ancestors_or_ancestor_siblings_affected_by_has_(false), + siblings_affected_by_has_(false) { // When The ElementSuperRareData flag is disabled, then always initialize // ElementSuperRareData immediately in order to measure the memory usage // improvements.
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.h b/third_party/blink/renderer/core/dom/element_rare_data.h index a06eb4f..ccb3be12 100644 --- a/third_party/blink/renderer/core/dom/element_rare_data.h +++ b/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -346,8 +346,14 @@ } bool AffectedByNonSubjectHas() const { return affected_by_non_subject_has_; } void SetAffectedByNonSubjectHas() { affected_by_non_subject_has_ = true; } - bool AncestorsAffectedByHas() const { return ancestors_affected_by_has_; } - void SetAncestorsAffectedByHas() { ancestors_affected_by_has_ = true; } + bool AncestorsOrAncestorSiblingsAffectedByHas() const { + return ancestors_or_ancestor_siblings_affected_by_has_; + } + void SetAncestorsOrAncestorSiblingsAffectedByHas() { + ancestors_or_ancestor_siblings_affected_by_has_ = true; + } + bool SiblingsAffectedByHas() const { return siblings_affected_by_has_; } + void SetSiblingsAffectedByHas() { siblings_affected_by_has_ = true; } AccessibleNode* GetAccessibleNode() const { if (super_rare_data_) @@ -468,26 +474,36 @@ unsigned scrollbar_pseudo_element_styles_depend_on_font_metrics_ : 1; // Flags for :has() invalidation. - // - affected_by_non_subject_has_ : Indicates that this element may match a - // non-subject :has() selector, which means - // we need to schedule descendant and sibling - // invalidation sets on this element when - // the :has() state changes. - // - ancestors_affected_by_has_ : Indicates that this element possibly matches - // any of the :has() subselectors, so we need - // to walk ancestors to find the elements - // affected by subject or non-subject :has() - // state change. Please refer the comments in - // SelectorChecker::CheckPseudoHas() for more - // details. // - // Example 1) Subject :has() + // - affected_by_non_subject_has_ : + // Indicates that this element may match a non-subject :has() selector, + // which means we need to schedule descendant and sibling invalidation + // sets on this element when the :has() state changes. + // + // - ancestors_or_ancestor_siblings_affected_by_has_ + // Indicates that this element possibly matches any of the :has() + // subselectors, and we need to walk ancestors or siblings of ancestors to + // find the elements affected by subject or non-subject :has() state + // change. Please refer the comments in SelectorChecker::CheckPseudoHas() + // for more details. + // + // - siblings_affected_by_has_ + // Indicates that this element possibly matches any of the :has() + // subselectors, and we need to walk siblings to find the elements + // affected by subject or non-subject :has() state change. + // + // Please refer the comments in WalkUpAndSetDynamicRestyleFlagForHas() in + // selector_checker.cc and HasArgumentSubtreeIterator::operator++() for more + // details. + // + // + // Example 1) Subject :has() (has only descendant relationship) // <style> .a:has(.b) {...} </style> // <div> // <div class=a> <!-- AffectedBySubjectHas (computed style extra flag) --> - // <div> <!-- AncestorsAffectedByHas --> - // <div></div> <!-- AncestorsAffectedByHas --> - // <div></div> <!-- AncestorsAffectedByHas --> + // <div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // <div></div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // <div></div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> // </div> // </div> // </div> @@ -496,16 +512,42 @@ // Example 2) Non-subject :has() // <style> .a:has(.b) .c {...} </style> // <div> - // <div class=a> <!-- AffectedByNonSubjectHas --> - // <div> <!-- AncestorsAffectedByHas --> - // <div></div> <!-- AncestorsAffectedByHas --> - // <div class=c></div> <!-- AncestorsAffectedByHas --> + // <div class=a> <!-- AffectedByNonSubjectHas --> + // <div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // <div></div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // <div class=c></div><!-- AncestorsOrAncestorSiblingsAffectedByHas --> // </div> // </div> // </div> // + // + // Example 3) Subject :has() (has only sibling relationship) + // <style> .a:has(~ .b) {...} </style> + // <div> + // <div></div> + // <div class=a> <!-- AffectedBySubjectHas (computed style extra flag) --> + // <div></div> + // </div> + // <div></div> <!-- SiblingsAffectedByHas --> + // <div></div> <!-- SiblingsAffectedByHas --> + // </div> + // + // + // Example 4) Subject :has() (has both sibling and descendant relationship) + // <style> .a:has(~ .b .c) {...} </style> + // <div> + // <div></div> + // <div class=a> <!-- AffectedBySubjectHas (computed style extra flag) --> + // </div> + // <div> <!-- SiblingsAffectedByHas --> + // <div></div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // <div></div> <!-- AncestorsOrAncestorSiblingsAffectedByHas --> + // </div> + // </div> + // unsigned affected_by_non_subject_has_ : 1; - unsigned ancestors_affected_by_has_ : 1; + unsigned ancestors_or_ancestor_siblings_affected_by_has_ : 1; + unsigned siblings_affected_by_has_ : 1; }; inline LayoutSize DefaultMinimumSizeForResizing() {
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index 2aa6f0f..3d7c0b2 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -1269,6 +1269,10 @@ auto* credential_manager = CredentialManagerProxy::From(script_state)->CredentialManager(); + + DCHECK_NE(mojom::blink::CredentialType::EMPTY, + CredentialInfo::From(credential)->type); + credential_manager->Store( CredentialInfo::From(credential), WTF::Bind(&OnStoreComplete,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc index fc710f7b..b9f4a1e6 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -176,12 +176,8 @@ #if !BUILDFLAG(IS_MAC) case WGPUTextureFormat_RGBA8Unorm: #endif - break; case WGPUTextureFormat_RGBA16Float: - configured_device_->InjectError( - WGPUErrorType_Validation, - "rgba16float swap chain is not yet supported"); - return; + break; default: configured_device_->InjectError(WGPUErrorType_Validation, "unsupported swap chain format");
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc index b92cf11b..4776766 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
@@ -96,8 +96,11 @@ const auto& sk_image_sync_token = transferable_resource.mailbox_holder.sync_token; - const SkImageInfo sk_image_info = SkImageInfo::MakeN32Premul( - transferable_resource.size.width(), transferable_resource.size.height()); + auto sk_color_type = viz::ResourceFormatToClosestSkColorType( + /*gpu_compositing=*/true, transferable_resource.format); + + const SkImageInfo sk_image_info = SkImageInfo::Make( + size_.width(), size_.height(), sk_color_type, kPremul_SkAlphaType); return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( sk_image_mailbox, sk_image_sync_token, /* shared_image_texture_id = */ 0,
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 76084463..1ecce887 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -13,6 +13,10 @@ # Tests that fail in legacy but pass in NG # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html [ Timeout ] crbug.com/626703 external/wpt/css/css-grid/abspos/positioned-grid-items-025.html [ Failure ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/exported-names.tentative.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/js-wasm-cycle.tentative.html [ Timeout ]
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials index a440ab6..4da46ed 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials +++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -44,6 +44,10 @@ crbug.com/1209223 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-security-check-same-origin-domain.sub.html [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/exported-names.tentative.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/js-wasm-cycle.tentative.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/wasm-import-wasm-export.tentative.html [ Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b9dd08a..357d2dc 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2794,39 +2794,39 @@ crbug.com/1040611 external/wpt/uievents/order-of-events/mouse-events/wheel-scrolling.html [ Failure Timeout ] # crbug.com/1298321: "element click intercepted error" when <body style="zoom:2">. -crbug.com/1298321 fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ Pass Failure Timeout ] -crbug.com/1298321 fast/forms/calendar-picker/date-picker-appearance-zoom150.html [ Pass Failure Timeout ] -crbug.com/1298321 fast/forms/select-popup/popup-menu-appearance-zoom.html [ Pass Failure Timeout ] -crbug.com/1298321 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Pass Failure Timeout ] -crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Pass Failure Timeout ] +crbug.com/1298321 fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ Failure Pass Timeout ] +crbug.com/1298321 fast/forms/calendar-picker/date-picker-appearance-zoom150.html [ Failure Pass Timeout ] +crbug.com/1298321 fast/forms/select-popup/popup-menu-appearance-zoom.html [ Failure Pass Timeout ] +crbug.com/1298321 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ] +crbug.com/1298321 virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure Pass Timeout ] # crbug.com/1299212: These need more work after the revamp of picker-common.js -crbug.com/1299212 fast/forms/select-popup/popup-menu-appearance-coarse.html [ Pass Failure Timeout ] -crbug.com/1299212 fast/forms/select-popup/popup-menu-position.html [ Pass Failure Timeout ] -crbug.com/1299212 http/tests/webfont/popup-menu-load-webfont-after-open.html [ Pass Failure Timeout ] -crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/date-suggestion-picker-mouse-operations.html [ Pass Failure Timeout ] -crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/week-suggestion-picker-mouse-operations.html [ Pass Failure Timeout ] -crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/month-suggestion-picker-mouse-operations.html [ Pass Failure Timeout ] -crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/time-suggestion-picker-mouse-operations.html [ Pass Failure Timeout ] -crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-mouse-operations.html [ Pass Failure Timeout ] -crbug.com/1299212 fast/forms/color-scheme/select/select-appearance-after-closing-popup.html [ Pass Failure Timeout Skip ] -crbug.com/1299212 fast/forms/color-scheme/select/select-popup-appearance-basic.html [ Pass Failure Timeout Skip ] -crbug.com/1299212 fast/forms/select/menulist-popup-type-ahead-style-change.html [ Pass Failure Timeout ] +crbug.com/1299212 fast/forms/select-popup/popup-menu-appearance-coarse.html [ Failure Pass Timeout ] +crbug.com/1299212 fast/forms/select-popup/popup-menu-position.html [ Failure Pass Timeout ] +crbug.com/1299212 http/tests/webfont/popup-menu-load-webfont-after-open.html [ Failure Pass Timeout ] +crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/date-suggestion-picker-mouse-operations.html [ Failure Pass Timeout ] +crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/week-suggestion-picker-mouse-operations.html [ Failure Pass Timeout ] +crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/month-suggestion-picker-mouse-operations.html [ Failure Pass Timeout ] +crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/time-suggestion-picker-mouse-operations.html [ Failure Pass Timeout ] +crbug.com/1299212 crbug.com/1047176 fast/forms/suggestion-picker/datetimelocal-suggestion-picker-mouse-operations.html [ Failure Pass Timeout ] +crbug.com/1299212 fast/forms/color-scheme/select/select-appearance-after-closing-popup.html [ Failure Pass Skip Timeout ] +crbug.com/1299212 fast/forms/color-scheme/select/select-popup-appearance-basic.html [ Failure Pass Skip Timeout ] +crbug.com/1299212 fast/forms/select/menulist-popup-type-ahead-style-change.html [ Failure Pass Timeout ] # This might be just flaky on Windows: -crbug.com/1299212 virtual/scroll-unification/fast/forms/suggestion-picker/* [ Pass Failure Timeout ] +crbug.com/1299212 virtual/scroll-unification/fast/forms/suggestion-picker/* [ Failure Pass Timeout ] # At least scrollbars, if not window sizes, are flaky on Win7: -crbug.com/1299212 [ Win7 ] fast/forms/select-popup/popup-menu-appearance-tall.html [ Pass Failure Timeout ] -crbug.com/1299212 [ Win7 ] fast/forms/suggestion-picker/* [ Pass Failure Timeout ] -crbug.com/1299212 [ Win7 ] virtual/scroll-unification/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl.html [ Pass Failure Timeout ] -crbug.com/1299212 [ Linux ] fast/forms/select/menulist-popup-mutation-crash.html [ Failure Timeout Pass ] +crbug.com/1299212 [ Win7 ] fast/forms/select-popup/popup-menu-appearance-tall.html [ Failure Pass Timeout ] +crbug.com/1299212 [ Win7 ] fast/forms/suggestion-picker/* [ Failure Pass Timeout ] +crbug.com/1299212 [ Win7 ] virtual/scroll-unification/fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl.html [ Failure Pass Timeout ] +crbug.com/1299212 [ Linux ] fast/forms/select/menulist-popup-mutation-crash.html [ Failure Pass Timeout ] # isInputPending requires threaded compositing and layerized iframes crbug.com/910421 external/wpt/is-input-pending/* [ Skip ] @@ -3319,6 +3319,16 @@ crbug.com/626703 virtual/prerender/external/wpt/speculation-rules/prerender/workers.html [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html [ Timeout ] +crbug.com/626703 external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html [ Timeout ] +crbug.com/626703 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-interpolation-005.https.html [ Failure ] +crbug.com/626703 external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html [ Failure ] +crbug.com/626703 external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html [ Failure ] +crbug.com/626703 virtual/dialogfocus-old-behavior/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html [ Failure ] +crbug.com/626703 virtual/dialogfocus-old-behavior/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html [ Failure ] +crbug.com/626703 [ Mac10.15 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/parse-input-arguments-021.https.html [ Failure ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/exported-names.tentative.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/js-wasm-cycle.tentative.html [ Timeout ] crbug.com/626703 external/wpt/wasm/webapi/esm-integration/wasm-import-wasm-export.tentative.html [ Timeout ] @@ -7583,11 +7593,11 @@ crbug.com/1173382 [ Win ] virtual/stable/http/tests/navigation/replacestate-base-legal.html [ Failure Pass ] # Sheriff 2022-02-22 -crbug.com/1299858 [ Win ] http/tests/fetch/serviceworker-proxied/thorough/nocors-base-https-other-https.html [ Skip Timeout Pass ] -crbug.com/1299858 [ Win ] http/tests/fetch/serviceworker/thorough/redirect-nocors-base-https-other-https.html [ Skip Timeout Pass ] -crbug.com/1299858 [ Win ] http/tests/fetch/window/thorough/cors-base-https-other-https.html [ Skip Timeout Pass ] -crbug.com/1299858 [ Win ] http/tests/fetch/workers/thorough/cookie-nocors-base-https-other-https.html [ Skip Timeout Pass ] +crbug.com/1299858 [ Win ] http/tests/fetch/serviceworker-proxied/thorough/nocors-base-https-other-https.html [ Pass Skip Timeout ] +crbug.com/1299858 [ Win ] http/tests/fetch/serviceworker/thorough/redirect-nocors-base-https-other-https.html [ Pass Skip Timeout ] +crbug.com/1299858 [ Win ] http/tests/fetch/window/thorough/cors-base-https-other-https.html [ Pass Skip Timeout ] +crbug.com/1299858 [ Win ] http/tests/fetch/workers/thorough/cookie-nocors-base-https-other-https.html [ Pass Skip Timeout ] crbug.com/1299903 [ Win7 ] virtual/prerender/external/wpt/speculation-rules/prerender/restriction-window-move.html [ Failure Pass ] -crbug.com/1299946 [ Mac ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Timeout Pass ] -crbug.com/1299948 [ Mac ] external/wpt/css/css-tables/crashtests/textarea-intrinsic-size-crash.html [ Timeout Pass ] -crbug.com/1299972 [ Linux ] screen_orientation/screenorientation-unsupported-no-crash.html [ Failure Timeout Pass ] +crbug.com/1299946 [ Mac ] external/wpt/css/css-sizing/min-content-negative-margin-crash.html [ Pass Timeout ] +crbug.com/1299948 [ Mac ] external/wpt/css/css-tables/crashtests/textarea-intrinsic-size-crash.html [ Pass Timeout ] +crbug.com/1299972 [ Linux ] screen_orientation/screenorientation-unsupported-no-crash.html [ Failure Pass Timeout ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index 2e63dfd..ba20e98 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -83,7 +83,12 @@ # These tests aren't working on CQ, unclear whether the test or harness (or Chrome) is broken. # Mac: mostly works # Linux: Crashes -crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/* [ Skip ] +crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_complex_bgra8unorm_copy.https.html [ Skip ] +crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_complex_bgra8unorm_draw.https.html [ Skip ] +crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque.https.html [ Skip ] +crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied.https.html [ Skip ] +crbug.com/1083478 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_size_different_with_back_buffer_size.https.html [ Skip ] + # Mac/Win: Shifted by about half a pixel crbug.com/1083478 [ Win ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque.https.html [ Failure ] crbug.com/1083478 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index a450c168..063d3ef 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 8fa6e1db9bcdd4f8a65055eceab4c6b9f132b1a2 +Version: 14e674b84241f534a4be0de230ae307429681d5e
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 0d1e90f2cc..cf692e1 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1354,6 +1354,13 @@ {} ] ], + "relayout-nested-with-oof.html": [ + "bdc7147337fed88b29bfb9af36b645756695d6f6", + [ + null, + {} + ] + ], "specified-height-with-just-spanner-and-oof.html": [ "3c4d51b0f433f4cbdb9e76f4301162924b6918f1", [ @@ -218944,7 +218951,7 @@ ] ], "modal-dialog-in-replaced-renderer.html": [ - "09490519fd7de1ffd0d53939fcbda6275cbb5d6f", + "75727b42f0429e59ffa1940eef768060e706af8c", [ null, [ @@ -218957,7 +218964,7 @@ ] ], "modal-dialog-in-table-column.html": [ - "89ee6977716bc961010b519224ff86253ce27b9c", + "3d72826b963feaceae0af44ff07ffca67fa70879", [ null, [ @@ -284219,6 +284226,10 @@ "59652e2e7ae0056a6cc4be7f004b6d0151fb9d44", [] ], + "feature-policy-geolocation.html": [ + "81943845447e6c6b7962b3961996e45c12e04cd4", + [] + ], "feature-policy-idle-detection-worker.html": [ "1ef5298abf1b2062f98c8aba5675decd36c5313d", [] @@ -287432,6 +287443,18 @@ "5c49de21a3b53dfe928d30a36400469d8238bb1d", [] ], + "disabled-by-feature-policy.https.sub.html.headers": [ + "7e75481ea6d71080aaef8b43e774f5da9c9741e5", + [] + ], + "enabled-by-feature-policy.https.sub.html.headers": [ + "40e9bc16ff98867d0d048fe3a48237a8189ee317", + [] + ], + "enabled-on-self-origin-by-feature-policy.https.sub.html.headers": [ + "b83264eee76491342a6328ca2ae82b7fb777cc37", + [] + ], "getCurrentPosition_IDL.https-expected.txt": [ "8781bccd59718f81b29112d2efbfe6407f697e52", [] @@ -299538,11 +299561,11 @@ [] ], "modal-dialog-in-replaced-renderer-ref.html": [ - "65886154df3dc3c462a87021693f5ca0fe78894a", + "c837503cafbcdb56c995e9b93f49cabde14293b0", [] ], "modal-dialog-in-table-column-ref.html": [ - "38b628c3092ab223010db32373e786787e4355b0", + "0310d1ba2437a59235a980f5fce2d95f2775b8fc", [] ], "modal-dialog-in-visibility-hidden-expected.txt": [ @@ -304358,10 +304381,6 @@ "b4a346ae68cb4726c82ff7bbdc1617164bcea293", [] ], - "input-events-get-target-ranges-forwarddelete.tentative.html.ini": [ - "aa9f10bfec564d3548013091daf87089e8bcb39a", - [] - ], "input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html.ini": [ "3682b5332d210f74721284474c626db0712515fc", [] @@ -423205,7 +423224,7 @@ }, "geolocation-API": { "PositionOptions.https.html": [ - "828224d50de5ad2c21a3e0b343dbfa6affb9e602", + "6b36d66d7358cccd6fe5143a1504a17db4170af4", [ null, { @@ -423213,13 +423232,54 @@ } ] ], - "clearWatch_TypeError.html": [ - "14b861bfc0aa3cbab46624ffde54a7825d7d76ab", + "clearWatch_TypeError.https.html": [ + "37ebeca885ff5df0447b18fdbf58cc4222c33ac9", [ null, {} ] ], + "disabled-by-feature-policy.https.sub.html": [ + "26fa7218a6d32a36ee4f99439580bcd19ddd7639", + [ + null, + { + "testdriver": true + } + ] + ], + "enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ + "30de411cb7a342d105e2c6e0ae21c4d64c8f05dd", + [ + null, + {} + ] + ], + "enabled-by-feature-policy-attribute.https.sub.html": [ + "49a6d777d66fa09df8d9ec38543f1097b95b6ffc", + [ + null, + {} + ] + ], + "enabled-by-feature-policy.https.sub.html": [ + "955ed10632e84f52f231a4a0beeedb1ae5a7fc35", + [ + null, + { + "testdriver": true + } + ] + ], + "enabled-on-self-origin-by-feature-policy.https.sub.html": [ + "12ff86fa4e554dc02524877ffb534e4c9cc11c5c", + [ + null, + { + "testdriver": true + } + ] + ], "getCurrentPosition_IDL.https.html": [ "c7ee10e7eb883f8eb7571065cf7925472d548c94", [ @@ -423229,8 +423289,8 @@ } ] ], - "getCurrentPosition_TypeError.html": [ - "6726e8ab6c7d892c4e93cf212c94f6622f89c116", + "getCurrentPosition_TypeError.https.html": [ + "953efb259bf931bce9c45e126a9938b0f0cbdafd", [ null, {} @@ -423244,10 +423304,12 @@ ] ], "getCurrentPosition_permission_deny.https.html": [ - "50129608ac7e6e8d64e6dd966eda1172b5929a70", + "297f9a2629737907b66743dfa8fd43c3b97f3020", [ null, - {} + { + "testdriver": true + } ] ], "idlharness.https.window.js": [ @@ -423269,7 +423331,7 @@ ] ], "non-fully-active.https.html": [ - "d75c787cabf861aed96664eab1805a76be98516b", + "13853c0ef860a6d099172c91db960b720760662a", [ null, { @@ -423284,18 +423346,20 @@ {} ] ], - "watchPosition_TypeError.html": [ - "dd8287f5713ea7ce0a13a5096c45d38f640553a0", + "watchPosition_TypeError.https.html": [ + "64f0616949f3c00ed0d24f7d34f173c69e8e65d6", [ null, {} ] ], "watchPosition_permission_deny.https.html": [ - "1e2a3c4bf4c4be0b050cffef2b2ba208e1bedc0c", + "d47f2b5594a55ca9852c874b9fa6b2880690dbf3", [ null, - {} + { + "testdriver": true + } ] ] }, @@ -470155,7 +470219,7 @@ ] ], "inert-iframe-hittest.tentative.html": [ - "63e347725ee360a0f0e0f240b673afcd2a31ea08", + "bcc542d35edff1bf93fdb7bcc6185fceb0d130d6", [ null, { @@ -470164,7 +470228,7 @@ ] ], "inert-iframe-tabbing.tentative.html": [ - "e346993cdcc2c66d4dcad27696ab1587e88bbb6d", + "a0146b74cc2abdb9590c322ec1a98d54c1adbf62", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/custom-layout-container-001.https.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/custom-layout-container-001.https.html new file mode 100644 index 0000000..ef8c5cc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/custom-layout-container-001.https.html
@@ -0,0 +1,66 @@ +<!doctype html> +<html class=reftest-wait> +<title>CSS Container Queries Test: Size queries on CSS Layout API containers</title> +<link rel="help" href="https://drafts.csswg.org/css-contain-3/#size-container"> +<link rel="help" href="https://drafts.css-houdini.org/css-layout-api/"> +<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/worklet-reftest.js"></script> +<style> + #test1 { + width: 400px; + height: 100px; + } + #outer { + display: inline; /* Shouldn't pass without layout api support */ + display: layout(half); + height: 100px; + container-type: inline-size; + } + @container size(width = 400px) { + #inner { + display: inline; /* Shouldn't pass without layout api support */ + display: layout(half); + height: 100px; + container-type: inline-size; + } + } + @container size(width = 200px) { + #green { + background-color: green; + height: 100px; + } + } +</style> +<p>Test passes if there is a filled green square.</p> +<div id="test1"> + <div id="outer"> + <div id="inner"> + <div id="green"></div> + </div> + </div> +</div> + +<script id="code" type="text/worklet"> + registerLayout("half", class { + async intrinsicSizes() {} + async layout(children, edges, constraints, styleMap) { + const childInlineSize = constraints.fixedInlineSize / 2; + const childFragments = await Promise.all(children.map((child) => { + return child.layoutNextFragment({fixedInlineSize: childInlineSize}); + })); + + for (let childFragment of childFragments) { + childFragment.inlineOffset = 0; + childFragment.blockOffset = 0; + } + const autoBlockSize = 100; + return {autoBlockSize, childFragments}; + } + }); +</script> + +<script> + importWorkletAndTerminateTestAfterAsyncPaint(CSS.layoutWorklet, document.getElementById("code").textContent); +</script> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-adjacent-position-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-adjacent-position-expected.txt deleted file mode 100644 index 4eca5d7..0000000 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-adjacent-position-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 57 PASS, 14 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Initial color -PASS add .test to previous_sibling -PASS remove .test from previous_sibling -PASS add .test to previous_sibling_child -PASS remove .test from previous_sibling_child -PASS add .test to previous_sibling_descendant -PASS remove .test from previous_sibling_descendant -FAIL add .test to subject assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove .test from subject -FAIL add .test to next_sibling assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling -FAIL add .test to next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_child -FAIL add .test to next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_descendant -PASS insert element div.test before previous_sibling -PASS remove element div.test before previous_sibling -PASS insert element div.test before previous_sibling_child -PASS remove element div.test before previous_sibling_child -PASS insert element div.test before previous_sibling_descendant -PASS remove element div.test before previous_sibling_descendant -PASS insert element div.test before subject -PASS remove element div.test before subject -PASS insert element div.test before next_sibling -PASS remove element div.test before next_sibling -FAIL insert element div.test before next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_child -FAIL insert element div.test before next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_descendant -PASS insert element div.test after previous_sibling -PASS remove element div.test after previous_sibling -PASS insert element div.test after previous_sibling_child -PASS remove element div.test after previous_sibling_child -PASS insert element div.test after previous_sibling_descendant -PASS remove element div.test after previous_sibling_descendant -PASS insert element div.test after subject -PASS remove element div.test after subject -FAIL insert element div.test after next_sibling assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling -FAIL insert element div.test after next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_child -FAIL insert element div.test after next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_descendant -PASS insert tree div>div.test before previous_sibling -PASS remove tree div>div.test before previous_sibling -PASS insert tree div>div.test before previous_sibling_child -PASS remove tree div>div.test before previous_sibling_child -PASS insert tree div>div.test before previous_sibling_descendant -PASS remove tree div>div.test before previous_sibling_descendant -PASS insert tree div>div.test before subject -PASS remove tree div>div.test before subject -PASS insert tree div>div.test before next_sibling -PASS remove tree div>div.test before next_sibling -FAIL insert tree div>div.test before next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_child -FAIL insert tree div>div.test before next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_descendant -PASS insert tree div>div.test after previous_sibling -PASS remove tree div>div.test after previous_sibling -PASS insert tree div>div.test after previous_sibling_child -PASS remove tree div>div.test after previous_sibling_child -PASS insert tree div>div.test after previous_sibling_descendant -PASS remove tree div>div.test after previous_sibling_descendant -PASS insert tree div>div.test after subject -PASS remove tree div>div.test after subject -FAIL insert tree div>div.test after next_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling -FAIL insert tree div>div.test after next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_child -FAIL insert tree div>div.test after next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-ancestor-position-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-ancestor-position-expected.txt deleted file mode 100644 index 010e5e18..0000000 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-ancestor-position-expected.txt +++ /dev/null
@@ -1,85 +0,0 @@ -This is a testharness.js-based test. -Found 81 tests; 64 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Initial color -PASS add .test to subject_ancestor -PASS remove .test from subject_ancestor -PASS add .test to subject_parent -PASS remove .test from subject_parent -PASS add .test to subject -PASS remove .test from subject -PASS add .test to subject_child -PASS remove .test from subject_child -PASS add .test to subject_descendant -PASS remove .test from subject_descendant -FAIL add .test to next_sibling assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling -FAIL add .test to next_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_child -FAIL add .test to next_sibling_descendant assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_descendant -PASS insert element div.test before subject_ancestor -PASS remove element div.test before subject_ancestor -PASS insert element div.test before subject_parent -PASS remove element div.test before subject_parent -PASS insert element div.test before subject -PASS remove element div.test before subject -PASS insert element div.test before subject_child -PASS remove element div.test before subject_child -PASS insert element div.test before subject_descendant -PASS remove element div.test before subject_descendant -FAIL insert element div.test before next_sibling assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling -FAIL insert element div.test before next_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_child -FAIL insert element div.test before next_sibling_descendant assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_descendant -FAIL insert element div.test after subject_ancestor assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test after subject_ancestor -PASS insert element div.test after subject_parent -PASS remove element div.test after subject_parent -PASS insert element div.test after subject -PASS remove element div.test after subject -PASS insert element div.test after subject_child -PASS remove element div.test after subject_child -PASS insert element div.test after subject_descendant -PASS remove element div.test after subject_descendant -FAIL insert element div.test after next_sibling assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling -FAIL insert element div.test after next_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_child -FAIL insert element div.test after next_sibling_descendant assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_descendant -PASS insert tree div>div.test before subject_ancestor -PASS remove tree div>div.test before subject_ancestor -PASS insert tree div>div.test before subject_parent -PASS remove tree div>div.test before subject_parent -PASS insert tree div>div.test before subject -PASS remove tree div>div.test before subject -PASS insert tree div>div.test before subject_child -PASS remove tree div>div.test before subject_child -PASS insert tree div>div.test before subject_descendant -PASS remove tree div>div.test before subject_descendant -FAIL insert tree div>div.test before next_sibling assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling -FAIL insert tree div>div.test before next_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_child -FAIL insert tree div>div.test before next_sibling_descendant assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_descendant -FAIL insert tree div>div.test after subject_ancestor assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after subject_ancestor -PASS insert tree div>div.test after subject_parent -PASS remove tree div>div.test after subject_parent -PASS insert tree div>div.test after subject -PASS remove tree div>div.test after subject -PASS insert tree div>div.test after subject_child -PASS remove tree div>div.test after subject_child -PASS insert tree div>div.test after subject_descendant -PASS remove tree div>div.test after subject_descendant -FAIL insert tree div>div.test after next_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling -FAIL insert tree div>div.test after next_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_child -FAIL insert tree div>div.test after next_sibling_descendant assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-parent-position-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-parent-position-expected.txt deleted file mode 100644 index 5cec677..0000000 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-parent-position-expected.txt +++ /dev/null
@@ -1,55 +0,0 @@ -This is a testharness.js-based test. -Found 51 tests; 49 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Initial color -PASS add .test to subject_ancestor -PASS remove .test from subject_ancestor -PASS add .test to subject_parent -PASS remove .test from subject_parent -PASS add .test to subject -PASS remove .test from subject -PASS add .test to subject_child -PASS remove .test from subject_child -PASS add .test to subject_descendant -PASS remove .test from subject_descendant -PASS insert element div.test before subject_ancestor -PASS remove element div.test before subject_ancestor -PASS insert element div.test before subject_parent -PASS remove element div.test before subject_parent -PASS insert element div.test before subject -PASS remove element div.test before subject -PASS insert element div.test before subject_child -PASS remove element div.test before subject_child -PASS insert element div.test before subject_descendant -PASS remove element div.test before subject_descendant -PASS insert element div.test after subject_ancestor -PASS remove element div.test after subject_ancestor -FAIL insert element div.test after subject_parent assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test after subject_parent -PASS insert element div.test after subject -PASS remove element div.test after subject -PASS insert element div.test after subject_child -PASS remove element div.test after subject_child -PASS insert element div.test after subject_descendant -PASS remove element div.test after subject_descendant -PASS insert tree div>div.test before subject_ancestor -PASS remove tree div>div.test before subject_ancestor -PASS insert tree div>div.test before subject_parent -PASS remove tree div>div.test before subject_parent -PASS insert tree div>div.test before subject -PASS remove tree div>div.test before subject -PASS insert tree div>div.test before subject_child -PASS remove tree div>div.test before subject_child -PASS insert tree div>div.test before subject_descendant -PASS remove tree div>div.test before subject_descendant -PASS insert tree div>div.test after subject_ancestor -PASS remove tree div>div.test after subject_ancestor -FAIL insert tree div>div.test after subject_parent assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after subject_parent -PASS insert tree div>div.test after subject -PASS remove tree div>div.test after subject -PASS insert tree div>div.test after subject_child -PASS remove tree div>div.test after subject_child -PASS insert tree div>div.test after subject_descendant -PASS remove tree div>div.test after subject_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-sibling-position-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-sibling-position-expected.txt deleted file mode 100644 index 4eca5d7..0000000 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-in-sibling-position-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 57 PASS, 14 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS Initial color -PASS add .test to previous_sibling -PASS remove .test from previous_sibling -PASS add .test to previous_sibling_child -PASS remove .test from previous_sibling_child -PASS add .test to previous_sibling_descendant -PASS remove .test from previous_sibling_descendant -FAIL add .test to subject assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove .test from subject -FAIL add .test to next_sibling assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling -FAIL add .test to next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_child -FAIL add .test to next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from next_sibling_descendant -PASS insert element div.test before previous_sibling -PASS remove element div.test before previous_sibling -PASS insert element div.test before previous_sibling_child -PASS remove element div.test before previous_sibling_child -PASS insert element div.test before previous_sibling_descendant -PASS remove element div.test before previous_sibling_descendant -PASS insert element div.test before subject -PASS remove element div.test before subject -PASS insert element div.test before next_sibling -PASS remove element div.test before next_sibling -FAIL insert element div.test before next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_child -FAIL insert element div.test before next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before next_sibling_descendant -PASS insert element div.test after previous_sibling -PASS remove element div.test after previous_sibling -PASS insert element div.test after previous_sibling_child -PASS remove element div.test after previous_sibling_child -PASS insert element div.test after previous_sibling_descendant -PASS remove element div.test after previous_sibling_descendant -PASS insert element div.test after subject -PASS remove element div.test after subject -FAIL insert element div.test after next_sibling assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling -FAIL insert element div.test after next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_child -FAIL insert element div.test after next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after next_sibling_descendant -PASS insert tree div>div.test before previous_sibling -PASS remove tree div>div.test before previous_sibling -PASS insert tree div>div.test before previous_sibling_child -PASS remove tree div>div.test before previous_sibling_child -PASS insert tree div>div.test before previous_sibling_descendant -PASS remove tree div>div.test before previous_sibling_descendant -PASS insert tree div>div.test before subject -PASS remove tree div>div.test before subject -PASS insert tree div>div.test before next_sibling -PASS remove tree div>div.test before next_sibling -FAIL insert tree div>div.test before next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_child -FAIL insert tree div>div.test before next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before next_sibling_descendant -PASS insert tree div>div.test after previous_sibling -PASS remove tree div>div.test after previous_sibling -PASS insert tree div>div.test after previous_sibling_child -PASS remove tree div>div.test after previous_sibling_child -PASS insert tree div>div.test after previous_sibling_descendant -PASS remove tree div>div.test after previous_sibling_descendant -PASS insert tree div>div.test after subject -PASS remove tree div>div.test after subject -FAIL insert tree div>div.test after next_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling -FAIL insert tree div>div.test after next_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_child -FAIL insert tree div>div.test after next_sibling_descendant assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after next_sibling_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-sibling-expected.txt b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-sibling-expected.txt deleted file mode 100644 index 01f64f5..0000000 --- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/has-sibling-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 36 PASS, 35 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS initial_color -FAIL add .test to first_sibling assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling -FAIL add .test to second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from second_sibling -FAIL add .test to third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling -FAIL add .test to first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling_child -FAIL add .test to first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling_descendant -FAIL add .test to third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling_child -FAIL add .test to third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling_descendant -FAIL insert element div.test before first_sibling assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling -FAIL insert element div.test before second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before second_sibling -FAIL insert element div.test before third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling -FAIL insert element div.test before first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling_child -FAIL insert element div.test before first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling_descendant -FAIL insert element div.test before third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling_child -FAIL insert element div.test before third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling_descendant -FAIL insert element div.test after first_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling -FAIL insert element div.test after second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after second_sibling -FAIL insert element div.test after third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling -FAIL insert element div.test after first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling_child -FAIL insert element div.test after first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling_descendant -FAIL insert element div.test after third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling_child -FAIL insert element div.test after third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling_descendant -FAIL insert tree div>div.test before first_sibling assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling -FAIL insert tree div>div.test before second_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before second_sibling -FAIL insert tree div>div.test before third_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling -FAIL insert tree div>div.test before first_sibling_child assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling_child -FAIL insert tree div>div.test before first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling_descendant -FAIL insert tree div>div.test before third_sibling_child assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling_child -FAIL insert tree div>div.test before third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling_descendant -FAIL insert tree div>div.test after first_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling -FAIL insert tree div>div.test after second_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after second_sibling -FAIL insert tree div>div.test after third_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling -FAIL insert tree div>div.test after first_sibling_child assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling_child -FAIL insert tree div>div.test after first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling_descendant -FAIL insert tree div>div.test after third_sibling_child assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling_child -FAIL insert tree div>div.test after third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-geolocation.html b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-geolocation.html new file mode 100644 index 0000000..8194384 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-geolocation.html
@@ -0,0 +1,21 @@ +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script> + "use strict"; + + Promise.resolve().then(async () => { + await test_driver.set_permission( + { name: "geolocation" }, + "granted", + false + ); + try { + await new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(resolve, reject); + }); + window.parent.postMessage({ enabled: true }, "*"); + } catch (e) { + window.parent.postMessage({ enabled: false }, "*"); + } + }); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/PositionOptions.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/PositionOptions.https.html index 828224d..6b36d66d 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/PositionOptions.https.html +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/PositionOptions.https.html
@@ -1,101 +1,93 @@ -<!DOCTYPE HTML> -<meta charset="utf-8"> +<!DOCTYPE html> +<meta charset="utf-8" /> <title>Geolocation Test: PositionOptions tests</title> -<link rel="help" href="http://www.w3.org/TR/geolocation-API/#position_options_interface"> +<link + rel="help" + href="http://www.w3.org/TR/geolocation-API/#position_options_interface" +/> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script> -<script src='support.js'></script> <script> -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00123 -test(function() { - try { - geo.getCurrentPosition(dummyFunction, null, {enableHighAccuracy: "boom"}); - geo.getCurrentPosition(dummyFunction, null, {enableHighAccuracy: 321}); - geo.getCurrentPosition(dummyFunction, null, {enableHighAccuracy: -Infinity}); - geo.getCurrentPosition(dummyFunction, null, {enableHighAccuracy: {foo: 5}}); - } catch(e) { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); - } -}, 'Call getCurrentPosition with wrong type for enableHighAccuracy. No exception expected.'); + const resetPermission = () => { + return test_driver.set_permission({ name: "geolocation" }, "prompt"); + }; + const invalidValues = ["boom", 321, -Infinity, { foo: 5 }]; -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00124 -test(function() { - try { - geo.watchPosition(dummyFunction, null, {enableHighAccuracy: "boom"}); - geo.watchPosition(dummyFunction, null, {enableHighAccuracy: 321}); - geo.watchPosition(dummyFunction, null, {enableHighAccuracy: -Infinity}); - geo.watchPosition(dummyFunction, null, {enableHighAccuracy: {foo: 5}}); - } catch(e) { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); - } -}, 'Call watchPosition with wrong type for enableHighAccuracy. No exception expected.'); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + for (const enableHighAccuracy of invalidValues) { + navigator.geolocation.getCurrentPosition(() => {}, null, { + enableHighAccuracy, + }); + } + }, "Call getCurrentPosition with wrong type for enableHighAccuracy. No exception expected."); -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00086, 00088, 00091 and 00092 -promise_test(async function() { - await test_driver.set_permission({name: 'geolocation'}, 'granted'); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + for (const enableHighAccuracy of invalidValues) { + const id = navigator.geolocation.watchPosition(() => {}, null, { + enableHighAccuracy, + }); + navigator.geolocation.clearWatch(id); + } + }, "Call watchPosition with wrong type for enableHighAccuracy. No exception expected."); - var t86 = async_test('Set timeout and maximumAge to 0, check that timeout error raised (getCurrentPosition)'), - t88 = async_test('Set timeout and maximumAge to 0, check that timeout error raised (watchPosition)'), - t91 = async_test('Check that a negative timeout value is equivalent to a 0 timeout value (getCurrentLocation)'), - t92 = async_test('Check that a negative timeout value is equivalent to a 0 timeout value (watchPosition)'); - - try { - geo.getCurrentPosition( - t86.unreached_func('A success callback was invoked unexpectedly'), - t86.step_func_done(function(err) { - assert_equals(err.code, err.TIMEOUT); - }), - {timeout: 0, maximumAge: 0} - ); - } catch(e) { - t86.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + const error = await new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(reject, resolve, { + timeout: 0, + maxAge: 0, + }); }); - } + assert_equals(error.code, GeolocationPositionError.TIMEOUT); + }, "Set timeout and maximumAge to 0, check that timeout error raised (getCurrentPosition)"); - try { - geo.watchPosition( - t88.unreached_func('A success callback was invoked unexpectedly'), - t88.step_func_done(function(err) { - assert_equals(err.code, err.TIMEOUT); - }), - {timeout: 0, maximumAge: 0} - ); - } catch(e) { - t88.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + let watchId; + const error = await new Promise((resolve, reject) => { + watchId = navigator.geolocation.watchPosition(reject, resolve, { + timeout: 0, + maxAge: 0, + }); }); - } + assert_equals(error.code, GeolocationPositionError.TIMEOUT); + navigator.geolocation.clearWatch(watchId); + }, "Set timeout and maximumAge to 0, check that timeout error raised (watchPosition)"); - try { - geo.getCurrentPosition( - t91.unreached_func('A success callback was invoked unexpectedly'), - t91.step_func_done(function(err) { - assert_equals(err.code, err.TIMEOUT); - }), - {timeout:-1, maximumAge: 0} - ); - } catch(e) { - t91.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + let watchId; + const error = await new Promise((resolve, reject) => { + watchId = navigator.geolocation.getCurrentPosition(reject, resolve, { + timeout: -100, + maxAge: -100, + }); }); - } + assert_equals(error.code, GeolocationPositionError.TIMEOUT); + navigator.geolocation.clearWatch(watchId); + }, "Check that a negative timeout and maxAge values are clamped to 0 (getCurrentPosition)"); - try { - geo.watchPosition( - t92.unreached_func('A success callback was invoked unexpectedly'), - t92.step_func_done(function(err) { - assert_equals(err.code, err.TIMEOUT); - }), - {timeout: -1, maximumAge: 0} - ); - } catch(e) { - t92.step(function() { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "granted"); + let watchId; + const error = await new Promise((resolve, reject) => { + watchId = navigator.geolocation.watchPosition(reject, resolve, { + timeout: -100, + maxAge: -100, + }); }); - } -}, 'PositionOptions tests'); + assert_equals(error.code, GeolocationPositionError.TIMEOUT); + navigator.geolocation.clearWatch(watchId); + }, "Check that a negative timeout and maxAge values are clamped to 0 (watchPosition)"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.html b/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.html deleted file mode 100644 index 14b861b..0000000 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.html +++ /dev/null
@@ -1,22 +0,0 @@ -<!DOCTYPE HTML> -<meta charset='utf-8'> -<title>Geolocation Test: clearWatch TypeError tests</title> -<link rel='help' href='http://www.w3.org/TR/geolocation-API/#clear-watch'> -<script src='/resources/testharness.js'></script> -<script src='/resources/testharnessreport.js'></script> -<script src='support.js'></script> - -<div id='log'></div> - -<script> -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00080 -test(function() { - try { - geo.clearWatch(-1); - geo.clearWatch(0); - geo.clearWatch(1); - } catch(e) { - assert_unreached('An exception was thrown unexpectedly: ' + e.message); - } -}, 'Test that calling clearWatch with invalid watch IDs does not cause an exception'); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.https.html new file mode 100644 index 0000000..37ebeca --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/clearWatch_TypeError.https.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<title>Geolocation Test: clearWatch TypeError tests</title> +<link rel="help" href="http://www.w3.org/TR/geolocation-API/#clear-watch" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + for (const invalidId of [NaN, -1, 0, 1, 2147483648, Infinity, -Infinity]) { + test(() => { + navigator.geolocation.clearWatch(invalidId); + }, `Test that calling clearWatch with invalid watch ID (${invalidId}) does not cause an exception`); + } +</script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html new file mode 100644 index 0000000..26fa721 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html
@@ -0,0 +1,71 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<body> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="/feature-policy/resources/featurepolicy.js"></script> + <script> + "use strict"; + + const same_origin_src = + "/feature-policy/resources/feature-policy-geolocation.html"; + const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; + + promise_test(async (t) => { + await test_driver.set_permission( + { name: "geolocation" }, + "granted", + false + ); + + const posError = await new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(reject, resolve); + }); + + assert_true( + posError instanceof GeolocationPositionError, + "Expected instance of GeolocationPositionError" + ); + + assert_equals( + posError.code, + GeolocationPositionError.prototype.PERMISSION_DENIED, + "Expected PERMISSION_DENIED" + ); + + const watchError = await new Promise((resolve, reject) => { + navigator.geolocation.watchPosition(reject, resolve); + }); + assert_true( + watchError instanceof GeolocationPositionError, + "Expected instance of GeolocationPositionError" + ); + assert_equals( + watchError.code, + GeolocationPositionError.prototype.PERMISSION_DENIED, + "Expected PERMISSION_DENIED" + ); + }, "Feature-Policy header geolocation : 'none' disallows the top-level document."); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + same_origin_src, + expect_feature_unavailable_default + ); + }, "Feature-Policy header geolocation : 'none' disallows same-origin iframes."); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + cross_origin_src, + expect_feature_unavailable_default + ); + }, "Feature-Policy header geolocation 'none' disallows cross-origin iframes."); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html.headers new file mode 100644 index 0000000..7e75481 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/disabled-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@ +Feature-Policy: geolocation 'none'
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html new file mode 100644 index 0000000..30de411 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/feature-policy/resources/featurepolicy.js"></script> +<script> + "use strict"; + + const relative_path = "/feature-policy/resources/feature-policy-geolocation.html"; + const base_src = "/feature-policy/resources/redirect-on-load.html#"; + const same_origin_src = base_src + relative_path; + const cross_origin_src = + base_src + "https://{{domains[www]}}:{{ports[https][0]}}" + relative_path; + + async_test(t => { + test_feature_availability( + 'geolocation', + t, + same_origin_src, + expect_feature_available_default, + "geolocation" + ); + }, 'Feature-Policy allow="geolocation" allows same-origin relocation'); + + async_test(t => { + test_feature_availability( + 'geolocation', + t, + cross_origin_src, + expect_feature_unavailable_default, + "geolocation" + ); + }, 'Feature-Policy allow="geolocation" disallows cross-origin relocation'); + +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html new file mode 100644 index 0000000..49a6d77 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy-attribute.https.sub.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/feature-policy/resources/featurepolicy.js"></script> +<script> + "use strict"; + + const same_origin_src = + "/feature-policy/resources/feature-policy-geolocation.html"; + const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; + + async_test(t => { + test_feature_availability( + "geolocation", + t, + same_origin_src, + expect_feature_available_default, + "geolocation" + ); + }, 'Feature policy "geolocation" can be enabled in same-origin iframe using allow="geolocation" attribute'); + + async_test(t => { + test_feature_availability( + "geolocation", + t, + cross_origin_src, + expect_feature_available_default, + "geolocation" + ); + }, 'Feature policy "geolocation" can be enabled in cross-origin iframe using allow="geolocation" attribute'); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html new file mode 100644 index 0000000..955ed10 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<body> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="/feature-policy/resources/featurepolicy.js"></script> + <script> + const same_origin_src = + "/feature-policy/resources/feature-policy-geolocation.html"; + const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; + + promise_test(async (t) => { + + await test_driver.set_permission( + { name: "geolocation" }, + "granted", + false + ); + + const result = await new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(resolve, reject); + }); + + assert_true( + result instanceof GeolocationPosition, + "Expected a GeolocationPosition" + ); + }, "Feature-Policy header geolocation: * allows the top-level document."); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + same_origin_src, + expect_feature_available_default + ); + }, "Feature-Policy header geolocation: * allows same-origin iframes."); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + cross_origin_src, + expect_feature_available_default + ); + }, "Feature-Policy header geolocation: * allows cross-origin iframes."); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html.headers new file mode 100644 index 0000000..40e9bc1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@ +Feature-Policy: geolocation *
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html new file mode 100644 index 0000000..12ff86f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<body> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="/feature-policy/resources/featurepolicy.js"></script> + + <script> + "use strict"; + + const same_origin_src = + "/feature-policy/resources/feature-policy-geolocation.html"; + const cross_origin_src = + "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; + + promise_test(async (t) => { + await test_driver.set_permission( + { name: "geolocation" }, + "granted", + false + ); + await new Promise(resolve => { + navigator.geolocation.getCurrentPosition(resolve); + }) + }, 'Feature-Policy header geolocation "self" allows the top-level document.'); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + same_origin_src, + expect_feature_available_default + ); + }, 'Feature-Policy header geolocation "self" allows same-origin iframes.'); + + async_test((t) => { + test_feature_availability( + "geolocation", + t, + cross_origin_src, + expect_feature_unavailable_default + ); + }, 'Feature-Policy header geolocation "self" disallows cross-origin iframes.'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html.headers b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html.headers new file mode 100644 index 0000000..b83264e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/enabled-on-self-origin-by-feature-policy.https.sub.html.headers
@@ -0,0 +1 @@ +Feature-Policy: geolocation 'self'
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.html b/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.https.html similarity index 82% rename from third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.html rename to third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.https.html index 6726e8a..953efb2 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.html +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_TypeError.https.html
@@ -4,52 +4,47 @@ <link rel='help' href='http://www.w3.org/TR/geolocation-API/'> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> -<script src='support.js'></script> - -<div id='log'></div> <script> // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00027 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(); + navigator.geolocation.getCurrentPosition(); }); }, 'Call getCurrentPosition without arguments, check that exception is thrown'); // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00011 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(null); + navigator.geolocation.getCurrentPosition(null); }); }, 'Call getCurrentPosition with null success callback, check that exception is thrown'); // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00013 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(null, null); + navigator.geolocation.getCurrentPosition(null, null); }); }, 'Call getCurrentPosition with null success and error callbacks, check that exception is thrown'); // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00028 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(3); + navigator.geolocation.getCurrentPosition(3); }); }, 'Call getCurrentPosition() with wrong type for first argument. Exception expected.'); // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00029 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(dummyFunction, 4); + navigator.geolocation.getCurrentPosition(()=>{}, 4); }); }, 'Call getCurrentPosition() with wrong type for second argument. Exception expected.'); // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00030 test(function() { assert_throws_js(TypeError, function() { - geo.getCurrentPosition(dummyFunction, dummyFunction, 4); + navigator.geolocation.getCurrentPosition(()=>{}, ()=>{}, 4); }); }, 'Call getCurrentPosition() with wrong type for third argument. Exception expected.'); - -done(); </script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_permission_deny.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_permission_deny.https.html index 5012960..297f9a2 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_permission_deny.https.html +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/getCurrentPosition_permission_deny.https.html
@@ -1,32 +1,24 @@ -<!DOCTYPE HTML> -<meta charset='utf-8'> +<!DOCTYPE html> +<meta charset="utf-8" /> <title>Geolocation Test: getCurrentPosition location access denied</title> -<link rel='help' href='http://www.w3.org/TR/geolocation-API/#privacy_for_uas'> -<script src='/resources/testharness.js'></script> -<script src='/resources/testharnessreport.js'></script> -<script src='support.js'></script> - -<p>Clear all Geolocation permissions before running this test. If prompted for permission, please deny.</p> -<div id='log'></div> - +<link rel="help" href="http://www.w3.org/TR/geolocation-API/#privacy_for_uas" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> <script> -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00001 -var t = async_test('User denies access, check that error callback is called with correct code'), - onSuccess, onError, hasMethodReturned = false; - -t.step(function() { - onSuccess = t.step_func_done(function(pos) { - assert_unreached('A success callback was invoked unexpectedly with position ' + positionToString(pos)); - }); - - onError = t.step_func_done(function(err) { - // http://dev.w3.org/geo/api/test-suite/t.html?00031 - assert_true(hasMethodReturned, 'Check that getCurrentPosition returns synchronously before any callbacks are invoked'); - assert_equals(err.code, err.PERMISSION_DENIED, errorToString(err)); - }); - - geo.getCurrentPosition(onSuccess, onError); - hasMethodReturned = true; -}); - + promise_test(async (t) => { + t.add_cleanup(() => { + return test_driver.set_permission({ name: "geolocation" }, "prompt"); + }); + await test_driver.set_permission({ name: "geolocation" }, "denied"); + const result = await new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition(reject, resolve); + }); + assert_true( + result instanceof GeolocationPositionError, + "should be a GeolocationPositionError" + ); + assert_equals(result.code, result.PERMISSION_DENIED); + }, "User denies access, check that error callback is called with correct code"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/non-fully-active.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/non-fully-active.https.html index d75c787..13853c0 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/non-fully-active.https.html +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/non-fully-active.https.html
@@ -9,7 +9,10 @@ <script src="support.js"></script> <body></body> <script> - promise_test(async function () { + promise_test(async (t) => { + t.add_cleanup(() => { + return test_driver.set_permission({ name: "geolocation" }, "prompt"); + }); await test_driver.set_permission({ name: "geolocation" }, "granted"); // Create the iframe, wait for it to load...
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.html b/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.html deleted file mode 100644 index dd8287f..0000000 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.html +++ /dev/null
@@ -1,55 +0,0 @@ -<!DOCTYPE HTML> -<meta charset='utf-8'> -<title>Geolocation Test: watchPosition TypeError tests</title> -<link rel='help' href='http://www.w3.org/TR/geolocation-API/'> -<script src='/resources/testharness.js'></script> -<script src='/resources/testharnessreport.js'></script> -<script src='support.js'></script> - -<div id='log'></div> - -<script> -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00058 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(); - }); -}, 'Call watchPosition without arguments, check that exception is thrown'); - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00015 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(null); - }); -}, 'Call watchPosition with null success callback, check that exception is thrown'); - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00017 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(null, null); - }); -}, 'Call watchPosition with null success and error callbacks, check that exception is thrown'); - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00059 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(3); - }); -}, 'Call watchPosition() with wrong type for first argument. Exception expected.'); - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00060 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(dummyFunction, 4); - }); -}, 'Call watchPosition() with wrong type for second argument. Exception expected.'); - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00061 -test(function() { - assert_throws_js(TypeError, function() { - geo.watchPosition(dummyFunction, dummyFunction, 4); - }); -}, 'Call watchPosition() with wrong type for third argument. Exception expected.'); - -done(); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.https.html new file mode 100644 index 0000000..64f0616 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_TypeError.https.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<title>Geolocation Test: watchPosition TypeError tests</title> +<link rel="help" href="http://www.w3.org/TR/geolocation-API/" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00058 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition(); + }); + }, "Call watchPosition without arguments, check that exception is thrown"); + + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00015 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition(null); + }); + }, "Call watchPosition with null success callback, check that exception is thrown"); + + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00017 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition(null, null); + }); + }, "Call watchPosition with null success and error callbacks, check that exception is thrown"); + + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00059 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition(3); + }); + }, "Call watchPosition() with wrong type for first argument. Exception expected."); + + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00060 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition(() => {}, 4); + }); + }, "Call watchPosition() with wrong type for second argument. Exception expected."); + + // Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00061 + test(() => { + assert_throws_js(TypeError, () => { + navigator.geolocation.watchPosition( + () => {}, + () => {}, + 4 + ); + }); + }, "Call watchPosition() with wrong type for third argument. Exception expected."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_permission_deny.https.html b/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_permission_deny.https.html index 1e2a3c4..d47f2b55 100644 --- a/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_permission_deny.https.html +++ b/third_party/blink/web_tests/external/wpt/geolocation-API/watchPosition_permission_deny.https.html
@@ -1,33 +1,45 @@ -<!DOCTYPE HTML> -<meta charset='utf-8'> +<!DOCTYPE html> +<meta charset="utf-8" /> <title>Geolocation Test: watchPosition location access denied</title> -<link rel='help' href='http://www.w3.org/TR/geolocation-API/#watch-position'> -<script src='/resources/testharness.js'></script> -<script src='/resources/testharnessreport.js'></script> -<script src='support.js'></script> - -<p>Clear all Geolocation permissions before running this test. If prompted for permission, please deny.</p> -<div id='log'></div> - +<link rel="help" href="http://www.w3.org/TR/geolocation-API/#privacy_for_uas" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> <script> -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00062 -var t = async_test('Check that watchPosition returns synchronously before any callbacks are invoked.'), - id, checkMethodHasReturned, hasMethodReturned = false; + const resetPermission = () => { + return test_driver.set_permission({ name: "geolocation" }, "prompt"); + }; -checkMethodHasReturned = t.step_func_done(function() { - assert_true(hasMethodReturned); -}); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "denied"); + let errorCBCalled = false; + let id; + const errorPromise = new Promise((resolve, reject) => { + id = navigator.geolocation.watchPosition(reject, () => { + errorCBCalled = true; + resolve(); + }); + }); + assert_false( + errorCBCalled, + "error callback must not be called synchronously" + ); + await errorPromise; + navigator.geolocation.clearWatch(id); + }, "Check that watchPosition returns synchronously before any callbacks are invoked."); -try { - id = geo.watchPosition(checkMethodHasReturned, checkMethodHasReturned); - hasMethodReturned = true; -} catch(e) { - t.unreached_func('An exception was thrown unexpectedly: ' + e.message); -} - -// Rewrite http://dev.w3.org/geo/api/test-suite/t.html?00151 -test(function() { - assert_greater_than_equal(id, -2147483648); - assert_less_than_equal(id, 2147483647); -}, 'Check that watchPosition returns a long'); + promise_test(async (t) => { + t.add_cleanup(resetPermission); + await test_driver.set_permission({ name: "geolocation" }, "denied"); + const promise = new Promise((resolve, reject) => { + navigator.geolocation.watchPosition(reject, resolve); + }); + const result = await promise; + assert_true( + result instanceof GeolocationPositionError, + "expected GeolocationPositionError" + ); + }, "User denies access, check that error callback is called."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer-ref.html index 6588615..c837503 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer-ref.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer-ref.html
@@ -12,13 +12,7 @@ </style> </head> <body> -<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make -NodeRenderingContext::parentRenderer and nextRenderer top layer aware -<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport. +<p>The test passes if you see a green square near the top of the viewport. <div></div> -<dialog id="dialog"></dialog> -<script> -document.getElementById('dialog').showModal(); -</script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html index 09490519..75727b4 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-replaced-renderer.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <html> <head> +<title>Modal dialog inside replaced renderer should not generate box</title> <link rel="match" href="modal-dialog-in-replaced-renderer-ref.html"> <link rel="help" href="https://fullscreen.spec.whatwg.org/#new-stacking-layer"> <style> @@ -14,9 +15,7 @@ </style> </head> <body> -<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make -NodeRenderingContext::parentRenderer and nextRenderer top layer aware -<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport. +<p>The test passes if you see a green square near the top of the viewport. <div> <dialog id="dialog"></dialog> </div>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column-ref.html index 38b628c..0310d1b 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column-ref.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column-ref.html
@@ -9,12 +9,6 @@ </style> </head> <body> -<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make -NodeRenderingContext::parentRenderer and nextRenderer top layer aware -<p>The test passes if you see a green rectangle in the center of the viewport. -<dialog id="dialog"></dialog> -<script> -document.getElementById('dialog').showModal(); -</script> +<p>The test passes if you see no green rectangle. </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html index 89ee6977..3d72826b 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-dialog-element/modal-dialog-in-table-column.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <html> <head> +<title>Modal dialog inside display: table-column should not generate box</title> <link rel="match" href="modal-dialog-in-table-column-ref.html"> <link rel="help" href="https://fullscreen.spec.whatwg.org/#new-stacking-layer"> <style> @@ -14,9 +15,7 @@ </style> </head> <body> -<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make -NodeRenderingContext::parentRenderer and nextRenderer top layer aware -<p>The test passes if you see a green rectangle in the center of the viewport. +<p>The test passes if you see no green rectangle. <div> <dialog id="dialog"></dialog> </div>
diff --git a/third_party/blink/web_tests/external/wpt/inert/inert-iframe-hittest.tentative.html b/third_party/blink/web_tests/external/wpt/inert/inert-iframe-hittest.tentative.html index 63e3477..bcc542d 100644 --- a/third_party/blink/web_tests/external/wpt/inert/inert-iframe-hittest.tentative.html +++ b/third_party/blink/web_tests/external/wpt/inert/inert-iframe-hittest.tentative.html
@@ -15,6 +15,10 @@ </div> <script> +const events = [ + "mousedown", "mouseenter", "mousemove", "mouseover", + "pointerdown", "pointerenter", "pointermove", "pointerover", +]; const iframe = document.getElementById("iframe"); let iframeDoc; let target; @@ -34,57 +38,64 @@ }); }); -promise_test(async function() { - let reachedTarget = false; - target.addEventListener("mousedown", () => { - reachedTarget = true; - }, { once: true }); - - let reachedWrapper = false; - wrapper.addEventListener("mousedown", () => { - reachedWrapper = true; - }, { once: true }); +async function mouseDownAndGetEvents(test) { + const receivedEvents = { + target: [], + wrapper: [], + }; + for (let event of events) { + target.addEventListener(event, () => { + receivedEvents.target.push(event); + }, { once: true, capture: true }); + wrapper.addEventListener(event, () => { + receivedEvents.wrapper.push(event); + }, { once: true, capture: true }); + } await new test_driver.Actions() .pointerMove(0, 0, { origin: wrapper }) .pointerDown() .send(); - this.add_cleanup(() => test_driver.click(document.body)); + test.add_cleanup(() => test_driver.click(document.body)); + + // Exact order of events is not interoperable. + receivedEvents.target.sort(); + receivedEvents.wrapper.sort(); + return receivedEvents; +} + +promise_test(async function() { + const receivedEvents = await mouseDownAndGetEvents(this); + assert_array_equals(receivedEvents.target, [], "target got no event"); + assert_array_equals(receivedEvents.wrapper, events, "wrapper got all events"); assert_false(target.matches(":focus"), "target is not focused"); assert_false(target.matches(":active"), "target is not active"); assert_false(target.matches(":hover"), "target is not hovered"); - assert_false(reachedTarget, "target didn't get event"); - assert_true(wrapper.matches(":hover"), "wrapper is hovered"); - assert_true(reachedWrapper, "wrapper got event"); }, "Hit-testing doesn't reach contents of an inert iframe"); promise_test(async function() { iframe.inert = false; - let reachedTarget = false; - target.addEventListener("mousedown", () => { - reachedTarget = true; - }, { once: true }); - - let reachedWrapper = false; - wrapper.addEventListener("mousedown", () => { - reachedWrapper = true; - }, { once: true }); - - await new test_driver.Actions() - .pointerMove(0, 0, { origin: wrapper }) - .pointerDown() - .send(); - this.add_cleanup(() => test_driver.click(document.body)); + const receivedEvents = await mouseDownAndGetEvents(this); + assert_array_equals(receivedEvents.target, events, "target got all events"); + if (receivedEvents.wrapper.length === 2) { + // Firefox is unstable, sometimes missing the mouse events. + assert_array_equals( + receivedEvents.wrapper, + ["pointerenter", "pointerover"], + "wrapper got enter and over pointer events"); + } else { + assert_array_equals( + receivedEvents.wrapper, + ["mouseenter", "mouseover", "pointerenter", "pointerover"], + "wrapper got enter and over events"); + } assert_true(target.matches(":focus"), "target is focused"); assert_true(target.matches(":active"), "target is active"); assert_true(target.matches(":hover"), "target is hovered"); - assert_true(reachedTarget, "target got event"); - assert_true(wrapper.matches(":hover"), "wrapper is hovered"); - assert_false(reachedWrapper, "wrapper didn't get event"); }, "Hit-testing can reach contents of a no longer inert iframe"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/inert/inert-iframe-tabbing.tentative.html b/third_party/blink/web_tests/external/wpt/inert/inert-iframe-tabbing.tentative.html index e346993..a0146b7 100644 --- a/third_party/blink/web_tests/external/wpt/inert/inert-iframe-tabbing.tentative.html +++ b/third_party/blink/web_tests/external/wpt/inert/inert-iframe-tabbing.tentative.html
@@ -4,63 +4,120 @@ <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> <link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#inert"> <link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation"> -<meta assert="assert" content="Contents of an inert iframe can't be focused by tabbing"> +<meta assert="assert" content="Tabbing can't enter an inert iframe from the outside, but can move within it and can leave it if focus is already there."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script> -<div id="start" tabindex="0">start</div> +<div id="before" tabindex="0">before</div> <div id="inert" inert> <iframe id="iframe"></iframe> </div> -<div id="end" tabindex="0">start</a> +<div id="after" tabindex="0">after</a> <script> const tabKey = "\uE004"; -const start = document.getElementById("start"); +const before = document.getElementById("before"); const inert = document.getElementById("inert"); -const end = document.getElementById("end"); +const after = document.getElementById("after"); const iframe = document.getElementById("iframe"); let iframeDoc; -let target; +let start; +let end; promise_setup(async () => { await new Promise(resolve => { iframe.addEventListener("load", resolve, { once: true }); - iframe.srcdoc = `<div id="target" tabindex="0">target</div>`; + iframe.srcdoc = ` + <div id="start" tabindex="0">target</div> + <div id="end" tabindex="0">target</div> + `; }); iframeDoc = iframe.contentDocument; - target = iframeDoc.getElementById("target"); + start = iframeDoc.getElementById("start"); + end = iframeDoc.getElementById("end"); }); promise_test(async function() { - start.focus(); - assert_equals(document.activeElement, start, "start got focus"); + before.focus(); + assert_equals(document.activeElement, before, "#before got outer focus"); assert_false(iframeDoc.hasFocus(), "iframeDoc doesn't have focus"); await test_driver.send_keys(document.activeElement, tabKey); - assert_equals(document.activeElement, end, "end got focus"); + assert_equals(document.activeElement, after, "#after got outer focus"); assert_false(iframeDoc.hasFocus(), "iframeDoc still doesn't have focus"); -}, "Sequential navigation skips contents of inert iframe"); +}, "Sequential navigation can't enter an inert iframe"); promise_test(async function() { start.focus(); - assert_equals(document.activeElement, start, "start got focus"); - assert_false(iframeDoc.hasFocus(), "iframeDoc doesn't have focus"); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); + assert_equals(iframeDoc.activeElement, start, "#start got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); + await test_driver.send_keys(iframeDoc.activeElement, tabKey); + assert_equals(document.activeElement, iframe, "#iframe still has outer focus"); + assert_equals(iframeDoc.activeElement, end, "#end got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc still has focus"); +}, "Sequential navigation can move within an inert iframe"); + +promise_test(async function() { + end.focus(); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); + assert_equals(iframeDoc.activeElement, end, "#end got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); + + await test_driver.send_keys(iframeDoc.activeElement, tabKey); + assert_equals(document.activeElement, after, "#after got outer focus"); + assert_false(iframeDoc.hasFocus(), "iframeDoc doesn't have focus"); +}, "Sequential navigation can leave an inert iframe"); + +// Test again without inertness. + +promise_test(async function() { inert.inert = false; + before.focus(); + assert_equals(document.activeElement, before, "#before got outer focus"); + assert_false(iframeDoc.hasFocus(), "iframeDoc doesn't have focus"); + await test_driver.send_keys(document.activeElement, tabKey); - assert_equals(document.activeElement, iframe, "iframe got focus"); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); // The document element is also focusable in Firefox. if (iframeDoc.activeElement === iframeDoc.documentElement) { await test_driver.send_keys(document.activeElement, tabKey); - assert_equals(document.activeElement, iframe, "iframe got focus"); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); } - assert_equals(iframeDoc.activeElement, target, "target got focus"); -}, "Sequential navigation can pick contents of a no longer inert iframe"); + assert_equals(iframeDoc.activeElement, start, "#start got inner focus"); +}, "Sequential navigation can enter a no longer inert iframe"); + +promise_test(async function() { + inert.inert = false; + + start.focus(); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); + assert_equals(iframeDoc.activeElement, start, "#start got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); + + await test_driver.send_keys(iframeDoc.activeElement, tabKey); + assert_equals(document.activeElement, iframe, "#iframe still has outer focus"); + assert_equals(iframeDoc.activeElement, end, "#end got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc still has focus"); +}, "Sequential navigation can move within a no longer inert iframe"); + +promise_test(async function() { + inert.inert = false; + + end.focus(); + assert_equals(document.activeElement, iframe, "#iframe got outer focus"); + assert_equals(iframeDoc.activeElement, end, "#end got inner focus"); + assert_true(iframeDoc.hasFocus(), "iframeDoc has focus"); + + await test_driver.send_keys(iframeDoc.activeElement, tabKey); + assert_equals(document.activeElement, after, "#after got outer focus"); + assert_false(iframeDoc.hasFocus(), "iframeDoc doesn't have focus"); +}, "Sequential navigation can leave a no longer inert iframe"); </script>
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/css/selectors/invalidation/has-sibling-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/css/selectors/invalidation/has-sibling-expected.txt deleted file mode 100644 index 01f64f5..0000000 --- a/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/css/selectors/invalidation/has-sibling-expected.txt +++ /dev/null
@@ -1,75 +0,0 @@ -This is a testharness.js-based test. -Found 71 tests; 36 PASS, 35 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS initial_color -FAIL add .test to first_sibling assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling -FAIL add .test to second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from second_sibling -FAIL add .test to third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling -FAIL add .test to first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling_child -FAIL add .test to first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove .test from first_sibling_descendant -FAIL add .test to third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling_child -FAIL add .test to third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove .test from third_sibling_descendant -FAIL insert element div.test before first_sibling assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling -FAIL insert element div.test before second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before second_sibling -FAIL insert element div.test before third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling -FAIL insert element div.test before first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling_child -FAIL insert element div.test before first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test before first_sibling_descendant -FAIL insert element div.test before third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling_child -FAIL insert element div.test before third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test before third_sibling_descendant -FAIL insert element div.test after first_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling -FAIL insert element div.test after second_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after second_sibling -FAIL insert element div.test after third_sibling assert_equals: expected "rgb(255, 0, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling -FAIL insert element div.test after first_sibling_child assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling_child -FAIL insert element div.test after first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove element div.test after first_sibling_descendant -FAIL insert element div.test after third_sibling_child assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling_child -FAIL insert element div.test after third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove element div.test after third_sibling_descendant -FAIL insert tree div>div.test before first_sibling assert_equals: expected "rgb(255, 192, 203)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling -FAIL insert tree div>div.test before second_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before second_sibling -FAIL insert tree div>div.test before third_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling -FAIL insert tree div>div.test before first_sibling_child assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling_child -FAIL insert tree div>div.test before first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before first_sibling_descendant -FAIL insert tree div>div.test before third_sibling_child assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling_child -FAIL insert tree div>div.test before third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test before third_sibling_descendant -FAIL insert tree div>div.test after first_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling -FAIL insert tree div>div.test after second_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after second_sibling -FAIL insert tree div>div.test after third_sibling assert_equals: expected "rgb(128, 0, 128)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling -FAIL insert tree div>div.test after first_sibling_child assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling_child -FAIL insert tree div>div.test after first_sibling_descendant assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after first_sibling_descendant -FAIL insert tree div>div.test after third_sibling_child assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling_child -FAIL insert tree div>div.test after third_sibling_descendant assert_equals: expected "rgb(0, 0, 255)" but got "rgb(128, 128, 128)" -PASS remove tree div>div.test after third_sibling_descendant -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/random-values-expected.txt b/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/random-values-expected.txt deleted file mode 100644 index a72656e1..0000000 --- a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/random-values-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -Tests crypto.randomValues. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS 'crypto' in self is true -PASS 'getRandomValues' in self.crypto is true -PASS self.crypto.__proto__.hasOwnProperty('getRandomValues') is true -PASS matchingBytes < 100 is true -PASS crypto.getRandomValues(new Uint8Array(new SharedArrayBuffer(100))) threw exception TypeError: Failed to execute 'getRandomValues' on 'Crypto': The provided ArrayBufferView value must not be shared.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/worker-random-values-expected.txt b/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/worker-random-values-expected.txt deleted file mode 100644 index 588b55a2..0000000 --- a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/crypto/worker-random-values-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -[Worker] Tests crypto.randomValues. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -Starting worker: random-values.js -PASS [Worker] 'crypto' in self is true -PASS [Worker] 'getRandomValues' in self.crypto is true -PASS [Worker] self.crypto.__proto__.hasOwnProperty('getRandomValues') is true -PASS [Worker] matchingBytes < 100 is true -PASS [Worker] crypto.getRandomValues(new Uint8Array(new SharedArrayBuffer(100))) threw exception TypeError: Failed to execute 'getRandomValues' on 'Crypto': The provided ArrayBufferView value must not be shared.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/tools/metrics/histograms/metadata/cros/histograms.xml b/tools/metrics/histograms/metadata/cros/histograms.xml index bccd0dc..b13fa04 100644 --- a/tools/metrics/histograms/metadata/cros/histograms.xml +++ b/tools/metrics/histograms/metadata/cros/histograms.xml
@@ -35,7 +35,7 @@ </histogram> <histogram name="CrosDisks.ArchiveType" enum="CrosDisksArchiveType" - expires_after="2022-04-03"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -45,7 +45,7 @@ </histogram> <histogram name="CrosDisks.DeviceMediaType" enum="CrosDisksDeviceMediaType" - expires_after="2022-04-24"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -55,7 +55,7 @@ </histogram> <histogram name="CrosDisks.FilesystemType" enum="CrosDisksFilesystemType" - expires_after="2022-04-24"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -65,7 +65,7 @@ </histogram> <histogram name="CrosDisks.Fuse.FuseArchive" enum="FuseArchiveError" - expires_after="2022-04-17"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -75,7 +75,7 @@ </histogram> <histogram name="CrosDisks.Fuse.FuseZip" enum="FuseZipError" - expires_after="2022-04-10"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -85,7 +85,7 @@ </histogram> <histogram name="CrosDisks.Fuse.Rar2fs" enum="Rar2fsError" - expires_after="2022-04-03"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -97,6 +97,7 @@ <histogram name="CrosDisksClient.FormatCompletedError" enum="CrosDisksClientFormatError" expires_after="2022-07-24"> <owner>austinct@chromium.org</owner> + <owner>src/ui/file_manager/OWNERS</owner> <summary> The error code of disk format signals received from the Chrome OS cros-disks daemon. @@ -106,6 +107,7 @@ <histogram name="CrosDisksClient.FormatTime" units="ms" expires_after="2022-07-03"> <owner>austinct@chromium.org</owner> + <owner>src/ui/file_manager/OWNERS</owner> <summary> Time taken for the Chrome OS cros-disks daemon to perform a format operation. @@ -113,7 +115,7 @@ </histogram> <histogram name="CrosDisksClient.MountCompletedError" - enum="CrosDisksClientMountError" expires_after="2022-10-19"> + enum="CrosDisksClientMountError" expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -123,7 +125,7 @@ </histogram> <histogram name="CrosDisksClient.MountErrorMountType" - enum="CrosDisksMountTypeError" expires_after="2022-10-19"> + enum="CrosDisksMountTypeError" expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -133,7 +135,7 @@ </histogram> <histogram name="CrosDisksClient.MountTime" units="ms" - expires_after="2022-10-19"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -142,7 +144,7 @@ </histogram> <histogram name="CrosDisksClient.UnmountError" enum="CrosDisksClientMountError" - expires_after="2022-10-19"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -152,7 +154,7 @@ </histogram> <histogram name="CrosDisksClient.UnmountTime" units="ms" - expires_after="2022-10-19"> + expires_after="2023-04-01"> <owner>fdegros@chromium.org</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/login/histograms.xml b/tools/metrics/histograms/metadata/login/histograms.xml index 9c90148..1769001 100644 --- a/tools/metrics/histograms/metadata/login/histograms.xml +++ b/tools/metrics/histograms/metadata/login/histograms.xml
@@ -67,8 +67,9 @@ </histogram> <histogram name="Login.BrowserShutdownTime" units="ms" - expires_after="2022-04-03"> + expires_after="2023-02-22"> <owner>xiyuan@chromium.org</owner> + <owner>cros-oac@google.com</owner> <summary> Tracks the browser process shutdown time from when SIGTERM is sent to the browser process to when the browser process group exits (or gets killed by
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index bc34010..a6d2d12 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -452,15 +452,6 @@ </summary> </histogram> -<histogram name="Signin.GetAccessTokenRetry" enum="GoogleServiceAuthError" - expires_after="2022-01-23"> - <owner>droger@chromium.org</owner> - <owner>msarda@chromium.org</owner> - <summary> - Retry reason of failed access token requests during Chrome reconcile. - </summary> -</histogram> - <histogram name="Signin.Intercept.AccountInfoFetchDuration" units="ms" expires_after="2022-05-01"> <owner>alexilin@chromium.org</owner>