diff --git a/DEPS b/DEPS index 06b8dfc..df23db5 100644 --- a/DEPS +++ b/DEPS
@@ -305,7 +305,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '6345e669a4a7df3db6a54f75feb3758f57574710', + 'skia_revision': '72c62c68dcaa1aa05ee4fae42a03296e9b49481f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -313,7 +313,7 @@ # 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': '52ba6071e19959873cc999c8c4382d5816932155', + 'angle_revision': '0cb0907436af1d915512bc18713a703085e152c0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -321,7 +321,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'fbd5dcdc49cc059df67e74dc4fbcc042bfafaa44', + 'pdfium_revision': '7bac6ae44fef54e80c086f95d0a074022051bd57', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -432,7 +432,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': '22895dbe40cc19bcb02da31022213108f4b5d94a', + 'dawn_revision': '03ee23ea9efa2c4d053cb2c23152fc23553a3eaf', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -1222,7 +1222,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '902fa9a8886d1b0aba62fddeb32c421a5a09deaf', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '638956ac7dfc1422188e3add9f6d5d9fe778785b', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1845,7 +1845,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@474fdec3226aa00a354b58201c1ad4a00f4555ff', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@9eee852dba528dac48411018177d85ce5820796b', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1955,7 +1955,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': Var('chrome_git') + '/chrome/src-internal.git@1ff36cb350a564ac571254040279a9011435f3c7', + 'url': Var('chrome_git') + '/chrome/src-internal.git@6036b3eeda9102f2d91081a74c6706fe25211cb7', 'condition': 'checkout_src_internal', },
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 0fcc8394..a3afa29 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -3172,31 +3172,31 @@ <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_CYCLE_BACKWARD_MRU" translateable="false" desc="Label for accelerator action - Cycle backwards in the MRU window list."> Cycle backwards in the MRU window list </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_CYCLE_FORWARD_MRU" translateable="false" desc="Label for accelerator action - Cycle forwards in the MRU window list."> - Cycle forwards in the MRU window list + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_CYCLE_FORWARD_MRU" translateable="false" desc="Label for accelerator action - Cycle forwards in the most recently used window list."> + Cycle forwards in the most recently used window list </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_LEFT" translateable="false" desc="Label for accelerator action - Activate desk on left."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_LEFT" desc="Label for accelerator action - Activate desk on left."> Activate desk on left </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_RIGHT" translateable="false" desc="Label for accelerator action - Activate desk on right."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_RIGHT" desc="Label for accelerator action - Activate desk on right."> Activate desk on right </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_LEFT" translateable="false" desc="Label for accelerator action - Move active window to desk on left."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_LEFT" desc="Label for accelerator action - Move active window to desk on left."> Move active window to desk on left </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_RIGHT" translateable="false" desc="Label for accelerator action - Move active window to desk on right."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_RIGHT" desc="Label for accelerator action - Move active window to desk on right."> Move active window to desk on right </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_NEW_DESK" translateable="false" desc="Label for accelerator action - Create new desk."> - Create a new desk + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_NEW_DESK" desc="Label for accelerator action - Create new desk."> + Create new desk </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_REMOVE_CURRENT_DESK" translateable="false" desc="Label for accelerator action - Remove current desk."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_REMOVE_CURRENT_DESK" desc="Label for accelerator action - Remove current desk."> Remove current desk </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE" translateable="false" desc="Label for accelerator action - Go to desk 1 to 8."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE" desc="Label for accelerator action - Go to desk 1 to 8."> Go to desk 1 to 8 </message> - <message name="IDS_ASH_ACCELERATOR_ACTIONDESKS_TOGGLE_ASSIGN_TO_ALL_DESKS" translateable="false" desc="Label for accelerator action - Assign active window to all desk."> + <message name="IDS_ASH_ACCELERATOR_ACTIONDESKS_TOGGLE_ASSIGN_TO_ALL_DESKS" desc="Label for accelerator action - Assign active window to all desk."> Assign active window to all desks </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_DISABLE_CAPS_LOCK" translateable="false" desc="Label for accelerator action - Disable Caps Lock."> @@ -3277,7 +3277,7 @@ <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_MICROPHONE_MUTE_TOGGLE" translateable="false" desc="Label for accelerator action - Toggle mute microphone."> Toggle mute microphone </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS" translateable="false" desc="Label for accelerator action - Move active window between displays."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS" desc="Label for accelerator action - Move active window between displays."> Move active window between displays </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_NEW_INCOGNITO_WINDOW" translateable="false" desc="Label for accelerator action - Open new Incognito window."> @@ -3406,7 +3406,7 @@ <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FLOATING" translateable="false" desc="Label for accelerator action - Toggle floating."> Toggle floating </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN" translateable="false" desc="Label for accelerator action - Enter or exit fullscreen."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN" desc="Label for accelerator action - Enter or exit fullscreen."> Enter or exit fullscreen </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN_MAGNIFIER" desc="Label for accelerator action - Turn fullscreen magnifer on or off."> @@ -3415,7 +3415,7 @@ <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_HIGH_CONTRAST" desc="Label for accelerator action - Turn on high contrast mode."> Turn on high contrast mode </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MAXIMIZED" translateable="false" desc="Label for accelerator action - Maximize window."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MAXIMIZED" desc="Label for accelerator action - Maximize window."> Maximize window </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MIRROR_MODE" translateable="false" desc="Label for accelerator action - Mirror monitors."> @@ -3445,13 +3445,13 @@ <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_VOLUME_UP" translateable="false" desc="Label for accelerator action - Turn volume up."> Turn volume up </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_CYCLE_SNAP_LEFT" translateable="false" desc="Label for accelerator action - Turn volume down."> - Dock a window on the left + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_CYCLE_SNAP_LEFT" translateable="false" desc="Label for accelerator action - Keep window on left."> + Keep window on left </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_CYCLE_SNAP_RIGHT" translateable="false" desc="Label for accelerator action - Keep window on right."> - Dock a window on the right + Keep window on right </message> - <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_MINIMIZE" translateable="false" desc="Label for accelerator action - Minimize window."> + <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_MINIMIZE" desc="Label for accelerator action - Minimize window."> Minimize window </message> <message name="IDS_ASH_ACCELERATOR_DESCRIPTION_MINIMIZE_TOP_WINDOW_ON_BACK" translateable="false" desc="Label for accelerator action - Minimize top window on back."> @@ -3574,8 +3574,8 @@ <message name="IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_TAB" translateable="false" desc="Label for accelerator action - Close the current tab."> Close the current tab </message> - <message name="IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_WINDOW" translateable="false" desc="Label for accelerator action - Close the current window."> - Close the current window + <message name="IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_WINDOW" desc="Label for accelerator action - Close current window."> + Close current window </message> <message name="IDS_BROWSER_ACCELERATOR_DESCRIPTION_SELECT_LAST_TAB" translateable="false" desc="Label for accelerator action - Go to the last tab in the window."> Go to the last tab in the window @@ -3745,8 +3745,8 @@ <message name="IDS_AMBIENT_ACCELERATOR_DESCRIPTION_OPEN_PAGE_IN_NEW_TAB" translateable="false" desc="Label for accelerator description - Open the webpage in a new tab."> Open the webpage in a new tab </message> - <message name="IDS_AMBIENT_ACCELERATOR_DESCRIPTION_CYCLE_BACKWARD_MRU" translateable="false" desc="Label for accelerator description - Open the window that has been unused for the longest time."> - Open the window that has been unused for the longest time + <message name="IDS_AMBIENT_ACCELERATOR_DESCRIPTION_CYCLE_BACKWARD_MRU" translateable="false" desc="Label for accelerator description - Cycle backwards in the most recently used window list."> + Cycle backwards in the most recently used window list </message> <message name="IDS_AMBIENT_ACCELERATOR_DESCRIPTION_RIGHT_CLICK" translateable="false" desc="Label for accelerator description - Right-click a link."> Right-click a link
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_ACTIONDESKS_TOGGLE_ASSIGN_TO_ALL_DESKS.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_ACTIONDESKS_TOGGLE_ASSIGN_TO_ALL_DESKS.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_ACTIONDESKS_TOGGLE_ASSIGN_TO_ALL_DESKS.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_LEFT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_LEFT.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_LEFT.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_RIGHT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_RIGHT.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_ACTIVATE_DESK_RIGHT.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_LEFT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_LEFT.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_LEFT.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_RIGHT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_RIGHT.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_MOVE_ACTIVE_ITEM_RIGHT.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_NEW_DESK.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_NEW_DESK.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_NEW_DESK.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_REMOVE_CURRENT_DESK.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_REMOVE_CURRENT_DESK.png.sha1 new file mode 100644 index 0000000..40e326c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_DESKS_REMOVE_CURRENT_DESK.png.sha1
@@ -0,0 +1 @@ +d7103f2416b8e206a944d344481ede444f270f18 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS.png.sha1 new file mode 100644 index 0000000..3ec054f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_MOVE_ACTIVE_WINDOW_BETWEEN_DISPLAYS.png.sha1
@@ -0,0 +1 @@ +7cfc683fddb06e635fed855fee3a7f9b418d1898 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN.png.sha1 new file mode 100644 index 0000000..3ec054f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_FULLSCREEN.png.sha1
@@ -0,0 +1 @@ +7cfc683fddb06e635fed855fee3a7f9b418d1898 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MAXIMIZED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MAXIMIZED.png.sha1 new file mode 100644 index 0000000..3ec054f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_TOGGLE_MAXIMIZED.png.sha1
@@ -0,0 +1 @@ +7cfc683fddb06e635fed855fee3a7f9b418d1898 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_MINIMIZE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_MINIMIZE.png.sha1 new file mode 100644 index 0000000..3ec054f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_ACCELERATOR_DESCRIPTION_WINDOW_MINIMIZE.png.sha1
@@ -0,0 +1 @@ +7cfc683fddb06e635fed855fee3a7f9b418d1898 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_WINDOW.png.sha1 b/ash/ash_strings_grd/IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_WINDOW.png.sha1 new file mode 100644 index 0000000..3ec054f --- /dev/null +++ b/ash/ash_strings_grd/IDS_BROWSER_ACCELERATOR_DESCRIPTION_CLOSE_WINDOW.png.sha1
@@ -0,0 +1 @@ +7cfc683fddb06e635fed855fee3a7f9b418d1898 \ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 2f6969fe..2ce93642 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1159,7 +1159,7 @@ // Enable or disable a new header bar for the ChromeOS virtual keyboard. BASE_FEATURE(kVirtualKeyboardNewHeader, "VirtualKeyboardNewHeader", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // If enabled, used to configure the heuristic rules for some advanced IME // features (e.g. auto-correct). @@ -2729,12 +2729,6 @@ return base::FeatureList::IsEnabled(kIppClientInfo); } -bool IsJellyEnabled() { - // TODO(b/270741618): Callers are being migrated to - // chromeos::features::IsJellyEnabled(). Do not use. - return chromeos::features::IsJellyEnabled(); -} - bool IsKeyboardBacklightToggleEnabled() { return base::FeatureList::IsEnabled(kEnableKeyboardBacklightToggle); } @@ -2888,7 +2882,8 @@ } bool IsOobeJellyEnabled() { - return IsJellyEnabled() && base::FeatureList::IsEnabled(kOobeJelly); + return chromeos::features::IsJellyEnabled() && + base::FeatureList::IsEnabled(kOobeJelly); } bool IsOobeNetworkScreenSkipEnabled() { @@ -2941,7 +2936,7 @@ bool IsPersonalizationJellyEnabled() { return base::FeatureList::IsEnabled(kPersonalizationJelly) && - IsJellyEnabled(); + chromeos::features::IsJellyEnabled(); } bool IsPhoneHubCameraRollEnabled() {
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 1e65bc7..6cef393 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -745,9 +745,6 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsInternalServerSideSpeechRecognitionControlEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsIppClientInfoEnabled(); -// TODO(b/270741618): Callers are being migrated to -// chromeos::features::IsJellyEnabled(). Do not use. -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsJellyEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsKeyboardBacklightToggleEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsLanguagePacksEnabled();
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc index 0f9ccd2..898d8df 100644 --- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc +++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -8,8 +8,6 @@ #include <memory> #include <vector> -#include "ash/constants/ash_features.h" -#include "ash/public/cpp/input_device_settings_controller.h" #include "ash/public/mojom/input_device_settings.mojom.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" @@ -31,8 +29,28 @@ namespace ash { namespace { + +mojom::MetaKey GetMetaKeyForKeyboard(const ui::InputDevice& keyboard) { + const auto device_type = + Shell::Get()->keyboard_capability()->GetDeviceType(keyboard); + switch (device_type) { + case ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard: + case ui::KeyboardCapability::DeviceType::kDeviceExternalChromeOsKeyboard: + case ui::KeyboardCapability::DeviceType::kDeviceHotrodRemote: + case ui::KeyboardCapability::DeviceType::kDeviceUnknown: + case ui::KeyboardCapability::DeviceType::kDeviceVirtualCoreKeyboard: + return Shell::Get()->keyboard_capability()->HasLauncherButton(keyboard) + ? mojom::MetaKey::kLauncher + : mojom::MetaKey::kSearch; + case ui::KeyboardCapability::DeviceType::kDeviceExternalAppleKeyboard: + return mojom::MetaKey::kCommand; + case ui::KeyboardCapability::DeviceType::kDeviceExternalGenericKeyboard: + case ui::KeyboardCapability::DeviceType::kDeviceExternalUnknown: + return mojom::MetaKey::kExternalMeta; + }; +} + mojom::KeyboardPtr BuildMojomKeyboard(const ui::InputDevice& keyboard) { - // TODO(dpad): Initialize the meta key property. mojom::KeyboardPtr mojom_keyboard = mojom::Keyboard::New(); mojom_keyboard->id = keyboard.id; mojom_keyboard->name = keyboard.name; @@ -41,6 +59,7 @@ keyboard.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL; mojom_keyboard->modifier_keys = Shell::Get()->keyboard_capability()->GetModifierKeys(keyboard); + mojom_keyboard->meta_key = GetMetaKeyForKeyboard(keyboard); return mojom_keyboard; }
diff --git a/ash/system/keyboard_brightness/unified_keyboard_brightness_slider_controller.cc b/ash/system/keyboard_brightness/unified_keyboard_brightness_slider_controller.cc index ed34a5a..0a1190f 100644 --- a/ash/system/keyboard_brightness/unified_keyboard_brightness_slider_controller.cc +++ b/ash/system/keyboard_brightness/unified_keyboard_brightness_slider_controller.cc
@@ -49,7 +49,9 @@ model_(model) { if (features::IsRgbKeyboardEnabled() && Shell::Get()->rgb_keyboard_manager()->IsRgbKeyboardSupported()) { - button()->SetBackgroundColor(keyboardBrightnessIconBackgroundColor); + if (button()) { + button()->SetBackgroundColor(keyboardBrightnessIconBackgroundColor); + } AddChildView(CreateKeyboardBacklightColorButton()); } model_->AddObserver(this);
diff --git a/ash/system/message_center/ash_notification_drag_controller.cc b/ash/system/message_center/ash_notification_drag_controller.cc index cce54abb..4c52421 100644 --- a/ash/system/message_center/ash_notification_drag_controller.cc +++ b/ash/system/message_center/ash_notification_drag_controller.cc
@@ -10,6 +10,7 @@ #include "ash/system/notification_center/notification_center_tray.h" #include "ash/system/status_area_widget.h" #include "ash/system/unified/unified_system_tray.h" +#include "base/metrics/histogram_functions.h" #include "ui/aura/client/drag_drop_client.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/drop_target_event.h" @@ -135,9 +136,14 @@ drag_drop_client_observer_.Observe( aura::client::GetDragDropClient(Shell::GetPrimaryRootWindow())); - // Hide the message center bubble if it is open. message_center::MessageCenter* message_center_ptr = message_center::MessageCenter::Get(); + message_center::Notification* notification = + message_center_ptr->FindNotificationById(*dragged_notification_id_); + base::UmaHistogramEnumeration("Ash.NotificationView.ImageDrag.Start", + notification->notifier_id().catalog_name); + + // Hide the message center bubble if it is open. if (message_center_ptr->IsMessageCenterVisible()) { StatusAreaWidget* status_area_widget = RootWindowController::ForWindow( @@ -173,8 +179,6 @@ // popup only shows when the message center is hidden. // NOTE: if the dragged notification is a child of a notification group, hide // the group notification popup. - message_center::Notification* notification = - message_center_ptr->FindNotificationById(*dragged_notification_id_); message_center_ptr->MarkSinglePopupAsShown( notification->group_child() ? message_center_ptr->FindParentNotification(notification)->id()
diff --git a/ash/system/message_center/ash_notification_view_unittest.cc b/ash/system/message_center/ash_notification_view_unittest.cc index 39618db3..f662342 100644 --- a/ash/system/message_center/ash_notification_view_unittest.cc +++ b/ash/system/message_center/ash_notification_view_unittest.cc
@@ -1514,9 +1514,14 @@ EXPECT_CALL(drag_drop_delegate(), HandleHtmlData); } } + base::HistogramTester tester; DragAndDropNotification(*GetViewForNotificationId(notification->id()), DroppedToWidget()); + // Check the notification catalog name. + tester.ExpectBucketCount("Ash.NotificationView.ImageDrag.Start", + ash::NotificationCatalogName::kNone, 1); + // The the message center bubble is closed and the popup notification is // dismissed when drag ends. MessageCenterTargetVisibilityWaiter(/*target_visible=*/false).Wait(); @@ -1859,9 +1864,14 @@ // Drag to the center of `widget` then release. Verify that the screenshot // image carried by the drag data is handled. EXPECT_CALL(drag_drop_delegate(), HandleFilePathData(image_file_path)); + base::HistogramTester tester; DragAndDropNotification( *GetViewForNotificationId(kScreenCaptureNotificationId), /*drag_to_widget=*/true); + + // Check the notification catalog name. + tester.ExpectBucketCount("Ash.NotificationView.ImageDrag.Start", + ash::NotificationCatalogName::kScreenCapture, 1); } } // namespace ash
diff --git a/ash/webui/projector_app/projector_xhr_sender.cc b/ash/webui/projector_app/projector_xhr_sender.cc index e30b50d..249193c 100644 --- a/ash/webui/projector_app/projector_xhr_sender.cc +++ b/ash/webui/projector_app/projector_xhr_sender.cc
@@ -33,7 +33,38 @@ "network call between the chromeOS Projector(Screencast) app and " "the server. If the screencast app is enabled, the XHR requests " "are made by the app to the allowlisted URLs after authorizing " - "the request with end user credentials or API key or auth token." + "the request with API key." + trigger: "When the user launches the Screencast app to create and " + "view screencasts." + data: "The recordings and transcripts done via the Screencast app." + destination: GOOGLE_OWNED_SERVICE + } + policy: { + cookies_allowed: NO + setting: "The admin can enable or disable this feature via Google " + "Admin console. On homepage, go to Devices > Chrome. On the left," + "click Settings > Users & browsers. Scroll down to Content and " + "locate Screencast to enable/diable it. The feature is enabled " + "by default." + chrome_policy { + ProjectorEnabled { + ProjectorEnabled: true + } + } + })"); + +// Projector network traffic annotation tags. +constexpr net::NetworkTrafficAnnotationTag + kNetworkTrafficAnnotationTagAllowCookie = + net::DefineNetworkTrafficAnnotation("projector_xhr_loader_allow_cookie", + R"( + semantics: { + sender: "ChromeOS Projector" + description: "ChromeOS send Projector XHR requests. This is the " + "network call between the chromeOS Projector(Screencast) app and " + "the server. If the screencast app is enabled, the XHR requests " + "are made by the app to the allowlisted URLs after authorizing " + "the request with end user credentials or auth token." trigger: "When the user launches the Screencast app to create and " "view screencasts." data: "The recordings and transcripts done via the Screencast app." @@ -107,12 +138,10 @@ if (use_api_key) { request_url = net::AppendQueryParameter(url, kApiKeyParam, google_apis::GetAPIKey()); - } - if (use_credentials || use_api_key) { // Use end user credentials or API key to authorize the request. Doesn't // need to fetch OAuth token. SendRequest(request_url, method, request_body, /*token=*/std::string(), - headers, std::move(callback)); + headers, /*allow_cookie=*/false, std::move(callback)); return; } @@ -135,10 +164,10 @@ .email; // Fetch OAuth token for authorizing the request. oauth_token_fetcher_.GetAccessTokenFor( - email, - base::BindOnce(&ProjectorXhrSender::OnAccessTokenRequestCompleted, - weak_factory_.GetWeakPtr(), request_url, method, - request_body, headers.Clone(), std::move(callback))); + email, base::BindOnce(&ProjectorXhrSender::OnAccessTokenRequestCompleted, + weak_factory_.GetWeakPtr(), request_url, method, + request_body, headers.Clone(), use_credentials, + std::move(callback))); } void ProjectorXhrSender::OnAccessTokenRequestCompleted( @@ -146,6 +175,7 @@ const std::string& method, const std::string& request_body, const base::Value::Dict& headers, + bool use_credentials, SendRequestCallback callback, const std::string& email, GoogleServiceAuthError error, @@ -159,7 +189,7 @@ } SendRequest(url, method, request_body, info.token, headers, - std::move(callback)); + /*allow_cookie=*/use_credentials, std::move(callback)); } void ProjectorXhrSender::SendRequest(const GURL& url, @@ -167,6 +197,7 @@ const std::string& request_body, const std::string& token, const base::Value::Dict& headers, + bool allow_cookie, SendRequestCallback callback) { // Build resource request. auto resource_request = std::make_unique<network::ResourceRequest>(); @@ -186,8 +217,10 @@ } // Send resource request. - auto loader = network::SimpleURLLoader::Create(std::move(resource_request), - kNetworkTrafficAnnotationTag); + auto loader = network::SimpleURLLoader::Create( + std::move(resource_request), allow_cookie + ? kNetworkTrafficAnnotationTagAllowCookie + : kNetworkTrafficAnnotationTag); // Return response body of non-2xx response. This allows passing response body // for non-2xx response. loader->SetAllowHttpErrorResults(true);
diff --git a/ash/webui/projector_app/projector_xhr_sender.h b/ash/webui/projector_app/projector_xhr_sender.h index 1c1fc4a..1a5653d 100644 --- a/ash/webui/projector_app/projector_xhr_sender.h +++ b/ash/webui/projector_app/projector_xhr_sender.h
@@ -50,9 +50,17 @@ virtual ~ProjectorXhrSender(); // Send XHR request and trigger the callback when complete. - // This will attempt to fetch OAuth token for the provided email address - // and fallback to primary account email if account_email is not provided - // or ProjectorViewerUseSecondaryAccount flag is disabled. + // There are a few credentials could be used for authorizing a request: + // 1. API Key: when `use_api_key` is true, it is a anonymous request. End + // user credentials will be ignored. + // 2. Account email: By default, primary account email is used to get OAuth + // token for authorizing the request. If `account_email` is specified, it + // will be used instead. + // 3. Credentials: when `use_credentials` is true, the request will be sent + // with cookie alongs with auth token. One use case is allowing + // get_video_info response to add streaming auth token in cookie. There is + // no use case for sending requests with credentials only (without oauth + // token). virtual void Send(const GURL& url, const std::string& method, const std::string& request_body, @@ -68,6 +76,7 @@ const std::string& method, const std::string& request_body, const base::Value::Dict& headers, + bool use_credentials, SendRequestCallback callback, const std::string& email, GoogleServiceAuthError error, @@ -78,6 +87,7 @@ const std::string& request_body, const std::string& token, const base::Value::Dict& headers, + bool allow_cookie, SendRequestCallback callback); // Triggered when an XHR request completed.
diff --git a/ash/webui/projector_app/test/projector_message_handler_unittest.cc b/ash/webui/projector_app/test/projector_message_handler_unittest.cc index 7c7459b..27839535 100644 --- a/ash/webui/projector_app/test/projector_message_handler_unittest.cc +++ b/ash/webui/projector_app/test/projector_message_handler_unittest.cc
@@ -262,6 +262,8 @@ base::RunLoop run_loop; message_handler()->SetXhrRequestRunLoopQuitClosure(run_loop.QuitClosure()); web_ui().HandleReceivedMessage("sendXhr", list_args); + mock_app_client().WaitForAccessRequest(kTestUserEmail); + run_loop.Run(); EXPECT_EQ(web_ui().call_data().size(), 1u); @@ -314,6 +316,7 @@ base::RunLoop run_loop; message_handler()->SetXhrRequestRunLoopQuitClosure(run_loop.QuitClosure()); web_ui().HandleReceivedMessage("sendXhr", list_args); + mock_app_client().WaitForAccessRequest(kTestUserEmail); run_loop.Run(); EXPECT_EQ(web_ui().call_data().size(), 1u); @@ -368,6 +371,8 @@ base::RunLoop run_loop; message_handler()->SetXhrRequestRunLoopQuitClosure(run_loop.QuitClosure()); web_ui().HandleReceivedMessage("sendXhr", list_args); + mock_app_client().WaitForAccessRequest(kTestUserEmail); + run_loop.Run(); EXPECT_EQ(web_ui().call_data().size(), 1u);
diff --git a/ash/webui/projector_app/test/projector_xhr_sender_unittest.cc b/ash/webui/projector_app/test/projector_xhr_sender_unittest.cc index df22ac14..c217bdbf 100644 --- a/ash/webui/projector_app/test/projector_xhr_sender_unittest.cc +++ b/ash/webui/projector_app/test/projector_xhr_sender_unittest.cc
@@ -156,10 +156,13 @@ }, test_response_body, run_loop.QuitClosure())); - // Verify that http request is sent without granting OAuth token. mock_app_client().test_url_loader_factory().AddResponse(kTestDriveRequestUrl, test_response_body); + mock_app_client().GrantOAuthTokenFor( + kTestUserEmail, + /* expiry_time = */ base::Time::Now() + kExpiryTimeFromNow); + run_loop.Run(); }
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc index 980a80f6..42d80ab9 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -173,16 +173,6 @@ return info_mojom; } -// Create base accelerator info using accelerator. -mojom::AcceleratorInfoPtr CreateBaseAcceleratorInfo( - const ui::Accelerator& accelerator) { - // TODO(longbowei): Some accelerators should not be locked when customization - // is allowed. - return CreateStandardAcceleratorInfo(accelerator, /*locked=*/true, - GetAcceleratorType(accelerator), - mojom::AcceleratorState::kEnabled); -} - } // namespace namespace shortcut_ui { @@ -284,7 +274,7 @@ } AcceleratorConfigurationProvider::AcceleratorConfigurationMap -AcceleratorConfigurationProvider::GetAcceleratorConfig() const { +AcceleratorConfigurationProvider::GetAcceleratorConfig() { return CreateConfigurationMap(); } @@ -383,20 +373,22 @@ } } -std::vector<mojom::AcceleratorInfoPtr> -AcceleratorConfigurationProvider::CreateAcceleratorInfos( - const std::vector<ui::Accelerator>& accelerators) const { - std::vector<mojom::AcceleratorInfoPtr> infos_mojom; - for (const auto& accelerator : accelerators) { - // Get the alias accelerators by doing F-Keys remapping and - // (reversed) six-pack-keys remapping if applicable. - std::vector<ui::Accelerator> accelerator_aliases = - accelerator_alias_converter_.CreateAcceleratorAlias(accelerator); - for (const auto& accelerator_alias : accelerator_aliases) { - infos_mojom.push_back(CreateBaseAcceleratorInfo(accelerator_alias)); - } +void AcceleratorConfigurationProvider::CreateAndAppendAliasedAccelerators( + const ui::Accelerator& accelerator, + bool locked, + mojom::AcceleratorType type, + mojom::AcceleratorState state, + std::vector<mojom::AcceleratorInfoPtr>& output) { + // Get the alias accelerators by doing F-Keys remapping and + // (reversed) six-pack-keys remapping if applicable. + std::vector<ui::Accelerator> accelerator_aliases = + accelerator_alias_converter_.CreateAcceleratorAlias(accelerator); + output.reserve(output.size() + accelerator_aliases.size()); + + for (const auto& accelerator_alias : accelerator_aliases) { + output.push_back(CreateStandardAcceleratorInfo( + accelerator_alias, locked, GetAcceleratorType(accelerator), state)); } - return infos_mojom; } mojom::TextAcceleratorPropertiesPtr @@ -447,20 +439,71 @@ } AcceleratorConfigurationProvider::AcceleratorConfigurationMap -AcceleratorConfigurationProvider::CreateConfigurationMap() const { +AcceleratorConfigurationProvider::CreateConfigurationMap() { AcceleratorConfigurationMap accelerator_config; - // For each source, create a mapping between <ActionId, AcceleratorInfoPtr>. - for (const auto& [source, id_to_accelerators] : accelerators_mapping_) { - base::flat_map<AcceleratorActionId, std::vector<mojom::AcceleratorInfoPtr>> - accelerators_mojom; - for (const auto& [action_id, accelerators] : id_to_accelerators) { - accelerators_mojom.emplace(action_id, - CreateAcceleratorInfos(accelerators)); - } - accelerator_config.emplace(source, std::move(accelerators_mojom)); - } + PopulateAshAcceleratorConfig(accelerator_config); + PopulateAmbientAcceleratorConfig(accelerator_config); + return accelerator_config; +} - // Add non-configuarable accelerators. +void AcceleratorConfigurationProvider::PopulateAshAcceleratorConfig( + AcceleratorConfigurationMap& accelerator_config_output) { + const auto& id_to_accelerators = + accelerators_mapping_.at(mojom::AcceleratorSource::kAsh); + auto& output_action_id_to_accelerators = + accelerator_config_output[mojom::AcceleratorSource::kAsh]; + + for (const auto& layout_info : kAcceleratorLayouts) { + if (layout_info.source != mojom::AcceleratorSource::kAsh) { + // Only ash accelerators can have dynamically modified properties. + // Note that ambient accelerators cannot be in kAsh. + continue; + } + + const auto& id_to_accelerator_iter = + id_to_accelerators.find(layout_info.action_id); + // For tests, we only want to test a subset of accelerators so it's possible + // that we don't have accelerators for the given `layout_info`. + if (id_to_accelerator_iter == id_to_accelerators.end() && + ignore_layouts_for_testing_) { + continue; + } else { + DCHECK(id_to_accelerator_iter != id_to_accelerators.end()); + } + + const auto& accelerators = id_to_accelerator_iter->second; + + // Check if the default accelerators are available, if not re-add them but + // mark them as disabled. + const std::vector<ui::Accelerator>& default_accelerators = + ash_accelerator_configuration_->GetDefaultAcceleratorsForId( + layout_info.action_id); + for (const auto& default_accelerator : default_accelerators) { + if (base::Contains(accelerators, default_accelerator)) { + continue; + } + + // Append the missing default accelerators but marked as disabled by user. + CreateAndAppendAliasedAccelerators( + default_accelerator, layout_info.locked, + mojom::AcceleratorType::kDefault, + mojom::AcceleratorState::kDisabledByUser, + output_action_id_to_accelerators[layout_info.action_id]); + } + + for (const auto& accelerator : accelerators) { + // TODO(jimmyxgong): Check pref storage to determine whether the + // AcceleratorType was user-added or default. + CreateAndAppendAliasedAccelerators( + accelerator, layout_info.locked, mojom::AcceleratorType::kDefault, + mojom::AcceleratorState::kEnabled, + output_action_id_to_accelerators[layout_info.action_id]); + } + } +} + +void AcceleratorConfigurationProvider::PopulateAmbientAcceleratorConfig( + AcceleratorConfigurationMap& accelerator_config_output) { ActionIdToAcceleratorsInfoMap non_configurable_accelerators; for (const auto& [ambient_action_id, accelerators_details] : non_configurable_actions_mapping_) { @@ -468,9 +511,14 @@ // These properties should only be set for text based layout accelerators DCHECK(!accelerators_details.replacements.has_value()); DCHECK(!accelerators_details.message_id.has_value()); - non_configurable_accelerators.emplace( - ambient_action_id, - CreateAcceleratorInfos(accelerators_details.accelerators.value())); + for (const auto& non_config_accelerator : + accelerators_details.accelerators.value()) { + CreateAndAppendAliasedAccelerators( + non_config_accelerator, + /*locked=*/true, mojom::AcceleratorType::kDefault, + mojom::AcceleratorState::kEnabled, + non_configurable_accelerators[ambient_action_id]); + } } else { // This property should only be set for standard accelerators DCHECK(!accelerators_details.accelerators.has_value()); @@ -483,9 +531,8 @@ std::move(text_accelerators_info)); } } - accelerator_config.emplace(mojom::AcceleratorSource::kAmbient, - std::move(non_configurable_accelerators)); - return accelerator_config; + accelerator_config_output.emplace(mojom::AcceleratorSource::kAmbient, + std::move(non_configurable_accelerators)); } } // namespace shortcut_ui
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h index b2f45e2..a2305a4bb 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h
@@ -86,7 +86,7 @@ // ui::KeyboardCapability::Observer: void OnTopRowKeysAreFKeysChanged() override; - AcceleratorConfigurationMap GetAcceleratorConfig() const; + AcceleratorConfigurationMap GetAcceleratorConfig(); std::vector<mojom::AcceleratorLayoutInfoPtr> GetAcceleratorLayoutInfos() const; @@ -116,12 +116,25 @@ void UpdateKeyboards(); - AcceleratorConfigurationMap CreateConfigurationMap() const; + AcceleratorConfigurationMap CreateConfigurationMap(); + + void PopulateAshAcceleratorConfig( + AcceleratorConfigurationMap& accelerator_config_output); + + void PopulateAmbientAcceleratorConfig( + AcceleratorConfigurationMap& accelerator_config_output); void NotifyAcceleratorsUpdated(); - std::vector<mojom::AcceleratorInfoPtr> CreateAcceleratorInfos( - const std::vector<ui::Accelerator>& accelerators) const; + void CreateAndAppendAliasedAccelerators( + const ui::Accelerator& accelerator, + bool locked, + mojom::AcceleratorType type, + mojom::AcceleratorState state, + std::vector<mojom::AcceleratorInfoPtr>& output); + + // Set only for testing purposes, this will ignore the default layouts. + bool ignore_layouts_for_testing_ = false; std::vector<mojom::AcceleratorLayoutInfoPtr> layout_infos_;
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc index 2e6652f..dc01c21 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -330,6 +330,7 @@ non_configurable_actions_map_ = provider_->GetNonConfigurableAcceleratorsForTesting(); fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>(); + provider_->ignore_layouts_for_testing_ = true; base::RunLoop().RunUntilIdle(); } @@ -854,7 +855,7 @@ EXPECT_EQ(u"esc", ash::GetKeyDisplay(ui::VKEY_ESCAPE)); EXPECT_EQ(u"backspace", ash::GetKeyDisplay(ui::VKEY_BACK)); EXPECT_EQ(u"enter", ash::GetKeyDisplay(ui::VKEY_RETURN)); - EXPECT_EQ(u"Space", ash::GetKeyDisplay(ui::VKEY_SPACE)); + EXPECT_EQ(u"space", ash::GetKeyDisplay(ui::VKEY_SPACE)); } TEST_F(AcceleratorConfigurationProviderTest, NonConfigurableActions) { @@ -933,15 +934,14 @@ } } -// TODO(jimmyxgong): This is removing a default accelerator, update this when -// disabling accelerators is implemented. TEST_F(AcceleratorConfigurationProviderTest, RemoveAccelerator) { + FakeAcceleratorsUpdatedMojoObserver observer; + SetUpObserver(&observer); + // Initialize with all custom accelerators. const AcceleratorData test_data[] = { {/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, TOGGLE_MIRROR_MODE}, - {/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_ALT_DOWN, - SWAP_PRIMARY_DISPLAY}, }; AshAcceleratorConfiguration* config = Shell::Get()->ash_accelerator_configuration(); @@ -962,9 +962,22 @@ // Verify the accelerator was removed. std::vector<ui::Accelerator> updated_accelerators = config->GetAllAccelerators(); - EXPECT_EQ(1u, updated_accelerators.size()); - ui::Accelerator expected_accelerator(ui::VKEY_ZOOM, ui::EF_ALT_DOWN); - EXPECT_EQ(expected_accelerator, updated_accelerators[0]); + EXPECT_EQ(0u, updated_accelerators.size()); + + // Now verify that removing the default for `TOGGLE_MIRROR_MODE` will + // only disable it from the config. + base::RunLoop().RunUntilIdle(); + AcceleratorConfigurationProvider::AcceleratorConfigurationMap + actual_config = observer.config(); + ExpectMojomAcceleratorsEqual(mojom::AcceleratorSource::kAsh, test_data, + mojo::Clone(actual_config)); + std::vector<mojom::AcceleratorInfoPtr> actual_infos(mojo::Clone( + actual_config[mojom::AcceleratorSource::kAsh][TOGGLE_MIRROR_MODE])); + EXPECT_EQ(1u, actual_infos.size()); + // A disabled default accelerator should be marked as `kDisabledByUser`. + EXPECT_EQ(mojom::AcceleratorState::kDisabledByUser, + actual_infos[0]->state); + EXPECT_EQ(mojom::AcceleratorType::kDefault, actual_infos[0]->type); })); base::RunLoop().RunUntilIdle(); }
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc index 2100d6f..932da1e 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
@@ -41,7 +41,10 @@ {ui::KeyboardCode::VKEY_DICTATE, u"ToggleDictation"}, {ui::KeyboardCode::VKEY_WLAN, u"ToggleWifi"}, {ui::KeyboardCode::VKEY_EMOJI_PICKER, u"EmojiPicker"}, - {ui::KeyboardCode::VKEY_SPACE, u"Space"}, + // TODO(longbowei): Determine if these strings require localization. + // PM/UX input needed + {ui::KeyboardCode::VKEY_SPACE, + l10n_util::GetStringUTF16(IDS_SHORTCUT_CUSTOMIZATION_KEY_SPACE)}, {ui::KeyboardCode::VKEY_TAB, l10n_util::GetStringUTF16(IDS_SHORTCUT_CUSTOMIZATION_KEY_TAB)}, {ui::KeyboardCode::VKEY_ESCAPE,
diff --git a/ash/webui/shortcut_customization_ui/resources/js/accelerator_edit_view.ts b/ash/webui/shortcut_customization_ui/resources/js/accelerator_edit_view.ts index a595a29..59ba248b 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/accelerator_edit_view.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/accelerator_edit_view.ts
@@ -18,7 +18,7 @@ import {getTemplate} from './accelerator_edit_view.html.js'; import {AcceleratorLookupManager} from './accelerator_lookup_manager.js'; import {ViewState} from './accelerator_view.js'; -import {getShortcutProvider} from './mojo_interface_provider.js'; +import {getShortcutProvider, useFakeProvider} from './mojo_interface_provider.js'; import {Accelerator, AcceleratorConfigResult, AcceleratorSource, AcceleratorState, AcceleratorType, ShortcutProviderInterface, StandardAcceleratorInfo} from './shortcut_types.js'; import {getAccelerator} from './shortcut_utils.js'; @@ -142,8 +142,11 @@ this.source, this.action, getAccelerator(this.acceleratorInfo)) .then((value: {result: AcceleratorResultData}) => { if (value.result.result === AcceleratorConfigResult.kSuccess) { - this.lookupManager.removeAccelerator( - this.source, this.action, getAccelerator(this.acceleratorInfo)); + if (useFakeProvider) { + this.lookupManager.removeAccelerator( + this.source, this.action, + getAccelerator(this.acceleratorInfo)); + } this.dispatchEvent(new CustomEvent('request-update-accelerator', { bubbles: true,
diff --git a/ash/webui/shortcut_customization_ui/resources/js/input_key.ts b/ash/webui/shortcut_customization_ui/resources/js/input_key.ts index 4f58f84..8260571e 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/input_key.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/input_key.ts
@@ -60,7 +60,6 @@ 'PrintScreen': 'screenshot', 'PrivacyScreenToggle': 'electronic-privacy-screen', 'Settings': 'settings', - 'Space': 'space-bar', 'ToggleDictation': 'dictation-toggle', 'ZoomToggle': 'fullscreen', };
diff --git a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts index 6b67f58b..d79b471 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/mojo_interface_provider.ts
@@ -25,13 +25,17 @@ * This variable is intended to be manually set by developers for the * purposes of debugging. */ -const useFakeProvider: boolean = false; +export let useFakeProvider: boolean = false; export function setShortcutProviderForTesting( testProvider: ShortcutProviderInterface): void { shortcutProvider = testProvider; } +export function setUseFakeProviderForTesting(useFake: boolean): void { + useFakeProvider = useFake; +} + /** * Sets up a FakeShortcutProvider to be used at runtime. * TODO(zentaro): Remove once mojo bindings are implemented. @@ -81,8 +85,7 @@ removeAccelerator( source: AcceleratorSource, action: number, accelerator: Accelerator): Promise<{result: AcceleratorResultData}> { - // TODO(cambickel) Replace with real mojo method. - return this.fakeProvider.removeAccelerator(source, action, accelerator); + return this.remote.removeAccelerator(source, action, accelerator); } replaceAccelerator(
diff --git a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts index 32b13ae..0f64468 100644 --- a/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts +++ b/ash/webui/shortcut_customization_ui/resources/js/shortcut_customization_app.ts
@@ -25,7 +25,7 @@ import {ShowEditDialogEvent} from './accelerator_row.js'; import {getShortcutProvider} from './mojo_interface_provider.js'; import {getTemplate} from './shortcut_customization_app.html.js'; -import {AcceleratorInfo, AcceleratorSource, AcceleratorState, AcceleratorType, MojoAcceleratorConfig, MojoLayoutInfo, ShortcutProviderInterface, StandardAcceleratorInfo} from './shortcut_types.js'; +import {AcceleratorInfo, AcceleratorSource, MojoAcceleratorConfig, MojoLayoutInfo, ShortcutProviderInterface} from './shortcut_types.js'; import {getCategoryNameStringId, isCustomizationDisabled} from './shortcut_utils.js'; export interface ShortcutCustomizationAppElement { @@ -184,14 +184,8 @@ private onRequestUpdateAccelerators(e: RequestUpdateAcceleratorEvent): void { this.$.navigationPanel.notifyEvent('updateSubsections'); const updatedAccels = - this.acceleratorlookupManager - .getStandardAcceleratorInfos(e.detail.source, e.detail.action) - ?.filter((accel: StandardAcceleratorInfo) => { - // Hide accelerators that are default and disabled. - return !( - accel.type === AcceleratorType.kDefault && - accel.state === AcceleratorState.kDisabledByUser); - }); + this.acceleratorlookupManager.getStandardAcceleratorInfos( + e.detail.source, e.detail.action); this.shadowRoot!.querySelector<AcceleratorEditDialogElement>('#editDialog')! .updateDialogAccelerators(updatedAccels as AcceleratorInfo[]);
diff --git a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc index 21f5820e..689d255 100644 --- a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc +++ b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
@@ -158,7 +158,6 @@ {"iconLabelPrivacyScreenToggle", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_PRIVACY_SCREEN_TOGGLE}, {"iconLabelSettings", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_SETTINGS}, - {"iconLabelSpace", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_SPACE}, {"iconLabelZoomToggle", IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ZOOM_TOGGLE}, };
diff --git a/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.cc b/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.cc index ee5f1a82..223b0fc 100644 --- a/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.cc +++ b/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler.cc
@@ -52,7 +52,10 @@ const ui::TouchEvent& event) { switch (event.type()) { case ui::ET_TOUCH_PRESSED: { - DCHECK(!drag_data_); + // Another drag is already underway from another finger. + if (drag_data_) { + return false; + } aura::Window* active_window = window_util::GetActiveWindow(); if (!active_window || !CanToggleFullscreen(active_window))
diff --git a/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc b/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc index 9736c5fc..7ebf6ad 100644 --- a/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_toggle_fullscreen_event_handler_unittest.cc
@@ -183,4 +183,26 @@ EXPECT_FALSE(IsFullscreen(foreground_window())); } +// Tests that we do not have a crash when using this feature with multiple +// fingers. Regression test for b/270155382. +TEST_F(TabletModeToggleFullscreenEventHandlerTest, SwipingWithMultipleFingers) { + ASSERT_TRUE(IsFullscreen(foreground_window())); + + const int kTouchId1 = 1; + const int kTouchId2 = 2; + + GetEventGenerator()->PressTouchId(kTouchId1, gfx::Point(400, 1)); + GetEventGenerator()->MoveTouchIdBy(kTouchId1, 0, 48); + + // Swipe with a second finger while the first one is still touching the + // screen. There should be no crash. + GetEventGenerator()->PressTouchId(kTouchId2, gfx::Point(400, 1)); + GetEventGenerator()->MoveTouchIdBy(kTouchId2, 0, 48); + GetEventGenerator()->ReleaseTouchId(kTouchId2); + + // Release the first finger and verify the window is un-fullscreened. + GetEventGenerator()->ReleaseTouchId(kTouchId1); + EXPECT_FALSE(IsFullscreen(foreground_window())); +} + } // namespace ash
diff --git a/base/allocator/partition_allocator/compressed_pointer.h b/base/allocator/partition_allocator/compressed_pointer.h index c7285c04..109b8a3 100644 --- a/base/allocator/partition_allocator/compressed_pointer.h +++ b/base/allocator/partition_allocator/compressed_pointer.h
@@ -92,7 +92,7 @@ return g_base_.base; } - PA_ALWAYS_INLINE static bool IsSet() { + static PA_ALWAYS_INLINE bool IsSet() { PA_DCHECK(IsBaseConsistent()); return (g_base_.base & ~kUsefulBitsMask) != 0; } @@ -107,7 +107,7 @@ char cache_line[kPartitionCachelineSize]; } g_base_ PA_CONSTINIT; - PA_ALWAYS_INLINE static bool IsBaseConsistent() { + static PA_ALWAYS_INLINE bool IsBaseConsistent() { return kUsefulBitsMask == (g_base_.base & kUsefulBitsMask); } @@ -128,19 +128,19 @@ public: using UnderlyingType = uint32_t; - PA_ALWAYS_INLINE constexpr CompressedPointer() = default; + constexpr PA_ALWAYS_INLINE CompressedPointer() = default; PA_ALWAYS_INLINE explicit CompressedPointer(T* ptr) : value_(Compress(ptr)) {} - PA_ALWAYS_INLINE constexpr explicit CompressedPointer(std::nullptr_t) + constexpr PA_ALWAYS_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {} - PA_ALWAYS_INLINE constexpr CompressedPointer(const CompressedPointer&) = + constexpr PA_ALWAYS_INLINE CompressedPointer(const CompressedPointer&) = default; - PA_ALWAYS_INLINE constexpr CompressedPointer( + constexpr PA_ALWAYS_INLINE CompressedPointer( CompressedPointer&& other) noexcept = default; template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr CompressedPointer( + constexpr PA_ALWAYS_INLINE CompressedPointer( const CompressedPointer<U>& other) { if constexpr (internal::IsDecayedSame<T, U>) { // When pointers have the same type modulo constness, avoid the @@ -156,20 +156,20 @@ template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr CompressedPointer( + constexpr PA_ALWAYS_INLINE CompressedPointer( CompressedPointer<U>&& other) noexcept : CompressedPointer(other) {} ~CompressedPointer() = default; - PA_ALWAYS_INLINE constexpr CompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE CompressedPointer& operator=( const CompressedPointer&) = default; - PA_ALWAYS_INLINE constexpr CompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE CompressedPointer& operator=( CompressedPointer&& other) noexcept = default; template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr CompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE CompressedPointer& operator=( const CompressedPointer<U>& other) { CompressedPointer copy(other); value_ = copy.value_; @@ -178,27 +178,27 @@ template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr CompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE CompressedPointer& operator=( CompressedPointer<U>&& other) noexcept { *this = other; return *this; } // Don't perform compression when assigning to nullptr. - PA_ALWAYS_INLINE constexpr CompressedPointer& operator=(std::nullptr_t) { + constexpr PA_ALWAYS_INLINE CompressedPointer& operator=(std::nullptr_t) { value_ = 0u; return *this; } PA_ALWAYS_INLINE T* get() const { return Decompress(value_); } - PA_ALWAYS_INLINE constexpr bool is_nonnull() const { return value_; } + constexpr PA_ALWAYS_INLINE bool is_nonnull() const { return value_; } - PA_ALWAYS_INLINE constexpr UnderlyingType GetAsIntegral() const { + constexpr PA_ALWAYS_INLINE UnderlyingType GetAsIntegral() const { return value_; } - PA_ALWAYS_INLINE constexpr explicit operator bool() const { + constexpr PA_ALWAYS_INLINE explicit operator bool() const { return is_nonnull(); } @@ -214,7 +214,7 @@ return get(); } - PA_ALWAYS_INLINE constexpr void swap(CompressedPointer& other) { + constexpr PA_ALWAYS_INLINE void swap(CompressedPointer& other) { std::swap(value_, other.value_); } @@ -274,7 +274,7 @@ }; template <typename T> -PA_ALWAYS_INLINE constexpr void swap(CompressedPointer<T>& a, +constexpr PA_ALWAYS_INLINE void swap(CompressedPointer<T>& a, CompressedPointer<T>& b) { a.swap(b); } @@ -296,61 +296,61 @@ } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator==(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a == static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator==(T* a, CompressedPointer<U> b) { return b == a; } template <typename T> -PA_ALWAYS_INLINE constexpr bool operator==(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator==(CompressedPointer<T> a, std::nullptr_t) { return !a.is_nonnull(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(std::nullptr_t, +constexpr PA_ALWAYS_INLINE bool operator==(std::nullptr_t, CompressedPointer<U> b) { return b == nullptr; } // operators!=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator!=(CompressedPointer<T> a, CompressedPointer<U> b) { return !(a == b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator!=(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a != static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator!=(T* a, CompressedPointer<U> b) { return b != a; } template <typename T> -PA_ALWAYS_INLINE constexpr bool operator!=(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator!=(CompressedPointer<T> a, std::nullptr_t) { return a.is_nonnull(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(std::nullptr_t, +constexpr PA_ALWAYS_INLINE bool operator!=(std::nullptr_t, CompressedPointer<U> b) { return b != nullptr; } // operators<. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator<(CompressedPointer<T> a, CompressedPointer<U> b) { if constexpr (internal::IsDecayedSame<T, U>) { // When pointers have the same type modulo constness, simply compare @@ -365,20 +365,20 @@ } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator<(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a < static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator<(T* a, CompressedPointer<U> b) { // Do compression, since it is less expensive. return static_cast<CompressedPointer<T>>(a) < b; } // operators<=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator<=(CompressedPointer<T> a, CompressedPointer<U> b) { if constexpr (internal::IsDecayedSame<T, U>) { // When pointers have the same type modulo constness, simply compare @@ -393,51 +393,51 @@ } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator<=(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a <= static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator<=(T* a, CompressedPointer<U> b) { // Do compression, since it is less expensive. return static_cast<CompressedPointer<T>>(a) <= b; } // operators>. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator>(CompressedPointer<T> a, CompressedPointer<U> b) { return !(a <= b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator>(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a > static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator>(T* a, CompressedPointer<U> b) { // Do compression, since it is less expensive. return static_cast<CompressedPointer<T>>(a) > b; } // operators>=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(CompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator>=(CompressedPointer<T> a, CompressedPointer<U> b) { return !(a < b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(CompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator>=(CompressedPointer<T> a, U* b) { // Do compression, since it is less expensive. return a >= static_cast<CompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(T* a, CompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator>=(T* a, CompressedPointer<U> b) { // Do compression, since it is less expensive. return static_cast<CompressedPointer<T>>(a) >= b; } @@ -448,38 +448,38 @@ template <typename T> class PA_TRIVIAL_ABI UncompressedPointer final { public: - PA_ALWAYS_INLINE constexpr UncompressedPointer() = default; - PA_ALWAYS_INLINE constexpr explicit UncompressedPointer(T* ptr) : ptr_(ptr) {} - PA_ALWAYS_INLINE constexpr explicit UncompressedPointer(std::nullptr_t) + constexpr PA_ALWAYS_INLINE UncompressedPointer() = default; + constexpr PA_ALWAYS_INLINE explicit UncompressedPointer(T* ptr) : ptr_(ptr) {} + constexpr PA_ALWAYS_INLINE explicit UncompressedPointer(std::nullptr_t) : ptr_(nullptr) {} - PA_ALWAYS_INLINE constexpr UncompressedPointer(const UncompressedPointer&) = + constexpr PA_ALWAYS_INLINE UncompressedPointer(const UncompressedPointer&) = default; - PA_ALWAYS_INLINE constexpr UncompressedPointer( + constexpr PA_ALWAYS_INLINE UncompressedPointer( UncompressedPointer&& other) noexcept = default; template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr UncompressedPointer( + constexpr PA_ALWAYS_INLINE UncompressedPointer( const UncompressedPointer<U>& other) : ptr_(other.ptr_) {} template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr UncompressedPointer( + constexpr PA_ALWAYS_INLINE UncompressedPointer( UncompressedPointer<U>&& other) noexcept : ptr_(std::move(other.ptr_)) {} ~UncompressedPointer() = default; - PA_ALWAYS_INLINE constexpr UncompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE UncompressedPointer& operator=( const UncompressedPointer&) = default; - PA_ALWAYS_INLINE constexpr UncompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE UncompressedPointer& operator=( UncompressedPointer&& other) noexcept = default; template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr UncompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE UncompressedPointer& operator=( const UncompressedPointer<U>& other) { ptr_ = other.ptr_; return *this; @@ -487,38 +487,38 @@ template <typename U, std::enable_if_t<std::is_convertible_v<U*, T*>>* = nullptr> - PA_ALWAYS_INLINE constexpr UncompressedPointer& operator=( + constexpr PA_ALWAYS_INLINE UncompressedPointer& operator=( UncompressedPointer<U>&& other) noexcept { ptr_ = std::move(other.ptr_); return *this; } - PA_ALWAYS_INLINE constexpr UncompressedPointer& operator=(std::nullptr_t) { + constexpr PA_ALWAYS_INLINE UncompressedPointer& operator=(std::nullptr_t) { ptr_ = nullptr; return *this; } - PA_ALWAYS_INLINE constexpr T* get() const { return ptr_; } + constexpr PA_ALWAYS_INLINE T* get() const { return ptr_; } - PA_ALWAYS_INLINE constexpr bool is_nonnull() const { return ptr_; } + constexpr PA_ALWAYS_INLINE bool is_nonnull() const { return ptr_; } - PA_ALWAYS_INLINE constexpr explicit operator bool() const { + constexpr PA_ALWAYS_INLINE explicit operator bool() const { return is_nonnull(); } template <typename U = T, std::enable_if_t<!std::is_void_v<std::remove_cv_t<U>>>* = nullptr> - PA_ALWAYS_INLINE constexpr U& operator*() const { + constexpr PA_ALWAYS_INLINE U& operator*() const { PA_DCHECK(is_nonnull()); return *get(); } - PA_ALWAYS_INLINE constexpr T* operator->() const { + constexpr PA_ALWAYS_INLINE T* operator->() const { PA_DCHECK(is_nonnull()); return get(); } - PA_ALWAYS_INLINE constexpr void swap(UncompressedPointer& other) { + constexpr PA_ALWAYS_INLINE void swap(UncompressedPointer& other) { std::swap(ptr_, other.ptr_); } @@ -530,134 +530,134 @@ }; template <typename T> -PA_ALWAYS_INLINE constexpr void swap(UncompressedPointer<T>& a, +constexpr PA_ALWAYS_INLINE void swap(UncompressedPointer<T>& a, UncompressedPointer<T>& b) { a.swap(b); } // operators==. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator==(UncompressedPointer<T> a, UncompressedPointer<U> b) { return a.get() == b.get(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator==(UncompressedPointer<T> a, U* b) { return a == static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator==(T* a, UncompressedPointer<U> b) { return b == a; } template <typename T> -PA_ALWAYS_INLINE constexpr bool operator==(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator==(UncompressedPointer<T> a, std::nullptr_t) { return !a.is_nonnull(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator==(std::nullptr_t, +constexpr PA_ALWAYS_INLINE bool operator==(std::nullptr_t, UncompressedPointer<U> b) { return b == nullptr; } // operators!=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator!=(UncompressedPointer<T> a, UncompressedPointer<U> b) { return !(a == b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator!=(UncompressedPointer<T> a, U* b) { return a != static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator!=(T* a, UncompressedPointer<U> b) { return b != a; } template <typename T> -PA_ALWAYS_INLINE constexpr bool operator!=(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator!=(UncompressedPointer<T> a, std::nullptr_t) { return a.is_nonnull(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator!=(std::nullptr_t, +constexpr PA_ALWAYS_INLINE bool operator!=(std::nullptr_t, UncompressedPointer<U> b) { return b != nullptr; } // operators<. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator<(UncompressedPointer<T> a, UncompressedPointer<U> b) { return a.get() < b.get(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator<(UncompressedPointer<T> a, U* b) { return a < static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator<(T* a, UncompressedPointer<U> b) { return static_cast<UncompressedPointer<T>>(a) < b; } // operators<=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator<=(UncompressedPointer<T> a, UncompressedPointer<U> b) { return a.get() <= b.get(); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator<=(UncompressedPointer<T> a, U* b) { return a <= static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator<=(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator<=(T* a, UncompressedPointer<U> b) { return static_cast<UncompressedPointer<T>>(a) <= b; } // operators>. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator>(UncompressedPointer<T> a, UncompressedPointer<U> b) { return !(a <= b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator>(UncompressedPointer<T> a, U* b) { return a > static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator>(T* a, UncompressedPointer<U> b) { return static_cast<UncompressedPointer<T>>(a) > b; } // operators>=. template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(UncompressedPointer<T> a, +constexpr PA_ALWAYS_INLINE bool operator>=(UncompressedPointer<T> a, UncompressedPointer<U> b) { return !(a < b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(UncompressedPointer<T> a, U* b) { +constexpr PA_ALWAYS_INLINE bool operator>=(UncompressedPointer<T> a, U* b) { return a >= static_cast<UncompressedPointer<U>>(b); } template <typename T, typename U> -PA_ALWAYS_INLINE constexpr bool operator>=(T* a, UncompressedPointer<U> b) { +constexpr PA_ALWAYS_INLINE bool operator>=(T* a, UncompressedPointer<U> b) { return static_cast<UncompressedPointer<T>>(a) >= b; }
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h index 010044ff..bddbefe 100644 --- a/base/allocator/partition_allocator/partition_address_space.h +++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -41,7 +41,7 @@ return setup_.regular_pool_base_mask_; } #else - static PA_ALWAYS_INLINE constexpr uintptr_t RegularPoolBaseMask() { + static constexpr PA_ALWAYS_INLINE uintptr_t RegularPoolBaseMask() { return kRegularPoolBaseMask; } #endif @@ -76,10 +76,10 @@ } return std::make_pair(pool, address - base); } - static PA_ALWAYS_INLINE constexpr size_t ConfigurablePoolMaxSize() { + static constexpr PA_ALWAYS_INLINE size_t ConfigurablePoolMaxSize() { return kConfigurablePoolMaxSize; } - static PA_ALWAYS_INLINE constexpr size_t ConfigurablePoolMinSize() { + static constexpr PA_ALWAYS_INLINE size_t ConfigurablePoolMinSize() { return kConfigurablePoolMinSize; } @@ -170,7 +170,7 @@ return RegularPoolSize() * 2; } #else - static PA_ALWAYS_INLINE constexpr size_t CorePoolsSize() { + static constexpr PA_ALWAYS_INLINE size_t CorePoolsSize() { return RegularPoolSize() * 2; } #endif // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE) @@ -226,16 +226,16 @@ static PA_ALWAYS_INLINE size_t BRPPoolSize(); #else // The pool sizes should be as large as maximum whenever possible. - constexpr static PA_ALWAYS_INLINE size_t RegularPoolSize() { + static constexpr PA_ALWAYS_INLINE size_t RegularPoolSize() { return kRegularPoolSize; } - constexpr static PA_ALWAYS_INLINE size_t BRPPoolSize() { + static constexpr PA_ALWAYS_INLINE size_t BRPPoolSize() { return kBRPPoolSize; } #endif // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE) #if BUILDFLAG(ENABLE_PKEYS) - constexpr static PA_ALWAYS_INLINE size_t PkeyPoolSize() { + static constexpr PA_ALWAYS_INLINE size_t PkeyPoolSize() { return kPkeyPoolSize; } #endif
diff --git a/base/allocator/partition_allocator/partition_alloc_base/bits.h b/base/allocator/partition_allocator/partition_alloc_base/bits.h index 5a3fc1d4..38aca0c4 100644 --- a/base/allocator/partition_allocator/partition_alloc_base/bits.h +++ b/base/allocator/partition_allocator/partition_alloc_base/bits.h
@@ -75,7 +75,7 @@ // instructions have defined behaviour for 0. We could drop to raw __asm__ to // do better, but we'll avoid doing that unless we see proof that we need to. template <typename T, int bits = sizeof(T) * 8> -PA_ALWAYS_INLINE constexpr +constexpr PA_ALWAYS_INLINE typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8, int>::type CountLeadingZeroBits(T value) { @@ -101,7 +101,7 @@ } template <typename T, int bits = sizeof(T) * 8> -PA_ALWAYS_INLINE constexpr +constexpr PA_ALWAYS_INLINE typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8, int>::type CountTrailingZeroBits(T value) {
diff --git a/base/allocator/partition_allocator/partition_alloc_hooks.h b/base/allocator/partition_allocator/partition_alloc_hooks.h index 8b97fd9..a6baeac 100644 --- a/base/allocator/partition_allocator/partition_alloc_hooks.h +++ b/base/allocator/partition_allocator/partition_alloc_hooks.h
@@ -72,7 +72,7 @@ const char* type_name); static bool ReallocOverrideHookIfEnabled(size_t* out, void* address); - PA_ALWAYS_INLINE static QuarantineOverrideHook* GetQuarantineOverrideHook() { + static PA_ALWAYS_INLINE QuarantineOverrideHook* GetQuarantineOverrideHook() { return quarantine_override_hook_.load(std::memory_order_acquire); }
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc index 1152367..92854b2 100644 --- a/base/allocator/partition_allocator/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -3509,7 +3509,7 @@ } TEST_P(PartitionAllocTest, ZeroFill) { - constexpr static size_t kAllZerosSentinel = + static constexpr size_t kAllZerosSentinel = std::numeric_limits<size_t>::max(); for (size_t size : kTestSizes) { char* p = static_cast<char*>(
diff --git a/base/allocator/partition_allocator/partition_bucket_lookup.h b/base/allocator/partition_allocator/partition_bucket_lookup.h index 5d4b570d..8f0c2e6 100644 --- a/base/allocator/partition_allocator/partition_bucket_lookup.h +++ b/base/allocator/partition_allocator/partition_bucket_lookup.h
@@ -104,10 +104,10 @@ // The class used to generate the bucket lookup table at compile-time. class BucketIndexLookup final { public: - PA_ALWAYS_INLINE constexpr static uint16_t GetIndexForDenserBuckets( - size_t size); - PA_ALWAYS_INLINE constexpr static uint16_t GetIndexFor8Buckets(size_t size); - PA_ALWAYS_INLINE constexpr static uint16_t GetIndex(size_t size); + static constexpr PA_ALWAYS_INLINE uint16_t + GetIndexForDenserBuckets(size_t size); + static constexpr PA_ALWAYS_INLINE uint16_t GetIndexFor8Buckets(size_t size); + static constexpr PA_ALWAYS_INLINE uint16_t GetIndex(size_t size); constexpr BucketIndexLookup() { constexpr uint16_t sentinel_bucket_index = kNumBuckets; @@ -204,13 +204,13 @@ bucket_index_lookup_[((kBitsPerSizeT + 1) * kNumBucketsPerOrder) + 1]{}; }; -PA_ALWAYS_INLINE constexpr size_t RoundUpToPowerOfTwo(size_t size) { +constexpr PA_ALWAYS_INLINE size_t RoundUpToPowerOfTwo(size_t size) { const size_t n = 1 << base::bits::Log2Ceiling(static_cast<uint32_t>(size)); PA_DCHECK(size <= n); return n; } -PA_ALWAYS_INLINE constexpr size_t RoundUpSize(size_t size) { +constexpr PA_ALWAYS_INLINE size_t RoundUpSize(size_t size) { const size_t next_power = RoundUpToPowerOfTwo(size); const size_t prev_power = next_power >> 1; PA_DCHECK(size <= next_power); @@ -222,13 +222,13 @@ } } -PA_ALWAYS_INLINE constexpr uint16_t RoundUpToOdd(uint16_t size) { +constexpr PA_ALWAYS_INLINE uint16_t RoundUpToOdd(uint16_t size) { return (size % 2 == 0) + size; } // static -PA_ALWAYS_INLINE constexpr uint16_t BucketIndexLookup::GetIndexFor8Buckets( - size_t size) { +constexpr PA_ALWAYS_INLINE uint16_t +BucketIndexLookup::GetIndexFor8Buckets(size_t size) { // This forces the bucket table to be constant-initialized and immediately // materialized in the binary. constexpr BucketIndexLookup lookup{}; @@ -249,8 +249,8 @@ } // static -PA_ALWAYS_INLINE constexpr uint16_t BucketIndexLookup::GetIndexForDenserBuckets( - size_t size) { +constexpr PA_ALWAYS_INLINE uint16_t +BucketIndexLookup::GetIndexForDenserBuckets(size_t size) { const auto index = GetIndexFor8Buckets(size); // Below the minimum size, 4 and 8 bucket distributions are the same, since we // can't fit any more buckets per order; this is due to alignment @@ -269,7 +269,7 @@ } // static -PA_ALWAYS_INLINE constexpr uint16_t BucketIndexLookup::GetIndex(size_t size) { +constexpr PA_ALWAYS_INLINE uint16_t BucketIndexLookup::GetIndex(size_t size) { // For any order 2^N, under the denser bucket distribution ("Distribution A"), // we have 4 evenly distributed buckets: 2^N, 1.25*2^N, 1.5*2^N, and 1.75*2^N. // These numbers represent the maximum size of an allocation that can go into
diff --git a/base/allocator/partition_allocator/partition_direct_map_extent.h b/base/allocator/partition_allocator/partition_direct_map_extent.h index 4d9bb61..4c405a8 100644 --- a/base/allocator/partition_allocator/partition_direct_map_extent.h +++ b/base/allocator/partition_allocator/partition_direct_map_extent.h
@@ -25,7 +25,7 @@ // the allocation. size_t padding_for_alignment; - PA_ALWAYS_INLINE static PartitionDirectMapExtent<thread_safe>* FromSlotSpan( + static PA_ALWAYS_INLINE PartitionDirectMapExtent<thread_safe>* FromSlotSpan( SlotSpanMetadata<thread_safe>* slot_span); }; @@ -45,7 +45,7 @@ PartitionBucket<thread_safe> bucket; PartitionDirectMapExtent<thread_safe> direct_map_extent; - PA_ALWAYS_INLINE static PartitionDirectMapMetadata<thread_safe>* FromSlotSpan( + static PA_ALWAYS_INLINE PartitionDirectMapMetadata<thread_safe>* FromSlotSpan( SlotSpanMetadata<thread_safe>* slot_span); };
diff --git a/base/allocator/partition_allocator/partition_freelist_entry.h b/base/allocator/partition_allocator/partition_freelist_entry.h index bace9be..b694471 100644 --- a/base/allocator/partition_allocator/partition_freelist_entry.h +++ b/base/allocator/partition_allocator/partition_freelist_entry.h
@@ -41,7 +41,7 @@ class EncodedPartitionFreelistEntryPtr { private: - explicit PA_ALWAYS_INLINE constexpr EncodedPartitionFreelistEntryPtr( + explicit constexpr PA_ALWAYS_INLINE EncodedPartitionFreelistEntryPtr( std::nullptr_t) : encoded_(Transform(0)) {} explicit PA_ALWAYS_INLINE EncodedPartitionFreelistEntryPtr(void* ptr) @@ -52,17 +52,17 @@ return reinterpret_cast<PartitionFreelistEntry*>(Transform(encoded_)); } - PA_ALWAYS_INLINE constexpr uintptr_t Inverted() const { return ~encoded_; } + constexpr PA_ALWAYS_INLINE uintptr_t Inverted() const { return ~encoded_; } - PA_ALWAYS_INLINE constexpr void Override(uintptr_t encoded) { + constexpr PA_ALWAYS_INLINE void Override(uintptr_t encoded) { encoded_ = encoded; } - explicit PA_ALWAYS_INLINE constexpr operator bool() const { return encoded_; } + explicit constexpr PA_ALWAYS_INLINE operator bool() const { return encoded_; } // Transform() works the same in both directions, so can be used for // encoding and decoding. - PA_ALWAYS_INLINE static constexpr uintptr_t Transform(uintptr_t address) { + static constexpr PA_ALWAYS_INLINE uintptr_t Transform(uintptr_t address) { // We use bswap on little endian as a fast transformation for two reasons: // 1) On 64 bit architectures, the pointer is very unlikely to be a // canonical address. Therefore, if an object is freed and its vtable is @@ -215,7 +215,7 @@ return SlotStartPtr2Addr(this); } - PA_ALWAYS_INLINE constexpr bool IsEncodedNextPtrZero() const { + constexpr PA_ALWAYS_INLINE bool IsEncodedNextPtrZero() const { return !encoded_next_; }
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h index b58fd02d..ec4a60f 100644 --- a/base/allocator/partition_allocator/partition_page.h +++ b/base/allocator/partition_allocator/partition_page.h
@@ -209,14 +209,14 @@ // |slot_span| pointer may be the result of an offset calculation and // therefore cannot be trusted. The objective of these functions is to // sanitize this input. - PA_ALWAYS_INLINE static uintptr_t ToSlotSpanStart( - const SlotSpanMetadata* slot_span); - PA_ALWAYS_INLINE static SlotSpanMetadata* FromAddr(uintptr_t address); - PA_ALWAYS_INLINE static SlotSpanMetadata* FromSlotStart(uintptr_t slot_start); - PA_ALWAYS_INLINE static SlotSpanMetadata* FromObject(void* object); - PA_ALWAYS_INLINE static SlotSpanMetadata* FromObjectInnerAddr( + static PA_ALWAYS_INLINE uintptr_t + ToSlotSpanStart(const SlotSpanMetadata* slot_span); + static PA_ALWAYS_INLINE SlotSpanMetadata* FromAddr(uintptr_t address); + static PA_ALWAYS_INLINE SlotSpanMetadata* FromSlotStart(uintptr_t slot_start); + static PA_ALWAYS_INLINE SlotSpanMetadata* FromObject(void* object); + static PA_ALWAYS_INLINE SlotSpanMetadata* FromObjectInnerAddr( uintptr_t address); - PA_ALWAYS_INLINE static SlotSpanMetadata* FromObjectInnerPtr(void* ptr); + static PA_ALWAYS_INLINE SlotSpanMetadata* FromObjectInnerPtr(void* ptr); PA_ALWAYS_INLINE PartitionSuperPageExtentEntry<thread_safe>* ToSuperPageExtent() const; @@ -405,7 +405,7 @@ bool has_valid_span_after_this : 1; uint8_t unused; - PA_ALWAYS_INLINE static PartitionPage* FromAddr(uintptr_t address); + static PA_ALWAYS_INLINE PartitionPage* FromAddr(uintptr_t address); }; #pragma pack(pop) static_assert(sizeof(PartitionPage<ThreadSafe>) == kPageMetadataSize,
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index c268f8e..20175b8 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -432,16 +432,16 @@ void EnableThreadCacheIfSupported(); - PA_ALWAYS_INLINE static bool IsValidSlotSpan(SlotSpan* slot_span); - PA_ALWAYS_INLINE static PartitionRoot* FromSlotSpan(SlotSpan* slot_span); + static PA_ALWAYS_INLINE bool IsValidSlotSpan(SlotSpan* slot_span); + static PA_ALWAYS_INLINE PartitionRoot* FromSlotSpan(SlotSpan* slot_span); // These two functions work unconditionally for normal buckets. // For direct map, they only work for the first super page of a reservation, // (see partition_alloc_constants.h for the direct map allocation layout). // In particular, the functions always work for a pointer to the start of a // reservation. - PA_ALWAYS_INLINE static PartitionRoot* FromFirstSuperPage( + static PA_ALWAYS_INLINE PartitionRoot* FromFirstSuperPage( uintptr_t super_page); - PA_ALWAYS_INLINE static PartitionRoot* FromAddrInFirstSuperpage( + static PA_ALWAYS_INLINE PartitionRoot* FromAddrInFirstSuperpage( uintptr_t address); PA_ALWAYS_INLINE void DecreaseTotalSizeOfAllocatedBytes(SlotSpan* slot_span) @@ -536,21 +536,21 @@ void* ptr, size_t new_size, const char* type_name) PA_MALLOC_ALIGNED; - PA_NOINLINE static void Free(void* object); - PA_ALWAYS_INLINE static void FreeWithFlags(unsigned int flags, void* object); + static PA_NOINLINE void Free(void* object); + static PA_ALWAYS_INLINE void FreeWithFlags(unsigned int flags, void* object); // Same as |Free()|, bypasses the allocator hooks. - PA_ALWAYS_INLINE static void FreeNoHooks(void* object); + static PA_ALWAYS_INLINE void FreeNoHooks(void* object); // Immediately frees the pointer bypassing the quarantine. |slot_start| is the // beginning of the slot that contains |object|. PA_ALWAYS_INLINE void FreeNoHooksImmediate(void* object, SlotSpan* slot_span, uintptr_t slot_start); - PA_ALWAYS_INLINE static size_t GetUsableSize(void* ptr); + static PA_ALWAYS_INLINE size_t GetUsableSize(void* ptr); // Same as GetUsableSize() except it adjusts the return value for macOS 11 // malloc_size() hack. - PA_ALWAYS_INLINE static size_t GetUsableSizeWithMac11MallocSizeHack( - void* ptr); + static PA_ALWAYS_INLINE size_t + GetUsableSizeWithMac11MallocSizeHack(void* ptr); PA_ALWAYS_INLINE PageAccessibilityConfiguration GetPageAccessibility() const; PA_ALWAYS_INLINE PageAccessibilityConfiguration
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr.h b/base/allocator/partition_allocator/pointers/raw_ptr.h index 9ae55d2..63ad1f2 100644 --- a/base/allocator/partition_allocator/pointers/raw_ptr.h +++ b/base/allocator/partition_allocator/pointers/raw_ptr.h
@@ -186,18 +186,18 @@ struct RawPtrNoOpImpl { // Wraps a pointer. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { return ptr; } // Notifies the allocator when a wrapped pointer is being removed or replaced. template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T*) {} + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T*) {} // Unwraps the pointer, while asserting that memory hasn't been freed. The // function is allowed to crash on nullptr. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { return wrapped_ptr; } @@ -205,7 +205,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function must handle nullptr gracefully. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { return wrapped_ptr; } @@ -213,14 +213,14 @@ // Unwraps the pointer, without making an assertion on whether memory was // freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { return wrapped_ptr; } // Upcasts the wrapped pointer. template <typename To, typename From> - constexpr static PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { static_assert(std::is_convertible<From*, To*>::value, "From must be convertible to To."); // Note, this cast may change the address if upcasting to base that lies in @@ -234,7 +234,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr + delta_elems; } @@ -244,12 +244,12 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr - delta_elems; } template <typename T> - constexpr static PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, + static constexpr PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, T* wrapped_ptr2) { return wrapped_ptr1 - wrapped_ptr2; } @@ -257,19 +257,19 @@ // Returns a copy of a wrapped pointer, without making an assertion on whether // memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { return wrapped_ptr; } // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { return ptr; } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { return wrapped_ptr; } @@ -326,7 +326,7 @@ // Wraps a pointer, and returns its uintptr_t representation. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return ptr; } @@ -376,12 +376,12 @@ // Notifies the allocator when a wrapped pointer is being removed or replaced. // No-op for MTECheckedPtrImpl. template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T*) {} + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T*) {} // Unwraps the pointer's uintptr_t representation, while asserting that memory // hasn't been freed. The function is allowed to crash on nullptr. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -414,7 +414,7 @@ // Unwraps the pointer as a T*, without making an assertion on whether // memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -431,7 +431,7 @@ // Unwraps the pointer's uintptr_t representation, without making an assertion // on whether memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -447,7 +447,7 @@ // Upcasts the wrapped pointer. template <typename To, typename From> - constexpr static PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { static_assert(std::is_convertible<From*, To*>::value, "From must be convertible to To."); @@ -461,7 +461,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr + delta_elems; } @@ -471,12 +471,12 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr - delta_elems; } template <typename T> - constexpr static PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, + static constexpr PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, T* wrapped_ptr2) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr1 - wrapped_ptr2; @@ -509,14 +509,14 @@ // Returns a copy of a wrapped pointer, without making an assertion // on whether memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { return wrapped_ptr; } // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return ptr; } @@ -524,7 +524,7 @@ } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -533,9 +533,9 @@ } // This is for accounting only, used by unit tests. - constexpr static PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} - constexpr static PA_ALWAYS_INLINE void IncrementLessCountForTest() {} - constexpr static PA_ALWAYS_INLINE void + static constexpr PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementLessCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {} private: @@ -576,65 +576,65 @@ using SuperImpl = typename raw_ptr_traits::TraitsToImpl<Traits>::Impl; template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { ++wrap_raw_ptr_cnt; return SuperImpl::WrapRawPtr(ptr); } template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* ptr) { ++release_wrapped_ptr_cnt; SuperImpl::ReleaseWrappedPtr(ptr); } template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { ++get_for_dereference_cnt; return SuperImpl::SafelyUnwrapPtrForDereference(wrapped_ptr); } template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { ++get_for_extraction_cnt; return SuperImpl::SafelyUnwrapPtrForExtraction(wrapped_ptr); } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { ++get_for_comparison_cnt; return SuperImpl::UnsafelyUnwrapPtrForComparison(wrapped_ptr); } - constexpr static PA_ALWAYS_INLINE void IncrementSwapCountForTest() { + static constexpr PA_ALWAYS_INLINE void IncrementSwapCountForTest() { ++wrapped_ptr_swap_cnt; } - constexpr static PA_ALWAYS_INLINE void IncrementLessCountForTest() { + static constexpr PA_ALWAYS_INLINE void IncrementLessCountForTest() { ++wrapped_ptr_less_cnt; } - constexpr static PA_ALWAYS_INLINE void + static constexpr PA_ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() { ++pointer_to_member_operator_cnt; } template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { ++wrap_raw_ptr_for_dup_cnt; return SuperImpl::WrapRawPtrForDuplication(ptr); } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { ++get_for_duplication_cnt; return SuperImpl::UnsafelyUnwrapPtrForDuplication(wrapped_ptr); } - constexpr static void ClearCounters() { + static constexpr void ClearCounters() { wrap_raw_ptr_cnt = 0; release_wrapped_ptr_cnt = 0; get_for_dereference_cnt = 0;
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr_asan_unowned_impl.h b/base/allocator/partition_allocator/pointers/raw_ptr_asan_unowned_impl.h index ad9915b..e6fd22a68 100644 --- a/base/allocator/partition_allocator/pointers/raw_ptr_asan_unowned_impl.h +++ b/base/allocator/partition_allocator/pointers/raw_ptr_asan_unowned_impl.h
@@ -27,13 +27,13 @@ struct RawPtrAsanUnownedImpl { // Wraps a pointer. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { return ptr; } // Notifies the allocator when a wrapped pointer is being removed or replaced. template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { ProbeForLowSeverityLifetimeIssue(wrapped_ptr); } @@ -42,7 +42,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function is allowed to crash on nullptr. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { // ASAN will catch use of dereferenced ptr without additional probing. return wrapped_ptr; @@ -51,7 +51,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function must handle nullptr gracefully. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { ProbeForLowSeverityLifetimeIssue(wrapped_ptr); @@ -62,14 +62,14 @@ // Unwraps the pointer, without making an assertion on whether memory was // freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { return wrapped_ptr; } // Upcasts the wrapped pointer. template <typename To, typename From> - constexpr static PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { static_assert(std::is_convertible<From*, To*>::value, "From must be convertible to To."); // Note, this cast may change the address if upcasting to base that lies in @@ -93,12 +93,12 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr - delta_elems; } template <typename T> - constexpr static PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, + static constexpr PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, T* wrapped_ptr2) { return wrapped_ptr1 - wrapped_ptr2; } @@ -106,7 +106,7 @@ // Returns a copy of a wrapped pointer, without making an assertion on whether // memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { return wrapped_ptr; } @@ -121,20 +121,20 @@ // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { return ptr; } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { return wrapped_ptr; } // This is for accounting only, used by unit tests. - constexpr static PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} - constexpr static PA_ALWAYS_INLINE void IncrementLessCountForTest() {} - constexpr static PA_ALWAYS_INLINE void + static constexpr PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementLessCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {} };
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr_backup_ref_impl.h b/base/allocator/partition_allocator/pointers/raw_ptr_backup_ref_impl.h index 568081aa..b941ec5 100644 --- a/base/allocator/partition_allocator/pointers/raw_ptr_backup_ref_impl.h +++ b/base/allocator/partition_allocator/pointers/raw_ptr_backup_ref_impl.h
@@ -130,7 +130,7 @@ public: // Wraps a pointer. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return ptr; } @@ -164,7 +164,7 @@ // Notifies the allocator when a wrapped pointer is being removed or replaced. template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return; } @@ -187,7 +187,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function is allowed to crash on nullptr. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -209,7 +209,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function must handle nullptr gracefully. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -235,7 +235,7 @@ // Unwraps the pointer, without making an assertion on whether memory was // freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -248,7 +248,7 @@ // Upcasts the wrapped pointer. template <typename To, typename From> - constexpr static PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { static_assert(std::is_convertible<From*, To*>::value, "From must be convertible to To."); // Note, this cast may change the address if upcasting to base that lies in @@ -335,7 +335,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr + delta_elems; } @@ -350,7 +350,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr - delta_elems; } @@ -360,7 +360,7 @@ } template <typename T> - constexpr static PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, + static constexpr PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, T* wrapped_ptr2) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr1 - wrapped_ptr2; @@ -389,7 +389,7 @@ // memory was freed or not. // This method increments the reference count of the allocation slot. template <typename T> - constexpr static PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; } @@ -405,7 +405,7 @@ // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return ptr; } else { @@ -414,7 +414,7 @@ } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { if (partition_alloc::internal::base::is_constant_evaluated()) { return wrapped_ptr; @@ -424,9 +424,9 @@ } // This is for accounting only, used by unit tests. - constexpr static PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} - constexpr static PA_ALWAYS_INLINE void IncrementLessCountForTest() {} - constexpr static PA_ALWAYS_INLINE void + static constexpr PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementLessCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {} private:
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr_hookable_impl.h b/base/allocator/partition_allocator/pointers/raw_ptr_hookable_impl.h index d5be338a..1a50391 100644 --- a/base/allocator/partition_allocator/pointers/raw_ptr_hookable_impl.h +++ b/base/allocator/partition_allocator/pointers/raw_ptr_hookable_impl.h
@@ -46,7 +46,7 @@ struct RawPtrHookableImpl { // Wraps a pointer. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtr(T* ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->wrap_ptr(reinterpret_cast<uintptr_t>(ptr)); } @@ -55,7 +55,7 @@ // Notifies the allocator when a wrapped pointer is being removed or replaced. template <typename T> - constexpr static PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* ptr) { + static constexpr PA_ALWAYS_INLINE void ReleaseWrappedPtr(T* ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->release_wrapped_ptr(reinterpret_cast<uintptr_t>(ptr)); } @@ -64,7 +64,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function is allowed to crash on nullptr. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForDereference( T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->safely_unwrap_for_dereference( @@ -76,7 +76,7 @@ // Unwraps the pointer, while asserting that memory hasn't been freed. The // function must handle nullptr gracefully. template <typename T> - constexpr static PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( + static constexpr PA_ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction( T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->safely_unwrap_for_extraction( @@ -88,7 +88,7 @@ // Unwraps the pointer, without making an assertion on whether memory was // freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison( T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->unsafely_unwrap_for_comparison( @@ -99,7 +99,7 @@ // Upcasts the wrapped pointer. template <typename To, typename From> - constexpr static PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE To* Upcast(From* wrapped_ptr) { static_assert(std::is_convertible<From*, To*>::value, "From must be convertible to To."); // Note, this cast may change the address if upcasting to base that lies in @@ -113,7 +113,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->advance( reinterpret_cast<uintptr_t>(wrapped_ptr), @@ -128,7 +128,7 @@ typename Z, typename = std::enable_if_t<partition_alloc::internal::is_offset_type<Z>, void>> - constexpr static PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { + static constexpr PA_ALWAYS_INLINE T* Retreat(T* wrapped_ptr, Z delta_elems) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->advance( reinterpret_cast<uintptr_t>(wrapped_ptr), @@ -138,7 +138,7 @@ } template <typename T> - constexpr static PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, + static constexpr PA_ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1, T* wrapped_ptr2) { return wrapped_ptr1 - wrapped_ptr2; } @@ -146,7 +146,7 @@ // Returns a copy of a wrapped pointer, without making an assertion on whether // memory was freed or not. template <typename T> - constexpr static PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { + static constexpr PA_ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) { if (!partition_alloc::internal::base::is_constant_evaluated()) { GetRawPtrHooks()->duplicate(reinterpret_cast<uintptr_t>(wrapped_ptr)); } @@ -156,20 +156,20 @@ // `WrapRawPtrForDuplication` and `UnsafelyUnwrapPtrForDuplication` are used // to create a new raw_ptr<T> from another raw_ptr<T> of a different flavor. template <typename T> - constexpr static PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { + static constexpr PA_ALWAYS_INLINE T* WrapRawPtrForDuplication(T* ptr) { return ptr; } template <typename T> - constexpr static PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( + static constexpr PA_ALWAYS_INLINE T* UnsafelyUnwrapPtrForDuplication( T* wrapped_ptr) { return wrapped_ptr; } // This is for accounting only, used by unit tests. - constexpr static PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} - constexpr static PA_ALWAYS_INLINE void IncrementLessCountForTest() {} - constexpr static PA_ALWAYS_INLINE void + static constexpr PA_ALWAYS_INLINE void IncrementSwapCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementLessCountForTest() {} + static constexpr PA_ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {} };
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc index dcf26fa..b68f6fe 100644 --- a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc +++ b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
@@ -29,6 +29,7 @@ #include <windows.h> #elif BUILDFLAG(IS_APPLE) #include <malloc/malloc.h> + #include "base/allocator/partition_allocator/shim/allocator_interception_mac.h" #include "third_party/apple_apsl/malloc.h" #else @@ -108,12 +109,13 @@ size_t size, void* context) { if (instance_) { - // Size 0xFEED a special sentinel for the NewHandlerConcurrency test. + // Size 0xFEED is a special sentinel for the NewHandlerConcurrency test. // Hitting it for the first time will cause a failure, causing the // invocation of the std::new_handler. if (size == 0xFEED) { if (!instance_->did_fail_realloc_0xfeed_once->Get()) { - instance_->did_fail_realloc_0xfeed_once->Set(true); + instance_->did_fail_realloc_0xfeed_once->Set( + instance_->did_fail_realloc_0xfeed_once.get()); return nullptr; } return address; @@ -258,7 +260,8 @@ aligned_reallocs_intercepted_by_size.resize(MaxSizeTracked()); aligned_reallocs_intercepted_by_addr.resize(MaxSizeTracked()); aligned_frees_intercepted_by_addr.resize(MaxSizeTracked()); - did_fail_realloc_0xfeed_once = std::make_unique<base::ThreadLocalBoolean>(); + did_fail_realloc_0xfeed_once = + std::make_unique<base::ThreadLocalStorage::Slot>(); num_new_handler_calls.store(0, std::memory_order_release); instance_ = this; @@ -300,7 +303,7 @@ std::vector<size_t> aligned_reallocs_intercepted_by_size; std::vector<size_t> aligned_reallocs_intercepted_by_addr; std::vector<size_t> aligned_frees_intercepted_by_addr; - std::unique_ptr<base::ThreadLocalBoolean> did_fail_realloc_0xfeed_once; + std::unique_ptr<base::ThreadLocalStorage::Slot> did_fail_realloc_0xfeed_once; std::atomic<uint32_t> num_new_handler_calls; private:
diff --git a/base/allocator/partition_allocator/starscan/pcscan.h b/base/allocator/partition_allocator/starscan/pcscan.h index ec6d4df..d585f1b 100644 --- a/base/allocator/partition_allocator/starscan/pcscan.h +++ b/base/allocator/partition_allocator/starscan/pcscan.h
@@ -95,7 +95,7 @@ // Registers a newly allocated super page for |root|. static void RegisterNewSuperPage(Root* root, uintptr_t super_page_base); - PA_ALWAYS_INLINE static void MoveToQuarantine(void* object, + static PA_ALWAYS_INLINE void MoveToQuarantine(void* object, size_t usable_size, uintptr_t slot_start, size_t slot_size); @@ -114,7 +114,7 @@ static void JoinScanIfNeeded(); // Checks if there is a PCScan task currently in progress. - PA_ALWAYS_INLINE static bool IsInProgress(); + static PA_ALWAYS_INLINE bool IsInProgress(); // Sets process name (used for histograms). |name| must be a string literal. static void SetProcessName(const char* name); @@ -135,7 +135,7 @@ static void UninitForTesting(); - inline static PCScanScheduler& scheduler(); + static inline PCScanScheduler& scheduler(); // Registers reporting class. static void RegisterStatsReporter(partition_alloc::StatsReporter* reporter); @@ -157,7 +157,7 @@ kSweepingAndFinishing }; - PA_ALWAYS_INLINE static PCScan& Instance(); + static PA_ALWAYS_INLINE PCScan& Instance(); PA_ALWAYS_INLINE bool IsJoinable() const; PA_ALWAYS_INLINE void SetJoinableIfSafepointEnabled(bool);
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.cc b/base/allocator/partition_allocator/starscan/pcscan_internal.cc index 1e1d88d9..7bbe783 100644 --- a/base/allocator/partition_allocator/starscan/pcscan_internal.cc +++ b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
@@ -121,7 +121,7 @@ class QuarantineCardTable final { public: // Avoid the load of the base of the regular pool. - PA_ALWAYS_INLINE static QuarantineCardTable& GetFrom(uintptr_t address) { + static PA_ALWAYS_INLINE QuarantineCardTable& GetFrom(uintptr_t address) { PA_SCAN_DCHECK(IsManagedByPartitionAllocRegularPool(address)); return *reinterpret_cast<QuarantineCardTable*>( address & PartitionAddressSpace::RegularPoolBaseMask()); @@ -150,7 +150,7 @@ QuarantineCardTable() = default; - PA_ALWAYS_INLINE static size_t Byte(uintptr_t address) { + static PA_ALWAYS_INLINE size_t Byte(uintptr_t address) { return (address & ~PartitionAddressSpace::RegularPoolBaseMask()) / kCardSize; } @@ -779,10 +779,10 @@ private: #if BUILDFLAG(HAS_64_BIT_POINTERS) - PA_ALWAYS_INLINE static uintptr_t RegularPoolBase() { + static PA_ALWAYS_INLINE uintptr_t RegularPoolBase() { return PartitionAddressSpace::RegularPoolBase(); } - PA_ALWAYS_INLINE static uintptr_t RegularPoolMask() { + static PA_ALWAYS_INLINE uintptr_t RegularPoolMask() { return PartitionAddressSpace::RegularPoolBaseMask(); } #endif // BUILDFLAG(HAS_64_BIT_POINTERS)
diff --git a/base/allocator/partition_allocator/starscan/state_bitmap.h b/base/allocator/partition_allocator/starscan/state_bitmap.h index cfd7b08..100f1db6 100644 --- a/base/allocator/partition_allocator/starscan/state_bitmap.h +++ b/base/allocator/partition_allocator/starscan/state_bitmap.h
@@ -193,7 +193,7 @@ inline void IterateImpl(size_t epoch, Callback); PA_ALWAYS_INLINE CellType LoadCell(size_t cell_index) const; - PA_ALWAYS_INLINE static constexpr std::pair<size_t, size_t> + static constexpr PA_ALWAYS_INLINE std::pair<size_t, size_t> AllocationIndexAndBit(uintptr_t); std::array<CellType, kBitmapSize> bitmap_; @@ -325,7 +325,7 @@ } template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment> -PA_ALWAYS_INLINE constexpr std::pair<size_t, size_t> +constexpr PA_ALWAYS_INLINE std::pair<size_t, size_t> StateBitmap<PageSize, PageAlignment, AllocationAlignment>:: AllocationIndexAndBit(uintptr_t address) { const uintptr_t offset_in_page = address & kPageOffsetMask;
diff --git a/base/win/scoped_handle_verifier.cc b/base/win/scoped_handle_verifier.cc index 4b252c67..cb9a8840 100644 --- a/base/win/scoped_handle_verifier.cc +++ b/base/win/scoped_handle_verifier.cc
@@ -11,6 +11,7 @@ #include <unordered_map> #include <utility> +#include "base/auto_reset.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/debug/stack_trace.h" @@ -20,6 +21,7 @@ #include "base/win/base_win_buildflags.h" #include "base/win/current_module.h" #include "base/win/scoped_handle.h" +#include "third_party/abseil-cpp/absl/base/attributes.h" extern "C" { __declspec(dllexport) void* GetHandleVerifier(); @@ -36,30 +38,31 @@ namespace { ScopedHandleVerifier* g_active_verifier = nullptr; +ABSL_CONST_INIT thread_local bool closing = false; using GetHandleVerifierFn = void* (*)(); using HandleMap = std::unordered_map<HANDLE, ScopedHandleVerifierInfo, HandleHash>; using NativeLock = base::internal::LockImpl; NOINLINE void ReportErrorOnScopedHandleOperation( - const base::debug::StackTrace& creation_stack, + const debug::StackTrace& creation_stack, HandleOperation operation) { auto creation_stack_copy = creation_stack; - base::debug::Alias(&creation_stack_copy); - base::debug::Alias(&operation); + debug::Alias(&creation_stack_copy); + debug::Alias(&operation); CHECK(false) << operation; __builtin_unreachable(); } NOINLINE void ReportErrorOnScopedHandleOperation( - const base::debug::StackTrace& creation_stack, + const debug::StackTrace& creation_stack, const ScopedHandleVerifierInfo& other, HandleOperation operation) { auto other_stack_copy = *other.stack; - base::debug::Alias(&other_stack_copy); + debug::Alias(&other_stack_copy); auto creation_stack_copy = creation_stack; - base::debug::Alias(&creation_stack_copy); - base::debug::Alias(&operation); + debug::Alias(&creation_stack_copy); + debug::Alias(&operation); CHECK(false) << operation; __builtin_unreachable(); } @@ -175,9 +178,8 @@ if (!enabled_) return CloseHandleWrapper(handle); - closing_.Set(true); + const AutoReset<bool> resetter(&closing, true); CloseHandleWrapper(handle); - closing_.Set(false); return true; } @@ -263,8 +265,9 @@ NOINLINE void ScopedHandleVerifier::OnHandleBeingClosedImpl( HANDLE handle, HandleOperation operation) { - if (closing_.Get()) + if (closing) { return; + } AutoNativeLock lock(*lock_); HandleMap::iterator i = map_.find(handle);
diff --git a/base/win/scoped_handle_verifier.h b/base/win/scoped_handle_verifier.h index b9b08692..2925136 100644 --- a/base/win/scoped_handle_verifier.h +++ b/base/win/scoped_handle_verifier.h
@@ -13,7 +13,6 @@ #include "base/hash/hash.h" #include "base/memory/raw_ptr.h" #include "base/synchronization/lock_impl.h" -#include "base/threading/thread_local.h" #include "base/win/windows_types.h" namespace base { @@ -57,11 +56,9 @@ // from emitting an unrecognized attribute warning. #pragma warning(push) #pragma warning(disable : 5030) -class [[clang::lto_visibility_public]] ScopedHandleVerifier { +class [[clang::lto_visibility_public, nodiscard]] ScopedHandleVerifier { #pragma warning(pop) public: - explicit ScopedHandleVerifier(bool enabled); - ScopedHandleVerifier(const ScopedHandleVerifier&) = delete; ScopedHandleVerifier& operator=(const ScopedHandleVerifier&) = delete; @@ -81,6 +78,7 @@ virtual HMODULE GetModule() const; private: + explicit ScopedHandleVerifier(bool enabled); ~ScopedHandleVerifier(); // Not implemented. void StartTrackingImpl(HANDLE handle, const void* owner, const void* pc1, @@ -96,7 +94,6 @@ base::debug::StackTrace creation_stack_; bool enabled_; - base::ThreadLocalBoolean closing_; raw_ptr<base::internal::LockImpl> lock_; std::unordered_map<HANDLE, ScopedHandleVerifierInfo, HandleHash> map_; };
diff --git a/build/android/dummy_libgcc/README.md b/build/android/dummy_libgcc/README.md new file mode 100644 index 0000000..01762db --- /dev/null +++ b/build/android/dummy_libgcc/README.md
@@ -0,0 +1,20 @@ +# Dummy libgcc.a + +This directory contains an empty `libgcc.a` file for use with the Rust toolchain +when targeting Android. + +The Rust compiler unconditionally attempts to link libgcc when targeting +Android, so `-lgcc` appears in the linker command when producing a `.so` file +for Android. Rustc expects libgcc will provide unwinding support, however we +already use libunwind, which we explicitly link ourselves through `ldflags`, to +provide this. Our Android toolchain has no libgcc present, which means Rustc +driven linking targeting Android fails with a missing library that we don't +actually want to use. + +This same issue occurs for other consumers of rustc, when building for targets +without a libgcc, and the solution is to [give rustc an empty `libgcc.a` file]( +https://www.reddit.com/r/rust/comments/jst1kk/building_rust_without_linking_against_libgcc/). + +Therefore this directory contains an empty `libgcc.a` file, and on Android we +include this directory in the linker paths so that the rustc-driven linking step +can succeed without needing a real libgcc.
diff --git a/build/android/dummy_libgcc/libgcc.a b/build/android/dummy_libgcc/libgcc.a new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build/android/dummy_libgcc/libgcc.a
diff --git a/build/rust/tests/BUILD.gn b/build/rust/tests/BUILD.gn index ba5d50a..04c1d9f 100644 --- a/build/rust/tests/BUILD.gn +++ b/build/rust/tests/BUILD.gn
@@ -7,10 +7,6 @@ if (toolchain_has_rust) { target_has_exe = !is_android - - # TODO(crbug.com/1278030): Dylib linking on Android fails due to trying to - # link the unwinder from `-lgcc`. - target_has_dylib = !is_android } # Build some minimal binaries to exercise the Rust toolchain @@ -52,13 +48,11 @@ "test_rlib_crate:test_rlib_crate_associated_bin", "test_rust_exe", "test_rust_multiple_dep_versions_exe", + "test_rust_shared_library", "test_simple_rust_exe", "//third_party/rust/bindgen/v0_60:bindgen", ] } - if (target_has_dylib) { - deps += [ "test_rust_shared_library" ] - } if (can_build_rust_unit_tests) { deps += [ "bindgen_test:bindgen_test_lib_unittests",
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index 713c1b9..cf9730e 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -747,12 +747,24 @@ outputs = [ rust_outfile ] } + # Rustc attempts to link `libgcc` unconditionally on Android, but it's a + # mistake to do so. We get our unwinding from `libunwind`, which we link + # in explicitly ourselves, and we have no `libgcc` present. To avoid a + # missing library, we point rustc to an empty `libgcc.a` file. This allows + # rustc to link .so files targeting android: http://crbug.com/1278030 + dummy_libgcc = "" + if (is_android) { + dummy_libgcc_path = + rebase_path("//build/android/dummy_libgcc", root_build_dir) + dummy_libgcc = "-L$dummy_libgcc_path" + } + tool("rust_cdylib") { rust_outfile = "{{output_dir}}/lib{{target_output_name}}.so" depfile = "{{output}}.d" rspfile = "$rust_outfile.rsp" rspfile_content = "{{rustdeps}} {{externs}}" - command = "$python_path \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $rust_outfile LDFLAGS {{ldflags}} ${extra_ldflags} RUSTENV {{rustenv}}" + command = "$python_path \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $rust_outfile LDFLAGS {{ldflags}} ${extra_ldflags} ${dummy_libgcc} RUSTENV {{rustenv}}" description = "RUST $rust_outfile" rust_sysroot = rust_sysroot_relative_to_out outputs = [ rust_outfile ]
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc index f6ca4c97d..8315ffe 100644 --- a/cc/paint/paint_op.cc +++ b/cc/paint/paint_op.cc
@@ -92,44 +92,18 @@ SkCanvas::SrcRectConstraint constraint) { if (!image) return; - if (constraint != SkCanvas::kStrict_SrcRectConstraint || - options.mipmap == SkMipmapMode::kNone) { - canvas->drawImageRect(image, src, dst, options, paint, constraint); - return; - } - // Skia downgrades to SkMipmap::kNone if kStrict_SrcRectConstraint is used - // with drawImageRect. - SkMatrix m; - m.setRectToRect(src, dst, SkMatrix::ScaleToFit::kFill_ScaleToFit); - if (src.contains(SkRect::Make(image->dimensions()))) { + if (constraint == SkCanvas::kStrict_SrcRectConstraint && + options.mipmap != SkMipmapMode::kNone && + src.contains(SkRect::Make(image->dimensions()))) { + SkMatrix m; + m.setRectToRect(src, dst, SkMatrix::ScaleToFit::kFill_ScaleToFit); canvas->save(); canvas->concat(m); canvas->drawImage(image, 0, 0, options, paint); canvas->restore(); return; } - // Draw a rect with an image shader wrapped in another shader that clamps - // the coordinates to a half pixel inset of the original source rectangle. - // This means in the base MIP level there will be no bleed from filtering. - // This matches Skia's behavior prior to changes related to skbug.com/13078 - sk_sp<SkShader> shader = image->makeShader(options); - SkRect clampRect = src.makeInset(0.5f, 0.5f); - if (clampRect.width() < 0) { - clampRect.fLeft = clampRect.fRight = clampRect.centerX(); - } - if (clampRect.height() < 0) { - clampRect.fTop = clampRect.fBottom = clampRect.centerY(); - } - shader = SkShaders::CoordClamp(std::move(shader), clampRect); - // The matrix must happen outside of the clamp so that the clamp is in the - // image coordinate space. - shader = shader->makeWithLocalMatrix(m); - SkPaint shaderPaint; - if (paint) { - shaderPaint = *paint; - } - shaderPaint.setShader(std::move(shader)); - canvas->drawRect(dst, shaderPaint); + canvas->drawImageRect(image, src, dst, options, paint, constraint); } #define TYPES(M) \
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index f2c80e9..5196001 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -737,7 +737,14 @@ int small_error_allowed = 0; if (!use_software_renderer()) { percentage_pixels_large_error = 4.0f; +#if BUILDFLAG(IS_IOS) + // iOS has some pixels difference. Affected tests: + // RotatedClippedCircle, RotatedClippedCircleUnderflow + // crbug.com/1422694 + percentage_pixels_small_error = 2.7f; +#else percentage_pixels_small_error = 2.0f; +#endif // BUILDFLAG(IS_IOS) average_error_allowed_in_bad_pixels = 2.1f; large_error_allowed = 11; small_error_allowed = 1;
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 6e3200e..4371f2ca 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -997,7 +997,6 @@ "java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java", "java/src/org/chromium/chrome/browser/share/ShareHelper.java", "java/src/org/chromium/chrome/browser/share/ShareUtils.java", - "java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java", "java/src/org/chromium/chrome/browser/sharing/SharingAdapter.java", "java/src/org/chromium/chrome/browser/sharing/SharingJNIBridge.java", "java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index e6f8d00a..37e01ce6 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -419,7 +419,6 @@ "javatests/src/org/chromium/chrome/browser/share/ShareButtonControllerTest.java", "javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java", - "javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java", "javatests/src/org/chromium/chrome/browser/signin/AccountsReloadingTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java deleted file mode 100644 index bd4d7f4..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImpl.java +++ /dev/null
@@ -1,250 +0,0 @@ -// Copyright 2022 The Chromium Authors -// 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.share.crow; - -import android.content.Context; -import android.net.Uri; - -import androidx.annotation.VisibleForTesting; -import androidx.browser.customtabs.CustomTabsIntent; - -import org.chromium.base.Callback; -import org.chromium.base.LocaleUtils; -import org.chromium.chrome.browser.ChromeActivitySessionTracker; -import org.chromium.chrome.browser.customtabs.CustomTabActivity; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault; -import org.chromium.chrome.browser.language.AppLocaleUtils; -import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridgeFactory; -import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.tab.TabLaunchType; -import org.chromium.chrome.browser.tabmodel.document.TabDelegate; -import org.chromium.components.optimization_guide.OptimizationGuideDecision; -import org.chromium.components.optimization_guide.proto.HintsProto; -import org.chromium.content_public.browser.LoadUrlParams; -import org.chromium.ui.util.ColorUtils; -import org.chromium.url.GURL; - -import java.util.Arrays; -import java.util.HashMap; - -/** Implementation of Crow share chip-related actions. */ -public class CrowButtonDelegateImpl implements CrowButtonDelegate { - /** Domain to ID map, populated on first read. */ - private HashMap<String, String> mDomainIdMap; - // Tracker used to get the latest country of the user. - private final ChromeActivitySessionTracker mChromeActivitySessionTracker; - - private static final String APP_MENU_BUTTON_TEXT_PARAM = "AppMenuButtonText"; - private static final String DEBUG_SERVER_URL_PARAM = "DebugServerURL"; - private static final String DOMAIN_LIST_URL_PARAM = "DomainList"; - private static final String DOMAIN_ID_NONE = "0"; - private static final String DEFAULT_BUTTON_TEXT = "Thank\u00A0creator"; - private static final String USE_PAGE_OPTIMIZATIONS_STUDY_PARAM = "UsePageOptimizations"; - - private static final String TAG = "CrowButton"; - - private static final MutableFlagWithSafeDefault sShareCrowButton = - new MutableFlagWithSafeDefault(ChromeFeatureList.SHARE_CROW_BUTTON, false); - private static final MutableFlagWithSafeDefault sShareCrowButtonLaunchTabFlag = - new MutableFlagWithSafeDefault(ChromeFeatureList.SHARE_CROW_BUTTON_LAUNCH_TAB, false); - - /** Constructs a new {@link CrowButtonDelegateImpl}. */ - public CrowButtonDelegateImpl() { - mChromeActivitySessionTracker = ChromeActivitySessionTracker.getInstance(); - } - - // Lazy initialization of OptimizationGuideBridgeFactory - private static class OptimizationGuideBridgeFactoryHolder { - private static final OptimizationGuideBridgeFactory sOptimizationGuideBridgeFactory; - static { - sOptimizationGuideBridgeFactory = new OptimizationGuideBridgeFactory( - Arrays.asList(HintsProto.OptimizationType.THANK_CREATOR_ELIGIBLE)); - } - } - - @Override - public void isEnabledForSite(GURL url, Callback<Boolean> callback) { - // TODO(skare): Make this an AMP-aware comparison if needed. - if (!isCrowEnabled()) { - callback.onResult(false); - return; - } - - // Any host present in the denylist should not have the feature enabled. - if (CrowBridge.denylistContainsHost(url.getHost())) { - callback.onResult(false); - return; - } - - // Check for an exact match against our allowlist. - // Fall back to page optimizations if the study param is enabled. - if (!getPublicationId(url).equals(DOMAIN_ID_NONE)) { - callback.onResult(true); - return; - } - if (!ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.SHARE_CROW_BUTTON, USE_PAGE_OPTIMIZATIONS_STUDY_PARAM, - false)) { - callback.onResult(false); - return; - } - checkPageOptimizations(url, callback); - } - - private static void checkPageOptimizations(GURL url, Callback<Boolean> callback) { - OptimizationGuideBridgeFactoryHolder.sOptimizationGuideBridgeFactory.create() - .canApplyOptimization(url, HintsProto.OptimizationType.THANK_CREATOR_ELIGIBLE, - (decision, metadata) -> { - callback.onResult(decision == OptimizationGuideDecision.TRUE); - }); - } - - @Override - public void launchCustomTab( - Tab tab, Context currentContext, GURL pageUrl, GURL canonicalUrl, boolean isFollowing) { - String customTabUrl = getUrlForWebFlow(pageUrl, canonicalUrl, isFollowing); - - // Experiment flag: open in standard new tab. - if (sShareCrowButtonLaunchTabFlag.isEnabled()) { - // TabLaunchType.FROM_LINK will allow back to navigate back to the - // current tab. - LoadUrlParams loadUrlParams = new LoadUrlParams(customTabUrl); - new TabDelegate(false).createNewTab(loadUrlParams, TabLaunchType.FROM_LINK, tab); - } else { - // Default to custom tab. - CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); - builder.setShowTitle(true); - builder.setColorScheme(ColorUtils.inNightMode(currentContext) - ? CustomTabsIntent.COLOR_SCHEME_DARK - : CustomTabsIntent.COLOR_SCHEME_LIGHT); - builder.setShareState(CustomTabsIntent.SHARE_STATE_OFF); - CustomTabsIntent customTabsIntent = builder.build(); - customTabsIntent.intent.setClassName(currentContext, CustomTabActivity.class.getName()); - customTabsIntent.launchUrl(currentContext, Uri.parse(customTabUrl)); - } - } - - /** - * Returns true if the user is in the US using en-US, and false otherwise. - * - * <p>This should match how Finch gates features by locale and country. See - * VariationsService::GetLatestCountry() and language::GetApplicationLocale(). - */ - private boolean isEnabledForLocaleAndCountry() { - String country = mChromeActivitySessionTracker.getVariationsLatestCountry(); - String locale = AppLocaleUtils.getAppLanguagePref(); - if (locale == null) { - locale = LocaleUtils.getDefaultLocaleString(); - } - return country != null && country.equals("us") && locale.equals("en-US"); - } - - public boolean isCrowEnabled() { - return isEnabledForLocaleAndCountry() && sShareCrowButton.isEnabled(); - } - - /** - * Parses a study-provided list of enabled domains of the form - * domain1^id1;domain2^id2;domain3^d3 - * Separators were chosen as they do not need to be URL-escaped in the Finch config, - * improving readability, as the domains and debug server URL _will_ have URL-encoded - * characters. Furthermore, study param-based configuration will go away during - * feature development. - * - * @param Domains study parameter in serialized string form. - */ - @VisibleForTesting - public HashMap<String, String> parseDomainIdMap(String mapStudyParam) { - HashMap<String, String> map = new HashMap<String, String>(); - // Limit to 20 domains during feature development. - String[] allowlistEntries = mapStudyParam.split("\\;", 20); - for (String entry : allowlistEntries) { - String[] pair = entry.split("\\^", 2); - if (pair.length < 2) break; - map.put(pair[0], pair[1]); - } - return map; - } - - private String getPublicationId(GURL url) { - String host = url.getHost(); - - // Check the allowlist for an exact match. - String publicationID = CrowBridge.getPublicationIDFromAllowlist(host); - if (!publicationID.isEmpty()) { - return publicationID; - } - - // Then check the experimental Finch config. - if (mDomainIdMap == null) { - mDomainIdMap = parseDomainIdMap(ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.SHARE_CROW_BUTTON, DOMAIN_LIST_URL_PARAM)); - } - if (!mDomainIdMap.containsKey(host)) { - return DOMAIN_ID_NONE; - } - return mDomainIdMap.get(host); - } - - @Override - public String getButtonText() { - String param = ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.SHARE_CROW_BUTTON, APP_MENU_BUTTON_TEXT_PARAM); - // Provide a default with non-breaking space. String is en-us only. - if (param.isEmpty()) { - return DEFAULT_BUTTON_TEXT; - } - return param; - } - - @Override - public void requestCanonicalUrl(Tab tab, Callback<GURL> callback) { - if (tab.getWebContents() == null || tab.getWebContents().getMainFrame() == null - || tab.getUrl().isEmpty()) { - callback.onResult(GURL.emptyGURL()); - return; - } - tab.getWebContents().getMainFrame().getCanonicalUrlForSharing(callback); - } - - private String getServerUrl() { - return ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.SHARE_CROW_BUTTON, DEBUG_SERVER_URL_PARAM); - } - - private boolean areMetricsEnabled() { - // Require UMA and "Make searches and browsing better" to be enabled. - return (PrivacyPreferencesManagerImpl.getInstance().isUsageAndCrashReportingPermitted() - && UnifiedConsentServiceBridge.isUrlKeyedAnonymizedDataCollectionEnabled( - Profile.getLastUsedRegularProfile())); - } - - @Override - public String getUrlForWebFlow(GURL pageUrl, GURL canonicalPageUrl, boolean isFollowing) { - return buildServerUrlInternal(new GURL(getServerUrl()), pageUrl, canonicalPageUrl, - getPublicationId(pageUrl), areMetricsEnabled(), isFollowing); - } - - @VisibleForTesting - public String buildServerUrlInternal(GURL serverUrl, GURL pageUrl, GURL canonicalPageUrl, - String publicationId, boolean allowMetrics, boolean isFollowing) { - String serverSpec = serverUrl.getSpec(); - if (serverSpec.isEmpty()) return ""; - Uri.Builder builder = Uri.parse(serverSpec).buildUpon(); - builder.appendQueryParameter("pageUrl", pageUrl.getSpec()); - builder.appendQueryParameter("entry", "menu"); - builder.appendQueryParameter("relCanonUrl", canonicalPageUrl.getSpec()); - builder.appendQueryParameter("publicationId", publicationId); - builder.appendQueryParameter("metrics", allowMetrics ? "true" : "false"); - if (isFollowing) { - builder.appendQueryParameter("following", "true"); - } - return builder.build().toString(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/share/crow/OWNERS deleted file mode 100644 index 009e2aa..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/share/crow/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/share/OWNERS
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java index 9e30f7a..02b7630 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTest.java
@@ -104,7 +104,10 @@ public DownloadTestRule mDownloadTestRule = new DownloadTestRule(this); private static final String TEST_PAGE = "/chrome/test/data/dom_distiller/simple_article.html"; - private static final String TITLE = "Test Page Title"; + // Suffix added to page titles, string is defined as IDS_DOM_DISTILLER_VIEWER_TITLE_SUFFIX in + // dom_distiller_strings.grdp. + private static final String TITLE_SUFFIX = " - Simplified View"; + private static final String PAGE_TITLE = "Test Page Title" + TITLE_SUFFIX; private static final String CONTENT = "Lorem ipsum"; @SuppressWarnings("FieldCanBeLocal") @@ -152,7 +155,7 @@ () -> Criteria.checkThat(customTabActivity.getActivityTab(), notNullValue())); @NonNull Tab distillerViewerTab = Objects.requireNonNull(customTabActivity.getActivityTab()); - waitForDistillation(TITLE, distillerViewerTab); + waitForDistillation(PAGE_TITLE, distillerViewerTab); } @Test @@ -175,7 +178,7 @@ () -> Criteria.checkThat(customTabActivity.getActivityTab(), notNullValue())); @NonNull Tab distillerViewerTab = Objects.requireNonNull(customTabActivity.getActivityTab()); - waitForDistillation(TITLE, distillerViewerTab); + waitForDistillation(PAGE_TITLE, distillerViewerTab); } @Test @@ -226,7 +229,7 @@ () -> Criteria.checkThat(customTabActivity.getActivityTab(), notNullValue())); @NonNull Tab distillerViewerTab = Objects.requireNonNull(customTabActivity.getActivityTab()); - waitForDistillation(TITLE, distillerViewerTab); + waitForDistillation(PAGE_TITLE, distillerViewerTab); assertTrue(distillerViewerTab.isIncognito()); return customTabActivity; @@ -269,7 +272,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { tab.getUserDataHost().getUserData(ReaderModeManager.USER_DATA_KEY).activateReaderMode(); }); - waitForDistillation(TITLE, mDownloadTestRule.getActivity().getActivityTab()); + waitForDistillation(PAGE_TITLE, mDownloadTestRule.getActivity().getActivityTab()); } @Test @@ -286,7 +289,7 @@ CriteriaHelper.pollUiThread(() -> customTabActivity.getActivityTab() != null); @NonNull Tab distillerViewerTab = Objects.requireNonNull(customTabActivity.getActivityTab()); - waitForDistillation(TITLE, distillerViewerTab); + waitForDistillation(PAGE_TITLE, distillerViewerTab); testPreference(customTabActivity, distillerViewerTab); } @@ -299,11 +302,11 @@ "Failing on Lollipop Phone Tester (https://crbug.com/1120830) and test-n-phone (https://crbug.com/1160911)") public void testPreferenceInTab() throws TimeoutException { - mDownloadTestRule.loadUrl( - DomDistillerUrlUtils.getDistillerViewUrlFromUrl(DOM_DISTILLER_SCHEME, mURL, TITLE)); + mDownloadTestRule.loadUrl(DomDistillerUrlUtils.getDistillerViewUrlFromUrl( + DOM_DISTILLER_SCHEME, mURL, PAGE_TITLE)); Tab tab = mDownloadTestRule.getActivity().getActivityTab(); - waitForDistillation(TITLE, tab); + waitForDistillation(PAGE_TITLE, tab); testPreference(mDownloadTestRule.getActivity(), tab); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index b4818f20..62c76344 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -47,8 +47,6 @@ import org.chromium.base.GarbageCollectionTestUtils; import org.chromium.base.MemoryPressureListener; import org.chromium.base.memory.MemoryPressureCallback; -import org.chromium.base.metrics.RecordHistogram; -import org.chromium.base.test.metrics.HistogramTestRule; import org.chromium.base.test.params.ParameterAnnotations; import org.chromium.base.test.params.ParameterProvider; import org.chromium.base.test.params.ParameterSet; @@ -59,6 +57,7 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -148,8 +147,6 @@ public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule(); @Rule public SigninTestRule mSigninTestRule = new SigninTestRule(); - @Rule - public HistogramTestRule mHistogramTestRule = new HistogramTestRule(); @Rule public ChromeRenderTestRule mRenderTestRule = @@ -331,6 +328,8 @@ @ParameterAnnotations.UseMethodParameter(MVTParams.class) public void testClickMostVisitedItem(boolean isScrollableMVTEnabled) { Assert.assertNotNull(mMvTilesLayout); + HistogramWatcher histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); + ChromeTabUtils.waitForTabPageLoaded( mTab, mSiteSuggestions.get(0).url.getSpec(), new Runnable() { @Override @@ -339,11 +338,9 @@ TouchCommon.singleClickView(mostVisitedItem); } }); - Assert.assertEquals(mSiteSuggestions.get(0).url, ChromeTabUtils.getUrlOnUiThread(mTab)); - assertEquals(1, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + Assert.assertEquals(mSiteSuggestions.get(0).url, ChromeTabUtils.getUrlOnUiThread(mTab)); + histogramWatcher.assertExpected(); } /** @@ -372,14 +369,14 @@ public void testOpenMostVisitedItemInIncognitoTab(boolean isScrollableMVTEnabled) throws ExecutionException { Assert.assertNotNull(mMvTilesLayout); + HistogramWatcher histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); + ChromeTabUtils.invokeContextMenuAndOpenInANewTab(mActivityTestRule, mMvTilesLayout.getChildAt(0), ContextMenuManager.ContextMenuItemId.OPEN_IN_INCOGNITO_TAB, true, mSiteSuggestions.get(0).url.getSpec()); - assertEquals(1, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(); } /** @@ -692,60 +689,47 @@ TileGroup.Delegate tileGroupDelegate = mNtp.getTileGroupDelegateForTesting(); // Test clicking on MV tiles. + HistogramWatcher histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); tileGroupDelegate.openMostVisitedItem(WindowOpenDisposition.CURRENT_TAB, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when click on MV tiles.", - 1, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when click on MV tiles."); // Test long press then open in new tab in group on MV tiles. + histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); tileGroupDelegate.openMostVisitedItemInGroup( WindowOpenDisposition.NEW_BACKGROUND_TAB, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then open in new tab in " - + "group on MV tiles.", - 2, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then open in new tab in group on " + + "MV tiles."); // Test long press then open in new tab on MV tiles. + histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); tileGroupDelegate.openMostVisitedItem( WindowOpenDisposition.NEW_BACKGROUND_TAB, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then open in new tab " - + "on MV tiles.", - 3, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then open in new tab on MV " + + "tiles."); // Test long press then open in other window on MV tiles. + histogramWatcher = expectNoRecordsForNtpModuleClick(); tileGroupDelegate.openMostVisitedItem(WindowOpenDisposition.NEW_WINDOW, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " shouldn't be recorded when long press then open in other " - + "window on MV tiles.", - 3, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " shouldn't be recorded when long press then open in other window on MV " + + "tiles."); // Test long press then download link on MV tiles. + histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); tileGroupDelegate.openMostVisitedItem(WindowOpenDisposition.SAVE_TO_DISK, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then download link on " - + "MV tiles.", - 4, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then download link on MV tiles."); // Test long press then open in Incognito tab on MV tiles. + histogramWatcher = expectMostVisitedTilesRecordForNtpModuleClick(); tileGroupDelegate.openMostVisitedItem( WindowOpenDisposition.OFF_THE_RECORD, tileForTest); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then open in Incognito " - + "tab on MV tiles.", - 5, - mHistogramTestRule.getHistogramValueCount(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then open in Incognito tab on MV " + + "tiles."); }); } @@ -760,64 +744,47 @@ FeedActionDelegate feedActionDelegate = mNtp.getFeedActionDelegateForTesting(); // Test click on Feeds or long press then check about this source & topic on Feeds. + HistogramWatcher histogramWatcher = expectFeedRecordForNtpModuleClick(); feedActionDelegate.openSuggestionUrl(WindowOpenDisposition.CURRENT_TAB, new LoadUrlParams(TEST_URL, PageTransition.AUTO_BOOKMARK), false, mOnPageLoaded, mOnVisitComplete); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when click on Feeds " - + "or long press then check about this source & topic on Feeds.", - 1, - RecordHistogram.getHistogramValueCountForTesting(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when click on Feeds or long press then check " + + "about this source & topic on Feeds."); // Test long press then open in new tab on Feeds. + histogramWatcher = expectFeedRecordForNtpModuleClick(); feedActionDelegate.openSuggestionUrl(WindowOpenDisposition.NEW_BACKGROUND_TAB, new LoadUrlParams(TEST_URL, PageTransition.AUTO_BOOKMARK), false, mOnPageLoaded, mOnVisitComplete); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then open in " - + "new tab on Feeds.", - 2, - RecordHistogram.getHistogramValueCountForTesting(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then open in new tab on Feeds."); // Test long press then open in incognito tab on Feeds. + histogramWatcher = expectFeedRecordForNtpModuleClick(); feedActionDelegate.openSuggestionUrl(WindowOpenDisposition.OFF_THE_RECORD, new LoadUrlParams(TEST_URL, PageTransition.AUTO_BOOKMARK), false, mOnPageLoaded, mOnVisitComplete); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when long press then open " - + "in incognito tab on Feeds.", - 3, - RecordHistogram.getHistogramValueCountForTesting(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when long press then open in incognito tab on " + + " Feeds."); // Test manage activity or manage interests on Feeds. + histogramWatcher = expectNoRecordsForNtpModuleClick(); feedActionDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB, new LoadUrlParams(TEST_URL, PageTransition.LINK)); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " shouldn't be recorded when manage activity or manage interests " - + "on Feeds.", - 3, - RecordHistogram.getHistogramValueCountForTesting(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " shouldn't be recorded when manage activity or manage interests " + + "on Feeds."); // Test click Learn More button on Feeds. + histogramWatcher = expectFeedRecordForNtpModuleClick(); feedActionDelegate.openHelpPage(); - assertEquals(HISTOGRAM_NTP_MODULE_CLICK - + " is not recorded correctly when click Learn More button on Feeds.", - 4, - RecordHistogram.getHistogramValueCountForTesting(HISTOGRAM_NTP_MODULE_CLICK, - BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED)); + histogramWatcher.assertExpected(HISTOGRAM_NTP_MODULE_CLICK + + " is not recorded correctly when click Learn More button on Feeds."); }); } - private void assertThumbnailInvalidAndRecapture() { - Assert.assertTrue(mNtp.shouldCaptureThumbnail()); - captureThumbnail(); - Assert.assertFalse(mNtp.shouldCaptureThumbnail()); - } - private void captureThumbnail() { Canvas canvas = new Canvas(); mNtp.captureThumbnail(canvas); @@ -881,4 +848,18 @@ private void waitForFakeboxTopPosition(final NewTabPage ntp, int position) { CriteriaHelper.pollUiThread(() -> Criteria.checkThat(getFakeboxTop(ntp), is(position))); } + + private static HistogramWatcher expectMostVisitedTilesRecordForNtpModuleClick() { + return HistogramWatcher.newSingleRecordWatcher(HISTOGRAM_NTP_MODULE_CLICK, + BrowserUiUtils.ModuleTypeOnStartAndNTP.MOST_VISITED_TILES); + } + + private static HistogramWatcher expectFeedRecordForNtpModuleClick() { + return HistogramWatcher.newSingleRecordWatcher( + HISTOGRAM_NTP_MODULE_CLICK, BrowserUiUtils.ModuleTypeOnStartAndNTP.FEED); + } + + private static HistogramWatcher expectNoRecordsForNtpModuleClick() { + return HistogramWatcher.newBuilder().expectNoRecords(HISTOGRAM_NTP_MODULE_CLICK).build(); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java deleted file mode 100644 index a778742..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegateImplTest.java +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2022 The Chromium Authors -// 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.share.crow; - -import static org.junit.Assert.assertEquals; - -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Batch; -import org.chromium.chrome.test.ChromeBrowserTestRule; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.url.GURL; - -import java.util.HashMap; -import java.util.concurrent.ExecutionException; - -/** - * Tests of the CrowButtonDelegateImpl. - * Requires native for GURL and canonicalization tests. - */ -@RunWith(BaseJUnit4ClassRunner.class) -@Batch(Batch.PER_CLASS) -public class CrowButtonDelegateImplTest { - @Rule - public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule(); - - private CrowButtonDelegateImpl mCrowButtonDelegate; - - @Before - public void setUp() throws ExecutionException { - mCrowButtonDelegate = TestThreadUtils.runOnUiThreadBlocking(CrowButtonDelegateImpl::new); - } - - @Test - @SmallTest - public void testBuildServerUrl() { - final GURL serverUrl = new GURL("https://www.foo.com/v1/api?q=hi"); - // No query string, http rather than https. - final GURL serverUrlWithoutQueryString = new GURL("http://www.foo.com/v1/api"); - final GURL shareUrl1 = new GURL("https://testSiteWeAreSharing.com/blog/entry"); - final GURL shareUrl2 = new GURL("https://testSiteWeAreSharing.com/?blog=1&entry=2"); - boolean allowMetrics = true; - boolean isFollowing = false; - - assertEquals("", - mCrowButtonDelegate.buildServerUrlInternal( - GURL.emptyGURL(), shareUrl1, shareUrl1, "", allowMetrics, isFollowing)); - - // Baseline/common case. - assertEquals( - "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=true", - mCrowButtonDelegate.buildServerUrlInternal( - serverUrl, shareUrl1, shareUrl1, "pubId1", allowMetrics, isFollowing)); - - // Sending a URL with urlparams of its own. - assertEquals( - "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2F%3Fblog%3D1%26entry%3D2&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2F%3Fblog%3D1%26entry%3D2&publicationId=pubId2&metrics=true", - mCrowButtonDelegate.buildServerUrlInternal( - serverUrl, shareUrl2, shareUrl2, "pubId2", allowMetrics, isFollowing)); - - // Empty canonical URL is ok, passes as empty param. - assertEquals( - "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=&publicationId=pubId1&metrics=true", - mCrowButtonDelegate.buildServerUrlInternal(serverUrl, shareUrl1, GURL.emptyGURL(), - "pubId1", allowMetrics, isFollowing)); - - // Experimental URL can be passed with an empty set of params. - assertEquals( - "http://www.foo.com/v1/api?pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=true", - mCrowButtonDelegate.buildServerUrlInternal(serverUrlWithoutQueryString, shareUrl1, - shareUrl1, "pubId1", allowMetrics, isFollowing)); - - // Metrics off and already following should be reflected. - allowMetrics = false; - isFollowing = true; - assertEquals( - "https://www.foo.com/v1/api?q=hi&pageUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&entry=menu&relCanonUrl=https%3A%2F%2Ftestsitewearesharing.com%2Fblog%2Fentry&publicationId=pubId1&metrics=false&following=true", - mCrowButtonDelegate.buildServerUrlInternal( - serverUrl, shareUrl1, shareUrl1, "pubId1", allowMetrics, isFollowing)); - } - - @Test - @SmallTest - public void testParseDomainMap() { - HashMap<String, String> map = mCrowButtonDelegate.parseDomainIdMap( - "foo1.com^pubId1;fooStaging.com^pubId2;news.foo.com^pubId3"); - assertEquals(3, map.size()); - assertEquals("pubId1", map.get("foo1.com")); - assertEquals("pubId2", map.get("fooStaging.com")); - assertEquals("pubId3", map.get("news.foo.com")); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/OWNERS deleted file mode 100644 index e4f7c48..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/crow/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/android/java/src/org/chromium/chrome/browser/share/crow/OWNERS
diff --git a/chrome/browser/PRESUBMIT.py b/chrome/browser/PRESUBMIT.py index b1a1fd39..7a00177 100644 --- a/chrome/browser/PRESUBMIT.py +++ b/chrome/browser/PRESUBMIT.py
@@ -8,6 +8,50 @@ import re +# Checks whether an autofill-related browsertest fixture class inherits from +# either InProcessBrowserTest or AndroidBrowserTest without having a member of +# type `autofill::test::AutofillBrowserTestEnvironment`. In that case, the +# functions registers a presubmit warning. +def _CheckNoAutofillBrowserTestsWithoutAutofillBrowserTestEnvironment( + input_api, output_api): + autofill_files_pattern = re.compile( + r'(autofill|password_manager).*\.(mm|cc|h)') + concerned_files = [(f, input_api.ReadFile(f)) + for f in input_api.AffectedFiles() + if autofill_files_pattern.search(f.LocalPath())] + + warning_files = [] + class_name = r'^( *)(class|struct)\s+\w+\s*:\s*' + target_base = r'[^\{]*\bpublic\s+(InProcess|Android)BrowserTest[^\{]*\{' + class_declaration_pattern = re.compile( + class_name + target_base, re.MULTILINE) + for autofill_file, file_content in concerned_files: + for class_match in re.finditer(class_declaration_pattern, file_content): + indentation = class_match.group(1) + class_end_pattern = re.compile( + r'^' + indentation + r'\};$', re.MULTILINE) + class_end = class_end_pattern.search(file_content[class_match.start():]) + + corresponding_subclass = ( + '' if class_end is None else + file_content[ + class_match.start(): + class_match.start() + class_end.end()]) + + required_member_pattern = re.compile( + r'^' + indentation + + r' (::)?(autofill::)?test::AutofillBrowserTestEnvironment\s+\w+_;', + re.MULTILINE) + if not required_member_pattern.search(corresponding_subclass): + warning_files.append(autofill_file) + + return [output_api.PresubmitPromptWarning( + 'Consider adding a member autofill::test::AutofillBrowserTestEnvironment ' + 'to the test fixtures that derive from InProcessBrowserTest or ' + 'AndroidBrowserTest in order to disable kAutofillServerCommunication in ' + 'browser tests.', + warning_files)] if len(warning_files) else [] + def _RunHistogramChecks(input_api, output_api, histogram_name): try: # Setup sys.path so that we can call histograms code. @@ -51,15 +95,16 @@ def _CommonChecks(input_api, output_api): """Checks common to both upload and commit.""" results = [] + results.extend( + _CheckNoAutofillBrowserTestsWithoutAutofillBrowserTestEnvironment( + input_api, output_api)) results.extend(_CheckUnwantedDependencies(input_api, output_api)) results.extend(_RunHistogramChecks(input_api, output_api, "BadMessageReasonChrome")) return results - def CheckChangeOnUpload(input_api, output_api): return _CommonChecks(input_api, output_api) - def CheckChangeOnCommit(input_api, output_api): return _CommonChecks(input_api, output_api)
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 12daa69..4fb09af 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -644,6 +644,12 @@ {"action_chip_time_ms", "3000"}, {"reader_mode_session_rate_limiting", "false"}, }; +const FeatureEntry::FeatureParam + kContextualPageActionReaderMode_ActionChip_NotRateLimited_6s[] = { + {"action_chip", "true"}, + {"action_chip_time_ms", "6000"}, + {"reader_mode_session_rate_limiting", "false"}, +}; const FeatureEntry::FeatureVariation kContextualPageActionReaderModeVariations[] = { {"Quiet", kContextualPageActionsUiParams_Quiet, @@ -660,10 +666,15 @@ kContextualPageActionsUiParams_ActionChip_AltColor_6s, std::size(kContextualPageActionsUiParams_ActionChip_AltColor_6s), nullptr}, - {"Action Chip - Not rate limited", + {"Action Chip - Not rate limited - 3s", kContextualPageActionReaderMode_ActionChip_NotRateLimited, std::size(kContextualPageActionReaderMode_ActionChip_NotRateLimited), nullptr}, + {"Action Chip - Not rate limited - 6s", + kContextualPageActionReaderMode_ActionChip_NotRateLimited_6s, + std::size( + kContextualPageActionReaderMode_ActionChip_NotRateLimited_6s), + nullptr}, }; #endif // BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/apps/almanac_api_client/BUILD.gn b/chrome/browser/apps/almanac_api_client/BUILD.gn index 155c85716..d421570e 100644 --- a/chrome/browser/apps/almanac_api_client/BUILD.gn +++ b/chrome/browser/apps/almanac_api_client/BUILD.gn
@@ -17,8 +17,8 @@ deps = [ "//ash/constants", "//base", + "//chrome/browser:browser_process", "//chrome/browser/apps:user_type_filter", - "//chrome/browser/profiles", "//chrome/browser/profiles:profile", "//chrome/common:channel_info", "//chromeos/version",
diff --git a/chrome/browser/apps/almanac_api_client/device_info_manager.cc b/chrome/browser/apps/almanac_api_client/device_info_manager.cc index d22fb2b5..981ec54 100644 --- a/chrome/browser/apps/almanac_api_client/device_info_manager.cc +++ b/chrome/browser/apps/almanac_api_client/device_info_manager.cc
@@ -8,6 +8,7 @@ #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "chrome/browser/apps/user_type_filter.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/channel_info.h" #include "chromeos/version/version_loader.h" @@ -55,6 +56,11 @@ PrefService* prefs = profile_->GetPrefs(); DCHECK(prefs); device_info.locale = prefs->GetString(language::prefs::kApplicationLocale); + // If there's no stored locale preference, fall back to the current UI + // language. + if (device_info.locale.empty()) { + device_info.locale = g_browser_process->GetApplicationLocale(); + } base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock()},
diff --git a/chrome/browser/apps/almanac_api_client/device_info_manager.h b/chrome/browser/apps/almanac_api_client/device_info_manager.h index 7103ed0..d2424ad 100644 --- a/chrome/browser/apps/almanac_api_client/device_info_manager.h +++ b/chrome/browser/apps/almanac_api_client/device_info_manager.h
@@ -47,7 +47,11 @@ // The version info of the device. VersionInfo version_info; - // The locale chosen by the user. + // The locale chosen by the user (e.g. "en-AU"). If no user preference is + // available, which happens during OOBE, instead falls back to the language + // the UI is currently showing in. This may be less specific (e.g. "en-GB" + // instead of "en-AU"), or may conflict with sync data (e.g. signing into a + // "fr" device with an account that has "de" in prefs). std::string locale; };
diff --git a/chrome/browser/apps/almanac_api_client/device_info_manager_unittest.cc b/chrome/browser/apps/almanac_api_client/device_info_manager_unittest.cc index e5e31eb..5c0be2e 100644 --- a/chrome/browser/apps/almanac_api_client/device_info_manager_unittest.cc +++ b/chrome/browser/apps/almanac_api_client/device_info_manager_unittest.cc
@@ -6,8 +6,8 @@ #include <memory> -#include "base/functional/callback.h" -#include "base/run_loop.h" +#include "base/test/test_future.h" +#include "chrome/browser/browser_process.h" #include "chrome/common/channel_info.h" #include "chrome/test/base/testing_profile.h" #include "components/language/core/browser/pref_names.h" @@ -15,52 +15,54 @@ #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" -namespace { - -static constexpr char kTestLocale[] = "test_locale"; - -} // namespace - namespace apps { class DeviceInfoManagerTest : public testing::Test { public: - std::unique_ptr<DeviceInfoManager> device_info_manager_; - - void VerifyDeviceInfo(base::OnceClosure on_complete, DeviceInfo device_info) { - ASSERT_FALSE(device_info.board.empty()); - ASSERT_FALSE(device_info.model.empty()); - ASSERT_FALSE(device_info.user_type.empty()); - ASSERT_FALSE(device_info.version_info.ash_chrome.empty()); - ASSERT_FALSE(device_info.version_info.platform.empty()); - ASSERT_EQ(device_info.version_info.channel, chrome::GetChannel()); - ASSERT_EQ(device_info.locale, kTestLocale); - std::move(on_complete).Run(); + void SetUp() override { + device_info_manager_ = std::make_unique<DeviceInfoManager>(&profile_); } - protected: - DeviceInfoManagerTest() { - device_info_manager_ = std::make_unique<DeviceInfoManager>(&profile_); - PrefService* prefs = profile_.GetPrefs(); - prefs->SetString(language::prefs::kApplicationLocale, kTestLocale); + Profile* profile() { return &profile_; } + DeviceInfoManager* device_info_manager() { + return device_info_manager_.get(); } private: - // To support context of browser threads. content::BrowserTaskEnvironment task_environment_; TestingProfile profile_; + + std::unique_ptr<DeviceInfoManager> device_info_manager_; }; TEST_F(DeviceInfoManagerTest, CheckDeviceInfo) { - ASSERT_TRUE(device_info_manager_ != nullptr); + static constexpr char kTestLocale[] = "test_locale"; + profile()->GetPrefs()->SetString(language::prefs::kApplicationLocale, + kTestLocale); - base::RunLoop run_loop; + base::test::TestFuture<DeviceInfo> info_future; + device_info_manager()->GetDeviceInfo(info_future.GetCallback()); - device_info_manager_->GetDeviceInfo( - base::BindOnce(&DeviceInfoManagerTest::VerifyDeviceInfo, - base::Unretained(this), run_loop.QuitClosure())); + DeviceInfo device_info = info_future.Take(); - run_loop.Run(); + ASSERT_FALSE(device_info.board.empty()); + ASSERT_FALSE(device_info.model.empty()); + ASSERT_FALSE(device_info.user_type.empty()); + ASSERT_FALSE(device_info.version_info.ash_chrome.empty()); + ASSERT_FALSE(device_info.version_info.platform.empty()); + ASSERT_EQ(device_info.version_info.channel, chrome::GetChannel()); + ASSERT_EQ(device_info.locale, kTestLocale); +} + +TEST_F(DeviceInfoManagerTest, CheckDeviceInfoNoLanguagePreference) { + base::test::TestFuture<DeviceInfo> info_future; + device_info_manager()->GetDeviceInfo(info_future.GetCallback()); + + DeviceInfo device_info = info_future.Take(); + + // If there's no preferred locale set in prefs, locale should fall back to the + // current UI language. + ASSERT_EQ(device_info.locale, g_browser_process->GetApplicationLocale()); } } // namespace apps
diff --git a/chrome/browser/ash/app_list/search/federated_metrics_manager.cc b/chrome/browser/ash/app_list/search/federated_metrics_manager.cc index 790a182..ae891d5b 100644 --- a/chrome/browser/ash/app_list/search/federated_metrics_manager.cc +++ b/chrome/browser/ash/app_list/search/federated_metrics_manager.cc
@@ -7,6 +7,7 @@ #include "ash/constants/ash_features.h" #include "ash/shell.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ash/app_list/search/search_features.h" @@ -26,10 +27,19 @@ constexpr char kClientName[] = "launcher_query_analytics_v1"; -// Prefixes are short, for bandwidth conservation. -constexpr char kExamplePrefixOnAbandon[] = "A_"; -constexpr char kExamplePrefixOnLaunch[] = "L_"; - +std::string SearchSessionConclusionToString( + ash::SearchSessionConclusion conclusion) { + switch (conclusion) { + case ash::SearchSessionConclusion::kQuit: + return "q"; + case ash::SearchSessionConclusion::kLaunch: + return "l"; + case ash::SearchSessionConclusion::kAnswerCardSeen: + return "ac"; + default: + NOTREACHED(); + } +} bool IsLoggingEnabled() { // TODO(b/262611120): Also check user metrics opt-in/out, any other relevant // federated flags, etc. @@ -37,8 +47,8 @@ search_features::IsLauncherQueryFederatedAnalyticsPHHEnabled(); } -void LogAction(FederatedMetricsManager::Action action) { - base::UmaHistogramEnumeration(kHistogramAction, action); +void LogSearchSessionConclusion(ash::SearchSessionConclusion conclusion) { + base::UmaHistogramEnumeration(kHistogramSearchSessionConclusion, conclusion); } void LogInitStatus(FederatedMetricsManager::InitStatus status) { @@ -61,7 +71,10 @@ const std::u16string& query) { // TODO(b/262611120): To be decided: Conversion to lowercase, white space // stripping, truncation, etc. - return base::StrCat({prefix, base::UTF16ToUTF8(query)}); + + // TODO(b/262611120): Don't annotate via prefixes. Use a different method. + // This will give greater flexibility in subsequent processing. + return base::StrCat({prefix, "_", base::UTF16ToUTF8(query)}); } } // namespace @@ -97,14 +110,38 @@ FederatedMetricsManager::~FederatedMetricsManager() = default; -void FederatedMetricsManager::OnAbandon(Location location, - const std::vector<Result>& results, - const std::u16string& query) { +void FederatedMetricsManager::OnSearchSessionStarted() { + if (!IsLoggingEnabled()) { + return; + } + session_active_ = true; +} + +void FederatedMetricsManager::OnSearchSessionEnded( + const std::u16string& query) { + if (!IsLoggingEnabled() || query.empty() || !session_active_) { + return; + } + // UMA logging: + LogSearchSessionConclusion(session_result_); + // Federated logging: + LogExample(CreateExampleString( + SearchSessionConclusionToString(session_result_), query)); + + session_result_ = ash::SearchSessionConclusion::kQuit; + session_active_ = false; +} + +void FederatedMetricsManager::OnSeen(Location location, + const std::vector<Result>& results, + const std::u16string& query) { if (!IsLoggingEnabled() || query.empty()) { return; } - LogAction(Action::kAbandon); - LogExample(CreateExampleString(kExamplePrefixOnAbandon, query)); + if (location == Location::kAnswerCard) { + DCHECK(session_active_); + session_result_ = ash::SearchSessionConclusion::kAnswerCardSeen; + } } void FederatedMetricsManager::OnLaunch(Location location, @@ -114,8 +151,10 @@ if (!IsLoggingEnabled() || query.empty()) { return; } - LogAction(Action::kLaunch); - LogExample(CreateExampleString(kExamplePrefixOnLaunch, query)); + if (location == Location::kList || location == Location::kAnswerCard) { + DCHECK(session_active_); + session_result_ = ash::SearchSessionConclusion::kLaunch; + } } bool FederatedMetricsManager::IsFederatedServiceAvailable() {
diff --git a/chrome/browser/ash/app_list/search/federated_metrics_manager.h b/chrome/browser/ash/app_list/search/federated_metrics_manager.h index 36b5935..bb9b93b 100644 --- a/chrome/browser/ash/app_list/search/federated_metrics_manager.h +++ b/chrome/browser/ash/app_list/search/federated_metrics_manager.h
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "ash/public/cpp/app_list/app_list_metrics.h" #include "ash/public/cpp/app_list/app_list_notifier.h" #include "ash/system/federated/federated_service_controller.h" #include "base/memory/raw_ptr.h" @@ -17,7 +18,8 @@ namespace app_list::federated { -constexpr char kHistogramAction[] = "Apps.AppList.Search.Federated.Action"; +constexpr char kHistogramSearchSessionConclusion[] = + "Apps.AppList.Search.Federated.SearchSessionConclusion"; constexpr char kHistogramInitStatus[] = "Apps.AppList.Search.Federated.InitStatus"; constexpr char kHistogramReportStatus[] = @@ -32,6 +34,7 @@ // Represents the actions a user can take in the launcher. These values // persist to logs. Entries should not be renumbered and numeric values should // never be reused. + // TODO(b/262611120): Currently unused. Deprecate if remains unused. enum class Action { kImpression = 0, kLaunch = 1, @@ -70,15 +73,30 @@ FederatedMetricsManager& operator=(const FederatedMetricsManager&) = delete; // ash::AppListNotifier::Observer: - void OnAbandon(Location location, - const std::vector<Result>& results, - const std::u16string& query) override; + // TODO(b/262611120): `FederatedMetricsManager` tracks session-level actions + // by monitoring finer-grained events. Certain orderings of events are assumed + // by `FederatedMetricsManager`, but are not strictly guaranteed by the + // `AppListNotifier`. For example, that `OnLaunch` is followed by + // `OnSearchSessionEnded`. Consider adding new methods to the + // `AppListNotifier` which more directly signal session-level events of + // interest. + void OnSearchSessionStarted() override; + void OnSearchSessionEnded(const std::u16string& query) override; + void OnSeen(Location location, + const std::vector<Result>& results, + const std::u16string& query) override; void OnLaunch(Location location, const Result& launched, const std::vector<Result>& shown, const std::u16string& query) override; private: + // Whether the metrics manager is tracking an active search session. + bool session_active_ = false; + // Tracks the metric recorded when EndSearchSession() is called. + ash::SearchSessionConclusion session_result_ = + ash::SearchSessionConclusion::kQuit; + // Note: There's no guarantee that the federated service will stay // available, so call `IsFederatedServiceAvailable()` before each attempt at // interacting with the service.
diff --git a/chrome/browser/ash/app_list/search/federated_metrics_manager_unittest.cc b/chrome/browser/ash/app_list/search/federated_metrics_manager_unittest.cc index ab4aaa4..e12ce9b1e 100644 --- a/chrome/browser/ash/app_list/search/federated_metrics_manager_unittest.cc +++ b/chrome/browser/ash/app_list/search/federated_metrics_manager_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "ash/constants/ash_features.h" +#include "ash/public/cpp/app_list/app_list_metrics.h" #include "ash/system/federated/federated_service_controller.h" #include "base/run_loop.h" #include "base/strings/strcat.h" @@ -92,10 +93,11 @@ TestFederatedServiceController federated_service_controller_; }; -TEST_F(FederatedMetricsManagerTest, OnAbandon) { - Location location = Location::kList; - std::vector<Result> shown_results; - metrics_manager_->OnAbandon(location, shown_results, u"fake_query"); +TEST_F(FederatedMetricsManagerTest, Quit) { + metrics_manager_->OnSearchSessionStarted(); + // Search session ends without user taking other action (e.g. without + // launching a result). + metrics_manager_->OnSearchSessionEnded(u"fake_query"); base::RunLoop().RunUntilIdle(); histogram_tester()->ExpectUniqueSample( @@ -103,8 +105,8 @@ app_list::federated::FederatedMetricsManager::InitStatus::kOk, 1); histogram_tester()->ExpectUniqueSample( - app_list::federated::kHistogramAction, - app_list::federated::FederatedMetricsManager::Action::kAbandon, 1); + app_list::federated::kHistogramSearchSessionConclusion, + ash::SearchSessionConclusion::kQuit, 1); histogram_tester()->ExpectUniqueSample( app_list::federated::kHistogramReportStatus, @@ -114,12 +116,72 @@ // functionality is available. } -TEST_F(FederatedMetricsManagerTest, OnLaunch) { - Location location = Location::kList; +TEST_F(FederatedMetricsManagerTest, Launch) { + metrics_manager_->OnSearchSessionStarted(); std::vector<Result> shown_results; Result launched_result = CreateFakeResult(Type::EXTENSION_APP, "fake_id"); - metrics_manager_->OnLaunch(location, launched_result, shown_results, - u"fake_query"); + std::u16string query = u"fake_query"; + + metrics_manager_->OnLaunch(Location::kList, launched_result, shown_results, + query); + metrics_manager_->OnSearchSessionEnded(query); + base::RunLoop().RunUntilIdle(); + + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramInitStatus, + app_list::federated::FederatedMetricsManager::InitStatus::kOk, 1); + + // TODO + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramSearchSessionConclusion, + ash::SearchSessionConclusion::kLaunch, 1); + + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramReportStatus, + app_list::federated::FederatedMetricsManager::ReportStatus::kOk, 1); + // TODO(b/262611120): Check contents of logged example, once this + // functionality is available. +} + +TEST_F(FederatedMetricsManagerTest, AnswerCardSeen) { + metrics_manager_->OnSearchSessionStarted(); + std::vector<Result> shown_results; + std::u16string query = u"fake_query"; + + metrics_manager_->OnSeen(Location::kAnswerCard, shown_results, query); + metrics_manager_->OnSearchSessionEnded(query); + base::RunLoop().RunUntilIdle(); + + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramInitStatus, + app_list::federated::FederatedMetricsManager::InitStatus::kOk, 1); + + // TODO + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramSearchSessionConclusion, + ash::SearchSessionConclusion::kAnswerCardSeen, 1); + + histogram_tester()->ExpectUniqueSample( + app_list::federated::kHistogramReportStatus, + app_list::federated::FederatedMetricsManager::ReportStatus::kOk, 1); + // TODO(b/262611120): Check contents of logged example, once this + // functionality is available. +} + +TEST_F(FederatedMetricsManagerTest, AnswerCardSeenThenListResultLaunched) { + // Tests that a Launch event takes precedence over an AnswerCardSeen event, + // within the same search session. + metrics_manager_->OnSearchSessionStarted(); + std::vector<Result> shown_results; + std::u16string query = u"fake_query"; + + metrics_manager_->OnSeen(Location::kAnswerCard, shown_results, query); + + Result launched_result = CreateFakeResult(Type::EXTENSION_APP, "fake_id"); + metrics_manager_->OnLaunch(Location::kList, launched_result, shown_results, + query); + + metrics_manager_->OnSearchSessionEnded(query); base::RunLoop().RunUntilIdle(); histogram_tester()->ExpectUniqueSample( @@ -127,8 +189,8 @@ app_list::federated::FederatedMetricsManager::InitStatus::kOk, 1); histogram_tester()->ExpectUniqueSample( - app_list::federated::kHistogramAction, - app_list::federated::FederatedMetricsManager::Action::kLaunch, 1); + app_list::federated::kHistogramSearchSessionConclusion, + ash::SearchSessionConclusion::kLaunch, 1); histogram_tester()->ExpectUniqueSample( app_list::federated::kHistogramReportStatus, @@ -138,16 +200,20 @@ } TEST_F(FederatedMetricsManagerTest, ZeroState) { - Location location = Location::kList; - std::vector<Result> shown_results; - Result launched_result = CreateFakeResult(Type::EXTENSION_APP, "fake_id"); + // Note: metrics_manager_->OnSearchSession{Started,Ended}() are not expected + // to be called during zero state search. // Simulate a series of user actions in zero state search. An empty query // indicates zero state search. + std::vector<Result> shown_results; std::u16string empty_query = u""; - metrics_manager_->OnAbandon(location, shown_results, empty_query); - metrics_manager_->OnLaunch(location, launched_result, shown_results, - empty_query); + + metrics_manager_->OnSeen(Location::kContinue, shown_results, empty_query); + metrics_manager_->OnSeen(Location::kRecentApps, shown_results, empty_query); + + Result launched_result = CreateFakeResult(Type::EXTENSION_APP, "fake_id"); + metrics_manager_->OnLaunch(Location::kRecentApps, launched_result, + shown_results, empty_query); base::RunLoop().RunUntilIdle(); histogram_tester()->ExpectUniqueSample( @@ -155,8 +221,8 @@ app_list::federated::FederatedMetricsManager::InitStatus::kOk, 1); // Zero state search should not trigger any logging on user action. - histogram_tester()->ExpectTotalCount(app_list::federated::kHistogramAction, - 0); + histogram_tester()->ExpectTotalCount( + app_list::federated::kHistogramSearchSessionConclusion, 0); histogram_tester()->ExpectTotalCount( app_list::federated::kHistogramReportStatus, 0);
diff --git a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.cc b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.cc index 4486cc6..f30fd10 100644 --- a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.cc +++ b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.cc
@@ -89,9 +89,6 @@ constexpr char kGhostWindowPopToArcHistogram[] = "Arc.LaunchedWithGhostWindow"; -constexpr char kNoGhostWindowReasonHistogram[] = - "Apps.RestoreNoGhostWindowReason"; - } // namespace ArcAppQueueRestoreHandler::ArcAppQueueRestoreHandler() { @@ -459,10 +456,6 @@ window_handler_->OnAppStatesUpdate(app_id, app_info->ready, app_info->need_fixup); } - } else { - // Only record bounds state when no ghost window launch. - RecordLaunchBoundsState(app_restore_data->bounds_in_root.has_value(), - app_restore_data->current_bounds.has_value()); } #endif RecordArcGhostWindowLaunch(launch_ghost_window); @@ -834,36 +827,6 @@ bool is_arc_ghost_window) { base::UmaHistogramBoolean(kArcGhostWindowLaunchHistogram, is_arc_ghost_window); - - if (!is_arc_ghost_window && !exo::WMHelper::HasInstance()) { - base::UmaHistogramEnumeration(kNoGhostWindowReasonHistogram, - NoGhostWindowReason::kNoExoHelper); - } -} - -void ArcAppQueueRestoreHandler::RecordLaunchBoundsState( - bool has_root_bounds, - bool has_screen_bounds) { - bool is_from_crash = ExitTypeService::GetLastSessionExitType( - handler_->profile()) == ExitType::kCrashed; - if (!has_root_bounds) { - base::UmaHistogramEnumeration( - kNoGhostWindowReasonHistogram, - is_from_crash ? NoGhostWindowReason::kNoRootBoundsFromCrash - : NoGhostWindowReason::kNoRootBounds); - } - if (!has_screen_bounds) { - base::UmaHistogramEnumeration( - kNoGhostWindowReasonHistogram, - is_from_crash ? NoGhostWindowReason::kNoScreenBoundsFromCrash - : NoGhostWindowReason::kNoScreenBounds); - } - if (!window_handler_) { - base::UmaHistogramEnumeration(kNoGhostWindowReasonHistogram, - is_from_crash - ? NoGhostWindowReason::kNoHandlerFromCrash - : NoGhostWindowReason::kNoHandler); - } } void ArcAppQueueRestoreHandler::RecordRestoreResult() {
diff --git a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h index 63919b4..29df797 100644 --- a/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h +++ b/chrome/browser/ash/app_restore/arc_app_queue_restore_handler.h
@@ -228,7 +228,6 @@ void OnProbeServiceDisconnect(); void RecordArcGhostWindowLaunch(bool is_arc_ghost_window); - void RecordLaunchBoundsState(bool has_root_bounds, bool has_screen_bounds); void RecordRestoreResult(); SchedulerConfigurationManager* GetSchedulerConfigurationManager();
diff --git a/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc b/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc index e084e33..27337bd 100644 --- a/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_security_delegate_unittest.cc
@@ -23,16 +23,6 @@ } // namespace -// TODO(b/244651040): Remove legacy tests when sommelier changes are complete. -TEST_F(BorealisSecurityDelegateTest, MainAppCanSelfActivateLegacy) { - CreateFakeMainApp(&profile_); - std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( - "org.chromium.borealis.wmclass.Steam", - &BorealisService::GetForProfile(&profile_)->WindowManager()); - EXPECT_TRUE( - BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window())); -} - TEST_F(BorealisSecurityDelegateTest, MainAppCanSelfActivate) { CreateFakeMainApp(&profile_); std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( @@ -42,20 +32,6 @@ BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window())); } -TEST_F(BorealisSecurityDelegateTest, NormalAppCanNotSelfActivateLegacy) { - CreateFakeApp(&profile_, "not_steam", "borealis/123"); - std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( - "org.chromium.borealis.wmclass.not_steam", - &BorealisService::GetForProfile(&profile_)->WindowManager()); - - ASSERT_FALSE(BorealisWindowManager::IsAnonymousAppId( - BorealisService::GetForProfile(&profile_)->WindowManager().GetShelfAppId( - window->window()))); - - EXPECT_FALSE( - BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window())); -} - TEST_F(BorealisSecurityDelegateTest, NormalAppCanNotSelfActivate) { CreateFakeApp(&profile_, "not_steam", "borealis/123"); std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( @@ -70,19 +46,6 @@ BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window())); } -TEST_F(BorealisSecurityDelegateTest, AnonymousAppCanNotSelfActivateLegacy) { - std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( - "org.chromium.borealis.wmclass.anonymous", - &BorealisService::GetForProfile(&profile_)->WindowManager()); - - ASSERT_TRUE(BorealisWindowManager::IsAnonymousAppId( - BorealisService::GetForProfile(&profile_)->WindowManager().GetShelfAppId( - window->window()))); - - EXPECT_FALSE( - BorealisSecurityDelegate(&profile_).CanSelfActivate(window->window())); -} - TEST_F(BorealisSecurityDelegateTest, AnonymousAppCanNotSelfActivate) { std::unique_ptr<ScopedTestWindow> window = MakeAndTrackWindow( "org.chromium.guest_os.borealis.wmclass.anonymous",
diff --git a/chrome/browser/ash/borealis/borealis_util.cc b/chrome/browser/ash/borealis/borealis_util.cc index c698f84..5ff9706d 100644 --- a/chrome/browser/ash/borealis/borealis_util.cc +++ b/chrome/browser/ash/borealis/borealis_util.cc
@@ -60,9 +60,6 @@ static constexpr char kJSONSteamKey[] = "steam_runtime_version"; // App IDs prefixed with this are identified with a numeric "Borealis ID". -// TODO(b/244651040): Remove legacy prefix when sommelier changes are complete. -const base::StringPiece kBorealisWindowWithIdPrefixLegacy( - "org.chromium.borealis.xprop."); const base::StringPiece kBorealisWindowWithIdPrefix( "org.chromium.guest_os.borealis.xprop."); @@ -150,15 +147,9 @@ absl::optional<int> GetBorealisAppId(const aura::Window* window) { const std::string* id = exo::GetShellApplicationId(window); - if (id) { + if (id && base::StartsWith(*id, kBorealisWindowWithIdPrefix)) { int borealis_id; - if (base::StartsWith(*id, kBorealisWindowWithIdPrefix) && - base::StringToInt(id->substr(kBorealisWindowWithIdPrefix.size()), - &borealis_id)) { - return borealis_id; - } - if (base::StartsWith(*id, kBorealisWindowWithIdPrefixLegacy) && - base::StringToInt(id->substr(kBorealisWindowWithIdPrefixLegacy.size()), + if (base::StringToInt(id->substr(kBorealisWindowWithIdPrefix.size()), &borealis_id)) { return borealis_id; }
diff --git a/chrome/browser/ash/borealis/borealis_util_unittest.cc b/chrome/browser/ash/borealis/borealis_util_unittest.cc index 1a7e8bab..a9a30c1 100644 --- a/chrome/browser/ash/borealis/borealis_util_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_util_unittest.cc
@@ -51,26 +51,12 @@ EXPECT_EQ(GetBorealisAppId("steam://rungameid/123").value(), 123); } -// TODO(b/244651040): Remove legacy tests when sommelier changes are complete. -TEST_F(BorealisUtilTest, - GetBorealisAppIdFromWindowReturnsEmptyOnFailureLegacy) { - std::unique_ptr<aura::Window> window = - MakeWindow("org.chromium.borealis.wmclass.foo"); - EXPECT_EQ(GetBorealisAppId(window.get()), absl::nullopt); -} - TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsEmptyOnFailure) { std::unique_ptr<aura::Window> window = MakeWindow("org.chromium.guest_os.borealis.wmclass.foo"); EXPECT_EQ(GetBorealisAppId(window.get()), absl::nullopt); } -TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsIdLegacy) { - std::unique_ptr<aura::Window> window = - MakeWindow("org.chromium.borealis.xprop.123"); - EXPECT_EQ(GetBorealisAppId(window.get()).value(), 123); -} - TEST_F(BorealisUtilTest, GetBorealisAppIdFromWindowReturnsId) { std::unique_ptr<aura::Window> window = MakeWindow("org.chromium.guest_os.borealis.xprop.123");
diff --git a/chrome/browser/ash/borealis/borealis_window_manager.cc b/chrome/browser/ash/borealis/borealis_window_manager.cc index 44054268..5135576a 100644 --- a/chrome/browser/ash/borealis/borealis_window_manager.cc +++ b/chrome/browser/ash/borealis/borealis_window_manager.cc
@@ -27,11 +27,7 @@ namespace borealis { -// TODO(b/244651040): Remove legacy prefix when sommelier changes are complete. -const char kBorealisWindowPrefixLegacy[] = "org.chromium.borealis."; const char kBorealisWindowPrefix[] = "org.chromium.guest_os.borealis."; -const char kFullscreenClientShellIdLegacy[] = - "org.chromium.borealis.wmclass.steam"; const char kFullscreenClientShellId[] = "org.chromium.guest_os.borealis.wmclass.steam"; const char kBorealisClientSuffix[] = "wmclass.Steam"; @@ -65,10 +61,6 @@ return {}; } -bool IsBorealisWindowIdLegacy(const std::string& window_id) { - return base::StartsWith(window_id, borealis::kBorealisWindowPrefixLegacy); -} - std::string WindowToAppId(Profile* profile, const aura::Window* window) { // The Borealis app ID is the most reliable method, if known. absl::optional<int> borealis_id = GetBorealisAppId(window); @@ -79,31 +71,13 @@ } // Fall back to GuestOS's logic for associating windows with apps. - // The legacy way to do this was to spoof a Crostini app ID. This will be - // supported until the new window ID version is fully supported. Once it is, - // this replacement will be removed and GetGuestOsShelfAppId should handle - // all borealis cases. - // TODO(b/244651040): remove the string replacement after new window_id format - // is deployed. - std::string window_id(*GetWindowId(window)); - if (IsBorealisWindowIdLegacy(window_id)) { - base::ReplaceFirstSubstringAfterOffset( - &window_id, 0, borealis::kBorealisWindowPrefixLegacy, - "org.chromium.guest_os.termina."); - } - std::string guest_os_shelf_app_id = - guest_os::GetGuestOsShelfAppId(profile, &window_id, nullptr); - - // If this app is registered by GuestOsRegistry, then it's actually registered - // for Borealis. - if (!guest_os::IsUnregisteredGuestOsShelfAppId(guest_os_shelf_app_id)) { - return guest_os_shelf_app_id; - } - - // Unregistered app. Unlike Crostini, we expect all Borealis apps to be - // registered, so we consider this a bug. - // TODO(cpelling): Log a warning here once this function is memoized. - return kBorealisAnonymousPrefix + *GetWindowId(window); + // GetGuestOsShelfAppId will handle both registered and anonymous borealis app + // windows correctly. For registered apps, it will return a matching shelf app + // ID. For unregistered apps, it will return an app_id prefixed with + // "borealis_anon:". + // TODO(cpelling): Log a warning here once all Steam startup windows and + // games are correctly registered. + return guest_os::GetGuestOsShelfAppId(profile, GetWindowId(window), nullptr); } } // namespace @@ -118,8 +92,7 @@ // static bool BorealisWindowManager::IsBorealisWindowId(const std::string& window_id) { - return base::StartsWith(window_id, borealis::kBorealisWindowPrefix) || - base::StartsWith(window_id, borealis::kBorealisWindowPrefixLegacy); + return base::StartsWith(window_id, borealis::kBorealisWindowPrefix); } // static @@ -147,8 +120,7 @@ // If the fullscreen window is the borealis client, then we allow windows to // take focus. - if (*active_window_id == borealis::kFullscreenClientShellId || - *active_window_id == borealis::kFullscreenClientShellIdLegacy) { + if (*active_window_id == borealis::kFullscreenClientShellId) { return false; }
diff --git a/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc b/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc index b89ed78..ec4a339 100644 --- a/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_window_manager_unittest.cc
@@ -60,14 +60,6 @@ EXPECT_EQ(window_manager.GetShelfAppId(window.get()), ""); } -// TODO(b/244651040): Remove legacy tests when sommelier changes are complete. -TEST_F(BorealisWindowManagerTest, BorealisWindowHasAnIdLegacy) { - BorealisWindowManager window_manager(profile()); - std::unique_ptr<aura::Window> window = - MakeWindow("org.chromium.borealis.foobarbaz"); - EXPECT_NE(window_manager.GetShelfAppId(window.get()), ""); -} - TEST_F(BorealisWindowManagerTest, BorealisWindowHasAnId) { BorealisWindowManager window_manager(profile()); std::unique_ptr<aura::Window> window = @@ -75,14 +67,6 @@ EXPECT_NE(window_manager.GetShelfAppId(window.get()), ""); } -TEST_F(BorealisWindowManagerTest, BorealisWindowHasCorrectIdLegacy) { - BorealisWindowManager window_manager(profile()); - std::unique_ptr<aura::Window> window = - MakeWindow("org.chromium.borealis.xprop.456789"); - CreateFakeApp(profile(), "some_app", "steam://rungameid/456789"); - EXPECT_EQ(window_manager.GetShelfAppId(window.get()), FakeAppId("some_app")); -} - TEST_F(BorealisWindowManagerTest, BorealisWindowHasCorrectId) { BorealisWindowManager window_manager(profile()); std::unique_ptr<aura::Window> window =
diff --git a/chrome/browser/ash/game_mode/game_mode_controller_for_arc_unittest.cc b/chrome/browser/ash/game_mode/game_mode_controller_for_arc_unittest.cc index 145c2c0..98ae968 100644 --- a/chrome/browser/ash/game_mode/game_mode_controller_for_arc_unittest.cc +++ b/chrome/browser/ash/game_mode/game_mode_controller_for_arc_unittest.cc
@@ -157,7 +157,7 @@ auto game_widget = CreateArcTaskWidget(14, "jp.foo.game"); std::unique_ptr<views::Widget> borealis_widget = - borealis::CreateFakeWidget("org.chromium.borealis.foo"); + borealis::CreateFakeWidget("org.chromium.guest_os.borealis.foo"); fake_resourced_client_->set_set_game_mode_response( ash::ResourcedClient::GameMode::OFF);
diff --git a/chrome/browser/ash/game_mode/game_mode_controller_for_borealis_unittest.cc b/chrome/browser/ash/game_mode/game_mode_controller_for_borealis_unittest.cc index 1e0fcba..05febe23 100644 --- a/chrome/browser/ash/game_mode/game_mode_controller_for_borealis_unittest.cc +++ b/chrome/browser/ash/game_mode/game_mode_controller_for_borealis_unittest.cc
@@ -42,7 +42,7 @@ TEST_F(GameModeControllerForBorealisTest, ChangingFullScreenTogglesGameMode_Borealis) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); @@ -63,13 +63,13 @@ TEST_F(GameModeControllerForBorealisTest, SwitchingWindowsTogglesGameMode) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); std::unique_ptr<views::Widget> other_test_widget = - CreateFakeWidget("org.chromium.borealis.bar"); + CreateFakeWidget("org.chromium.guest_os.borealis.bar"); aura::Window* other_window = other_test_widget->GetNativeWindow(); EXPECT_TRUE(other_window->HasFocus()); @@ -83,7 +83,7 @@ TEST_F(GameModeControllerForBorealisTest, DestroyingWindowExitsGameMode) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); @@ -95,12 +95,12 @@ TEST_F(GameModeControllerForBorealisTest, SwitchingWindowsMaintainsGameMode) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); std::unique_ptr<views::Widget> other_test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); @@ -112,7 +112,7 @@ fake_resourced_client_->set_set_game_mode_with_timeout_response( absl::nullopt); std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); test_widget->SetFullscreen(false); @@ -121,7 +121,7 @@ TEST_F(GameModeControllerForBorealisTest, GameModeRefreshes) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); EXPECT_EQ(1, fake_resourced_client_->get_enter_game_mode_count()); @@ -131,7 +131,7 @@ TEST_F(GameModeControllerForBorealisTest, GameModeMetricsRecorded) { std::unique_ptr<views::Widget> test_widget = - CreateFakeWidget("org.chromium.borealis.foo", true); + CreateFakeWidget("org.chromium.guest_os.borealis.foo", true); aura::Window* window = test_widget->GetNativeWindow(); EXPECT_TRUE(ash::WindowState::Get(window)->IsFullscreen()); histogram_tester_->ExpectBucketCount( @@ -198,7 +198,7 @@ // If a game window without focus goes fullscreen, game mode should not // activate. std::unique_ptr<views::Widget> borealis_widget = - CreateFakeWidget("org.chromium.borealis.foo"); + CreateFakeWidget("org.chromium.guest_os.borealis.foo"); std::unique_ptr<views::Widget> other_widget = CreateFakeWidget("org.chromium.other.baz");
diff --git a/chrome/browser/ash/login/screens/multidevice_setup_screen.cc b/chrome/browser/ash/login/screens/multidevice_setup_screen.cc index 9eaaa602..5868bbbc 100644 --- a/chrome/browser/ash/login/screens/multidevice_setup_screen.cc +++ b/chrome/browser/ash/login/screens/multidevice_setup_screen.cc
@@ -108,6 +108,14 @@ command_line->GetSwitchValueASCII(kQuickStartPhoneInstanceIDSwitch); } + // Use WizardContext here to check if user already connected phone during + // Quick Start. If so, the multidevice setup screen will display UI + // enhancements. + const std::string& phone_instance_id = context.quick_start_phone_instance_id; + if (!phone_instance_id.empty()) { + setup_client_->SetQuickStartPhoneInstanceID(phone_instance_id); + } + // Do not skip if potential host exists but none is set yet. if (setup_client_->GetHostStatus().first == multidevice_setup::mojom::HostStatus::kEligibleHostExistsButNoHostSet) {
diff --git a/chrome/browser/ash/login/screens/multidevice_setup_screen_browsertest.cc b/chrome/browser/ash/login/screens/multidevice_setup_screen_browsertest.cc index 29322bb..4e758cb5 100644 --- a/chrome/browser/ash/login/screens/multidevice_setup_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/multidevice_setup_screen_browsertest.cc
@@ -265,6 +265,8 @@ absl::optional<MultiDeviceSetupScreen::Result> screen_result_; base::HistogramTester histogram_tester_; + std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient> + fake_multidevice_setup_client_; private: void CheckSkippedReason( @@ -312,8 +314,6 @@ bool screen_exited_ = false; base::RepeatingClosure screen_exit_callback_; - std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient> - fake_multidevice_setup_client_; std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_; LoginManagerMixin login_manager_mixin_{&mixin_host_}; @@ -431,4 +431,31 @@ CheckUnknownSkippedReason(); } +IN_PROC_BROWSER_TEST_F(MultiDeviceSetupScreenTest, + NoQuickStartPhoneInstanceIdSet) { + WizardContext* context = + LoginDisplayHost::default_host()->GetWizardContextForTesting(); + ASSERT_TRUE(context->quick_start_phone_instance_id.empty()); + + SimulateHostStatusChange(); + ShowMultiDeviceSetupScreen(); + WaitForScreenShown(); + EXPECT_TRUE(fake_multidevice_setup_client_->qs_phone_instance_id().empty()); +} + +IN_PROC_BROWSER_TEST_F(MultiDeviceSetupScreenTest, + QuickStartPhoneInstanceIdSet) { + WizardContext* context = + LoginDisplayHost::default_host()->GetWizardContextForTesting(); + ASSERT_TRUE(context->quick_start_phone_instance_id.empty()); + std::string expected_phone_instance_id = "someArbitraryID"; + context->quick_start_phone_instance_id = expected_phone_instance_id; + + SimulateHostStatusChange(); + ShowMultiDeviceSetupScreen(); + WaitForScreenShown(); + EXPECT_EQ(fake_multidevice_setup_client_->qs_phone_instance_id(), + expected_phone_instance_id); +} + } // namespace ash
diff --git a/chrome/browser/ash/web_applications/firmware_update_system_web_app_info.cc b/chrome/browser/ash/web_applications/firmware_update_system_web_app_info.cc index e69d4cba..9920abd7 100644 --- a/chrome/browser/ash/web_applications/firmware_update_system_web_app_info.cc +++ b/chrome/browser/ash/web_applications/firmware_update_system_web_app_info.cc
@@ -6,7 +6,6 @@ #include <memory> -#include "ash/constants/ash_features.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/color_util.h" @@ -16,6 +15,7 @@ #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" #include "chrome/browser/web_applications/web_app_install_info.h" +#include "chromeos/constants/chromeos_features.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" @@ -59,7 +59,7 @@ info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; info->theme_color = web_app::GetDefaultBackgroundColor(/*use_dark_mode=*/false); - if (!ash::features::IsJellyEnabled()) { + if (!chromeos::features::IsJellyEnabled()) { // Once Jelly is launched, the theme and background colors for SWA are // ignored and this can be deleted. info->dark_mode_theme_color = GetDarkModeBackgroundColor();
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc index c829045..e64446e 100644 --- a/chrome/browser/autofill/autofill_browsertest.cc +++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -563,7 +563,7 @@ } // Test profiles are not merged without minimum address values. -// Mininum address values needed during aggregation are: address line 1, city, +// Minimum address values needed during aggregation are: address line 1, city, // state, and zip code. // Profiles are merged when data for address line 1 and city match. IN_PROC_BROWSER_TEST_F(AutofillTest, ProfilesNotMergedWhenNoMinAddressData) { @@ -992,7 +992,7 @@ run_loop.Run(); } -// Tests that non-link-click, renderer-inititiated navigation triggers a +// Tests that non-link-click, renderer-initiated navigation triggers a // submission event in BrowserAutofillManager. IN_PROC_BROWSER_TEST_P(AutofillTestFormSubmission, ProbableSubmission) { base::RunLoop run_loop;
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc index 61acd75..7ea09400 100644 --- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -260,7 +260,8 @@ } protected: - AutofillCapturedSitesInteractiveTest() = default; + AutofillCapturedSitesInteractiveTest() + : AutofillUiTest({.disable_server_communication = false}) {} ~AutofillCapturedSitesInteractiveTest() override = default;
diff --git a/chrome/browser/autofill/autofill_uitest.cc b/chrome/browser/autofill/autofill_uitest.cc index 646b6d9..8cd7fc2 100644 --- a/chrome/browser/autofill/autofill_uitest.cc +++ b/chrome/browser/autofill/autofill_uitest.cc
@@ -121,10 +121,12 @@ } // AutofillUiTest ---------------------------------------------------- -AutofillUiTest::AutofillUiTest() +AutofillUiTest::AutofillUiTest( + const test::AutofillTestEnvironment::Options& options) : key_press_event_sink_( base::BindRepeating(&AutofillUiTest::HandleKeyPressEvent, - base::Unretained(this))) {} + base::Unretained(this))), + autofill_test_environment_(options) {} AutofillUiTest::~AutofillUiTest() = default;
diff --git a/chrome/browser/autofill/autofill_uitest.h b/chrome/browser/autofill/autofill_uitest.h index 43e9c9db..5fe4c414 100644 --- a/chrome/browser/autofill/autofill_uitest.h +++ b/chrome/browser/autofill/autofill_uitest.h
@@ -82,7 +82,9 @@ class AutofillUiTest : public InProcessBrowserTest, public content::WebContentsObserver { public: - AutofillUiTest(); + explicit AutofillUiTest( + const test::AutofillTestEnvironment::Options& options = { + .disable_server_communication = true}); ~AutofillUiTest() override; AutofillUiTest(const AutofillUiTest&) = delete;
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc index 37aaa9e..45302280 100644 --- a/chrome/browser/download/notification/download_item_notification.cc +++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -718,6 +718,12 @@ void DownloadItemNotification::OnImageCropped(const SkBitmap& bitmap) { gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); notification_->set_image(image); + +// Provide the file path that backs the image to facilitate notification drag. +#if BUILDFLAG(IS_CHROMEOS) + notification_->set_image_path(item_->GetFullPath()); +#endif + image_decode_status_ = DONE; UpdateNotificationData(!closed_, false); }
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc index f08555b..022a298 100644 --- a/chrome/browser/extensions/api/management/management_api_unittest.cc +++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -11,6 +11,7 @@ #include "base/memory/scoped_refptr.h" #include "base/strings/stringprintf.h" #include "base/test/metrics/histogram_tester.h" +#include "base/types/optional_ref.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/extensions/extension_service.h" @@ -39,7 +40,6 @@ #include "extensions/common/extension_set.h" #include "extensions/common/extension_urls.h" #include "extensions/common/permissions/permission_set.h" -#include "third_party/abseil-cpp/absl/types/optional.h" // TODO(b/265970428): Fix and include extensions tests on LaCrOS. // TODO(b/266051970): Fix and include extensions tests on Windows/Mac/Linux. @@ -51,7 +51,9 @@ #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_test_util.h" +#include "chrome/browser/ui/extensions/extensions_dialogs.h" #include "content/public/browser/gpu_data_manager.h" +#include "extensions/browser/supervised_user_extensions_delegate.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) using extensions::mojom::ManifestLocation; @@ -949,27 +951,55 @@ return supervised_user_service->IsExtensionAllowed(extension); } - void PromptForParentPermissionOrShowError( + void RequestToAddExtensionOrShowError( const extensions::Extension& extension, content::BrowserContext* context, content::WebContents* contents, - ParentPermissionDialogDoneCallback parent_permission_callback, - base::OnceClosure error_callback) override { + const gfx::ImageSkia& icon, + ExtensionApprovalDoneCallback extension_approval_callback) override { // Preconditions. DCHECK(IsChild(context)); DCHECK(!IsExtensionAllowedByParent(extension, context)); if (CanInstallExtensions(context)) { ShowParentPermissionDialogForExtension( - extension, context, contents, std::move(parent_permission_callback)); + extension, context, contents, std::move(extension_approval_callback), + icon); } else { - ShowExtensionEnableBlockedByParentDialogForExtension( - extension, contents, std::move(error_callback)); + ShowInstallBlockedByParentDialogForExtension( + extension, contents, + ExtensionInstalledBlockedByParentDialogAction::kAdd, + base::BindOnce(std::move(extension_approval_callback), + SupervisedUserExtensionsDelegate:: + ExtensionApprovalResult::kBlocked)); + } + } + + void RequestToEnableExtensionOrShowError( + const extensions::Extension& extension, + content::BrowserContext* context, + content::WebContents* contents, + ExtensionApprovalDoneCallback extension_approval_callback) override { + // Preconditions. + DCHECK(IsChild(context)); + DCHECK(!IsExtensionAllowedByParent(extension, context)); + + if (CanInstallExtensions(context)) { + ShowParentPermissionDialogForExtension( + extension, context, contents, std::move(extension_approval_callback), + gfx::ImageSkia()); + } else { + ShowInstallBlockedByParentDialogForExtension( + extension, contents, + ExtensionInstalledBlockedByParentDialogAction::kEnable, + base::BindOnce(std::move(extension_approval_callback), + SupervisedUserExtensionsDelegate:: + ExtensionApprovalResult::kBlocked)); } } void set_next_parent_permission_dialog_result( - ParentPermissionDialogResult result) { + ExtensionApprovalResult result) { dialog_result_ = result; } @@ -991,16 +1021,19 @@ const extensions::Extension& extension, content::BrowserContext* context, content::WebContents* contents, - ParentPermissionDialogDoneCallback done_callback) { + extensions::SupervisedUserExtensionsDelegate:: + ExtensionApprovalDoneCallback done_callback, + const gfx::ImageSkia& icon) { ++show_dialog_count_; std::move(done_callback).Run(dialog_result_); } // Shows a dialog indicating that |extension| has been blocked and call // |done_callback| when it completes. - void ShowExtensionEnableBlockedByParentDialogForExtension( + void ShowInstallBlockedByParentDialogForExtension( const extensions::Extension& extension, content::WebContents* contents, + ExtensionInstalledBlockedByParentDialogAction blocked_action, base::OnceClosure done_callback) { show_block_dialog_count_++; SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics( @@ -1009,8 +1042,7 @@ std::move(done_callback).Run(); } - ParentPermissionDialogResult dialog_result_ = - ParentPermissionDialogResult::kParentPermissionFailed; + ExtensionApprovalResult dialog_result_ = ExtensionApprovalResult::kFailed; int show_dialog_count_ = 0; int show_block_dialog_count_ = 0; }; @@ -1349,8 +1381,7 @@ // Now try again with parent approval, and this should succeed. { supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved); std::string error; bool success = RunSetEnabledFunction(web_contents_.get(), extension_id, /*use_user_gesture=*/true, @@ -1401,8 +1432,7 @@ // Parent approval should fail because of the unsupported requirements. { supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved); std::string error; bool success = RunSetEnabledFunction(web_contents_.get(), extension->id(), /*user_user_gesture=*/true, @@ -1436,8 +1466,7 @@ // The parent will approve. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved); RunSetEnabledFunction(web_contents_.get(), extension->id(), /*use_user_gesture=*/true, /*accept_dialog=*/true, @@ -1523,8 +1552,7 @@ // The parent will approve. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved); // Simulate a call to chrome.management.setEnabled(). It should succeed. std::string error; @@ -1548,8 +1576,7 @@ // The parent will deny the next dialog. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionCanceled); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kCanceled); // Simulate a call to chrome.management.setEnabled(). It should not succeed. std::string error; @@ -1574,8 +1601,7 @@ // The next dialog will close due to a failure (e.g. network failure while // looking up parent information). supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionFailed); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kFailed); // Simulate a call to chrome.management.setEnabled(). It should not succeed. std::string error; @@ -1622,8 +1648,7 @@ // The parent will approve. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved); // Simulate a call to chrome.management.setEnabled(). It should succeed // despite a lack of web contents. @@ -1655,8 +1680,7 @@ // The parent will cancel. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionCanceled); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kCanceled); // Simulate a call to chrome.management.setEnabled() with no web contents. std::string error; @@ -1689,8 +1713,7 @@ // The request will fail. supervised_user_delegate_->set_next_parent_permission_dialog_result( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionFailed); + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kFailed); // Simulate a call to chrome.management.setEnabled() with no web contents. std::string error;
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc index f868851..0290398 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -72,6 +72,7 @@ // flag to #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "extensions/browser/api/management/management_api.h" #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) using safe_browsing::SafeBrowsingNavigationObserverManager; @@ -225,31 +226,6 @@ const char kParentBlockedExtensionInstallError[] = "Parent has blocked extension/app installation"; - -void ShowBlockedByParentDialog(const Extension* extension, - content::WebContents* contents, - base::OnceClosure done_callback) { - DCHECK(extension); - DCHECK(contents); - - // Need to record UMA metrics before the ScopedTestDialogAutoConfirm early - // return so tests pass. - SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics( - SupervisedUserExtensionsMetricsRecorder::EnablementState:: - kFailedToEnable); - - if (ScopedTestDialogAutoConfirm::GetAutoConfirmValue() != - ScopedTestDialogAutoConfirm::NONE) { - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, std::move(done_callback)); - return; - } - - extensions::ShowExtensionInstallBlockedByParentDialog( - extensions::ExtensionInstalledBlockedByParentDialogAction::kAdd, - extension, contents, std::move(done_callback)); -} - #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) // The number of user gestures to trace back for the referrer chain. @@ -551,11 +527,23 @@ SupervisedUserService* service = SupervisedUserServiceFactory::GetForProfile(profile_); if (profile_->IsChild() && !service->CanInstallExtensions()) { - ShowBlockedByParentDialog( - dummy_extension_.get(), web_contents, + SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate = + ManagementAPI::GetFactoryInstance() + ->Get(profile_) + ->GetSupervisedUserExtensionsDelegate(); + DCHECK(supervised_user_extensions_delegate); + auto extension_approval_callback = base::BindOnce(&WebstorePrivateBeginInstallWithManifest3Function:: - OnBlockedByParentDialogDone, - this)); + OnExtensionApprovalDone, + this); + // Assume that the block dialog will be shown here since it was checked + // that extensions cannot be installed by the child user. If extensions + // are allowed, the install prompt will be shown before the request + // permission dialog is shown. + supervised_user_extensions_delegate->RequestToAddExtensionOrShowError( + *dummy_extension_, profile_, web_contents, + gfx::ImageSkia::CreateFrom1xBitmap(icon_), + std::move(extension_approval_callback)); return; } } @@ -615,33 +603,36 @@ #if BUILDFLAG(ENABLE_SUPERVISED_USERS) -void WebstorePrivateBeginInstallWithManifest3Function::OnParentPermissionDone( - ParentPermissionDialog::Result result) { +void WebstorePrivateBeginInstallWithManifest3Function::OnExtensionApprovalDone( + SupervisedUserExtensionsDelegate::ExtensionApprovalResult result) { switch (result) { - case ParentPermissionDialog::Result::kParentPermissionReceived: - OnParentPermissionReceived(); + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved: + OnExtensionApprovalApproved(); break; - case ParentPermissionDialog::Result::kParentPermissionCanceled: - OnParentPermissionCanceled(); + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kCanceled: + OnExtensionApprovalCanceled(); break; - case ParentPermissionDialog::Result::kParentPermissionFailed: - OnParentPermissionFailed(); + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kFailed: + OnExtensionApprovalFailed(); + break; + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kBlocked: + OnExtensionApprovalBlocked(); break; } + Release(); // Matches the AddRef in Run(). } void WebstorePrivateBeginInstallWithManifest3Function:: - OnParentPermissionReceived() { + OnExtensionApprovalApproved() { SupervisedUserService* service = SupervisedUserServiceFactory::GetForProfile(profile_); service->AddExtensionApproval(*dummy_extension_); HandleInstallProceed(); - Release(); // Matches the AddRef in Run(). } void WebstorePrivateBeginInstallWithManifest3Function:: - OnParentPermissionCanceled() { + OnExtensionApprovalCanceled() { if (test_webstore_installer_delegate) { test_webstore_installer_delegate->OnExtensionInstallFailure( dummy_extension_->id(), kWebstoreParentPermissionFailedError, @@ -649,11 +640,10 @@ } HandleInstallAbort(true /* user_initiated */); - Release(); // Matches the AddRef in Run(). } void WebstorePrivateBeginInstallWithManifest3Function:: - OnParentPermissionFailed() { + OnExtensionApprovalFailed() { if (test_webstore_installer_delegate) { test_webstore_installer_delegate->OnExtensionInstallFailure( dummy_extension_->id(), kWebstoreParentPermissionFailedError, @@ -662,8 +652,12 @@ Respond(BuildResponse(api::webstore_private::RESULT_UNKNOWN_ERROR, kWebstoreParentPermissionFailedError)); +} - Release(); // Matches the AddRef in Run(). +void WebstorePrivateBeginInstallWithManifest3Function:: + OnExtensionApprovalBlocked() { + Respond(BuildResponse(api::webstore_private::RESULT_BLOCKED_FOR_CHILD_ACCOUNT, + kParentBlockedExtensionInstallError)); } bool WebstorePrivateBeginInstallWithManifest3Function:: @@ -677,28 +671,29 @@ return false; } - ParentPermissionDialog::DoneCallback done_callback = base::BindOnce( - &WebstorePrivateBeginInstallWithManifest3Function::OnParentPermissionDone, - this); + auto extension_approval_callback = + base::BindOnce(&WebstorePrivateBeginInstallWithManifest3Function:: + OnExtensionApprovalDone, + this); - parent_permission_dialog_ = - ParentPermissionDialog::CreateParentPermissionDialogForExtension( - profile_, web_contents->GetTopLevelNativeWindow(), - gfx::ImageSkia::CreateFrom1xBitmap(icon_), dummy_extension_.get(), - std::move(done_callback)); - parent_permission_dialog_->ShowDialog(); + SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate = + ManagementAPI::GetFactoryInstance() + ->Get(profile_) + ->GetSupervisedUserExtensionsDelegate(); + DCHECK(supervised_user_extensions_delegate); + + // Assume that the block dialog will not be shown by the + // SupervisedUserExtensionsDelegate, because if permissions for extensions + // were disabled, the block dialog would have been shown at the install prompt + // step. + supervised_user_extensions_delegate->RequestToAddExtensionOrShowError( + *dummy_extension_, profile_, web_contents, + gfx::ImageSkia::CreateFrom1xBitmap(icon_), + std::move(extension_approval_callback)); return true; } -void WebstorePrivateBeginInstallWithManifest3Function:: - OnBlockedByParentDialogDone() { - Respond(BuildResponse(api::webstore_private::RESULT_BLOCKED_FOR_CHILD_ACCOUNT, - kParentBlockedExtensionInstallError)); - // Matches the AddRef in Run(). - Release(); -} - #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void WebstorePrivateBeginInstallWithManifest3Function::OnFrictionPromptDone(
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h index 27d637ae0a..4d42a32 100644 --- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h +++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -27,7 +27,7 @@ // TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build // flag to #if BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/supervised_user/supervised_user_extensions_metrics_recorder.h" -#include "chrome/browser/ui/supervised_user/parent_permission_dialog.h" +#include "extensions/browser/supervised_user_extensions_delegate.h" #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) class Profile; @@ -92,19 +92,21 @@ const std::string& error_message) override; #if BUILDFLAG(ENABLE_SUPERVISED_USERS) - void OnParentPermissionDone(ParentPermissionDialog::Result result); + // Handles the result of the extension approval flow. + void OnExtensionApprovalDone( + SupervisedUserExtensionsDelegate::ExtensionApprovalResult result); - void OnParentPermissionReceived(); + void OnExtensionApprovalApproved(); - void OnParentPermissionCanceled(); + void OnExtensionApprovalCanceled(); - void OnParentPermissionFailed(); + void OnExtensionApprovalFailed(); + + void OnExtensionApprovalBlocked(); // Returns true if the parental approval prompt was shown, false if there was // an error showing it. bool PromptForParentApproval(); - - void OnBlockedByParentDialogDone(); #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void OnFrictionPromptDone(bool result); @@ -156,7 +158,6 @@ std::u16string blocked_by_policy_error_message_; #if BUILDFLAG(ENABLE_SUPERVISED_USERS) - std::unique_ptr<ParentPermissionDialog> parent_permission_dialog_; SupervisedUserExtensionsMetricsRecorder supervised_user_extensions_metrics_recorder_; #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc index 48bcd8b..14354d303 100644 --- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc +++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -70,7 +70,6 @@ #include "extensions/common/constants.h" #include "extensions/common/extension_urls.h" #include "extensions/common/manifest_constants.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/background_info.h" #include "extensions/common/manifest_handlers/web_accessible_resources_info.h" #include "extensions/common/mojom/event_router.mojom.h"
diff --git a/chrome/browser/extensions/data_deleter.cc b/chrome/browser/extensions/data_deleter.cc index fabf3b0..1b79c0a 100644 --- a/chrome/browser/extensions/data_deleter.cc +++ b/chrome/browser/extensions/data_deleter.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/extensions/chrome_extension_cookies.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_special_storage_policy.h" +#include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_io_data.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" @@ -26,7 +27,6 @@ #include "extensions/browser/extension_util.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" using base::WeakPtr; using content::BrowserContext; @@ -106,7 +106,7 @@ GURL launch_web_url_origin; StoragePartition* partition = nullptr; - if (AppIsolationInfo::HasIsolatedStorage(extension)) { + if (extensions::util::LegacyHasIsolatedStorage(extension)) { has_isolated_storage = true; ++num_tasks; } else {
diff --git a/chrome/browser/extensions/extension_garbage_collector.cc b/chrome/browser/extensions/extension_garbage_collector.cc index c87ea4a..3a546bf 100644 --- a/chrome/browser/extensions/extension_garbage_collector.cc +++ b/chrome/browser/extensions/extension_garbage_collector.cc
@@ -24,6 +24,7 @@ #include "base/time/time.h" #include "chrome/browser/extensions/extension_garbage_collector_factory.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/install_tracker.h" #include "chrome/browser/extensions/pending_extension_manager.h" #include "components/crx_file/id_util.h" @@ -37,7 +38,6 @@ #include "extensions/browser/extension_util.h" #include "extensions/common/extension.h" #include "extensions/common/file_util.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" namespace extensions { @@ -223,7 +223,7 @@ const ExtensionSet extensions = ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet(); for (const auto& ext : extensions) { - if (AppIsolationInfo::HasIsolatedStorage(ext.get())) { + if (extensions::util::LegacyHasIsolatedStorage(ext.get())) { active_paths.insert( util::GetStoragePartitionForExtensionId(ext->id(), context_) ->GetPath());
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc index 4244b31..e65bef40a 100644 --- a/chrome/browser/extensions/extension_special_storage_policy.cc +++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -24,6 +24,7 @@ #include "base/thread_annotations.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" +#include "chrome/browser/extensions/extension_util.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "components/content_settings/core/browser/cookie_settings.h" @@ -35,7 +36,6 @@ #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/content_capabilities_handler.h" #include "extensions/common/permissions/permissions_data.h" #include "url/gurl.h" @@ -229,7 +229,7 @@ APIPermissionID::kUnlimitedStorage) || extension->permissions_data()->HasAPIPermission( APIPermissionID::kFileBrowserHandler) || - extensions::AppIsolationInfo::HasIsolatedStorage(extension) || + extensions::util::LegacyHasIsolatedStorage(extension) || extension->is_app()) { if (NeedsProtection(extension) && protected_apps_.Add(extension)) { change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED; @@ -246,7 +246,7 @@ file_handler_extensions_.Add(extension); } - if (extensions::AppIsolationInfo::HasIsolatedStorage(extension)) { + if (extensions::util::LegacyHasIsolatedStorage(extension)) { isolated_extensions_.Add(extension); } } @@ -274,7 +274,7 @@ APIPermissionID::kUnlimitedStorage) || extension->permissions_data()->HasAPIPermission( APIPermissionID::kFileBrowserHandler) || - extensions::AppIsolationInfo::HasIsolatedStorage(extension) || + extensions::util::LegacyHasIsolatedStorage(extension) || extension->is_app()) { if (NeedsProtection(extension) && protected_apps_.Remove(extension)) { change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED; @@ -291,7 +291,7 @@ file_handler_extensions_.Remove(extension); } - if (extensions::AppIsolationInfo::HasIsolatedStorage(extension)) { + if (extensions::util::LegacyHasIsolatedStorage(extension)) { isolated_extensions_.Remove(extension); } }
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc index 0559630..7be06ca 100644 --- a/chrome/browser/extensions/extension_util.cc +++ b/chrome/browser/extensions/extension_util.cc
@@ -30,7 +30,6 @@ #include "extensions/common/extension.h" #include "extensions/common/extension_icon_set.h" #include "extensions/common/extension_urls.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/incognito_info.h" #include "extensions/common/manifest_handlers/permissions_parser.h" #include "extensions/common/permissions/permissions_data.h" @@ -78,10 +77,14 @@ const Extension* extension = ExtensionRegistry::Get(context)->enabled_extensions().GetByID( extension_id); + return extension && HasIsolatedStorage(*extension, context); +} +bool HasIsolatedStorage(const Extension& extension, + content::BrowserContext* context) { #if BUILDFLAG(IS_CHROMEOS_ASH) const bool is_policy_extension = - extension && Manifest::IsPolicyLocation(extension->location()); + Manifest::IsPolicyLocation(extension.location()); Profile* profile = Profile::FromBrowserContext(context); if (profile && ash::ProfileHelper::IsSigninProfile(profile) && is_policy_extension) { @@ -89,7 +92,11 @@ } #endif - return extension && AppIsolationInfo::HasIsolatedStorage(extension); + return LegacyHasIsolatedStorage(&extension); +} + +bool LegacyHasIsolatedStorage(const Extension* extension) { + return extension->is_platform_app(); } void SetIsIncognitoEnabled(const std::string& extension_id,
diff --git a/chrome/browser/extensions/extension_util.h b/chrome/browser/extensions/extension_util.h index 2d4d76d8..2235d04 100644 --- a/chrome/browser/extensions/extension_util.h +++ b/chrome/browser/extensions/extension_util.h
@@ -33,6 +33,13 @@ // the Chrome OS sign-in profile. bool HasIsolatedStorage(const std::string& extension_id, content::BrowserContext* context); +bool HasIsolatedStorage(const Extension& extension, + content::BrowserContext* context); + +// Returns whether `extension` has isolated storage due to being a platform app. +// TODO(https://crbug.com/159932): Move all callers to HasIsolatedStorage, so +// that Chrome OS sign-in profile cases are handled as well. +bool LegacyHasIsolatedStorage(const Extension* extension); // Sets whether |extension_id| can run in an incognito window. Reloads the // extension if it's enabled since this permission is applied at loading time
diff --git a/chrome/browser/extensions/extension_util_unittest.cc b/chrome/browser/extensions/extension_util_unittest.cc index 1737f9c..7778099 100644 --- a/chrome/browser/extensions/extension_util_unittest.cc +++ b/chrome/browser/extensions/extension_util_unittest.cc
@@ -12,16 +12,19 @@ #include "components/sessions/content/session_tab_helper.h" #include "content/public/test/web_contents_tester.h" #include "extensions/browser/test_extension_registry_observer.h" +#include "extensions/common/extension_builder.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/test/test_extension_dir.h" #include "url/gurl.h" namespace extensions { -using ExtensionUtilUnittest = ExtensionServiceTestBase; +class ExtensionUtilUnittest : public ExtensionServiceTestBase { + public: + void SetUp() override { InitializeEmptyExtensionService(); } +}; TEST_F(ExtensionUtilUnittest, SetAllowFileAccess) { - InitializeEmptyExtensionService(); constexpr char kManifest[] = R"({ "name": "foo", @@ -78,7 +81,6 @@ } TEST_F(ExtensionUtilUnittest, SetAllowFileAccessWhileDisabled) { - InitializeEmptyExtensionService(); constexpr char kManifest[] = R"({ "name": "foo", @@ -146,4 +148,19 @@ file_url, tab_id, nullptr, CaptureRequirement::kActiveTabOrAllUrls)); } +TEST_F(ExtensionUtilUnittest, HasIsolatedStorage) { + // Platform apps should have isolated storage. + scoped_refptr<const Extension> app = + ExtensionBuilder("foo_app", ExtensionBuilder::Type::PLATFORM_APP).Build(); + EXPECT_TRUE(app->is_platform_app()); + EXPECT_TRUE(extensions::util::HasIsolatedStorage(*app.get(), profile())); + + // Extensions should not have isolated storage. + scoped_refptr<const Extension> extension = + ExtensionBuilder("foo_ext", ExtensionBuilder::Type::EXTENSION).Build(); + EXPECT_FALSE(extension->is_platform_app()); + EXPECT_FALSE( + extensions::util::HasIsolatedStorage(*extension.get(), profile())); +} + } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index c7083a09..b0069ada 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -4436,6 +4436,11 @@ "expiry_milestone": 120 }, { + "name": "ios-password-bottom-sheet", + "owners": ["veronguyen", "sugoi", "tmartino", "bling-integrations-team@google.com"], + "expiry_milestone": 117 + }, + { "name": "ios-password-checkup", "owners": ["noemies", "eic", "bling-integrations-team@google.com"], "expiry_milestone": 117
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc index 36d5ce9..b257c9c 100644 --- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc +++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -272,6 +272,10 @@ } } +// TODO(crbug.com/1418747): The auto-join and/or "mirroring to flinging" +// features result in multiple presentations with identical presentation IDs +// of "auto-join". This is a latent bug because the rest of the code assumes +// presentation IDs are unique. void MediaRouterMojoImpl::JoinRoute(const MediaSource::Id& source_id, const std::string& presentation_id, const url::Origin& origin,
diff --git a/chrome/browser/media/router/providers/cast/cast_activity.h b/chrome/browser/media/router/providers/cast/cast_activity.h index ca42b4a..82d87047 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity.h +++ b/chrome/browser/media/router/providers/cast/cast_activity.h
@@ -31,6 +31,10 @@ class MirroringActivity; class CastSessionTracker; +using OnSourceChangedCallback = + base::RepeatingCallback<void(int old_frame_tree_node_id, + int frame_tree_node_id)>; + class CastActivityFactoryForTest { public: virtual std::unique_ptr<AppActivity> MakeAppActivity( @@ -39,7 +43,8 @@ virtual std::unique_ptr<MirroringActivity> MakeMirroringActivity( const MediaRoute& route, const std::string& app_id, - base::OnceClosure on_stop) = 0; + base::OnceClosure on_stop, + OnSourceChangedCallback on_source_changed) = 0; }; class CastActivity {
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc index 31ac203..e5007d3 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -541,12 +541,17 @@ auto on_stop = base::BindOnce(&CastActivityManager::OnActivityStopped, weak_ptr_factory_.GetWeakPtr(), route.media_route_id()); - auto activity = cast_activity_factory_for_test_ - ? cast_activity_factory_for_test_->MakeMirroringActivity( - route, app_id, std::move(on_stop)) - : std::make_unique<MirroringActivity>( - route, app_id, message_handler_, session_tracker_, - frame_tree_node_id, cast_data, std::move(on_stop)); + auto on_source_changed = base::BindRepeating( + &CastActivityManager::OnSourceChanged, weak_ptr_factory_.GetWeakPtr(), + route.media_route_id()); + auto activity = + cast_activity_factory_for_test_ + ? cast_activity_factory_for_test_->MakeMirroringActivity( + route, app_id, std::move(on_stop), std::move(on_source_changed)) + : std::make_unique<MirroringActivity>( + route, app_id, message_handler_, session_tracker_, + frame_tree_node_id, cast_data, std::move(on_stop), + std::move(on_source_changed)); activity->CreateMojoBindings(media_router_); activity->CreateMirroringServiceHost(); auto* const activity_ptr = activity.get(); @@ -666,6 +671,7 @@ void CastActivityManager::OnSourceChanged(const std::string& media_route_id, int old_frame_tree_node_id, int frame_tree_node_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto current_it = routes_by_frame_.find(old_frame_tree_node_id); if (current_it == routes_by_frame_.end() || current_it->second != media_route_id) {
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h index ab22197..d88d0f2 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -119,9 +119,10 @@ void OnMediaStatusUpdated(const MediaSinkInternal& sink, const base::Value::Dict& media_status, absl::optional<int> request_id) override; + void OnSourceChanged(const std::string& media_route_id, int old_frame_tree_node_id, - int frame_tree_node_id) override; + int frame_tree_node_id); static void SetActitityFactoryForTest(CastActivityFactoryForTest* factory) { cast_activity_factory_for_test_ = factory;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc index c767f7f6..778e73a 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
@@ -66,8 +66,8 @@ constexpr int kChannelId2 = 43; constexpr char kClientId[] = "theClientId"; constexpr char kOrigin[] = "https://google.com"; -constexpr int kFrameTreeNodeId = 1; -constexpr int kFrameTreeNodeId2 = 2; +constexpr int kFrameTreeNodeId = 123; +constexpr int kFrameTreeNodeId2 = 234; constexpr char kAppId1[] = "ABCDEFGH"; constexpr char kAppId2[] = "BBBBBBBB"; constexpr char kAppParams[] = R"( @@ -187,9 +187,10 @@ std::unique_ptr<MirroringActivity> MakeMirroringActivity( const MediaRoute& route, const std::string& app_id, - MirroringActivity::OnStopCallback on_stop) override { + MirroringActivity::OnStopCallback on_stop, + OnSourceChangedCallback on_source_changed) override { auto activity = std::make_unique<NiceMock<MockMirroringActivity>>( - route, app_id, std::move(on_stop)); + route, app_id, std::move(on_stop), std::move(on_source_changed)); mirroring_activity_ = activity.get(); mirroring_activity_callback_.Run(activity.get()); return activity; @@ -478,8 +479,12 @@ EXPECT_TRUE(manager_->GetRoute(route_id_to_terminate)); EXPECT_EQ(manager_->GetSinkForMirroringActivity(frame_id_after), sink2_); - session_tracker_->OnSourceChanged(route_id_to_move, frame_id_before, - frame_id_after); + ExpectMirroringActivityStoppedTimes(1); + ExpectSingleRouteUpdate(); + manager_->OnSourceChanged(route_id_to_move, frame_id_before, + frame_id_after); + router_remote_.FlushForTesting(); + testing::Mock::VerifyAndClearExpectations(&mock_router_); // The route with id `route_id_to_terminate` should be terminated. // `frame_id_before` should have no route connected to it. // `frame_id_after` should be connected to `route_id_to_move`. @@ -493,8 +498,9 @@ EXPECT_FALSE(manager_->GetSinkForMirroringActivity(frame_id_before)); EXPECT_EQ(manager_->GetSinkForMirroringActivity(frame_id_after), sink_); - session_tracker_->OnSourceChanged(route_id_to_move, frame_id_before, - frame_id_after); + ExpectNoRouteUpdate(); + manager_->OnSourceChanged(route_id_to_move, frame_id_before, + frame_id_after); // Nothing is expected to happen as there is no route exist for the given // `frame_id_before`. EXPECT_EQ(1u, manager_->GetRoutes().size());
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc index af7f069..e0b8095 100644 --- a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
@@ -50,6 +50,7 @@ static constexpr char kOrigin[] = "https://www.youtube.com"; static constexpr int kFrameTreeNodeId = 1; static constexpr base::TimeDelta kRouteTimeout = base::Seconds(30); +static constexpr char kRouteId[] = "test_route_id"; base::Value::Dict MakeReceiverStatus() { return base::test::ParseJsonDict(R"({ @@ -319,40 +320,42 @@ } TEST_F(CastMediaRouteProviderTest, GetMirroringStatsNoActiveMirroringActivity) { - provider_->GetMirroringStats( - "test_route_id", - base::BindOnce([](base::Value dict) { EXPECT_EQ(base::Value(), dict); })); + provider_->GetMirroringStats(kRouteId, base::BindOnce([](base::Value dict) { + EXPECT_EQ(base::Value(), dict); + })); } TEST_F(CastMediaRouteProviderTest, GetMirroringStatsNoMirroringHost) { - auto stub_route = MediaRoute("test_route_id", - MediaSource("https://example.com/receiver.html"), - "test_sink_id", "", false); + auto stub_route = + MediaRoute(kRouteId, MediaSource("https://example.com/receiver.html"), + "test_sink_id", "", false); stub_route.set_controller_type(RouteControllerType::kMirroring); auto activity = std::make_unique<NiceMock<MockMirroringActivity>>( - std::move(stub_route), "test_app_id", base::DoNothing()); + std::move(stub_route), "test_app_id", base::DoNothing(), + base::DoNothing()); provider_->GetCastActivityManagerForTest()->AddMirroringActivityForTest( - "test_route_id", std::move(activity)); - provider_->GetMirroringStats( - "test_route_id", - base::BindOnce([](base::Value dict) { EXPECT_EQ(base::Value(), dict); })); + kRouteId, std::move(activity)); + provider_->GetMirroringStats(kRouteId, base::BindOnce([](base::Value dict) { + EXPECT_EQ(base::Value(), dict); + })); } TEST_F(CastMediaRouteProviderTest, GetMirroringStats) { - auto stub_route = MediaRoute("test_route_id", - MediaSource("https://example.com/receiver.html"), - "test_sink_id", "", false); + auto stub_route = + MediaRoute(kRouteId, MediaSource("https://example.com/receiver.html"), + "test_sink_id", "", false); stub_route.set_controller_type(RouteControllerType::kMirroring); auto activity = std::make_unique<NiceMock<MockMirroringActivity>>( - std::move(stub_route), "test_app_id", base::DoNothing()); + std::move(stub_route), "test_app_id", base::DoNothing(), + base::DoNothing()); auto mirroring_service = std::make_unique<MockMirroringServiceHost>(); EXPECT_CALL(*mirroring_service, GetMirroringStats(_)); activity->SetMirroringServiceHostForTest(std::move(mirroring_service)); provider_->GetCastActivityManagerForTest()->AddMirroringActivityForTest( - "test_route_id", std::move(activity)); - provider_->GetMirroringStats("test_route_id", base::DoNothing()); + kRouteId, std::move(activity)); + provider_->GetMirroringStats(kRouteId, base::DoNothing()); } TEST_F(CastMediaRouteProviderTest, GetRemotePlaybackCompatibleSinks) {
diff --git a/chrome/browser/media/router/providers/cast/cast_session_tracker.cc b/chrome/browser/media/router/providers/cast/cast_session_tracker.cc index b7bb43b3..3fe69c2 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_tracker.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_tracker.cc
@@ -55,15 +55,6 @@ return it != sessions_by_sink_id_.end() ? it->second.get() : nullptr; } -void CastSessionTracker::OnSourceChanged(const std::string& media_route_id, - int old_frame_tree_node_id, - int frame_tree_node_id) { - for (auto& observer : observers_) { - observer.OnSourceChanged(media_route_id, old_frame_tree_node_id, - frame_tree_node_id); - } -} - CastSessionTracker::CastSessionTracker( MediaSinkServiceBase* media_sink_service, cast_channel::CastMessageHandler* message_handler,
diff --git a/chrome/browser/media/router/providers/cast/cast_session_tracker.h b/chrome/browser/media/router/providers/cast/cast_session_tracker.h index ff58ace..6d3ce7a 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_tracker.h +++ b/chrome/browser/media/router/providers/cast/cast_session_tracker.h
@@ -39,9 +39,6 @@ virtual void OnMediaStatusUpdated(const MediaSinkInternal& sink, const base::Value::Dict& media_status, absl::optional<int> request_id) = 0; - virtual void OnSourceChanged(const std::string& media_route_id, - int old_frame_tree_node_id, - int frame_tree_node_id) = 0; }; CastSessionTracker(const CastSessionTracker&) = delete; @@ -64,10 +61,6 @@ // Returns nullptr if there is no session with the specified ID. CastSession* GetSessionById(const std::string& session_id) const; - void OnSourceChanged(const std::string& media_route_id, - int old_frame_tree_node_id, - int frame_tree_node_id); - private: friend class CastSessionTrackerTest; friend class CastActivityManagerTest;
diff --git a/chrome/browser/media/router/providers/cast/cast_session_tracker_unittest.cc b/chrome/browser/media/router/providers/cast/cast_session_tracker_unittest.cc index 432da378..601101f 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_tracker_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_tracker_unittest.cc
@@ -78,11 +78,6 @@ (const MediaSinkInternal& sink, const base::Value::Dict& media_status, absl::optional<int> request_id)); - MOCK_METHOD(void, - OnSourceChanged, - (const std::string& media_route_id, - int old_frame_tree_node_id, - int frame_tree_node_id)); }; class CastSessionTrackerTest : public testing::Test {
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.cc b/chrome/browser/media/router/providers/cast/mirroring_activity.cc index c21ce18..b9c5134 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.cc
@@ -27,9 +27,8 @@ #include "chrome/browser/media/router/providers/cast/cast_activity_manager.h" #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h" #include "chrome/grit/generated_resources.h" -#include "components/media_router/browser/media_router.h" -#include "components/media_router/browser/media_router_factory.h" -#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" +#include "components/media_router/browser/media_router_debugger.h" +#include "components/media_router/browser/mirroring_to_flinging_switcher.h" #include "components/media_router/common/discovery/media_sink_internal.h" #include "components/media_router/common/mojom/media_router.mojom.h" #include "components/media_router/common/providers/cast/channel/cast_message_util.h" @@ -37,11 +36,7 @@ #include "components/media_router/common/providers/cast/channel/enum_table.h" #include "components/media_router/common/route_request_result.h" #include "components/mirroring/mojom/session_parameters.mojom.h" -#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/presentation_request.h" -#include "content/public/browser/web_contents.h" #include "media/base/media_switches.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -151,42 +146,6 @@ return model_name.find("Nest Hub") != base::StringPiece::npos; } -void AutoSwitchToFlingingIfNeeded(const std::string& sink_id, - int frame_tree_node_id) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - auto* web_contents = - content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); - if (!web_contents) - return; - - base::WeakPtr<WebContentsPresentationManager> - web_contents_presentation_manager = - WebContentsPresentationManager::Get(web_contents); - if (!web_contents_presentation_manager || - !web_contents_presentation_manager->HasDefaultPresentationRequest()) { - return; - } - - auto* media_router = MediaRouterFactory::GetApiForBrowserContextIfExists( - web_contents->GetBrowserContext()); - if (!media_router) - return; - - const auto& presentation_request = - web_contents_presentation_manager->GetDefaultPresentationRequest(); - const auto source_id = - MediaSource::ForPresentationUrl(presentation_request.presentation_urls[0]) - .id(); - bool incognito = web_contents->GetBrowserContext()->IsOffTheRecord(); - media_router->JoinRoute( - source_id, kAutoJoinPresentationId, presentation_request.frame_origin, - web_contents, - base::BindOnce(&WebContentsPresentationManager::OnPresentationResponse, - std::move(web_contents_presentation_manager), - presentation_request), - base::TimeDelta(), incognito); -} - bool IsRtcpReportingEnabled(int frame_tree_node_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); auto* debugger = MediaRouterDebugger::GetForFrameTreeNode(frame_tree_node_id); @@ -203,12 +162,14 @@ CastSessionTracker* session_tracker, int frame_tree_node_id, const CastSinkExtraData& cast_data, - OnStopCallback callback) + OnStopCallback callback, + OnSourceChangedCallback source_changed_callback) : CastActivity(route, app_id, message_handler, session_tracker), mirroring_type_(GetMirroringType(route)), frame_tree_node_id_(frame_tree_node_id), cast_data_(cast_data), - on_stop_(std::move(callback)) {} + on_stop_(std::move(callback)), + source_changed_callback_(std::move(source_changed_callback)) {} MirroringActivity::~MirroringActivity() { if (!did_start_mirroring_timestamp_) { @@ -370,20 +331,17 @@ void MirroringActivity::OnSourceChanged() { DCHECK(host_); absl::optional<int> frame_tree_node_id = host_->GetTabSourceId(); - if (!frame_tree_node_id || frame_tree_node_id == frame_tree_node_id_) { + if (!source_changed_callback_ || !frame_tree_node_id || + frame_tree_node_id == frame_tree_node_id_) { return; } - session_tracker_->OnSourceChanged(route_.media_route_id(), - frame_tree_node_id_, *frame_tree_node_id); + source_changed_callback_.Run(frame_tree_node_id_, *frame_tree_node_id); frame_tree_node_id_ = *frame_tree_node_id; - // Posting to UI thread, as while obtaining WebContents instance through - // `FromFrameTreeNodeId()`, a call to `GloballyFindByID()` would happen and - // that is only allowed on UI thread. content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&AutoSwitchToFlingingIfNeeded, - route_.media_sink_id(), frame_tree_node_id_)); + FROM_HERE, + base::BindOnce(&SwitchToFlingingIfPossible, frame_tree_node_id_)); } void MirroringActivity::OnMessage(mirroring::mojom::CastMessagePtr message) {
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity.h b/chrome/browser/media/router/providers/cast/mirroring_activity.h index baeb31e4f..ded5e94 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity.h +++ b/chrome/browser/media/router/providers/cast/mirroring_activity.h
@@ -51,7 +51,8 @@ CastSessionTracker* session_tracker, int frame_tree_node_id, const CastSinkExtraData& cast_data, - OnStopCallback callback); + OnStopCallback callback, + OnSourceChangedCallback source_changed_callback); ~MirroringActivity() override; virtual void CreateMojoBindings(mojom::MediaRouter* media_router); @@ -150,6 +151,7 @@ int frame_tree_node_id_; const CastSinkExtraData cast_data_; OnStopCallback on_stop_; + OnSourceChangedCallback source_changed_callback_; base::WeakPtrFactory<MirroringActivity> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc b/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc index aed6364..4232470 100644 --- a/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc +++ b/chrome/browser/media/router/providers/cast/mirroring_activity_unittest.cc
@@ -51,27 +51,6 @@ constexpr char kHistogramSessionLengthTab[] = "MediaRouter.CastStreaming.Session.Length.Tab"; -class MockCastSessionTrackerObserver : public CastSessionTracker::Observer { - public: - MockCastSessionTrackerObserver() = default; - ~MockCastSessionTrackerObserver() override = default; - - MOCK_METHOD(void, - OnSessionAddedOrUpdated, - (const MediaSinkInternal& sink, const CastSession& session)); - MOCK_METHOD(void, OnSessionRemoved, (const MediaSinkInternal& sink)); - MOCK_METHOD(void, - OnMediaStatusUpdated, - (const MediaSinkInternal& sink, - const base::Value::Dict& media_status, - absl::optional<int> request_id)); - MOCK_METHOD(void, - OnSourceChanged, - (const std::string& media_route_id, - int old_frame_tree_node_id, - int frame_tree_node_id)); -}; - class MockMirroringServiceHostFactory : public mirroring::MirroringServiceHostFactory { public: @@ -134,7 +113,7 @@ route.set_presentation_id(kPresentationId); activity_ = std::make_unique<MirroringActivity>( route, kAppId, &message_handler_, &session_tracker_, frame_tree_node_id, - cast_data, on_stop_.Get()); + cast_data, on_stop_.Get(), on_source_changed_.Get()); activity_->CreateMojoBindings(&media_router_); activity_->CreateMirroringServiceHost(&mirroring_service_host_factory_); @@ -167,6 +146,7 @@ NiceMock<MockMirroringServiceHostFactory> mirroring_service_host_factory_; NiceMock<MockMojoMediaRouter> media_router_; base::MockCallback<MirroringActivity::OnStopCallback> on_stop_; + base::MockCallback<OnSourceChangedCallback> on_source_changed_; std::unique_ptr<MirroringActivity> activity_; }; @@ -466,14 +446,11 @@ TEST_F(MirroringActivityTest, OnSourceChanged) { MakeActivity(); - MockCastSessionTrackerObserver session_tracker_observer_; - session_tracker_.AddObserver(&session_tracker_observer_); // A random int indicating the new tab source. const int new_tab_source = 3; - EXPECT_CALL(session_tracker_observer_, - OnSourceChanged(kRouteId, kFrameTreeNodeId, new_tab_source)); + EXPECT_CALL(on_source_changed_, Run(kFrameTreeNodeId, new_tab_source)); EXPECT_CALL(*mirroring_service_, GetTabSourceId()) .WillOnce(testing::Return(new_tab_source)); @@ -481,8 +458,8 @@ EXPECT_EQ(activity_->frame_tree_node_id_, kFrameTreeNodeId); activity_->OnSourceChanged(); EXPECT_EQ(activity_->frame_tree_node_id_, new_tab_source); + RunUntilIdle(); testing::Mock::VerifyAndClearExpectations(mirroring_service_); - testing::Mock::VerifyAndClearExpectations(&session_tracker_observer_); // Nothing should happen as no value was returned for tab source. EXPECT_CALL(*mirroring_service_, GetTabSourceId())
diff --git a/chrome/browser/media/router/providers/cast/mock_mirroring_activity.cc b/chrome/browser/media/router/providers/cast/mock_mirroring_activity.cc index e4aae20..2f40e16 100644 --- a/chrome/browser/media/router/providers/cast/mock_mirroring_activity.cc +++ b/chrome/browser/media/router/providers/cast/mock_mirroring_activity.cc
@@ -6,16 +6,19 @@ namespace media_router { -MockMirroringActivity::MockMirroringActivity(const MediaRoute& route, - const std::string& app_id, - OnStopCallback on_stop) +MockMirroringActivity::MockMirroringActivity( + const MediaRoute& route, + const std::string& app_id, + OnStopCallback on_stop, + OnSourceChangedCallback on_source_changed) : MirroringActivity(route, app_id, nullptr, nullptr, 0, CastSinkExtraData(), - std::move(on_stop)) {} + std::move(on_stop), + std::move(on_source_changed)) {} MockMirroringActivity::~MockMirroringActivity() = default;
diff --git a/chrome/browser/media/router/providers/cast/mock_mirroring_activity.h b/chrome/browser/media/router/providers/cast/mock_mirroring_activity.h index ad5ebcb..28e886f 100644 --- a/chrome/browser/media/router/providers/cast/mock_mirroring_activity.h +++ b/chrome/browser/media/router/providers/cast/mock_mirroring_activity.h
@@ -14,7 +14,8 @@ public: MockMirroringActivity(const MediaRoute& route, const std::string& app_id, - OnStopCallback on_stop); + OnStopCallback on_stop, + OnSourceChangedCallback on_source_changed); ~MockMirroringActivity() override; MOCK_METHOD(void, CreateMojoBindings, (mojom::MediaRouter * media_router));
diff --git a/chrome/browser/metrics/perf/profile_provider_unittest_main.cc b/chrome/browser/metrics/perf/profile_provider_unittest_main.cc index f086938..2e7c6cd 100644 --- a/chrome/browser/metrics/perf/profile_provider_unittest_main.cc +++ b/chrome/browser/metrics/perf/profile_provider_unittest_main.cc
@@ -184,6 +184,7 @@ StopSpinningCPU(); profile_provider_.reset(); + aura_env_.reset(); TestingBrowserProcess::DeleteInstance(); ash::LoginState::Shutdown(); chromeos::PowerManagerClient::Shutdown();
diff --git a/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc b/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc index 43eaec9ee..e7f6afc 100644 --- a/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc +++ b/chrome/browser/new_tab_page/modules/new_tab_page_modules.cc
@@ -26,6 +26,11 @@ bool drive_module_enabled) { std::vector<std::pair<const std::string, int>> details; + if (base::FeatureList::IsEnabled(ntp_features::kNtpHistoryClustersModule)) { + details.emplace_back("history_clusters", + IDS_HISTORY_CLUSTERS_JOURNEYS_TAB_LABEL); + } + if (IsRecipeTasksModuleEnabled()) { std::vector<std::string> splitExperimentGroup = base::SplitString( base::GetFieldTrialParamValueByFeature( @@ -58,11 +63,6 @@ details.emplace_back("feed", IDS_NTP_MODULES_FEED_TITLE); } - if (base::FeatureList::IsEnabled(ntp_features::kNtpHistoryClustersModule)) { - details.emplace_back("history_clusters", - IDS_HISTORY_CLUSTERS_JOURNEYS_TAB_LABEL); - } - #if !defined(OFFICIAL_BUILD) if (base::FeatureList::IsEnabled(ntp_features::kNtpDummyModules)) { details.emplace_back("dummy", IDS_NTP_MODULES_DUMMY_TITLE);
diff --git a/chrome/browser/resources/bookmarks/folder_node.ts b/chrome/browser/resources/bookmarks/folder_node.ts index 3875a2d..1bb58993 100644 --- a/chrome/browser/resources/bookmarks/folder_node.ts +++ b/chrome/browser/resources/bookmarks/folder_node.ts
@@ -32,14 +32,6 @@ } export class BookmarksFolderNodeElement extends BookmarksFolderNodeElementBase { - constructor() { - super(); - // TODO(dizhangg): With KeyboardFocusableScrollers enabled, need - // delegatesFocus=true so bookmarks-folder-node shadow root doesn't get - // focused. - this.attachShadow({mode: 'open', delegatesFocus: true}); - } - static get is() { return 'bookmarks-folder-node'; }
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/history_clusters.gni b/chrome/browser/resources/new_tab_page/modules/history_clusters/history_clusters.gni index dabeb651..6074d25 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/history_clusters.gni +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/history_clusters.gni
@@ -5,6 +5,7 @@ # List of files that should be passed to html_to_wrapper(). history_clusters_web_component_files = [ "modules/history_clusters/module.ts", + "modules/history_clusters/page_favicon.ts", "modules/history_clusters/suggest_tile.ts", "modules/history_clusters/tile.ts", ]
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/module.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/module.html index 7dec43f..aa23bda 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/module.html +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/module.html
@@ -19,9 +19,9 @@ .small-tiles { display: flex; flex-direction: row; + gap: 16px; grid-column: 2 / 3; grid-row: 1 / 2; - justify-content: space-between; } .layout { @@ -55,13 +55,13 @@ </style> <div id="content"> <ntp-module-header - disable-text="[[i18n('modulesDisableButtonText', cluster.label)]]" + disable-text="[[i18n('modulesDisableButtonText', title_)]]" show-dismiss-button - dismiss-text="[[i18n('modulesDismissButtonText', cluster.label)]]" + dismiss-text="[[i18n('modulesDismissButtonText', title_)]]" on-disable-button-click="onDisableButtonClick_" show-info-button on-info-button-click="onInfoButtonClick_" icon-src="chrome://resources/images/icon_journeys.svg"> - [[i18n('modulesJourneysResumeJourney', cluster.label)]] + [[i18n('modulesJourneysResumeJourney', title_)]] <button id="showAllButton" type="button" on-click="onShowAllClick_" slot="title-actions"> [[i18n('modulesJourneyShowAll')]]
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/module.ts b/chrome/browser/resources/new_tab_page/modules/history_clusters/module.ts index 2c9360e..2c2128947 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/module.ts
@@ -53,13 +53,23 @@ /** The cluster displayed by this element. */ cluster: Object, searchResultPage: Object, + title_: { + type: String, + computed: 'computeClusterTitle_(cluster)', + }, }; } + private title_: string; cluster: Cluster; layoutType: HistoryClusterLayoutType; searchResultPage: URLVisit; + private computeClusterTitle_() { + return this.cluster.label ? this.cluster.label : + this.searchResultPage.pageTitle; + } + private isLayout_(type: HistoryClusterLayoutType): boolean { return type === this.layoutType; }
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.html new file mode 100644 index 0000000..814aea58 --- /dev/null +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.html
@@ -0,0 +1,15 @@ +<style> + :host { + align-items: center; + background-color: var(--google-grey-50); + background-position: center; + background-repeat: no-repeat; + border-radius: 5px; + display: flex; + flex-shrink: 0; + height: 36px; + justify-content: center; + margin-inline: 0 12px; + width: 36px; + } +</style>
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.ts b/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.ts new file mode 100644 index 0000000..c9b8d804 --- /dev/null +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/page_favicon.ts
@@ -0,0 +1,73 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; + +import {getFaviconForPageURL} from 'chrome://resources/js/icon.js'; +import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './page_favicon.html.js'; + +/** + * @fileoverview This file provides a custom element displaying a page favicon. + */ + +declare global { + interface HTMLElementTagNameMap { + 'page-favicon': PageFavicon; + } +} + +class PageFavicon extends PolymerElement { + static get is() { + return 'page-favicon'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + /* The element's style attribute. */ + style: { + type: String, + computed: `computeStyle_(url, imageUrl)`, + reflectToAttribute: true, + }, + + /* The URL for which the favicon is shown. */ + url: Object, + + /** + * Whether this visit is known to sync already. Used for the purpose of + * fetching higher quality favicons in that case. + */ + isKnownToSync: Boolean, + }; + } + + //============================================================================ + // Properties + //============================================================================ + + url: Url; + isKnownToSync: boolean; + + //============================================================================ + // Helper methods + //============================================================================ + + private computeStyle_(): string { + if (!this.url) { + return ''; + } + return `background-image:${ + getFaviconForPageURL( + this.url.url, this.isKnownToSync, '', /** --favicon-size */ 16)}`; + } +} + +customElements.define(PageFavicon.is, PageFavicon);
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html index bf8a1026..6a794ef 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html
@@ -6,6 +6,13 @@ width: 100%; } + a:link, + a:visited, + a:hover, + a:active { + text-decoration: none; + } + .related-search { background: var(--color-new-tab-page-history-clusters-module-item-background);
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html index 20180ba..0d7c62c 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html
@@ -1,5 +1,5 @@ <style include="history-clusters-shared-style"> - #content { + :host { background: var(--color-new-tab-page-history-clusters-module-item-background); border-radius: 25px; @@ -8,9 +8,11 @@ width: 100%; } - :host([large-format]) #content { - display: flex; - flex-direction: column; + a:link, + a:visited, + a:hover, + a:active { + text-decoration: none; } :host([medium-format]) #content { @@ -18,11 +20,6 @@ flex-direction: row; } - :host([small-format]) #content { - display: flex; - flex-direction: column; - } - #image { background: red; border-radius: 25px; @@ -44,16 +41,11 @@ display: none; } - /* TODO(crbug.com/1418528): Add favicon */ - /*#icon {*/ - /* background-color: white;*/ - /* height: 16px;*/ - /* margin-inline-end: 8px;*/ - /* width: 16px;*/ - /*}*/ - - :host([medium-format]) #icon { - margin-inline-start: 8px; + #icon { + background-color: white; + height: 16px; + margin-inline-end: 8px; + width: 16px; } #title { @@ -65,7 +57,7 @@ :host([large-format]) #title { height: 48px; max-width: 298px; - padding: 16px 24px 24px; + padding: 16px 16px 24px; } :host([medium-format]) #title { @@ -85,13 +77,16 @@ display: flex; flex-direction: row; font-size: 11px; - margin-inline-start: 24px; + margin-inline: 16px; + } + + :host([medium-format]) #info-container { + margin-inline-start: 8px; } :host([small-format]) #info-container { height: 20px; margin-bottom: 14px; - margin-inline-start: 16px; } #label, @@ -101,7 +96,7 @@ } :host([large-format]) #label { - max-width: 200px; + max-width: 220px; } :host([medium-format]) #label { @@ -109,7 +104,7 @@ } :host([small-format]) #label, - #dot { + :host([small-format]) #dot { display: none; } @@ -123,6 +118,9 @@ <div id="text-container"> <div id="title" class="truncate">[[visit.pageTitle]]</div> <div id="info-container"> + <page-favicon id="icon" url="[[visit.normalizedUrl]]" + is-known-to-sync="[[visit.isKnownToSync]]"> + </page-favicon> <div id="label" class="truncate"> [[label_]]</div> <span id="dot"> • </span> <div id="date">[[visit.relativeDate]]</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.ts b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.ts index bf2e6f0..f33295de 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.ts +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.ts
@@ -3,6 +3,7 @@ // found in the LICENSE file. import 'chrome://resources/cr_components/history_clusters/history_clusters_shared_style.css.js'; +import './page_favicon.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -45,7 +46,9 @@ } private computeLabel_(): string { - return this.visit.urlForDisplay; + let domain = (new URL(this.visit.normalizedUrl.url)).hostname; + domain = domain.replace('www.', ''); + return domain; } }
diff --git a/chrome/browser/resources/print_preview/ui/sidebar.html b/chrome/browser/resources/print_preview/ui/sidebar.html index 60e14d2..24c24911 100644 --- a/chrome/browser/resources/print_preview/ui/sidebar.html +++ b/chrome/browser/resources/print_preview/ui/sidebar.html
@@ -39,10 +39,7 @@ error="[[error]]" sheet-count="[[sheetCount_]]" state="[[state]]" settings="[[settings]]" managed="[[controlsManaged]]"> </print-preview-header> -<!-- TODO(dizhangg): Need negative tabindex so the container doesn't get - focused. Delete this comment when KeyboardFocusableScrollers is enabled - by default. --> -<div id="container" show-bottom-shadow tabindex="-1"> +<div id="container" show-bottom-shadow> <print-preview-destination-settings id="destinationSettings" dark="[[inDarkMode]]" destination="{{destination}}" destination-state="{{destinationState}}"
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.html b/chrome/browser/resources/settings/autofill_page/payments_section.html index 2e1fd57..830b50e 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_section.html +++ b/chrome/browser/resources/settings/autofill_page/payments_section.html
@@ -113,7 +113,9 @@ class$="list-frame [[computeCssClass_( removeCardExpirationAndTypeTitlesEnabled_)]]" credit-cards="[[creditCards]]" ibans="[[ibans]]" upi-ids="[[upiIds]]" - on-dots-iban-menu-click="onDotsIbanMenuClick_"> + on-dots-iban-menu-click="onDotsIbanMenuClick_" + on-dots-card-menu-click="onCreditCardDotsMenuClick_" + on-remote-card-menu-click="onRemoteEditCreditCardClick_"> </settings-payments-list> <cr-action-menu id="creditCardSharedMenu" role-description="$i18n{menu}"> @@ -160,7 +162,7 @@ <template is="dom-if" if="[[showCreditCardDialog_]]" restamp> <settings-credit-card-edit-dialog credit-card="[[activeCreditCard_]]" - on-close="onCreditCardDialogClose_"> + on-close="onCreditCardDialogClose_" on-save-credit-card="saveCreditCard_"> </settings-credit-card-edit-dialog> </template> <template is="dom-if" if="[[showIbanDialog_]]" restamp> @@ -171,7 +173,8 @@ <template is="dom-if" if="[[showVirtualCardUnenrollDialog_]]" restamp> <settings-virtual-card-unenroll-dialog credit-card="[[activeCreditCard_]]" - on-close="onVirtualCardUnenrollDialogClose_"> + on-close="onVirtualCardUnenrollDialogClose_" + on-unenroll-virtual-card="unenrollVirtualCard_"> </settings-virtual-card-unenroll-dialog> </template>
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.ts b/chrome/browser/resources/settings/autofill_page/payments_section.ts index 91bb0e7..663a140 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_section.ts +++ b/chrome/browser/resources/settings/autofill_page/payments_section.ts
@@ -197,33 +197,11 @@ private migrationEnabled_: boolean; private removeCardExpirationAndTypeTitlesEnabled_: boolean; private virtualCardEnrollmentEnabled_: boolean; - private activeDialogAnchor_: HTMLElement|null; + private activeDialogAnchor_: HTMLElement|null = null; private paymentsManager_: PaymentsManagerProxy = PaymentsManagerImpl.getInstance(); private setPersonalDataListener_: PersonalDataChangedListener|null = null; - constructor() { - super(); - - /** - * The element to return focus to; when the currently active dialog is - * closed. - */ - this.activeDialogAnchor_ = null; - } - - override ready() { - super.ready(); - - // TODO(crbug.com/1409766): Add the listener declaratively for all above. - this.addEventListener('save-credit-card', this.saveCreditCard_); - this.addEventListener( - 'dots-card-menu-click', this.onCreditCardDotsMenuClick_); - this.addEventListener( - 'remote-card-menu-click', this.onRemoteEditCreditCardClick_); - this.addEventListener('unenroll-virtual-card', this.unenrollVirtualCard_); - } - override connectedCallback() { super.connectedCallback();
diff --git a/chrome/browser/resources/settings/chromeos/device_page/storage.html b/chrome/browser/resources/settings/chromeos/device_page/storage.html index 879f6b4..0fea6718 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/storage.html +++ b/chrome/browser/resources/settings/chromeos/device_page/storage.html
@@ -202,7 +202,7 @@ role-description="$i18n{subpageArrowRoleDescription}"> </cr-link-row> </template> -<template is="dom-if" if="[[!isGuest_]]"> +<template is="dom-if" if="[[!isEphemeralUser_]]"> <div id="systemSize" class="settings-box two-line single-column stretch settings-box-text" aria-describedby="systemSizeLabel"
diff --git a/chrome/browser/resources/settings/chromeos/device_page/storage.ts b/chrome/browser/resources/settings/chromeos/device_page/storage.ts index f737184..5f94a3c9 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/storage.ts +++ b/chrome/browser/resources/settings/chromeos/device_page/storage.ts
@@ -4,12 +4,12 @@ import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; -import 'chrome://resources/cr_elements/icons.html.js'; import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; +import 'chrome://resources/cr_elements/icons.html.js'; import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import './storage_external.js'; import '../../prefs/prefs.js'; import '../../settings_shared.css.js'; +import './storage_external.js'; import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; @@ -68,18 +68,18 @@ showCrostini: Boolean, - isGuest_: { + isEphemeralUser_: { type: Boolean, value() { - return loadTimeData.getBoolean('isGuest'); + return loadTimeData.getBoolean('isCryptohomeDataEphemeral'); }, }, showOtherUsers_: { type: Boolean, - // Initialize showOtherUsers_ to false if the user is in guest mode. + // Initialize showOtherUsers_ to false if the user is ephemeral. value() { - return !loadTimeData.getBoolean('isGuest'); + return !loadTimeData.getBoolean('isCryptohomeDataEphemeral'); }, }, @@ -93,7 +93,7 @@ showCrostini: boolean; private browserProxy_: DevicePageBrowserProxy; - private isGuest_: boolean; + private isEphemeralUser_: boolean; private route_: Route; private showCrostiniStorage_: boolean; private showDriveOfflineStorage_: boolean; @@ -287,7 +287,7 @@ */ private handleOtherUsersSizeChanged_(size: string, noOtherUsers: boolean): void { - if (this.isGuest_ || noOtherUsers) { + if (this.isEphemeralUser_ || noOtherUsers) { this.showOtherUsers_ = false; return; }
diff --git a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.html b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.html index 3033ada..6d73e6c 100644 --- a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.html +++ b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.html
@@ -228,6 +228,11 @@ .action-button:focus { box-shadow: none; } + + cr-toast { + justify-content: space-between; + margin: 58px 8px; + } </style> <div id="container" role="treeitem" aria-expanded="[[open_]]"> @@ -284,4 +289,10 @@ </button> </template> </template> + <cr-toast id="errorToast" duration="5000"> + <div>$i18n{shoppingListErrorMessage}</div> + <cr-button on-click="onErrorRetryClicked_"> + $i18n{shoppingListErrorButton} + </cr-button> + </cr-toast> </div>
diff --git a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts index ab8ea13..80379b93 100644 --- a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts +++ b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts
@@ -6,8 +6,10 @@ import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; import 'chrome://resources/cr_elements/mwb_element_shared_style.css.js'; import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; +import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import './icons.html.js'; +import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import {getFaviconForPageURL} from 'chrome://resources/js/icon.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -25,6 +27,12 @@ export const ACTION_BUTTON_UNTRACK_IMAGE = 'shopping-list:shopping-list-untrack-icon'; +export interface ShoppingListElement { + $: { + errorToast: CrToastElement, + }; +} + export class ShoppingListElement extends PolymerElement { static get is() { return 'shopping-list'; @@ -62,6 +70,7 @@ private shoppingListApi_: ShoppingListApiProxy = ShoppingListApiProxyImpl.getInstance(); private listenerIds_: number[] = []; + private retryOperationCallback_: () => void; override connectedCallback() { super.connectedCallback(); @@ -73,6 +82,9 @@ this.onBookmarkPriceTracked(product)), callbackRouter.priceUntrackedForBookmark.addListener( (bookmarkId: bigint) => this.onBookmarkPriceUntracked(bookmarkId)), + callbackRouter.operationFailedForBookmark.addListener( + (bookmarkId: bigint, attemptedTrack: boolean) => + this.onBookmarkOperationFailed(bookmarkId, attemptedTrack)), ); try { this.open_ = @@ -241,6 +253,26 @@ chrome.metricsPrivate.recordBoolean( 'Commerce.PriceTracking.SidePanelImageLoad', false); } + + private onBookmarkOperationFailed( + bookmarkId: bigint, attemptedTrack: boolean) { + this.retryOperationCallback_ = () => { + if (attemptedTrack) { + this.shoppingListApi_.trackPriceForBookmark(bookmarkId); + } else { + this.shoppingListApi_.untrackPriceForBookmark(bookmarkId); + } + }; + this.$.errorToast.show(); + } + + private onErrorRetryClicked_() { + if (this.retryOperationCallback_ == null) { + return; + } + this.retryOperationCallback_(); + this.$.errorToast.hide(); + } } declare global {
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service.cc index 7d15f0ea..281a0af 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/cloud_binary_upload_service.cc
@@ -319,7 +319,8 @@ request->set_fcm_token(instance_id); - if (CanUseAccessToken(*request, profile_)) { + if (base::FeatureList::IsEnabled(kConnectorsScanningAccessToken) && + CanUseAccessToken(*request, profile_)) { if (!token_fetcher_) { token_fetcher_ = std::make_unique<SafeBrowsingPrimaryAccountTokenFetcher>( IdentityManagerFactory::GetForProfile(profile_));
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc index d5f6528..f842fca1 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
@@ -321,6 +321,9 @@ event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent; threat_type_ = expected_threat_type; dlp_verdicts_.erase(expected_filename); + scan_ids_.erase(expected_filename); + source_.reset(); + destination_.reset(); ValidateReport(&report); if (!done_closure_.is_null()) { done_closure_.Run(); @@ -568,8 +571,7 @@ << "Mismatch in field " << field_key; } else { ASSERT_EQ(nullptr, value->FindString(field_key)) - << "Field " << field_key << " should not be populated. It has value " - << *value->FindString(field_key); + << "Field " << field_key << " should not be populated"; } } @@ -584,8 +586,7 @@ << "Mismatch in field " << field_key; } else { ASSERT_EQ(nullptr, s) << "Field " << field_key - << " should not be populated. It has value " - << *value->FindString(field_key); + << " should not be populated"; } }
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc index 5b91f16..64204c63 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc
@@ -49,7 +49,6 @@ #include "components/enterprise/common/proto/connectors.pb.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/prefs/pref_service.h" -#include "components/safe_browsing/content/common/file_type_policies_test_util.h" #include "components/safe_browsing/core/browser/db/test_database_manager.h" #include "components/safe_browsing/core/common/features.h" #include "components/safe_browsing/core/common/proto/csd.pb.h" @@ -135,7 +134,11 @@ explicit DownloadDeepScanningBrowserTestBase(bool connectors_machine_scope, bool is_consumer) : is_consumer_(is_consumer), - connectors_machine_scope_(connectors_machine_scope) {} + connectors_machine_scope_(connectors_machine_scope) { + scoped_feature_list_.InitWithFeatures( + {}, {kSafeBrowsingEnterpriseCsd, + kSafeBrowsingDisableConsumerCsdForEnterprise}); + } void OnDownloadCreated(content::DownloadManager* manager, download::DownloadItem* item) override { @@ -480,6 +483,8 @@ bool connectors_machine_scope_; mojo::Remote<network::mojom::DataPipeGetter> data_pipe_getter_; + + base::test::ScopedFeatureList scoped_feature_list_; }; class ConsumerDeepScanningBrowserTest @@ -693,6 +698,33 @@ } IN_PROC_BROWSER_TEST_P(DownloadDeepScanningBrowserTest, + DangerousHostNotMalwareScanned) { + base::HistogramTester histograms; + + // The file is DANGEROUS_HOST according to the metadata check + ClientDownloadResponse metadata_response; + metadata_response.set_verdict(ClientDownloadResponse::DANGEROUS_HOST); + ExpectMetadataResponse(metadata_response); + + GURL url = embedded_test_server()->GetURL( + "/safe_browsing/download_protection/signed.exe"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + + WaitForDownloadToFinish(); + + // The file should be blocked. + ASSERT_EQ(download_items().size(), 1u); + download::DownloadItem* item = *download_items().begin(); + EXPECT_EQ(item->GetDangerType(), + download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST); + EXPECT_EQ(item->GetState(), download::DownloadItem::IN_PROGRESS); + + histograms.ExpectTotalCount("SafeBrowsingBinaryUploadRequest.Result", 0); +} + +IN_PROC_BROWSER_TEST_P(DownloadDeepScanningBrowserTest, PasswordProtectedTxtFilesAreBlocked) { // This allows the blocking DM token reads happening on profile-Connector // triggers. @@ -822,6 +854,11 @@ SetUpReporting(); base::HistogramTester histograms; + // The file is POTENTIALLY_UNWANTED according to the metadata check + ClientDownloadResponse metadata_response; + metadata_response.set_verdict(ClientDownloadResponse::POTENTIALLY_UNWANTED); + ExpectMetadataResponse(metadata_response); + GURL url = embedded_test_server()->GetURL( "/safe_browsing/download_protection/zipfile_two_archives.zip"); ui_test_utils::NavigateToURLWithDisposition( @@ -829,7 +866,7 @@ ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); // The DLP scan finishes synchronously and find a violation. Malware scanning - // finds violation. + // finds nothing. enterprise_connectors::ContentAnalysisResponse sync_response; auto* dlp_result = sync_response.add_results(); dlp_result->set_tag("dlp"); @@ -842,11 +879,9 @@ malware_result->set_tag("malware"); malware_result->set_status( enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS); - auto* malware_rule = malware_result->add_triggered_rules(); - malware_rule->set_action(enterprise_connectors::TriggeredRule::WARN); - malware_rule->set_rule_name("uws"); ExpectContentAnalysisSynchronousResponse(sync_response, {"dlp", "malware"}); + WaitForMetadataCheck(); WaitForDeepScanRequest(); // Both the DLP and malware violations generate an event. @@ -927,27 +962,34 @@ IN_PROC_BROWSER_TEST_P(DownloadRestrictionsDeepScanningBrowserTest, ReportsDownloadsBlockedByDownloadRestrictions) { - safe_browsing::FileTypePoliciesTestOverlay scoped_all_file_types_dangerous = - safe_browsing::ScopedMarkAllFilesDangerousForTesting(); - // This allows the blocking DM token reads happening on profile-Connector // triggers. base::ScopedAllowBlockingForTesting allow_blocking; SetUpReporting(); + // The file is DANGEROUS according to the metadata check + ClientDownloadResponse metadata_response; + metadata_response.set_verdict(ClientDownloadResponse::DANGEROUS); + ExpectMetadataResponse(metadata_response); + GURL url = embedded_test_server()->GetURL( "/safe_browsing/download_protection/zipfile_two_archives.zip"); ui_test_utils::NavigateToURLWithDisposition( browser(), url, WindowOpenDisposition::CURRENT_TAB, - ui_test_utils::BROWSER_TEST_NONE); + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + + WaitForMetadataCheck(); EventReportValidator validator(client()); std::set<std::string> zip_types = {"application/zip", "application/x-zip-compressed"}; validator.ExpectDangerousDownloadEvent( /*url*/ url.spec(), - /*filename*/ "zipfile_two_archives.zip", + (*download_items().begin()) + ->GetTargetFilePath() + .BaseName() + .AsUTF8Unsafe(), // sha256sum chrome/test/data/safe_browsing/download_protection/\ // zipfile_two_archives.zip | tr '[:lower:]' '[:upper:]' /*sha*/ @@ -993,7 +1035,7 @@ testing::Bool()); IN_PROC_BROWSER_TEST_P(AllowlistedUrlDeepScanningBrowserTest, - AllowlistedUrlStillDoesDlpAndMalware) { + AllowlistedUrlStillDoesDlp) { // This allows the blocking DM token reads happening on profile-Connector // triggers. base::ScopedAllowBlockingForTesting allow_blocking; @@ -1011,20 +1053,13 @@ enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS); auto* dlp_rule = result->add_triggered_rules(); dlp_rule->set_action(enterprise_connectors::TriggeredRule::BLOCK); - - // The malware scan also runs synchronously, but finds no violation - result = sync_response.add_results(); - result->set_tag("malware"); - result->set_status( - enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS); - - ExpectContentAnalysisSynchronousResponse(sync_response, {"dlp", "malware"}); + ExpectContentAnalysisSynchronousResponse(sync_response, {"dlp"}); GURL url = embedded_test_server()->GetURL( "/safe_browsing/download_protection/zipfile_two_archives.zip"); ui_test_utils::NavigateToURLWithDisposition( browser(), url, WindowOpenDisposition::CURRENT_TAB, - ui_test_utils::BROWSER_TEST_NONE); + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); WaitForDeepScanRequest(); @@ -1039,6 +1074,309 @@ EXPECT_EQ(item->GetState(), download::DownloadItem::INTERRUPTED); } +enum class ScanningVerdict { MALWARE, UNWANTED, SAFE }; + +// This test validates that metadata check verdicts and deep scanning verdicts +// override each other correctly and only report up to 1 event. +class MetadataCheckAndDeepScanningBrowserTest + : public DownloadDeepScanningBrowserTestBase, + public testing::WithParamInterface< + std::tuple<ClientDownloadResponse::Verdict, + ScanningVerdict, + /*connectors_machine_scope*/ bool>> { + public: + MetadataCheckAndDeepScanningBrowserTest() + : DownloadDeepScanningBrowserTestBase( + /*connectors_machine_scope=*/std::get<2>(GetParam()), + /*is_consumer=*/false) {} + + ClientDownloadResponse::Verdict metadata_check_verdict() const { + return std::get<0>(GetParam()); + } + + ScanningVerdict scanning_verdict() const { return std::get<1>(GetParam()); } + + enterprise_connectors::ContentAnalysisResponse scanning_response() const { + enterprise_connectors::ContentAnalysisResponse response; + response.set_request_token(last_request().request_token()); + auto* result = response.add_results(); + result->set_tag("malware"); + result->set_status( + enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS); + if (scanning_verdict() == ScanningVerdict::MALWARE) { + auto* rule = result->add_triggered_rules(); + rule->set_action(enterprise_connectors::TriggeredRule::BLOCK); + rule->set_rule_name("malware"); + } else if (scanning_verdict() == ScanningVerdict::UNWANTED) { + auto* rule = result->add_triggered_rules(); + rule->set_action(enterprise_connectors::TriggeredRule::WARN); + rule->set_rule_name("uws"); + } + return response; + } + + std::string metadata_check_threat_type() const { + switch (metadata_check_verdict()) { + case ClientDownloadResponse::UNKNOWN: + case ClientDownloadResponse::SAFE: + return ""; + case ClientDownloadResponse::DANGEROUS: + return "DANGEROUS"; + case ClientDownloadResponse::UNCOMMON: + return "UNCOMMON"; + case ClientDownloadResponse::POTENTIALLY_UNWANTED: + return "POTENTIALLY_UNWANTED"; + case ClientDownloadResponse::DANGEROUS_HOST: + return "DANGEROUS_HOST"; + case ClientDownloadResponse::DANGEROUS_ACCOUNT_COMPROMISE: + return "DANGEROUS_ACCOUNT_COMPROMISE"; + } + } + + std::string expected_threat_type() const { + // These results exempt the file from being deep scanned. + if (metadata_check_verdict() == ClientDownloadResponse::DANGEROUS || + metadata_check_verdict() == ClientDownloadResponse::DANGEROUS_HOST || + metadata_check_verdict() == + ClientDownloadResponse::DANGEROUS_ACCOUNT_COMPROMISE) { + return metadata_check_threat_type(); + } + switch (scanning_verdict()) { + case ScanningVerdict::MALWARE: + return "DANGEROUS"; + case ScanningVerdict::UNWANTED: + return "POTENTIALLY_UNWANTED"; + case ScanningVerdict::SAFE: + return metadata_check_threat_type(); + } + } + + download::DownloadDangerType expected_danger_type() const { + switch (metadata_check_verdict()) { + case ClientDownloadResponse::DANGEROUS: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT; + case ClientDownloadResponse::DANGEROUS_HOST: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST; + case ClientDownloadResponse::DANGEROUS_ACCOUNT_COMPROMISE: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_DANGEROUS_ACCOUNT_COMPROMISE; + case ClientDownloadResponse::UNCOMMON: + if (scanning_verdict() != ScanningVerdict::MALWARE) { + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT; + } + break; + + case ClientDownloadResponse::POTENTIALLY_UNWANTED: + if (scanning_verdict() != ScanningVerdict::MALWARE) { + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED; + } + break; + case ClientDownloadResponse::UNKNOWN: + case ClientDownloadResponse::SAFE: + break; + } + + switch (scanning_verdict()) { + case ScanningVerdict::MALWARE: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT; + case ScanningVerdict::UNWANTED: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED; + case ScanningVerdict::SAFE: + return download::DownloadDangerType:: + DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE; + } + } + + bool deep_scan_needed() const { + return metadata_check_verdict() != ClientDownloadResponse::DANGEROUS && + metadata_check_verdict() != ClientDownloadResponse::DANGEROUS_HOST && + metadata_check_verdict() != + ClientDownloadResponse::DANGEROUS_ACCOUNT_COMPROMISE; + } +}; + +INSTANTIATE_TEST_SUITE_P( + , + MetadataCheckAndDeepScanningBrowserTest, + testing::Combine( + testing::Values(ClientDownloadResponse::SAFE, + ClientDownloadResponse::DANGEROUS, + ClientDownloadResponse::UNCOMMON, + ClientDownloadResponse::POTENTIALLY_UNWANTED, + ClientDownloadResponse::DANGEROUS_HOST, + ClientDownloadResponse::UNKNOWN, + ClientDownloadResponse::DANGEROUS_ACCOUNT_COMPROMISE), + testing::Values(ScanningVerdict::MALWARE, + ScanningVerdict::UNWANTED, + ScanningVerdict::SAFE), + testing::Bool()), + [](const ::testing::TestParamInfo< + std::tuple<ClientDownloadResponse::Verdict, ScanningVerdict, bool>>& + info) { + auto metadata_check_verdict = std::get<0>(info.param); + auto scanning_verdict = std::get<1>(info.param); + auto connectors_machine_scope = std::get<2>(info.param); + std::string name; + name += ClientDownloadResponse::Verdict_Name(metadata_check_verdict); + switch (scanning_verdict) { + case ScanningVerdict::MALWARE: + name += "_malware_"; + break; + case ScanningVerdict::UNWANTED: + name += "_unwanted_"; + break; + case ScanningVerdict::SAFE: + name += "_safe_"; + break; + } + name += connectors_machine_scope ? "machinescope" : "userscope"; + return name; + }); + +IN_PROC_BROWSER_TEST_P(MetadataCheckAndDeepScanningBrowserTest, Test) { + // This allows the blocking DM token reads happening on profile-Connector + // triggers. + base::ScopedAllowBlockingForTesting allow_blocking; + + SetUpReporting(); + SetAnalysisConnector(browser()->profile()->GetPrefs(), + enterprise_connectors::FILE_DOWNLOADED, + R"({ + "service_provider": "google", + "enable": [ + { + "url_list": ["*"], + "tags": ["malware"] + } + ], + "block_until_verdict": 1 + })", + connectors_machine_scope()); + base::HistogramTester histograms; + + // Set up the metadata response. + ClientDownloadResponse metadata_response; + metadata_response.set_verdict(metadata_check_verdict()); + ExpectMetadataResponse(metadata_response); + + // Nothing is returned synchronously. + if (deep_scan_needed()) { + enterprise_connectors::ContentAnalysisResponse sync_response; + sync_response.set_request_token(last_request().request_token()); + ExpectContentAnalysisSynchronousResponse(sync_response, {"malware"}); + } + + GURL url = embedded_test_server()->GetURL( + "/safe_browsing/download_protection/zipfile_two_archives.zip"); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + + WaitForMetadataCheck(); + if (deep_scan_needed()) { + WaitForDeepScanRequest(); + } + + // Both the DLP and malware violations generate an event. + std::set<std::string> zip_types = {"application/zip", + "application/x-zip-compressed"}; + EventReportValidator validator(client()); + std::string threat_type = expected_threat_type(); + if (threat_type.empty()) { + validator.ExpectNoReport(); + } else { + // Reporting of the source, destination and scan ID is only expected when a + // deep scan is performed and when its result will be reported over the + // metadata check result. + bool expect_dangerous_deep_scan = + deep_scan_needed() && scanning_verdict() != ScanningVerdict::SAFE; + + if (expect_dangerous_deep_scan) { + validator.ExpectDangerousDeepScanningResult( + /*url*/ url.spec(), + /*source*/ "", + /*destination*/ "", + /*filename*/ "zipfile_two_archives.zip", + // sha256sum chrome/test/data/safe_browsing/download_protection/\ + // zipfile_two_archives.zip | tr '[:lower:]' '[:upper:]' + /*sha*/ + "339C8FFDAE735C4F1846D0E6FF07FBD85CAEE6D96045AAEF5B30F3220836643C", + /*threat_type*/ threat_type, + /*trigger*/ + extensions::SafeBrowsingPrivateEventRouter::kTriggerFileDownload, + /*mimetypes*/ &zip_types, + /*size*/ 276, + /*result*/ EventResultToString(EventResult::WARNED), + /*username*/ kUserName, + /*scan_id*/ + absl::optional<std::string>(last_request().request_token())); + } else { + validator.ExpectDangerousDownloadEvent( + /*url*/ url.spec(), + /*filename*/ "zipfile_two_archives.zip", + // sha256sum chrome/test/data/safe_browsing/download_protection/\ + // zipfile_two_archives.zip | tr '[:lower:]' '[:upper:]' + /*sha*/ + "339C8FFDAE735C4F1846D0E6FF07FBD85CAEE6D96045AAEF5B30F3220836643C", + /*threat_type*/ threat_type, + /*trigger*/ + extensions::SafeBrowsingPrivateEventRouter::kTriggerFileDownload, + /*mimetypes*/ &zip_types, + /*size*/ 276, + /*result*/ EventResultToString(EventResult::WARNED), + /*username*/ kUserName); + } + } + + // The deep scanning malware verdict is returned asynchronously. It is not + // done if the previous verdict is DANGEROUS or DANGEROUS_HOST. + if (deep_scan_needed()) { + SendFcmMessage(scanning_response()); + } else { + base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + validator.SetDoneClosure(run_loop.QuitClosure()); + run_loop.Run(); + } + + // The file should be blocked. + ASSERT_EQ(download_items().size(), 1u); + download::DownloadItem* item = *download_items().begin(); + EXPECT_EQ(item->GetDangerType(), expected_danger_type()); + EXPECT_EQ(item->GetState(), download::DownloadItem::IN_PROGRESS); + + if (metadata_check_verdict() == ClientDownloadResponse::UNCOMMON) { + // UNCOMMON is not a verdict that's considered malicious, so the download + // will not allow Chrome to close before being accepted or cancelled first + // (see DownloadManagerImpl::NonMaliciousInProgressCount). This makes the + // test crash after it runs as some callbacks are left unresolved, so a + // "cancel" is simulated. + item->SimulateErrorForTesting( + download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); + } + + if (threat_type.empty()) { + // Safe verdicts on both SB and deep scanning tests need to wait for the + // download to complete so they don't crash after being done. + WaitForDownloadToFinish(); + EXPECT_EQ(item->GetDangerType(), expected_danger_type()); + EXPECT_EQ(item->GetState(), download::DownloadItem::COMPLETE); + } + + // UMAs for this request should only be recorded once, and only if the malware + // deep scan takes place. + int samples = deep_scan_needed() ? 1 : 0; + histograms.ExpectUniqueSample("SafeBrowsingBinaryUploadRequest.Result", + BinaryUploadService::Result::SUCCESS, samples); + histograms.ExpectUniqueSample("SafeBrowsingBinaryUploadRequest.MalwareResult", + true, samples); +} + class WaitForModalObserver : public DeepScanningRequest::Observer { public: explicit WaitForModalObserver(DeepScanningRequest* request)
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc index cf9784d5..81abb5ea 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -497,7 +497,8 @@ void DeepScanningRequest::PrepareClientDownloadRequest( const base::FilePath& current_path, std::unique_ptr<FileAnalysisRequest> request) { - if (trigger_ == DeepScanTrigger::TRIGGER_POLICY) { + if (base::FeatureList::IsEnabled(kSafeBrowsingEnterpriseCsd) && + trigger_ == DeepScanTrigger::TRIGGER_POLICY) { download_request_maker_ = DownloadRequestMaker::CreateFromDownloadItem( new BinaryFeatureExtractor(), item_); download_request_maker_->Start(base::BindOnce( @@ -734,8 +735,9 @@ if (trigger_ == DeepScanTrigger::TRIGGER_APP_PROMPT) return false; - return analysis_settings_.block_until_verdict == - enterprise_connectors::BlockUntilVerdict::kNoBlock; + return base::FeatureList::IsEnabled(kConnectorsScanningReportOnlyUI) && + analysis_settings_.block_until_verdict == + enterprise_connectors::BlockUntilVerdict::kNoBlock; } void DeepScanningRequest::AcknowledgeRequest(EventResult event_result) {
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc index f7ba0b6..8876491 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -230,6 +230,7 @@ profile && IsSafeBrowsingEnabled(*profile->GetPrefs()); auto settings = DeepScanningRequest::ShouldUploadBinary(item); bool report_only_scan = + base::FeatureList::IsEnabled(kConnectorsScanningReportOnlyUI) && settings.has_value() && settings.value().block_until_verdict == enterprise_connectors::BlockUntilVerdict::kNoBlock; @@ -237,7 +238,10 @@ profile && IsRealTimeDownloadProtectionRequestAllowed(*profile->GetPrefs()); - if (settings.has_value() && !report_only_scan) { + if (base::FeatureList::IsEnabled(kSafeBrowsingEnterpriseCsd) && + base::FeatureList::IsEnabled( + kSafeBrowsingDisableConsumerCsdForEnterprise) && + settings.has_value() && !report_only_scan) { // Since this branch implies that the CSD check is done through the deep // scanning request and not with a consumer check, the pre-deep scanning // DownloadCheckResult is considered UNKNOWN. This shouldn't trigger on
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc index 4cd3affd..bb0594f 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -4704,12 +4704,27 @@ EXPECT_TRUE(IsResult(DownloadCheckResult::UNCOMMON)); } -class EnterpriseCsdDownloadTest : public DownloadProtectionServiceTestBase { +// Test fixture with the enterprise CSD checks either enabled or disabled. +class EnterpriseCsdDownloadTest : public DownloadProtectionServiceTestBase, + public ::testing::WithParamInterface<bool> { public: - EnterpriseCsdDownloadTest() = default; + EnterpriseCsdDownloadTest() { + // Enable the feature early to prevent race condition trying to access + // the enabled features set. This happens for example when the history + // service is started below. + if (flag_enabled()) { + EnableFeatures({kSafeBrowsingEnterpriseCsd, + kSafeBrowsingDisableConsumerCsdForEnterprise}); + } else { + DisableFeatures({kSafeBrowsingEnterpriseCsd, + kSafeBrowsingDisableConsumerCsdForEnterprise}); + } + } + + bool flag_enabled() const { return GetParam(); } }; -TEST_F(EnterpriseCsdDownloadTest, SkipsConsumerCsdWhenEnabled) { +TEST_P(EnterpriseCsdDownloadTest, SkipsConsumerCsdWhenEnabled) { NiceMockDownloadItem item; PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain "http://www.google.com/", // referrer @@ -4717,6 +4732,16 @@ FILE_PATH_LITERAL("a.exe")); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); + if (!flag_enabled()) { + EXPECT_CALL(*sb_service_->mock_database_manager(), + MatchDownloadAllowlistUrl(_)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _)); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageFeatures( + tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _)); + } + SetAnalysisConnector(profile()->GetPrefs(), enterprise_connectors::FILE_DOWNLOADED, R"( { @@ -4743,17 +4768,26 @@ base::Unretained(this), run_loop.QuitClosure())); run_loop.Run(); - EXPECT_EQ(HasClientDownloadRequest(), false); + EXPECT_EQ(HasClientDownloadRequest(), !flag_enabled()); EXPECT_TRUE(test_upload_service->was_called()); } -TEST_F(EnterpriseCsdDownloadTest, PopulatesCsdFieldWhenEnabled) { +TEST_P(EnterpriseCsdDownloadTest, PopulatesCsdFieldWhenEnabled) { NiceMockDownloadItem item; PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain "http://www.google.com/", // referrer FILE_PATH_LITERAL("a.tmp"), // tmp_path FILE_PATH_LITERAL("a.exe")); // final_path content::DownloadItemUtils::AttachInfoForTesting(&item, profile(), nullptr); + if (!flag_enabled()) { + EXPECT_CALL(*sb_service_->mock_database_manager(), + MatchDownloadAllowlistUrl(_)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _)); + EXPECT_CALL(*binary_feature_extractor_.get(), + ExtractImageFeatures( + tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _)); + } SetAnalysisConnector(profile()->GetPrefs(), enterprise_connectors::FILE_DOWNLOADED, @@ -4782,10 +4816,11 @@ run_loop.Run(); EXPECT_TRUE(test_upload_service->was_called()); - EXPECT_EQ(test_upload_service->last_request().request_data().has_csd(), true); + EXPECT_EQ(test_upload_service->last_request().request_data().has_csd(), + flag_enabled()); } -TEST_F(EnterpriseCsdDownloadTest, StillDoesMetadataCheckForLargeFile) { +TEST_P(EnterpriseCsdDownloadTest, StillDoesMetadataCheckForLargeFile) { NiceMockDownloadItem item; PrepareBasicDownloadItem(&item, {"http://www.evil.com/a.exe"}, // url_chain "http://www.google.com/", // referrer @@ -4830,4 +4865,6 @@ EXPECT_TRUE(IsResult(DownloadCheckResult::SAFE)); } +INSTANTIATE_TEST_SUITE_P(, EnterpriseCsdDownloadTest, testing::Bool()); + } // namespace safe_browsing
diff --git a/chrome/browser/share/BUILD.gn b/chrome/browser/share/BUILD.gn index 6b4b52c..19c617c 100644 --- a/chrome/browser/share/BUILD.gn +++ b/chrome/browser/share/BUILD.gn
@@ -40,7 +40,6 @@ if (is_android) { sources += [ "bitmap_download_request.cc", - "crow_bridge.cc", "default_ranking_android.cc", "editor_screenshot_task.cc", "link_to_text_bridge.cc", @@ -50,8 +49,6 @@ deps += [ ":jni_headers", "//chrome/browser/share/android:jni_headers", - "//chrome/browser/share/core/crow:crow_configuration", - "//chrome/browser/share/proto:crow_proto", "//components/history/core/browser:browser", "//components/ukm/content:content", "//ui/android", @@ -67,7 +64,6 @@ "android/java/src/org/chromium/chrome/browser/share/ShareDelegate.java", "android/java/src/org/chromium/chrome/browser/share/ShareHistoryBridge.java", "android/java/src/org/chromium/chrome/browser/share/ShareRankingBridge.java", - "android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java", "android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeOptionShareCallback.java", ]
diff --git a/chrome/browser/share/android/BUILD.gn b/chrome/browser/share/android/BUILD.gn index 251999c..f384a31a 100644 --- a/chrome/browser/share/android/BUILD.gn +++ b/chrome/browser/share/android/BUILD.gn
@@ -38,7 +38,6 @@ generate_jni("jni_headers") { sources = [ "java/src/org/chromium/chrome/browser/share/BitmapDownloadRequest.java", - "java/src/org/chromium/chrome/browser/share/crow/CrowBridge.java", "java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextBridge.java", "java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabService.java", "java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsTabServiceFactory.java",
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowBridge.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowBridge.java deleted file mode 100644 index fcbc887..0000000 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowBridge.java +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2022 The Chromium Authors -// 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.share.crow; - -import org.chromium.base.Callback; -import org.chromium.base.annotations.NativeMethods; -import org.chromium.url.GURL; - -/** - * Class providing access to functionality provided by the Crow native component. - */ -class CrowBridge { - /** Container for past visit counts. */ - static class VisitCounts { - /** The total number of visits. */ - public final int visits; - /** The number of per day boolean visits (days when at least one visit happened) */ - public final int dailyVisits; - - VisitCounts(int visits, int dailyVisits) { - this.visits = visits; - this.dailyVisits = dailyVisits; - } - } - - /** - * Obtains visit information for a website within a limited number of days in the past. - * @param url The URL for which the host will be queried for past visits. - * @param numDays The number of days to look back on. - * @param callback The callback to receive the past visits query results. - * Upon failure, VisitCounts is populated with 0 visits. - */ - static void getVisitCountsToHost(GURL url, int numDays, Callback<VisitCounts> callback) { - CrowBridgeJni.get().getRecentVisitCountsToHost( - url, numDays, (result) -> callback.onResult(new VisitCounts(result[0], result[1]))); - } - - /** - * Returns the publication ID for a hostname; empty string if host is not on the allowlist. - * @param host The hostname to check against the allowlist. - */ - static String getPublicationIDFromAllowlist(String host) { - return CrowBridgeJni.get().getPublicationIDFromAllowlist(host); - } - - /** - * Returns whether |host| is on the denylist. - * @param host The hostname to check against the denylist. - */ - static boolean denylistContainsHost(String host) { - return CrowBridgeJni.get().denylistContainsHost(host); - } - - @NativeMethods - interface Natives { - void getRecentVisitCountsToHost(GURL url, int numDays, Callback<int[]> callback); - String getPublicationIDFromAllowlist(String host); - boolean denylistContainsHost(String host); - } -}
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java deleted file mode 100644 index 1ffb3ae..0000000 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowButtonDelegate.java +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2022 The Chromium Authors -// 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.share.crow; - -import android.content.Context; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.url.GURL; - -/** - * Interface to expose the experimental 'Crow' sharing feature in the App menu - * footer and Feed to external classes. - */ -public interface CrowButtonDelegate { - /** - * @return Whether to show the chip for |url|. - * - * @param url URL for current tab where the app menu was launched. - * @param callback Callback informing whether the feature is enabled for 'url.' - */ - void isEnabledForSite(GURL url, Callback<Boolean> callback); - - /** - * Launches a custom tab to a server-provided interaction flow. - * Uses URL defined by the study config. - * - * @param currentContext the current Context for which the user activated an - * entry point. - * @param pageUrl URL for the page; passed in rather than derived from currentTab - * or WebContents's lastCommittedURL as it was used to construct UI in the caller. - * @param canonicalPageUrl Canonical URL for 'pageUrl.' May be empty. - * @param isFollowing Whether the user is following the associated host in the feed. - */ - void launchCustomTab(Tab tab, Context currentContext, GURL pageUrl, GURL canonicalPageUrl, - boolean isFollowing); - - /** - * @return experiment-configured chip text. - */ - String getButtonText(); - - /** - * Obtains the Canonical URL for a Tab. - * @param tab The tab for which to find the canonical URL. - * @param Callback<String> callback returning the canonical URL, or empty. - */ - void requestCanonicalUrl(Tab tab, Callback<GURL> url); - - /** - * Returns a URL that can be loaded for the web-hosted piece of this feature. - * - * @param pageUrl the URL of the page with content. - * @param canonicalPageUrl canonical URL for |pageUrl|, may be an empty GURL. - * @param isFollowing whether the user is following |pageUrl|'s site on the feed. - */ - String getUrlForWebFlow(GURL pageUrl, GURL canonicalPageUrl, boolean isFollowing); -}
diff --git a/chrome/browser/share/android/java_sources.gni b/chrome/browser/share/android/java_sources.gni index 62bcf86..c48de3c 100644 --- a/chrome/browser/share/android/java_sources.gni +++ b/chrome/browser/share/android/java_sources.gni
@@ -10,7 +10,6 @@ "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ChromeProvidedSharingOptionsProviderBase.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/SaveBitmapDelegate.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/ShareContentTypeHelper.java", - "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/crow/CrowBridge.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextBridge.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinator.java", "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java",
diff --git a/chrome/browser/share/crow_bridge.cc b/chrome/browser/share/crow_bridge.cc deleted file mode 100644 index 6b3d427..0000000 --- a/chrome/browser/share/crow_bridge.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <string> - -#include "base/android/callback_android.h" -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/no_destructor.h" -#include "base/task/cancelable_task_tracker.h" -#include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/share/android/jni_headers/CrowBridge_jni.h" -#include "chrome/browser/share/core/crow/crow_configuration.h" -#include "components/history/core/browser/history_service.h" -#include "components/history/core/browser/history_types.h" -#include "url/android/gurl_android.h" - -base::CancelableTaskTracker& TaskTracker() { - static base::NoDestructor<base::CancelableTaskTracker> task_tracker; - return *task_tracker; -} - -static void JNI_CrowBridge_GetRecentVisitCountsToHost( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& j_url, - jint j_num_days, - const base::android::JavaParamRef<jobject>& j_callback) { - auto adaptor = [](const base::android::JavaRef<jobject>& callback, - history::DailyVisitsResult result) { - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::RunObjectCallbackAndroid( - callback, base::android::ToJavaIntArray( - env, std::vector<int>({result.total_visits, - result.days_with_visits}))); - }; - base::OnceCallback<void(history::DailyVisitsResult)> callback = - base::BindOnce(adaptor, - base::android::ScopedJavaGlobalRef<jobject>(j_callback)); - - Profile* profile = ProfileManager::GetLastUsedProfile(); - history::HistoryService* history_service = nullptr; - if (profile) { - history_service = HistoryServiceFactory::GetForProfile( - profile, ServiceAccessType::IMPLICIT_ACCESS); - } - if (!history_service) { - std::move(callback).Run({}); - return; - } - - // Ignore any visits within the last hour so that we do not count the current - // visit to the page. - auto end_time = base::Time::Now() - base::Hours(1); - auto begin_time = base::Time::Now() - base::Days(j_num_days); - history_service->GetDailyVisitsToHost( - *url::GURLAndroid::ToNativeGURL(env, j_url), begin_time, end_time, - std::move(callback), &TaskTracker()); -} - -static base::android::ScopedJavaLocalRef<jstring> -JNI_CrowBridge_GetPublicationIDFromAllowlist( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& host) { - std::string publication_id = - crow::CrowConfiguration::GetInstance()->GetPublicationIDFromAllowlist( - base::android::ConvertJavaStringToUTF8(env, host)); - base::android::ScopedJavaLocalRef<jstring> j_publication_id = - base::android::ConvertUTF8ToJavaString(env, publication_id); - return j_publication_id; -} - -static jboolean JNI_CrowBridge_DenylistContainsHost( - JNIEnv* env, - const base::android::JavaParamRef<jstring>& host) { - bool on_denylist = - crow::CrowConfiguration::GetInstance()->DenylistContainsHost( - base::android::ConvertJavaStringToUTF8(env, host)); - return on_denylist; -}
diff --git a/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.cc b/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.cc index 3686456..3f890dd1 100644 --- a/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.cc +++ b/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.cc
@@ -16,28 +16,29 @@ #include "chrome/browser/ui/supervised_user/parent_permission_dialog.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_dialog_auto_confirm.h" +#include "ui/gfx/image/image_skia.h" namespace { void OnParentPermissionDialogComplete( - extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogDoneCallback delegate_done_callback, + extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalDoneCallback + delegate_done_callback, ParentPermissionDialog::Result result) { switch (result) { case ParentPermissionDialog::Result::kParentPermissionReceived: std::move(delegate_done_callback) .Run(extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionReceived); + ExtensionApprovalResult::kApproved); break; case ParentPermissionDialog::Result::kParentPermissionCanceled: std::move(delegate_done_callback) .Run(extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionCanceled); + ExtensionApprovalResult::kCanceled); break; case ParentPermissionDialog::Result::kParentPermissionFailed: std::move(delegate_done_callback) .Run(extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionFailed); + ExtensionApprovalResult::kFailed); break; } } @@ -67,12 +68,38 @@ return supervised_user_service->IsExtensionAllowed(extension); } -void SupervisedUserExtensionsDelegateImpl::PromptForParentPermissionOrShowError( +void SupervisedUserExtensionsDelegateImpl::RequestToAddExtensionOrShowError( const extensions::Extension& extension, content::BrowserContext* browser_context, content::WebContents* web_contents, - ParentPermissionDialogDoneCallback parent_permission_callback, - base::OnceClosure error_callback) { + const gfx::ImageSkia& icon, + ExtensionApprovalDoneCallback extension_approval_callback) { + DCHECK(IsChild(browser_context)); + DCHECK(!IsExtensionAllowedByParent(extension, browser_context)); + + // Supervised users who can install extensions still need parent permission + // for installation. If the user isn't allowed to install extensions at all, + // then we will just show a "blocked" dialog. + if (CanInstallExtensions(browser_context)) { + ShowParentPermissionDialogForExtension( + extension, browser_context, web_contents, + std::move(extension_approval_callback), icon); + return; + } + + ShowInstallBlockedByParentDialogForExtension( + extension, web_contents, + ExtensionInstalledBlockedByParentDialogAction::kAdd, + base::BindOnce( + std::move(extension_approval_callback), + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kBlocked)); +} + +void SupervisedUserExtensionsDelegateImpl::RequestToEnableExtensionOrShowError( + const extensions::Extension& extension, + content::BrowserContext* browser_context, + content::WebContents* web_contents, + ExtensionApprovalDoneCallback extension_approval_callback) { DCHECK(IsChild(browser_context)); DCHECK(!IsExtensionAllowedByParent(extension, browser_context)); @@ -80,13 +107,21 @@ // for installation or enablement. If the user isn't allowed to install // extensions at all, then we will just show a "blocked" dialog. if (CanInstallExtensions(browser_context)) { + // TODO(b/271320501): Move extension icon loading from + // ParentPermissionDialogView to this class instead of passing in an empty + // image for the icon. ShowParentPermissionDialogForExtension( extension, browser_context, web_contents, - std::move(parent_permission_callback)); - } else { - ShowExtensionEnableBlockedByParentDialogForExtension( - extension, web_contents, std::move(error_callback)); + std::move(extension_approval_callback), gfx::ImageSkia()); + return; } + + ShowInstallBlockedByParentDialogForExtension( + extension, web_contents, + ExtensionInstalledBlockedByParentDialogAction::kEnable, + base::BindOnce( + std::move(extension_approval_callback), + SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kBlocked)); } bool SupervisedUserExtensionsDelegateImpl::CanInstallExtensions( @@ -101,7 +136,8 @@ const extensions::Extension& extension, content::BrowserContext* context, content::WebContents* contents, - ParentPermissionDialogDoneCallback done_callback) { + ExtensionApprovalDoneCallback done_callback, + const gfx::ImageSkia& icon) { ParentPermissionDialog::DoneCallback inner_done_callback = base::BindOnce( &::OnParentPermissionDialogComplete, std::move(done_callback)); @@ -109,15 +145,16 @@ contents ? contents->GetTopLevelNativeWindow() : nullptr; parent_permission_dialog_ = ParentPermissionDialog::CreateParentPermissionDialogForExtension( - Profile::FromBrowserContext(context), parent_window, gfx::ImageSkia(), - &extension, std::move(inner_done_callback)); + Profile::FromBrowserContext(context), parent_window, icon, &extension, + std::move(inner_done_callback)); parent_permission_dialog_->ShowDialog(); } void SupervisedUserExtensionsDelegateImpl:: - ShowExtensionEnableBlockedByParentDialogForExtension( + ShowInstallBlockedByParentDialogForExtension( const extensions::Extension& extension, content::WebContents* contents, + ExtensionInstalledBlockedByParentDialogAction blocked_action, base::OnceClosure done_callback) { SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics( SupervisedUserExtensionsMetricsRecorder::EnablementState:: @@ -128,9 +165,8 @@ FROM_HERE, std::move(done_callback)); return; } - ShowExtensionInstallBlockedByParentDialog( - ExtensionInstalledBlockedByParentDialogAction::kEnable, &extension, - contents, std::move(done_callback)); + ShowExtensionInstallBlockedByParentDialog(blocked_action, &extension, + contents, std::move(done_callback)); } } // namespace extensions
diff --git a/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h b/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h index 98070c0..fc6896d 100644 --- a/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h +++ b/chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h
@@ -15,6 +15,8 @@ namespace extensions { +enum class ExtensionInstalledBlockedByParentDialogAction; + class SupervisedUserExtensionsDelegateImpl : public extensions::SupervisedUserExtensionsDelegate { public: @@ -26,12 +28,17 @@ bool IsExtensionAllowedByParent( const extensions::Extension& extension, content::BrowserContext* context) const override; - void PromptForParentPermissionOrShowError( + void RequestToAddExtensionOrShowError( const extensions::Extension& extension, content::BrowserContext* browser_context, content::WebContents* web_contents, - ParentPermissionDialogDoneCallback parent_permission_callback, - base::OnceClosure error_callback) override; + const gfx::ImageSkia& icon, + ExtensionApprovalDoneCallback extension_approval_callback) override; + void RequestToEnableExtensionOrShowError( + const extensions::Extension& extension, + content::BrowserContext* browser_context, + content::WebContents* web_contents, + ExtensionApprovalDoneCallback extension_approval_callback) override; private: // Returns true if |context| represents a supervised child account who may @@ -45,15 +52,22 @@ content::BrowserContext* context, content::WebContents* contents, extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogDoneCallback done_callback); + ExtensionApprovalDoneCallback done_callback, + const gfx::ImageSkia& icon); // Shows a dialog indicating that |extension| has been blocked and call - // |done_callback| when it completes. - void ShowExtensionEnableBlockedByParentDialogForExtension( + // |done_callback| when it completes. Depending on the blocked_action type, + // the UI of the dialog may differ. + void ShowInstallBlockedByParentDialogForExtension( const extensions::Extension& extension, content::WebContents* contents, + ExtensionInstalledBlockedByParentDialogAction blocked_action, base::OnceClosure done_callback); + // The dialog pointer is only destroyed when a new dialog is created or the + // SupervisedUserExtensionsDelegate is destroyed. Therefore there can only be + // one dialog opened at a time and the last dialog object can have a pretty + // long lifetime. std::unique_ptr<ParentPermissionDialog> parent_permission_dialog_; };
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc index dfb8305..582c597 100644 --- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc +++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc
@@ -436,7 +436,8 @@ // Generate a fake app. std::string app_id = MakeBorealisApp("vm", "container", "foo"); - views::Widget* widget = CreateExoWindow("org.chromium.borealis.wmclass.foo"); + views::Widget* widget = + CreateExoWindow("org.chromium.guest_os.borealis.wmclass.foo"); EXPECT_EQ(1u, app_service_proxy_->InstanceRegistry().GetInstances(app_id).size()); @@ -449,8 +450,10 @@ IN_PROC_BROWSER_TEST_F(AppServiceAppWindowBorealisBrowserTest, BorealisUnknownApp) { - views::Widget* widget = CreateExoWindow("org.chromium.borealis.wmclass.bar"); - std::string app_id = "borealis_anon:org.chromium.borealis.wmclass.bar"; + views::Widget* widget = + CreateExoWindow("org.chromium.guest_os.borealis.wmclass.bar"); + std::string app_id = + "borealis_anon:org.chromium.guest_os.borealis.wmclass.bar"; EXPECT_EQ(1u, app_service_proxy_->InstanceRegistry().GetInstances(app_id).size()); @@ -484,7 +487,8 @@ EXPECT_CALL(observer, OnSessionStarted()); EXPECT_CALL(observer, OnAppStarted(app_id)); EXPECT_CALL(observer, OnWindowStarted(app_id, testing::_)); - views::Widget* widget = CreateExoWindow("org.chromium.borealis.wmclass.foo"); + views::Widget* widget = + CreateExoWindow("org.chromium.guest_os.borealis.wmclass.foo"); EXPECT_CALL(observer, OnWindowFinished(app_id, widget->GetNativeWindow())); EXPECT_CALL(observer, OnAppFinished(app_id, widget->GetNativeWindow()));
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index d6e3c669..2968582 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -338,7 +338,7 @@ TestAutofillDriverInjector<NiceMock<MockAutofillDriver>> autofill_driver_injector_; - test::AutofillUnitTestEnvironment autofill_environment_; + test::AutofillUnitTestEnvironment autofill_test_environment_; std::unique_ptr<NiceMock<MockAutofillExternalDelegate>> external_delegate_; std::unique_ptr<NiceMock<MockAutofillPopupView>> autofill_popup_view_; raw_ptr<NiceMock<TestAutofillPopupController>> autofill_popup_controller_ =
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc index e6c1b3e..86987f35 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.cc +++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -107,15 +107,12 @@ *extension, profile_)) { // Either ask for parent permission or notify the child that their parent // has disabled this action. - auto parent_permission_callback = - base::BindOnce(&ExtensionEnableFlow::OnParentPermissionDialogDone, + auto extension_approval_callback = + base::BindOnce(&ExtensionEnableFlow::OnExtensionApprovalDone, weak_ptr_factory_.GetWeakPtr()); - auto error_callback = - base::BindOnce(&ExtensionEnableFlow::OnBlockedByParentDialogDone, - weak_ptr_factory_.GetWeakPtr()); - supervised_user_extensions_delegate->PromptForParentPermissionOrShowError( + supervised_user_extensions_delegate->RequestToEnableExtensionOrShowError( *extension, profile_, parent_contents_, - std::move(parent_permission_callback), std::move(error_callback)); + std::move(extension_approval_callback)); return; } #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) @@ -168,31 +165,28 @@ } #if BUILDFLAG(ENABLE_SUPERVISED_USERS) -void ExtensionEnableFlow::OnParentPermissionDialogDone( - extensions::SupervisedUserExtensionsDelegate::ParentPermissionDialogResult +void ExtensionEnableFlow::OnExtensionApprovalDone( + extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult result) { switch (result) { - case extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionReceived: + case extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult:: + kApproved: EnableExtension(); break; - case extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionCanceled: + case extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult:: + kCanceled: delegate_->ExtensionEnableFlowAborted( /*user_initiated=*/true); // |delegate_| may delete us. break; - case extensions::SupervisedUserExtensionsDelegate:: - ParentPermissionDialogResult::kParentPermissionFailed: + case extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult:: + kFailed: + case extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult:: + kBlocked: delegate_->ExtensionEnableFlowAborted( /*user_initiated=*/false); // |delegate_| may delete us. break; } } - -void ExtensionEnableFlow::OnBlockedByParentDialogDone() { - delegate_->ExtensionEnableFlowAborted( - /*user_initiated=*/false); // |delegate_| may delete us. -} #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void ExtensionEnableFlow::StartObserving() {
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.h b/chrome/browser/ui/extensions/extension_enable_flow.h index 5ee75ae..d1bd1873 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.h +++ b/chrome/browser/ui/extensions/extension_enable_flow.h
@@ -82,14 +82,10 @@ void CreatePrompt(); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) - // Called when the user dismisses the Parent Permission Dialog. - void OnParentPermissionDialogDone( - extensions::SupervisedUserExtensionsDelegate::ParentPermissionDialogResult + // Called when the extension approval flow is complete. + void OnExtensionApprovalDone( + extensions::SupervisedUserExtensionsDelegate::ExtensionApprovalResult result); - - // Called when the user dismisses the Extension Install Blocked By Parent - // Dialog. - void OnBlockedByParentDialogDone(); #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) // Starts/stops observing extension load notifications.
diff --git a/chrome/browser/ui/extensions/extensions_overrides/simple_overrides_unittest.cc b/chrome/browser/ui/extensions/extensions_overrides/simple_overrides_unittest.cc index 024c55f..3bafbaf 100644 --- a/chrome/browser/ui/extensions/extensions_overrides/simple_overrides_unittest.cc +++ b/chrome/browser/ui/extensions/extensions_overrides/simple_overrides_unittest.cc
@@ -44,7 +44,6 @@ extensions::manifest_keys::kApp, extensions::manifest_keys::kPlatformAppBackground, extensions::manifest_keys::kPlatformAppContentSecurityPolicy, - extensions::manifest_keys::kIsolation, extensions::manifest_keys::kLaunch, extensions::manifest_keys::kLinkedAppIcons, extensions::manifest_keys::kAutomation,
diff --git a/chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.cc index 2b36427..86d2548 100644 --- a/chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.cc +++ b/chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.cc
@@ -147,6 +147,9 @@ password_store->UpdateLoginWithPrimaryKey( updated_form, currently_selected_password_.value()); currently_selected_password_ = updated_form; + + metrics_util::LogUserInteractionsInPasswordManagementBubble( + metrics_util::PasswordManagementBubbleInteractions::kUsernameAdded); } void ItemsBubbleController::AuthenticateUserAndDisplayDetailsOf(
diff --git a/chrome/browser/ui/views/borealis/borealis_splash_screen_view_browsertest.cc b/chrome/browser/ui/views/borealis/borealis_splash_screen_view_browsertest.cc index 769eebb7..c38b6af 100644 --- a/chrome/browser/ui/views/borealis/borealis_splash_screen_view_browsertest.cc +++ b/chrome/browser/ui/views/borealis/borealis_splash_screen_view_browsertest.cc
@@ -101,7 +101,7 @@ EXPECT_TRUE(VerifyUi()); EXPECT_NE(nullptr, BorealisSplashScreenView::GetActiveViewForTesting()); MakeAndTrackWindow( - "org.chromium.borealis.foobarbaz", + "org.chromium.guest_os.borealis.foobarbaz", &borealis::BorealisService::GetForProfile(browser()->profile()) ->WindowManager()); base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc index aebef8e2..6d1084a 100644 --- a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/download/bubble/download_dialog_view.h" #include "base/functional/bind.h" +#include "base/functional/callback_forward.h" #include "base/logging.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/ui/chrome_pages.h" @@ -23,6 +24,7 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/animation/ink_drop.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button_factory.h" #include "ui/views/controls/highlight_path_generator.h" @@ -35,11 +37,72 @@ #include "ui/views/layout/flex_layout_types.h" #include "ui/views/layout/flex_layout_view.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/layout/table_layout.h" #include "ui/views/view.h" #include "ui/views/view_class_properties.h" #include "ui/views/widget/widget.h" #include "ui/views/window/vector_icons/vector_icons.h" +namespace { + +class ShowAllDownloadsButton : public RichHoverButton { + public: + explicit ShowAllDownloadsButton( + base::RepeatingClosure show_all_downloads_callback) + : RichHoverButton( + std::move(show_all_downloads_callback), + /*main_image_icon=*/ui::ImageModel(), + l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK), + /*secondary_text=*/std::u16string(), + l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP), + /*subtitle_text=*/std::u16string(), + ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon, + ui::kColorIconSecondary)) { + // Override the table layout from RichHoverButton, in order to control the + // spacing/padding. Code below is copied from rich_hover_button.cc but with + // padding columns rearranged. + views::TableLayout* table_layout = + SetLayoutManager(std::make_unique<views::TableLayout>()); + table_layout + // Column for |main_image_icon|. + ->AddColumn(views::LayoutAlignment::kCenter, + views::LayoutAlignment::kCenter, + views::TableLayout::kFixedSize, + views::TableLayout::ColumnSize::kUsePreferred, 0, 0) + // Column for title. + .AddColumn(views::LayoutAlignment::kStretch, + views::LayoutAlignment::kCenter, 1.0f, + views::TableLayout::ColumnSize::kUsePreferred, 0, 0) + // Column for |secondary_text|. + .AddColumn(views::LayoutAlignment::kEnd, + views::LayoutAlignment::kStretch, + views::TableLayout::kFixedSize, + views::TableLayout::ColumnSize::kUsePreferred, 0, 0) + // Column for |action_icon|. + .AddColumn(views::LayoutAlignment::kCenter, + views::LayoutAlignment::kCenter, + views::TableLayout::kFixedSize, + views::TableLayout::ColumnSize::kFixed, 16, 0) + .AddPaddingColumn(views::TableLayout::kFixedSize, + GetLayoutInsets(DOWNLOAD_ICON).right()) + .AddRows( + 1, views::TableLayout::kFixedSize, + // Force row to have sufficient height for full line-height of + // the title. + views::style::GetLineHeight(views::style::CONTEXT_DIALOG_BODY_TEXT, + views::style::STYLE_PRIMARY)); + + // TODO(pkasting): This class should subclass Button, not HoverButton. + table_layout->SetChildViewIgnoredByLayout(image(), true); + table_layout->SetChildViewIgnoredByLayout(label(), true); + table_layout->SetChildViewIgnoredByLayout(ink_drop_container(), true); + + Layout(); + } +}; + +} // namespace + void DownloadDialogView::CloseBubble() { navigation_handler_->CloseDialog( views::Widget::ClosedReason::kCloseButtonClicked); @@ -78,16 +141,8 @@ void DownloadDialogView::AddFooter() { AddChildView( - std::make_unique<RichHoverButton>( - base::BindRepeating(&DownloadDialogView::ShowAllDownloads, - base::Unretained(this)), - /*main_image_icon=*/ui::ImageModel(), - l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK), - /*secondary_text=*/std::u16string(), - l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP), - /*subtitle_text=*/std::u16string(), - ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon, - ui::kColorIconSecondary))) + std::make_unique<ShowAllDownloadsButton>(base::BindRepeating( + &DownloadDialogView::ShowAllDownloads, base::Unretained(this)))) ->SetBorder(views::CreateEmptyBorder(GetLayoutInsets(DOWNLOAD_ROW))); }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc index 2f67220..38e30ef 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc
@@ -221,6 +221,8 @@ // TODO(crbug.com/1382017): use internationalized string. (*textfield)->SetAccessibleName(u"Username"); (*textfield) + ->SetID(static_cast<int>(ManagePasswordsViewIDs::kUsernameTextField)); + (*textfield) ->SetProperty( views::kFlexBehaviorKey, views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred, @@ -291,6 +293,10 @@ : switched_to_edit_mode_callback_( std::move(switched_to_edit_mode_callback)) { SetOrientation(views::BoxLayout::Orientation::kVertical); + std::unique_ptr<views::Label> username_label = + CreateUsernameLabel(password_form); + username_label->SetID( + static_cast<int>(ManagePasswordsViewIDs::kUsernameLabel)); if (!password_form.username_value.empty()) { auto copy_username_button_callback = base::BindRepeating(&WriteToClipboard, password_form.username_value) @@ -300,7 +306,7 @@ PasswordManagementBubbleInteractions:: kUsernameCopyButtonClicked)); AddChildView(CreateDetailsRow( - kAccountCircleIcon, CreateUsernameLabel(password_form), + kAccountCircleIcon, std::move(username_label), vector_icons::kContentCopyIcon, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UI_COPY_USERNAME), std::move(copy_username_button_callback), @@ -310,14 +316,18 @@ // action // button tooltip text. read_username_row_ = AddChildView(CreateDetailsRow( - kAccountCircleIcon, CreateUsernameLabel(password_form), - vector_icons::kEditIcon, u"Edit Username", + kAccountCircleIcon, std::move(username_label), vector_icons::kEditIcon, + u"Edit Username", base::BindRepeating( &ManagePasswordsDetailsView::SwitchToEditUsernameMode, base::Unretained(this)), ManagePasswordsViewIDs::kEditUsernameButton)); + read_username_row_->SetID( + static_cast<int>(ManagePasswordsViewIDs::kReadUsernameRow)); edit_username_row_ = AddChildView( CreateEditUsernameRow(password_form, &username_textfield_)); + edit_username_row_->SetID( + static_cast<int>(ManagePasswordsViewIDs::kEditUsernameRow)); edit_username_row_->SetVisible(false); } @@ -389,6 +399,8 @@ switched_to_edit_mode_callback_.Run(); DCHECK(username_textfield_); username_textfield_->RequestFocus(); + LogUserInteractionsInPasswordManagementBubble( + PasswordManagementBubbleInteractions::kUsernameEditButtonClicked); } void ManagePasswordsDetailsView::SwitchToEditNoteMode() {
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_view_ids.h b/chrome/browser/ui/views/passwords/manage_passwords_view_ids.h index fd8a38f0..bc7ca7b 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_view_ids.h +++ b/chrome/browser/ui/views/passwords/manage_passwords_view_ids.h
@@ -10,13 +10,24 @@ // Defines an enumeration of IDs that can uniquely identify a view within the // scope of password management bubble. Used to validate views in browser tests. enum class ManagePasswordsViewIDs { + // The following ids are for credential list views. kManagePasswordsButton = 1, + + // The following ids are for username in the details views. kCopyUsernameButton, - kCopyPasswordButton, kEditUsernameButton, - kEditNoteButton, + kEditUsernameRow, + kReadUsernameRow, + kUsernameTextField, + kUsernameLabel, + + // The following ids are for password in the details views. + kCopyPasswordButton, kRevealPasswordButton, kPasswordLabel, + + // The following ids are for note in the details views. + kEditNoteButton, }; } // namespace password_manager
diff --git a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc index 6ac72288..e23c6e1 100644 --- a/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc +++ b/chrome/browser/ui/views/passwords/password_bubble_interactive_uitest.cc
@@ -39,6 +39,7 @@ #include "ui/events/base_event_utils.h" #include "ui/views/controls/editable_combobox/editable_combobox.h" #include "ui/views/controls/styled_label.h" +#include "ui/views/controls/textfield/textfield.h" #include "ui/views/focus/focus_manager.h" using base::Bucket; @@ -591,3 +592,60 @@ kPasswordShowButtonClicked, 1); } + +IN_PROC_BROWSER_TEST_F(PasswordManagementRevampedBubbleInteractiveUiTest, + DisplaysNewUsernameAfterEditing) { + base::HistogramTester histogram_tester; + + SetupManagingPasswords(); + EXPECT_FALSE(IsBubbleShowing()); + ExecuteManagePasswordsCommand(); + ASSERT_TRUE(IsBubbleShowing()); + + auto* bubble = PasswordBubbleViewBase::manage_password_bubble(); + test_form()->username_value = u""; + static_cast<ManagePasswordsView*>(bubble)->DisplayDetailsOfPasswordForTesting( + *test_form()); + + auto* edit_username_row = bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kEditUsernameRow)); + auto* read_username_row = bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kReadUsernameRow)); + ASSERT_FALSE(edit_username_row->GetVisible()); + ASSERT_TRUE(read_username_row->GetVisible()); + ASSERT_EQ(static_cast<views::Label*>( + bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kUsernameLabel))) + ->GetText(), + u"No username"); + + ClickOnView(bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kEditUsernameButton))); + EXPECT_TRUE(edit_username_row->GetVisible()); + EXPECT_FALSE(read_username_row->GetVisible()); + + auto* username_textfield = + static_cast<views::Textfield*>(bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kUsernameTextField))); + EXPECT_EQ(username_textfield->GetText(), u""); + + username_textfield->SetText(u"new_username"); + bubble->AcceptDialog(); + EXPECT_EQ(static_cast<views::Label*>( + bubble->GetViewByID(static_cast<int>( + password_manager::ManagePasswordsViewIDs::kUsernameLabel))) + ->GetText(), + u"new_username"); + + EXPECT_THAT( + histogram_tester.GetAllSamples( + "PasswordManager.PasswordManagementBubble.UserAction"), + ElementsAre( + Bucket(password_manager::metrics_util:: + PasswordManagementBubbleInteractions:: + kUsernameEditButtonClicked, + 1), + Bucket(password_manager::metrics_util:: + PasswordManagementBubbleInteractions::kUsernameAdded, + 1))); +}
diff --git a/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc b/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc index 2f4b61c..2fd19ecf0 100644 --- a/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc +++ b/chrome/browser/ui/webui/settings/ash/calculator/size_calculator.cc
@@ -115,7 +115,8 @@ TotalDiskSpaceCalculator::~TotalDiskSpaceCalculator() = default; void TotalDiskSpaceCalculator::PerformCalculation() { - if (profile_->IsGuestSession()) { + if (user_manager::UserManager::Get() + ->IsCurrentUserCryptohomeDataEphemeral()) { GetTotalDiskSpace(); return; }
diff --git a/chrome/browser/ui/webui/settings/ash/device_section.cc b/chrome/browser/ui/webui/settings/ash/device_section.cc index 981a4d9..f2306cfd 100644 --- a/chrome/browser/ui/webui/settings/ash/device_section.cc +++ b/chrome/browser/ui/webui/settings/ash/device_section.cc
@@ -29,6 +29,7 @@ #include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "ui/base/l10n/l10n_util.h" @@ -930,6 +931,10 @@ "displayArrangementText", IDS_SETTINGS_DISPLAY_ARRANGEMENT_WITH_KEYBOARD_TEXT); + html_source->AddBoolean( + "isCryptohomeDataEphemeral", + user_manager::UserManager::Get()->IsCurrentUserCryptohomeDataEphemeral()); + html_source->AddBoolean("unifiedDesktopAvailable", IsUnifiedDesktopAvailable());
diff --git a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc index 5069eaf..1820c62a 100644 --- a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc +++ b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.cc
@@ -67,6 +67,8 @@ IDS_PRICE_TRACKING_TRACK_PRODUCT_ACCESSIBILITY}, {"shoppingListUntrackPriceButtonDescription", IDS_PRICE_TRACKING_UNTRACK_PRODUCT_ACCESSIBILITY}, + {"shoppingListErrorMessage", IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_MESSAGE}, + {"shoppingListErrorButton", IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON}, {"sortByType", IDS_BOOKMARKS_SORT_BY_TYPE}, {"allBookmarks", IDS_BOOKMARKS_ALL_BOOKMARKS}, {"priceTrackingLabel", IDS_BOOKMARKS_LABEL_TRACKED_PRODUCTS},
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 756628d..250b38c 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1678305542-22dc2b7e3472b23cee9b5800e2abf09ae3a6ab8f.profdata +chrome-mac-arm-main-1678312782-69ec178d299e07fd1f5efc2554323539df4098cd.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index e99b7ac4..dd4f835 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1678298389-d5881b2d3b0c53c1a4ae054078c1eb1c0e1cbb0b.profdata +chrome-win32-main-1678309150-6adc10d823bccf625ce70c53fe39cf9939693858.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index a0b90da..5d0b20dc 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1678287323-15038fe496357444f0c3949b85c48c785efdcad3.profdata +chrome-win64-main-1678309150-b944feaf3fd50d8bc1f4610ded1d0658833c4699.profdata
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index ab46ff7e..d06224f 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -358,7 +358,8 @@ { "internal": true, "channel": "stable", - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + "dependencies": ["permission:downloads"] }, { "internal": true,
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json index 6c3ca4a..6ca92d7 100644 --- a/chrome/common/extensions/api/_manifest_features.json +++ b/chrome/common/extensions/api/_manifest_features.json
@@ -20,12 +20,6 @@ "channel": "stable", "extension_types": ["hosted_app"] }, - "app.isolation": { - "channel": "stable", - // Platform apps always have isolated storage, thus they cannot specify it - // via the manifest. - "extension_types": ["legacy_packaged_app", "hosted_app"] - }, "app.launch": { "channel": "stable", "extension_types": ["legacy_packaged_app", "hosted_app"]
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc index 885953b..63ee0e5 100644 --- a/chrome/common/extensions/chrome_manifest_handlers.cc +++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -20,7 +20,6 @@ #include "chrome/common/extensions/manifest_handlers/natively_connectable_handler.h" #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h" #include "chrome/common/extensions/manifest_handlers/theme_handler.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/options_page_info.h" #include "extensions/common/manifest_url_handlers.h" @@ -42,7 +41,6 @@ DCHECK(!ManifestHandler::IsRegistrationFinalized()); registry->RegisterHandler(std::make_unique<AboutPageHandler>()); - registry->RegisterHandler(std::make_unique<AppIsolationHandler>()); registry->RegisterHandler(std::make_unique<AppLaunchManifestHandler>()); registry->RegisterHandler(std::make_unique<DevToolsPageHandler>()); registry->RegisterHandler(std::make_unique<HomepageURLHandler>());
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc index f60e0a8..25b9ade 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -10,7 +10,6 @@ #include "extensions/common/error_utils.h" #include "extensions/common/features/simple_feature.h" #include "extensions/common/manifest_constants.h" -#include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/csp_info.h" #include "extensions/common/manifest_handlers/incognito_info.h" #include "extensions/common/switches.h" @@ -27,7 +26,10 @@ TEST_F(PlatformAppsManifestTest, PlatformApps) { scoped_refptr<Extension> extension = LoadAndExpectSuccess("init_valid_platform_app.json"); - EXPECT_TRUE(AppIsolationInfo::HasIsolatedStorage(extension.get())); + // Ensure this is treated as platform app, which causes it to have isolated + // storage in the browser process. See also + // ExtensionUtilUnittest.HasIsolatedStorage. + EXPECT_TRUE(extension->is_platform_app()); EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get())); extension =
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts index db093e4a..3cd9cc5 100644 --- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts +++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -16,11 +16,11 @@ import {AcceleratorViewElement} from 'chrome://shortcut-customization/js/accelerator_view.js'; import {fakeAcceleratorConfig, fakeLayoutInfo, fakeSearchResults} from 'chrome://shortcut-customization/js/fake_data.js'; import {FakeShortcutProvider} from 'chrome://shortcut-customization/js/fake_shortcut_provider.js'; -import {setShortcutProviderForTesting} from 'chrome://shortcut-customization/js/mojo_interface_provider.js'; +import {setShortcutProviderForTesting, setUseFakeProviderForTesting} from 'chrome://shortcut-customization/js/mojo_interface_provider.js'; import {FakeShortcutSearchHandler} from 'chrome://shortcut-customization/js/search/fake_shortcut_search_handler.js'; import {setShortcutSearchHandlerForTesting} from 'chrome://shortcut-customization/js/search/shortcut_search_handler.js'; import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/js/shortcut_customization_app.js'; -import {AcceleratorCategory, AcceleratorSubcategory, LayoutInfo, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js'; +import {AcceleratorCategory, AcceleratorState, AcceleratorSubcategory, LayoutInfo, Modifier} from 'chrome://shortcut-customization/js/shortcut_types.js'; import {getCategoryNameStringId, getSubcategoryNameStringId} from 'chrome://shortcut-customization/js/shortcut_utils.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; @@ -49,6 +49,7 @@ manager = AcceleratorLookupManager.getInstance(); // Set up provider. + setUseFakeProviderForTesting(true); provider = new FakeShortcutProvider(); provider.setFakeAcceleratorConfig(fakeAcceleratorConfig); provider.setFakeAcceleratorLayoutInfos(fakeLayoutInfo); @@ -252,7 +253,7 @@ assertTrue(!!editDialog); // Grab the first accelerator from the second subsection. - let editView = + const editView = editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll( 'accelerator-edit-view')[0] as AcceleratorEditViewElement; @@ -262,7 +263,7 @@ await flushTasks(); - let accelViewElement = + const accelViewElement = editView.shadowRoot!.querySelector('#acceleratorItem'); // Assert no error has occurred prior to pressing a shortcut. @@ -298,20 +299,38 @@ await flushTasks(); // Requery the view element. - editView = + const editViews = editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll( - 'accelerator-edit-view')[0] as AcceleratorEditViewElement; - accelViewElement = editView.shadowRoot!.querySelector('#acceleratorItem'); + 'accelerator-edit-view'); + // Replacing a default accelerator will disable the default and add a new + // accelerator. + assertEquals(2, editViews!.length); + + const accelViewElement1 = + editViews[0]!.shadowRoot!.querySelector('#acceleratorItem'); + const acceleratorInfo1 = + (accelViewElement1 as AcceleratorViewElement).acceleratorInfo; + const actualAccelerator1 = + acceleratorInfo1.layoutProperties.standardAccelerator.accelerator; + assertEquals( + Modifier.COMMAND | Modifier.SHIFT, actualAccelerator1!.modifiers); + assertEquals(187, actualAccelerator1.keyCode); + assertEquals( + '+', acceleratorInfo1.layoutProperties.standardAccelerator.keyDisplay); + assertEquals(AcceleratorState.kDisabledByUser, acceleratorInfo1.state); // Assert that the accelerator was updated with the new shortcut (Alt + ']') - const acceleratorInfo = - (accelViewElement as AcceleratorViewElement).acceleratorInfo; - const actualAccelerator = - acceleratorInfo.layoutProperties.standardAccelerator.accelerator; - assertEquals(Modifier.ALT, actualAccelerator!.modifiers); - assertEquals(221, actualAccelerator.keyCode); + const accelViewElement2 = + editViews[1]!.shadowRoot!.querySelector('#acceleratorItem'); + const acceleratorInfo2 = + (accelViewElement2 as AcceleratorViewElement).acceleratorInfo; + const actualAccelerator2 = + acceleratorInfo2.layoutProperties.standardAccelerator.accelerator; + assertEquals(Modifier.ALT, actualAccelerator2!.modifiers); + assertEquals(221, actualAccelerator2.keyCode); assertEquals( - ']', acceleratorInfo.layoutProperties.standardAccelerator.keyDisplay); + ']', acceleratorInfo2.layoutProperties.standardAccelerator.keyDisplay); + assertEquals(AcceleratorState.kEnabled, acceleratorInfo2.state); }); test('AddAccelerator', async () => { @@ -395,7 +414,7 @@ ']', acceleratorInfo.layoutProperties.standardAccelerator.keyDisplay); }); - test('RemoveAccelerator', async () => { + test('DisableDefaultAccelerator', async () => { page = initShortcutCustomizationAppElement(); await flushTasks(); @@ -423,8 +442,16 @@ editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll( 'accelerator-edit-view'); - // Expect that the accelerator has now been removed. - assertEquals(0, acceleratorList!.length); + // Expect that the accelerator has now been disabled but not removed. + acceleratorList = + editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll( + 'accelerator-edit-view'); + assertEquals(1, acceleratorList!.length); + const accelViewElement = + acceleratorList[0]!.shadowRoot!.querySelector('#acceleratorItem'); + const acceleratorInfo = + (accelViewElement as AcceleratorViewElement).acceleratorInfo; + assertEquals(AcceleratorState.kDisabledByUser, acceleratorInfo.state); }); test('RestoreAllButton', async () => {
diff --git a/chrome/test/data/webui/new_tab_page/modules/history_clusters/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/history_clusters/module_test.ts index 5553b1de7..2f05e21 100644 --- a/chrome/test/data/webui/new_tab_page/modules/history_clusters/module_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/history_clusters/module_test.ts
@@ -26,6 +26,13 @@ assertEquals(layoutElements[0]!.id, `layout${layoutType}`); } +function assertModuleHeaderTitle(headerElement: HTMLElement, title: string) { + const moduleHeaderTextContent = headerElement.textContent!.trim(); + const headerText = moduleHeaderTextContent.split(/\r?\n/); + assertTrue(headerText.length > 0); + assertEquals(title, headerText[0]!.trim()); +} + function createVisit( visitId: bigint, normalizedUrl: string, urlForDisplay: string, pageTitle: string, hasUrlKeyedImage: boolean): URLVisit { @@ -316,8 +323,10 @@ }); test('Header element populated with correct data', async () => { - handler.setResultFor( - 'getCluster', Promise.resolve({cluster: createSampleCluster()})); + const sampleClusterLabel = '"Sample Journey"'; + handler.setResultFor('getCluster', Promise.resolve({ + cluster: createSampleCluster({label: sampleClusterLabel}), + })); const moduleElement = await historyClustersDescriptor.initialize(0) as HistoryClustersModuleElement; @@ -331,7 +340,26 @@ assertTrue(!!headerElement); assertEquals( - headerElement.querySelector('#showAllButton')!.innerHTML.trim(), - 'Show all'); + 'Show all', + headerElement.querySelector('#showAllButton')!.innerHTML.trim()); + assertModuleHeaderTitle( + headerElement, `Resume your journey for ${sampleClusterLabel}`); + }); + + test('Header title falls back to Visit title', async () => { + handler.setResultFor( + 'getCluster', Promise.resolve({cluster: createSampleCluster()})); + + const moduleElement = await historyClustersDescriptor.initialize(0) as + HistoryClustersModuleElement; + + document.body.append(moduleElement); + assertTrue(!!moduleElement); + await handler.whenCalled('getCluster'); + await waitAfterNextRender(moduleElement); + + const headerElement = $$(moduleElement, 'ntp-module-header'); + assertTrue(!!headerElement); + assertModuleHeaderTitle(headerElement, 'Resume your journey for SRP'); }); });
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index dfff6036..3ab4665 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -4,7 +4,7 @@ import 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; -import {crosAudioConfigMojom, DevicePageBrowserProxyImpl, fakeCrosAudioConfig, FakeInputDeviceSettingsProvider, fakeKeyboards, fakeMice, fakePointingSticks, IdleBehavior, LidClosedBehavior, NoteAppLockScreenSupport, Router, routes, setCrosAudioConfigForTesting, setDisplayApiForTesting, setInputDeviceSettingsProviderForTesting, StorageSpaceState} from 'chrome://os-settings/chromeos/os_settings.js'; +import {crosAudioConfigMojom, DevicePageBrowserProxyImpl, fakeCrosAudioConfig, FakeInputDeviceSettingsProvider, fakeKeyboards, IdleBehavior, LidClosedBehavior, NoteAppLockScreenSupport, Router, routes, setCrosAudioConfigForTesting, setDisplayApiForTesting, setInputDeviceSettingsProviderForTesting, StorageSpaceState} from 'chrome://os-settings/chromeos/os_settings.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; import {webUIListenerCallback} from 'chrome://resources/ash/common/cr.m.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; @@ -3738,7 +3738,7 @@ .innerText); // In guest mode, the system row should be hidden. - storagePage.isGuest_ = true; + storagePage.isEphemeralUser_ = true; flush(); assertFalse( isVisible(storagePage.shadowRoot.querySelector('#systemSize'))); @@ -3779,7 +3779,7 @@ assertEquals('322 MB', getStorageItemSubLabelFromId('otherUsersSize')); // If the user is in Guest mode, the row is not visible. - storagePage.isGuest_ = true; + storagePage.isEphemeralUser_ = true; webUIListenerCallback( 'storage-other-users-size-changed', '322 MB', false); flush();
diff --git a/chrome/test/data/webui/settings/security_page_test.ts b/chrome/test/data/webui/settings/security_page_test.ts index 7606f12..506faa1 100644 --- a/chrome/test/data/webui/settings/security_page_test.ts +++ b/chrome/test/data/webui/settings/security_page_test.ts
@@ -685,19 +685,40 @@ 'recordSafeBrowsingInteractionHistogram')); }); - test('enhancedProtectionAutoExpanded', function() { + test('standardProtectionExpandedIfNoQueryParam', function() { // Standard protection should be pre-expanded if there is no param. Router.getInstance().navigateTo(routes.SECURITY); + assertEquals( + page.prefs.generated.safe_browsing.value, SafeBrowsingSetting.STANDARD); assertFalse(page.$.safeBrowsingEnhanced.expanded); assertTrue(page.$.safeBrowsingStandard.expanded); + }); + + test('enhancedProtectionExpandedIfEsbCollapseDisabled', function() { // Enhanced protection should be pre-expanded if the param is set to - // enhanced. + // enhanced and enableEsbCollapse is false. + loadTimeData.overrideValues({enableEsbCollapse: false}); Router.getInstance().navigateTo( routes.SECURITY, /* dynamicParams= */ new URLSearchParams('q=enhanced')); assertEquals( - SafeBrowsingSetting.STANDARD, page.prefs.generated.safe_browsing.value); + page.prefs.generated.safe_browsing.value, SafeBrowsingSetting.STANDARD); assertTrue(page.$.safeBrowsingEnhanced.expanded); assertFalse(page.$.safeBrowsingStandard.expanded); }); + + test('enhancedProtectionCollapsedIfEsbCollapseEnabled', function() { + // Enhanced protection should be collapsed if the param is set to + // enhanced and enableEsbCollapse is true. + loadTimeData.overrideValues({enableEsbCollapse: true}); + + Router.getInstance().navigateTo( + routes.SECURITY, + /* dynamicParams= */ new URLSearchParams('q=enhanced')); + assertEquals( + page.prefs.generated.safe_browsing.value, SafeBrowsingSetting.STANDARD); + assertFalse(page.$.safeBrowsingEnhanced.expanded); + assertFalse(page.$.safeBrowsingStandard.expanded); + }); + });
diff --git a/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts b/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts index cb13e76b..88b558f8 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts
@@ -386,4 +386,26 @@ '.action-button')! as HTMLElement; checkActionButtonStatus(actionButton, true); }); + + test('ShowErrorToastWhenTrackAndUntrackFailed', async () => { + shoppingListApi.getCallbackRouterRemote().operationFailedForBookmark( + products[0]!.bookmarkId, true); + await flushTasks(); + + assertTrue(shoppingList.$.errorToast.open); + shoppingList.$.errorToast.querySelector('cr-button')!.click(); + let id = await shoppingListApi.whenCalled('trackPriceForBookmark'); + assertEquals(id, products[0]!.bookmarkId); + assertFalse(shoppingList.$.errorToast.open); + + shoppingListApi.getCallbackRouterRemote().operationFailedForBookmark( + products[1]!.bookmarkId, false); + await flushTasks(); + + assertTrue(shoppingList.$.errorToast.open); + shoppingList.$.errorToast.querySelector('cr-button')!.click(); + id = await shoppingListApi.whenCalled('untrackPriceForBookmark'); + assertEquals(id, products[1]!.bookmarkId); + assertFalse(shoppingList.$.errorToast.open); + }); });
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/BUILD.gn b/chromeos/ash/services/multidevice_setup/public/cpp/BUILD.gn index fb9cfc26..51c70cd 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/BUILD.gn +++ b/chromeos/ash/services/multidevice_setup/public/cpp/BUILD.gn
@@ -121,6 +121,7 @@ ":cpp", "//chromeos/ash/services/multidevice_setup", "//chromeos/ash/services/multidevice_setup/public/mojom", + "//testing/gmock", "//url", ]
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.cc b/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.cc index ee4f673..d7befe0f 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.cc +++ b/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.cc
@@ -149,6 +149,11 @@ type, std::move(callback)); } +void FakeMultiDeviceSetupClient::SetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) { + qs_phone_instance_id_ = qs_phone_instance_id; +} + } // namespace multidevice_setup } // namespace ash
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h b/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h index fb50240..245c03b 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h +++ b/chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h
@@ -59,6 +59,8 @@ return num_remove_host_device_called_; } + const std::string& qs_phone_instance_id() { return qs_phone_instance_id_; } + // MultiDeviceSetupClient: const HostStatusWithDevice& GetHostStatus() const override; const FeatureStatesMap& GetFeatureStates() const override; @@ -83,8 +85,11 @@ mojom::EventTypeForDebugging type, mojom::MultiDeviceSetup::TriggerEventForDebuggingCallback callback) override; + void SetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) override; size_t num_remove_host_device_called_ = 0u; + std::string qs_phone_instance_id_; std::queue<GetEligibleHostDevicesCallback> get_eligible_host_devices_callback_queue_;
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h index e4c500e7..b9928903 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h +++ b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h
@@ -81,6 +81,8 @@ virtual void TriggerEventForDebugging( mojom::EventTypeForDebugging type, mojom::MultiDeviceSetup::TriggerEventForDebuggingCallback callback) = 0; + virtual void SetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) = 0; protected: void NotifyHostStatusChanged(
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.cc b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.cc index e1377fe..1e60388 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.cc +++ b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.cc
@@ -168,6 +168,11 @@ std::move(callback)); } +void MultiDeviceSetupClientImpl::SetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) { + multidevice_setup_remote_->SetQuickStartPhoneInstanceID(qs_phone_instance_id); +} + void MultiDeviceSetupClientImpl::OnHostStatusChanged( mojom::HostStatus host_status, const absl::optional<multidevice::RemoteDevice>& host_device) {
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h index 6730412..dca3a2d 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h +++ b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h
@@ -71,6 +71,8 @@ mojom::EventTypeForDebugging type, mojom::MultiDeviceSetup::TriggerEventForDebuggingCallback callback) override; + void SetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) override; // mojom::HostStatusObserver: void OnHostStatusChanged(
diff --git a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc index fa59aea2..e2b3560 100644 --- a/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc +++ b/chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl_unittest.cc
@@ -344,6 +344,20 @@ EXPECT_EQ(expect_success, trigger_event_for_debugging_success_); } + void CallSetQuickStartPhoneInstanceID( + const std::string& qs_phone_instance_id) { + EXPECT_EQ(0u, + fake_multidevice_setup_->set_qs_phone_instance_id_args().size()); + + client_->SetQuickStartPhoneInstanceID(qs_phone_instance_id); + SendPendingMojoMessages(); + + EXPECT_EQ(1u, + fake_multidevice_setup_->set_qs_phone_instance_id_args().size()); + EXPECT_EQ(qs_phone_instance_id, + fake_multidevice_setup_->set_qs_phone_instance_id_args().front()); + } + MultiDeviceSetupClient* client() { return client_.get(); } base::HistogramTester histogram_tester_; @@ -589,6 +603,12 @@ false /* expect_success */); } +TEST_F(MultiDeviceSetupClientImplTest, TestSetQuickStartPhoneInstanceID) { + InitializeClient(); + CallSetQuickStartPhoneInstanceID( + "phoneInstanceID1" /* qs_phone_instance_id */); +} + } // namespace multidevice_setup } // namespace ash
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 14ff043..b81f039 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -3905,9 +3905,6 @@ <message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_SETTINGS" desc="The text read aloud by the screen reader describing the keyboard icon 'settings'." translateable="false"> settings </message> - <message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_SPACE" desc="The text read aloud by the screen reader describing the keyboard icon 'space'." translateable="false"> - space - </message> <message name="IDS_SHORTCUT_CUSTOMIZATION_ICON_LABEL_ZOOM_TOGGLE" desc="The text read aloud by the screen reader describing the keyboard icon 'full screen'." translateable="false"> full screen </message>
diff --git a/components/app_restore/app_restore_data.cc b/components/app_restore/app_restore_data.cc index 2eb89ba0..11814d84 100644 --- a/components/app_restore/app_restore_data.cc +++ b/components/app_restore/app_restore_data.cc
@@ -69,23 +69,23 @@ // Gets bool value from base::Value::Dict, e.g. { "key": true } returns // true. absl::optional<bool> GetBoolValueFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { return dict.FindBool(key_name); } // Gets int value from base::Value::Dict, e.g. { "key": 100 } returns 100. absl::optional<int32_t> GetIntValueFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { return dict.FindInt(key_name); } // Gets uint32_t value from base::Value::Dict, e.g. { "key": "123" } returns // 123. absl::optional<uint32_t> GetUIntValueFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { uint32_t result = 0; - if (!dict.contains(key_name) || - !base::StringToUint(dict.FindString(key_name)->c_str(), &result)) { + const std::string* value = dict.FindString(key_name); + if (!value || !base::StringToUint(*value, &result)) { return absl::nullopt; } return result; @@ -93,20 +93,20 @@ absl::optional<std::string> GetStringValueFromDict( const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { const std::string* value = dict.FindString(key_name); return value ? absl::optional<std::string>(*value) : absl::nullopt; } absl::optional<GURL> GetUrlValueFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { const std::string* value = dict.FindString(key_name); return value ? absl::optional<GURL>(*value) : absl::nullopt; } absl::optional<std::u16string> GetU16StringValueFromDict( const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { std::u16string result; const std::string* value = dict.FindString(key_name); if (!value || !base::UTF8ToUTF16(value->c_str(), value->length(), &result)) @@ -170,7 +170,7 @@ // Gets gfx::Size from base::Value, e.g. { 100, 300 } returns // gfx::Size(100, 300). absl::optional<gfx::Size> GetSizeFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { const base::Value::List* size_value = dict.FindList(key_name); if (!size_value || size_value->size() != 2) { return absl::nullopt; @@ -186,7 +186,7 @@ // Gets gfx::Rect from base::Value, e.g. { 0, 100, 200, 300 } returns // gfx::Rect(0, 100, 200, 300). absl::optional<gfx::Rect> GetBoundsRectFromDict(const base::Value::Dict& dict, - const std::string& key_name) { + base::StringPiece key_name) { const base::Value::List* rect_value = dict.FindList(key_name); if (!rect_value || rect_value->empty()) return absl::nullopt; @@ -223,42 +223,34 @@ AppRestoreData::AppRestoreData() = default; -AppRestoreData::AppRestoreData(base::Value&& value) { - const base::Value::Dict* data_dict = value.GetIfDict(); - if (!data_dict) { - DVLOG(0) << "Fail to parse app restore data. " - << "Cannot find the app restore data dict."; - return; - } - - event_flag = GetIntValueFromDict(*data_dict, kEventFlagKey); - container = GetIntValueFromDict(*data_dict, kContainerKey); - disposition = GetIntValueFromDict(*data_dict, kDispositionKey); - override_url = GetUrlValueFromDict(*data_dict, kOverrideUrlKey); - display_id = GetDisplayIdFromDict(*data_dict); - handler_id = GetStringValueFromDict(*data_dict, kHandlerIdKey); - urls = GetUrlsFromDict(*data_dict); - active_tab_index = GetIntValueFromDict(*data_dict, kActiveTabIndexKey); - file_paths = GetFilePathsFromDict(*data_dict); - app_type_browser = GetBoolValueFromDict(*data_dict, kAppTypeBrowserKey); - app_name = GetStringValueFromDict(*data_dict, kAppNameKey); - activation_index = GetIntValueFromDict(*data_dict, kActivationIndexKey); +AppRestoreData::AppRestoreData(base::Value::Dict&& data) { + event_flag = GetIntValueFromDict(data, kEventFlagKey); + container = GetIntValueFromDict(data, kContainerKey); + disposition = GetIntValueFromDict(data, kDispositionKey); + override_url = GetUrlValueFromDict(data, kOverrideUrlKey); + display_id = GetDisplayIdFromDict(data); + handler_id = GetStringValueFromDict(data, kHandlerIdKey); + urls = GetUrlsFromDict(data); + active_tab_index = GetIntValueFromDict(data, kActiveTabIndexKey); + file_paths = GetFilePathsFromDict(data); + app_type_browser = GetBoolValueFromDict(data, kAppTypeBrowserKey); + app_name = GetStringValueFromDict(data, kAppNameKey); + activation_index = GetIntValueFromDict(data, kActivationIndexKey); first_non_pinned_tab_index = - GetIntValueFromDict(*data_dict, kFirstNonPinnedTabIndexKey); - desk_id = GetIntValueFromDict(*data_dict, kDeskIdKey); - current_bounds = GetBoundsRectFromDict(*data_dict, kCurrentBoundsKey); - window_state_type = GetWindowStateTypeFromDict(*data_dict); - pre_minimized_show_state_type = - GetPreMinimizedShowStateTypeFromDict(*data_dict); - snap_percentage = GetUIntValueFromDict(*data_dict, kSnapPercentageKey); - maximum_size = GetSizeFromDict(*data_dict, kMaximumSizeKey); - minimum_size = GetSizeFromDict(*data_dict, kMinimumSizeKey); - title = GetU16StringValueFromDict(*data_dict, kTitleKey); - bounds_in_root = GetBoundsRectFromDict(*data_dict, kBoundsInRoot); - primary_color = GetUIntValueFromDict(*data_dict, kPrimaryColorKey); - status_bar_color = GetUIntValueFromDict(*data_dict, kStatusBarColorKey); + GetIntValueFromDict(data, kFirstNonPinnedTabIndexKey); + desk_id = GetIntValueFromDict(data, kDeskIdKey); + current_bounds = GetBoundsRectFromDict(data, kCurrentBoundsKey); + window_state_type = GetWindowStateTypeFromDict(data); + pre_minimized_show_state_type = GetPreMinimizedShowStateTypeFromDict(data); + snap_percentage = GetUIntValueFromDict(data, kSnapPercentageKey); + maximum_size = GetSizeFromDict(data, kMaximumSizeKey); + minimum_size = GetSizeFromDict(data, kMinimumSizeKey); + title = GetU16StringValueFromDict(data, kTitleKey); + bounds_in_root = GetBoundsRectFromDict(data, kBoundsInRoot); + primary_color = GetUIntValueFromDict(data, kPrimaryColorKey); + status_bar_color = GetUIntValueFromDict(data, kStatusBarColorKey); - const base::Value::Dict* intent_value = data_dict->FindDict(kIntentKey); + const base::Value::Dict* intent_value = data.FindDict(kIntentKey); if (intent_value) { intent = apps_util::ConvertDictToIntent(*intent_value); }
diff --git a/components/app_restore/app_restore_data.h b/components/app_restore/app_restore_data.h index fd0edc2..e7684d5 100644 --- a/components/app_restore/app_restore_data.h +++ b/components/app_restore/app_restore_data.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/component_export.h" +#include "base/values.h" #include "chromeos/ui/base/window_state_type.h" #include "components/services/app_service/public/cpp/app_launch_util.h" #include "components/services/app_service/public/cpp/intent.h" @@ -18,10 +19,6 @@ #include "ui/gfx/geometry/rect.h" #include "url/gurl.h" -namespace base { -class Value; -} - namespace app_restore { struct AppLaunchInfo; @@ -32,7 +29,7 @@ // written to the FullRestoreData file. struct COMPONENT_EXPORT(APP_RESTORE) AppRestoreData { AppRestoreData(); - explicit AppRestoreData(base::Value&& value); + explicit AppRestoreData(base::Value::Dict&& value); explicit AppRestoreData(std::unique_ptr<AppLaunchInfo> app_launch_info); AppRestoreData(const AppRestoreData&) = delete;
diff --git a/components/app_restore/full_restore_file_handler.cc b/components/app_restore/full_restore_file_handler.cc index 3b3bee14..acea9a0 100644 --- a/components/app_restore/full_restore_file_handler.cc +++ b/components/app_restore/full_restore_file_handler.cc
@@ -51,20 +51,19 @@ // This JSON file is written by Chrome, so it is safe to deserialise it // in-process. - JSONStringValueDeserializer deserializer(full_restore_data); - int error_code; - std::string error_message; - auto full_restore_value = - deserializer.Deserialize(&error_code, &error_message); - - if (!full_restore_value) { - DVLOG(0) << "Fail to deserialize json value from string with error code: " - << error_code << " and error message: " << error_message; + base::JSONReader::Result full_restore_value = + base::JSONReader::ReadAndReturnValueWithError(full_restore_data); + if (!full_restore_value.has_value()) { + DVLOG(0) + << "Fail to deserialize json value from string with error message: " + << full_restore_value.error().message << ", in line " + << full_restore_value.error().line << ", column " + << full_restore_value.error().column; return nullptr; } return std::make_unique<app_restore::RestoreData>( - std::move(full_restore_value)); + std::move(*full_restore_value)); } FullRestoreFileHandler::~FullRestoreFileHandler() = default;
diff --git a/components/app_restore/restore_data.cc b/components/app_restore/restore_data.cc index f606c1f..b50e79e 100644 --- a/components/app_restore/restore_data.cc +++ b/components/app_restore/restore_data.cc
@@ -29,32 +29,38 @@ RestoreData::RestoreData() = default; -RestoreData::RestoreData(std::unique_ptr<base::Value> restore_data_value) { - if (!restore_data_value || !restore_data_value->is_dict()) { +RestoreData::RestoreData(base::Value restore_data_value) { + base::Value::Dict* dict = restore_data_value.GetIfDict(); + if (!dict) { DVLOG(0) << "Fail to parse full restore data. " << "Cannot find the full restore data dict."; return; } - for (auto iter : restore_data_value->DictItems()) { + for (auto iter : *dict) { const std::string& app_id = iter.first; - base::Value* value = restore_data_value->FindDictKey(app_id); - if (!value || !value->is_dict()) { + base::Value::Dict* value = dict->FindDict(app_id); + if (!value) { DVLOG(0) << "Fail to parse full restore data. " << "Cannot find the app restore data dict."; continue; } - for (auto data_iter : value->DictItems()) { + for (auto data_iter : *value) { int window_id = 0; if (!base::StringToInt(data_iter.first, &window_id)) { DVLOG(0) << "Fail to parse full restore data. " << "Cannot find the valid id."; continue; } + base::Value::Dict* app_restore_data = value->FindDict(data_iter.first); + if (!app_restore_data) { + DVLOG(0) << "Fail to parse app restore data. " + << "Cannot find the app restore data dict."; + continue; + } app_id_to_launch_list_[app_id][window_id] = - std::make_unique<AppRestoreData>( - std::move(*value->FindDictKey(data_iter.first))); + std::make_unique<AppRestoreData>(std::move(*app_restore_data)); } } }
diff --git a/components/app_restore/restore_data.h b/components/app_restore/restore_data.h index 5607bd9e..019d001 100644 --- a/components/app_restore/restore_data.h +++ b/components/app_restore/restore_data.h
@@ -9,6 +9,7 @@ #include <memory> #include "base/component_export.h" +#include "base/values.h" #include "components/app_restore/app_restore_data.h" namespace base { @@ -32,7 +33,7 @@ using AppIdToLaunchList = std::map<std::string, LaunchList>; RestoreData(); - explicit RestoreData(std::unique_ptr<base::Value> restore_data_value); + explicit RestoreData(base::Value restore_data_value); RestoreData(const RestoreData&) = delete; RestoreData& operator=(const RestoreData&) = delete; ~RestoreData();
diff --git a/components/app_restore/restore_data_unittest.cc b/components/app_restore/restore_data_unittest.cc index c30e6212..5afe53c 100644 --- a/components/app_restore/restore_data_unittest.cc +++ b/components/app_restore/restore_data_unittest.cc
@@ -603,10 +603,8 @@ AddAppLaunchInfos(); ModifyWindowInfos(); ModifyThemeColors(); - std::unique_ptr<base::Value> value = - std::make_unique<base::Value>(restore_data().ConvertToValue()); std::unique_ptr<RestoreData> restore_data = - std::make_unique<RestoreData>(std::move(value)); + std::make_unique<RestoreData>(this->restore_data().ConvertToValue()); // Full restore is not responsible for serializing or deseraizling // TabGroupInfos. VerifyRestoreData(*restore_data, /*test_tab_group_infos=*/false); @@ -616,10 +614,8 @@ restore_data().AddAppLaunchInfo(nullptr); EXPECT_TRUE(app_id_to_launch_list().empty()); - std::unique_ptr<base::Value> value = - std::make_unique<base::Value>(restore_data().ConvertToValue()); std::unique_ptr<RestoreData> restore_data = - std::make_unique<RestoreData>(std::move(value)); + std::make_unique<RestoreData>(this->restore_data().ConvertToValue()); EXPECT_TRUE(app_id_to_launch_list(*restore_data).empty()); }
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index ad01abd8..24c6f2ed 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -14,6 +14,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_external_delegate.h" @@ -93,10 +94,14 @@ return *current_instance_; } -AutofillTestEnvironment::AutofillTestEnvironment() { +AutofillTestEnvironment::AutofillTestEnvironment(const Options& options) { CHECK(!current_instance_) << "An autofill::test::AutofillTestEnvironment has " "already been registered."; current_instance_ = this; + if (options.disable_server_communication) { + scoped_feature_list_.InitAndDisableFeature( + features::test::kAutofillServerCommunication); + } } AutofillTestEnvironment::~AutofillTestEnvironment() { @@ -117,7 +122,9 @@ return FieldRendererId(++field_renderer_id_counter_); } -AutofillBrowserTestEnvironment::AutofillBrowserTestEnvironment() = default; +AutofillBrowserTestEnvironment::AutofillBrowserTestEnvironment( + const Options& options) + : AutofillTestEnvironment(options) {} LocalFrameToken MakeLocalFrameToken(RandomizeFrame randomize) { if (*randomize) {
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h index 82cfcb2c..b83c1c9 100644 --- a/components/autofill/core/browser/autofill_test_utils.h +++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -84,6 +84,10 @@ // be reset automatically after each test. class AutofillTestEnvironment { public: + struct Options { + bool disable_server_communication = true; + }; + static AutofillTestEnvironment& GetCurrent(const base::Location& = FROM_HERE); AutofillTestEnvironment(const AutofillTestEnvironment&) = delete; @@ -95,10 +99,12 @@ FieldRendererId NextFieldRendererId(); protected: - AutofillTestEnvironment(); + explicit AutofillTestEnvironment(const Options& options = { + .disable_server_communication = false}); private: static AutofillTestEnvironment* current_instance_; + base::test::ScopedFeatureList scoped_feature_list_; // Use some distinct 64 bit numbers to start the counters. uint64_t local_frame_token_counter_high_ = 0xAAAAAAAAAAAAAAAA; @@ -113,10 +119,12 @@ AutofillUnitTestEnvironment() = default; }; -// This encapsulates global browsertest state. +// This encapsulates global browsertest state. By default this environment +// disables `kAutofillServerCommunication` feature. class AutofillBrowserTestEnvironment : public AutofillTestEnvironment { public: - AutofillBrowserTestEnvironment(); + explicit AutofillBrowserTestEnvironment( + const Options& options = {.disable_server_communication = false}); }; // Creates non-empty LocalFrameToken. If `randomize` is false, the
diff --git a/components/commerce/core/mojom/shopping_list.mojom b/components/commerce/core/mojom/shopping_list.mojom index 3398362..510cbb1 100644 --- a/components/commerce/core/mojom/shopping_list.mojom +++ b/components/commerce/core/mojom/shopping_list.mojom
@@ -77,4 +77,10 @@ // Callback when a bookmark with `bookmark_id` is observed to stop being // price tracked. PriceUntrackedForBookmark(int64 bookmark_id); + + // Callback to notify the WebUI to show error UI when a track/untrack + // attempt for bookmark with `bookmark_id` failed. `attempted_track` is + // true when the failed operation is to track price, false when the + // failed operation is to untrack price. + OperationFailedForBookmark(int64 bookmark_id, bool attempted_track); }; \ No newline at end of file
diff --git a/components/commerce/core/webui/shopping_list_handler.cc b/components/commerce/core/webui/shopping_list_handler.cc index 4412904..dc2c8ba 100644 --- a/components/commerce/core/webui/shopping_list_handler.cc +++ b/components/commerce/core/webui/shopping_list_handler.cc
@@ -236,5 +236,9 @@ } else { remote_page_->PriceUntrackedForBookmark(bookmark_id); } + // Pass in whether the failed operation was to track or untrack price. It + // should be the reverse of the current tracking status since the operation + // failed. + remote_page_->OperationFailedForBookmark(bookmark_id, is_tracking); } } // namespace commerce
diff --git a/components/commerce/core/webui/shopping_list_handler_unittest.cc b/components/commerce/core/webui/shopping_list_handler_unittest.cc index 65517da3..a9cf5fe7 100644 --- a/components/commerce/core/webui/shopping_list_handler_unittest.cc +++ b/components/commerce/core/webui/shopping_list_handler_unittest.cc
@@ -43,6 +43,8 @@ MOCK_METHOD1(PriceTrackedForBookmark, void(shopping_list::mojom::BookmarkProductInfoPtr product)); MOCK_METHOD1(PriceUntrackedForBookmark, void(int64_t bookmark_id)); + MOCK_METHOD2(OperationFailedForBookmark, + void(int64_t bookmark_id, bool is_tracked)); }; void GetEvaluationProductInfos( @@ -186,6 +188,8 @@ EXPECT_CALL(page_, PriceTrackedForBookmark(MojoBookmarkInfoWithId(product->id()))) .Times(1); + EXPECT_CALL(page_, OperationFailedForBookmark(testing::_, testing::_)) + .Times(0); handler_->TrackPriceForBookmark(product->id()); @@ -205,6 +209,8 @@ Unsubscribe(VectorHasSubscriptionWithId("123"), testing::_)) .Times(1); EXPECT_CALL(page_, PriceUntrackedForBookmark(product->id())).Times(1); + EXPECT_CALL(page_, OperationFailedForBookmark(testing::_, testing::_)) + .Times(0); handler_->UntrackPriceForBookmark(product->id()); @@ -227,6 +233,7 @@ // "untrack" should be called once to undo the "track" change in the UI. EXPECT_CALL(page_, PriceUntrackedForBookmark(product->id())).Times(1); EXPECT_CALL(page_, PriceTrackedForBookmark(testing::_)).Times(0); + EXPECT_CALL(page_, OperationFailedForBookmark(product->id(), true)).Times(1); handler_->TrackPriceForBookmark(product->id()); @@ -249,6 +256,7 @@ // "track" should be called once to undo the "untrack" change in the UI. EXPECT_CALL(page_, PriceTrackedForBookmark(testing::_)).Times(1); EXPECT_CALL(page_, PriceUntrackedForBookmark(product->id())).Times(0); + EXPECT_CALL(page_, OperationFailedForBookmark(product->id(), false)).Times(1); handler_->UntrackPriceForBookmark(product->id());
diff --git a/components/commerce_strings.grdp b/components/commerce_strings.grdp index 492ebfe..b0a39db 100644 --- a/components/commerce_strings.grdp +++ b/components/commerce_strings.grdp
@@ -142,6 +142,9 @@ <message name="IDS_PRICE_TRACKING_TRACK_PRODUCT_ACCESSIBILITY" desc="Accessibility string for the price tracking toggle button and bell icon when this product is not currently being tracked. User can click this button or icon to track this product."> Track Price </message> + <message name="IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON" desc="Text shown in side panel toast button when an attempt to track or untrack a product failed. Clicking the button would retry the failed attempt to track or untrack a product."> + Try Again + </message> </if> <!-- is_macosx --> <if expr="not is_macosx"> <message name="IDS_SIDE_PANEL_UNTRACK_BUTTON" desc="Text shown when user right-clicks a tracked product from the side panel. User can click this button to untrack this product."> @@ -162,6 +165,9 @@ <message name="IDS_PRICE_TRACKING_TRACK_PRODUCT_ACCESSIBILITY" desc="Accessibility string for the price tracking toggle button and bell icon when this product is not currently being tracked. User can click this button or icon to track this product."> Track price </message> + <message name="IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON" desc="Text shown in side panel toast button when an attempt to track or untrack a product failed. Clicking the button would retry the failed attempt to track or untrack a product."> + Try again + </message> </if> <!-- not is_macosx --> <message name="IDS_PRICE_TRACKING_SETTINGS_TITLE" desc="Text shown in chrome settings. User can turn on or off the toggle next to this setting item to manage whether they want to receive price drop notifications."> @@ -173,6 +179,9 @@ <message name="IDS_PRICE_TRACKING_SETTINGS_POPUP_DESCRIPTION" desc="Text shown in chrome settings indicating that the price drop notifications will be sent via chrome popups. User can turn on or off the toggle next to this setting item to manage whether they want to receive such notifications."> Price drop alerts show up as popup notifications on your desktop </message> + <message name="IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_MESSAGE" desc="Text shown in side panel toast when an attempt to track or untrack a product failed."> + Something went wrong. + </message> </if> <!-- Android only -->
diff --git a/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON.png.sha1 b/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON.png.sha1 new file mode 100644 index 0000000..09898381 --- /dev/null +++ b/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_BUTTON.png.sha1
@@ -0,0 +1 @@ +7c745e3237fbc6706ff69a6c4de73c808237f7d6 \ No newline at end of file
diff --git a/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_MESSAGE.png.sha1 b/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_MESSAGE.png.sha1 new file mode 100644 index 0000000..09898381 --- /dev/null +++ b/components/commerce_strings_grdp/IDS_PRICE_TRACKING_SIDE_PANEL_ERROR_MESSAGE.png.sha1
@@ -0,0 +1 @@ +7c745e3237fbc6706ff69a6c4de73c808237f7d6 \ No newline at end of file
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc index c375676..987e947 100644 --- a/components/dom_distiller/core/viewer.cc +++ b/components/dom_distiller/core/viewer.cc
@@ -230,9 +230,9 @@ } const std::string GetSetTitleJs(std::string title) { -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) +#if BUILDFLAG(IS_IOS) base::Value suffixValue(""); -#else // Desktop +#else // Desktop and Android. std::string suffix( l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_TITLE_SUFFIX)); base::Value suffixValue(" - " + suffix);
diff --git a/components/dom_distiller_strings.grdp b/components/dom_distiller_strings.grdp index b67a6fde..658d5a0 100644 --- a/components/dom_distiller_strings.grdp +++ b/components/dom_distiller_strings.grdp
@@ -88,8 +88,17 @@ <message name="IDS_DOM_DISTILLER_WEBUI_TITLE" desc="The title to show on the DOM Distiller debug page."> DOM Distiller </message> - <message name="IDS_DOM_DISTILLER_VIEWER_TITLE_SUFFIX" desc="The suffix to show after the page title to indicate we are in reader mode. For example, if the page title was 'An Article', this would be appended to create the title 'An Article - Reader Mode'."> - Reader Mode - </message> + <if expr="is_android"> + <then> + <message name="IDS_DOM_DISTILLER_VIEWER_TITLE_SUFFIX" desc="The suffix to show after the page title to indicate we are in reader mode. For example, if the page title was 'An Article', this would be appended to create the title 'An Article - Simplified View'."> + Simplified View + </message> + </then> + <else> + <message name="IDS_DOM_DISTILLER_VIEWER_TITLE_SUFFIX" desc="The suffix to show after the page title to indicate we are in reader mode. For example, if the page title was 'An Article', this would be appended to create the title 'An Article - Reader Mode'."> + Reader Mode + </message> + </else> + </if> </grit-part>
diff --git a/components/exo/wayland/clients/globals.h b/components/exo/wayland/clients/globals.h index 5fbdf9e..654d1a2 100644 --- a/components/exo/wayland/clients/globals.h +++ b/components/exo/wayland/clients/globals.h
@@ -46,6 +46,8 @@ std::unique_ptr<wl_registry> registry; + // TODO(aluh): Support multiple outputs, and probably other globals like + // aura_output, seat, etc. Object<wl_output> output; Object<wl_compositor> compositor; Object<wl_shm> shm;
diff --git a/components/exo/wayland/test/test_client.h b/components/exo/wayland/test/test_client.h index 89e6959..199549f2 100644 --- a/components/exo/wayland/test/test_client.h +++ b/components/exo/wayland/test/test_client.h
@@ -45,6 +45,11 @@ return globals_; } + clients::Globals& globals() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return globals_; + } + // Convenient getters of globals. wl_output* output() { return globals().output.get(); } wl_compositor* compositor() { return globals().compositor.get(); }
diff --git a/components/exo/wayland/wayland_display_observer.cc b/components/exo/wayland/wayland_display_observer.cc index bfa8c803..3c9b695 100644 --- a/components/exo/wayland/wayland_display_observer.cc +++ b/components/exo/wayland/wayland_display_observer.cc
@@ -22,17 +22,22 @@ namespace exo { namespace wayland { +WaylandDisplayObserver::WaylandDisplayObserver() = default; + +WaylandDisplayObserver::~WaylandDisplayObserver() = default; + WaylandDisplayHandler::WaylandDisplayHandler(WaylandDisplayOutput* output, wl_resource* output_resource) - : output_(output), output_resource_(output_resource) { -} + : output_(output), output_resource_(output_resource) {} WaylandDisplayHandler::~WaylandDisplayHandler() { ash::Shell::Get()->RemoveShellObserver(this); - for (auto& obs : observers_) + for (auto& obs : observers_) { obs.OnOutputDestroyed(); - if (xdg_output_resource_) + } + if (xdg_output_resource_) { wl_resource_set_user_data(xdg_output_resource_, nullptr); + } output_->UnregisterOutput(output_resource_); } @@ -47,8 +52,8 @@ observers_.AddObserver(observer); display::Display display; - bool exists = display::Screen::GetScreen()->GetDisplayWithDisplayId( - output_->id(), &display); + bool exists = + display::Screen::GetScreen()->GetDisplayWithDisplayId(id(), &display); if (!exists) { // WaylandDisplayHandler is created asynchronously, and the // display can be deleted before created. This usually won't happen @@ -81,12 +86,14 @@ uint32_t changed_metrics) { DCHECK(output_resource_); - if (output_->id() != display.id()) + if (id() != display.id()) { return; + } bool needs_done = false; - for (auto& observer : observers_) + for (auto& observer : observers_) { needs_done |= observer.SendDisplayMetrics(display, changed_metrics); + } if (needs_done) { if (wl_resource_get_version(output_resource_) >= @@ -99,13 +106,13 @@ void WaylandDisplayHandler::OnDisplayForNewWindowsChanged() { DCHECK(output_resource_); - if (output_->id() != - display::Screen::GetScreen()->GetDisplayForNewWindows().id()) { + if (id() != display::Screen::GetScreen()->GetDisplayForNewWindows().id()) { return; } - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SendActiveDisplay(); + } } void WaylandDisplayHandler::OnXdgOutputCreated( @@ -114,8 +121,7 @@ xdg_output_resource_ = xdg_output_resource; display::Display display; - if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(output_->id(), - &display)) { + if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(id(), &display)) { return; } OnDisplayMetricsChanged(display, 0xFFFFFFFF); @@ -143,8 +149,9 @@ bool WaylandDisplayHandler::SendDisplayMetrics(const display::Display& display, uint32_t changed_metrics) { - if (!output_resource_) + if (!output_resource_) { return false; + } // There is no need to check DISPLAY_METRIC_PRIMARY because when primary // changes, bounds always changes. (new primary should have had non @@ -197,8 +204,9 @@ size_t WaylandDisplayHandler::CountObserversForTesting() const { size_t count = 0; for (auto& obs : observers_) { - if (&obs != this) + if (&obs != this) { count++; + } } return count; }
diff --git a/components/exo/wayland/wayland_display_observer.h b/components/exo/wayland/wayland_display_observer.h index 1a67938..f0c92bc 100644 --- a/components/exo/wayland/wayland_display_observer.h +++ b/components/exo/wayland/wayland_display_observer.h
@@ -24,7 +24,7 @@ // "done" event through WaylandDisplayHandler. class WaylandDisplayObserver : public base::CheckedObserver { public: - WaylandDisplayObserver() {} + WaylandDisplayObserver(); // Returns |true| if the observer reported any changes and needs // to be followed by "done" event, |false| otherwise. @@ -39,7 +39,7 @@ virtual void OnOutputDestroyed() = 0; protected: - ~WaylandDisplayObserver() override {} + ~WaylandDisplayObserver() override; }; class WaylandDisplayHandler : public display::DisplayObserver, @@ -69,7 +69,6 @@ void UnsetXdgOutputResource(); size_t CountObserversForTesting() const; - WaylandDisplayOutput* GetWaylandDisplayOutputForTesting() { return output_; } protected: wl_resource* output_resource() const { return output_resource_; }
diff --git a/components/exo/wayland/wayland_display_output_unittest.cc b/components/exo/wayland/wayland_display_output_unittest.cc index c471366..c2f6677 100644 --- a/components/exo/wayland/wayland_display_output_unittest.cc +++ b/components/exo/wayland/wayland_display_output_unittest.cc
@@ -36,11 +36,10 @@ } // namespace -// TODO(crbug.com/1420468): Failing on an ASAN + LSAN builder; also flaky on -// other builds. -TEST_F(WaylandDisplayOutputTest, DISABLED_DelayedSelfDestruct) { +TEST_F(WaylandDisplayOutputTest, DelayedSelfDestruct) { class ClientData : public test::TestClient::CustomData { public: + wl_output* output = nullptr; uint32_t output_name = 0; uint32_t output_version = 0; }; @@ -52,6 +51,9 @@ test::ResourceKey output_resource_key; PostToClientAndWait([&](test::TestClient* client) { auto data = std::make_unique<ClientData>(); + // This gets the latest bound output on the client side, which should be the + // 2nd display here. + data->output = client->output(); data->output_name = client->globals().output.name(); data->output_version = wl_proxy_get_version(reinterpret_cast<wl_proxy*>(client->output())); @@ -68,34 +70,27 @@ // Remove the 2nd display. UpdateDisplay("800x600"); - // Fast forward until a couple deletes have been attempted. - task_environment()->FastForwardBy( - WaylandDisplayOutput::kDeleteTaskDelay * - (WaylandDisplayOutput::kDeleteRetries - 0.5)); + // Fast forward until at least one delete has been attempted. + task_environment()->FastForwardBy(WaylandDisplayOutput::kDeleteTaskDelay * + 1.5); // Try binding and check for client error. PostToClientAndWait([&](test::TestClient* client) { auto* data = client->GetDataAs<ClientData>(); - EXPECT_TRUE(static_cast<wl_output*>( - wl_registry_bind(client->globals().registry.get(), data->output_name, - &wl_output_interface, data->output_version))); + EXPECT_EQ(data->output, client->globals().output.get()); + wl_output_release(client->globals().output.release()); client->Roundtrip(); EXPECT_EQ(wl_display_get_error(client->display()), 0); }); + + task_environment()->FastForwardBy(WaylandDisplayOutput::kDeleteTaskDelay * + WaylandDisplayOutput::kDeleteRetries); } // Verify that in the case where an output is added and removed quickly before // the client's initial bind, the server still waits for the full amount of // delete delays before deleting the global resource. -// TODO(crbug.com/1420468): Flaky on an ASAN + LSAN builder. -#if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER) -#define MAYBE_DelayedSelfDestructBeforeFirstBind \ - DISABLED_DelayedSelfDestructBeforeFirstBind -#else -#define MAYBE_DelayedSelfDestructBeforeFirstBind \ - DelayedSelfDestructBeforeFirstBind -#endif -TEST_F(WaylandDisplayOutputTest, MAYBE_DelayedSelfDestructBeforeFirstBind) { +TEST_F(WaylandDisplayOutputTest, DelayedSelfDestructBeforeFirstBind) { UpdateDisplay("800x600"); // Block client thread so the initial bind request doesn't happen yet. @@ -107,10 +102,9 @@ UpdateDisplay("800x600,1024x786"); UpdateDisplay("800x600"); - // Fast forward so at least one delete has been attempted. - task_environment()->FastForwardBy( - WaylandDisplayOutput::kDeleteTaskDelay * - (WaylandDisplayOutput::kDeleteRetries - 0.5)); + // Fast forward until at least one delete has been attempted. + task_environment()->FastForwardBy(WaylandDisplayOutput::kDeleteTaskDelay * + 1.5); // Unblock client thread so the bind request happens now. block_bind_event.Signal(); @@ -121,6 +115,9 @@ client->Roundtrip(); EXPECT_EQ(wl_display_get_error(client->display()), 0); }); + + task_environment()->FastForwardBy(WaylandDisplayOutput::kDeleteTaskDelay * + WaylandDisplayOutput::kDeleteRetries); } } // namespace exo::wayland
diff --git a/components/language/core/common/language_experiments.cc b/components/language/core/common/language_experiments.cc index 07a4d2b..eddc4487f 100644 --- a/components/language/core/common/language_experiments.cc +++ b/components/language/core/common/language_experiments.cc
@@ -28,7 +28,7 @@ base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kDesktopDetailedLanguageSettings, "DesktopDetailedLanguageSettings", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kTranslateAssistContent, "TranslateAssistContent", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/media_message_center/media_notification_view_ash_impl.cc b/components/media_message_center/media_notification_view_ash_impl.cc index ca2c6f4..856d8bbd 100644 --- a/components/media_message_center/media_notification_view_ash_impl.cc +++ b/components/media_message_center/media_notification_view_ash_impl.cc
@@ -36,7 +36,7 @@ constexpr int kMainSeparator = 12; constexpr int kMainRowSeparator = 8; constexpr int kMediaInfoSeparator = 4; -constexpr int kPlayPauseContainerSeperator = 8; +constexpr int kPlayPauseContainerSeparator = 8; constexpr int kPlayPauseIconSize = 26; constexpr int kControlsIconSize = 20; constexpr int kBackgroundCornerRadius = 12; @@ -48,9 +48,6 @@ constexpr auto kPlayPauseButtonSize = gfx::Size(48, 48); constexpr auto kControlsButtonSize = gfx::Size(32, 32); -// TODO(jazzhsu): Make sure the media button style match the mock. 1. The play -// pause button should always have a background; 2. Figure out the hover effect -// for the rest of the controls. class MediaButton : public views::ImageButton { public: MediaButton(PressedCallback callback, int icon_size, gfx::Size button_size) @@ -59,8 +56,7 @@ views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(), button_size.height() / 2); views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::ON); - views::InkDrop::Get(this)->SetBaseColorCallback(base::BindRepeating( - &MediaButton::GetForegroundColor, base::Unretained(this))); + views::InkDrop::Get(this)->SetBaseColor(foreground_color_); SetImageHorizontalAlignment(ImageButton::ALIGN_CENTER); SetImageVerticalAlignment(ImageButton::ALIGN_MIDDLE); SetFocusBehavior(views::View::FocusBehavior::ALWAYS); @@ -93,8 +89,6 @@ } private: - SkColor GetForegroundColor() { return foreground_color_; } - SkColor foreground_color_ = gfx::kPlaceholderColor; SkColor foreground_disabled_color_ = gfx::kPlaceholderColor; int icon_size_; @@ -175,18 +169,20 @@ artist_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); artist_label_->SetEnabledColor(theme_->secondary_text_color); - // |play_payse_container| holds the play/pause button and dismiss button. + // |play_pause_container| holds the play/pause button and dismiss button. auto* play_pause_container = main_row->AddChildView(std::make_unique<views::View>()); play_pause_container ->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, gfx::Insets(), - kPlayPauseContainerSeperator)) + kPlayPauseContainerSeparator)) ->set_cross_axis_alignment(views::BoxLayout::CrossAxisAlignment::kEnd); play_pause_container->AddChildView(std::move(dismiss_button)); play_pause_button_ = CreateMediaButton(play_pause_container, MediaSessionAction::kPlay); + play_pause_button_->SetBackground(views::CreateRoundedRectBackground( + theme_->background_color, kPlayPauseButtonSize.height() / 2)); // |controls_row| holds all available media action buttons and the progress // bar. @@ -237,9 +233,9 @@ button->set_tag(static_cast<int>(action)); button->SetButtonColor(theme_->enabled_icon_color, theme_->disabled_icon_color); + auto* button_ptr = parent->AddChildView(std::move(button)); action_buttons_.push_back(button_ptr); - return button_ptr; }
diff --git a/components/media_router/browser/BUILD.gn b/components/media_router/browser/BUILD.gn index 4db9ab0..4ea97b83 100644 --- a/components/media_router/browser/BUILD.gn +++ b/components/media_router/browser/BUILD.gn
@@ -88,6 +88,8 @@ "logger_impl.h", "media_router_debugger.cc", "media_router_debugger.h", + "mirroring_to_flinging_switcher.cc", + "mirroring_to_flinging_switcher.h", "presentation/presentation_navigation_policy.cc", "presentation/presentation_navigation_policy.h", ] @@ -145,6 +147,7 @@ "issue_manager_unittest.cc", "logger_impl_unittest.cc", "media_router_debugger_unittest.cc", + "mirroring_to_flinging_switcher_unittest.cc", ] } }
diff --git a/components/media_router/browser/mirroring_to_flinging_switcher.cc b/components/media_router/browser/mirroring_to_flinging_switcher.cc new file mode 100644 index 0000000..667d7b6e --- /dev/null +++ b/components/media_router/browser/mirroring_to_flinging_switcher.cc
@@ -0,0 +1,57 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/media_router/browser/mirroring_to_flinging_switcher.h" + +#include "components/media_router/browser/media_router.h" +#include "components/media_router/browser/media_router_factory.h" +#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/presentation_request.h" +#include "content/public/browser/web_contents.h" + +namespace media_router { + +void SwitchToFlingingIfPossible(int frame_tree_node_id) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + auto* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); + if (!web_contents) { + return; + } + + base::WeakPtr<WebContentsPresentationManager> + web_contents_presentation_manager = + WebContentsPresentationManager::Get(web_contents); + if (!web_contents_presentation_manager || + !web_contents_presentation_manager->HasDefaultPresentationRequest()) { + return; + } + + auto* media_router = MediaRouterFactory::GetApiForBrowserContextIfExists( + web_contents->GetBrowserContext()); + if (!media_router) { + return; + } + + // TODO(crbug.com/1418744): Handle multiple URLs. + const auto& presentation_request = + web_contents_presentation_manager->GetDefaultPresentationRequest(); + const auto source_id = + MediaSource::ForPresentationUrl(presentation_request.presentation_urls[0]) + .id(); + bool incognito = web_contents->GetBrowserContext()->IsOffTheRecord(); + + media_router->JoinRoute( + source_id, kAutoJoinPresentationId, presentation_request.frame_origin, + web_contents, + base::BindOnce(&WebContentsPresentationManager::OnPresentationResponse, + std::move(web_contents_presentation_manager), + presentation_request), + base::TimeDelta(), incognito); +} + +} // namespace media_router
diff --git a/components/media_router/browser/mirroring_to_flinging_switcher.h b/components/media_router/browser/mirroring_to_flinging_switcher.h new file mode 100644 index 0000000..eb14ed4 --- /dev/null +++ b/components/media_router/browser/mirroring_to_flinging_switcher.h
@@ -0,0 +1,18 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_MEDIA_ROUTER_BROWSER_MIRRORING_TO_FLINGING_SWITCHER_H_ +#define COMPONENTS_MEDIA_ROUTER_BROWSER_MIRRORING_TO_FLINGING_SWITCHER_H_ + +namespace media_router { + +// Switch mirroring session to a flinging session if the site (e.g. WebContents +// associated with the given `frame_tree_node_id`) has a +// DefaultPresentationRequest (e.g. uses the Cast Web Sender). +// Must be called on the UI thread. +void SwitchToFlingingIfPossible(int frame_tree_node_id); + +} // namespace media_router + +#endif // COMPONENTS_MEDIA_ROUTER_BROWSER_MIRRORING_TO_FLINGING_SWITCHER_H_
diff --git a/components/media_router/browser/mirroring_to_flinging_switcher_unittest.cc b/components/media_router/browser/mirroring_to_flinging_switcher_unittest.cc new file mode 100644 index 0000000..9d809ed0 --- /dev/null +++ b/components/media_router/browser/mirroring_to_flinging_switcher_unittest.cc
@@ -0,0 +1,143 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/media_router/browser/mirroring_to_flinging_switcher.h" + +#include "components/media_router/browser/media_router_factory.h" +#include "components/media_router/browser/presentation/web_contents_presentation_manager.h" +#include "components/media_router/browser/test/mock_media_router.h" +#include "content/public/browser/presentation_request.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/test_browser_context.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace media_router { + +class TestMediaRouterFactory : public MediaRouterFactory { + public: + TestMediaRouterFactory() = default; + ~TestMediaRouterFactory() override = default; + + void ResetTestingFactory(content::BrowserContext* context) { + BrowserContextDestroyed(context); + } + + MOCK_METHOD(KeyedService*, + BuildServiceInstanceFor, + (content::BrowserContext * context), + (const)); +}; + +class TestWebContentsPresentationManager + : public WebContentsPresentationManager { + public: + TestWebContentsPresentationManager() = default; + ~TestWebContentsPresentationManager() override = default; + + void SetDefaultPresentationRequest( + const content::PresentationRequest& request) { + default_presentation_request_ = request; + } + + bool HasDefaultPresentationRequest() const override { + return default_presentation_request_.has_value(); + } + + const content::PresentationRequest& GetDefaultPresentationRequest() + const override { + return *default_presentation_request_; + } + + base::WeakPtr<media_router::WebContentsPresentationManager> GetWeakPtr() + override { + return weak_factory_.GetWeakPtr(); + } + + // Not relevant for this test. + void AddObserver(content::PresentationObserver* observer) override {} + void RemoveObserver(content::PresentationObserver* observer) override {} + std::vector<MediaRoute> GetMediaRoutes() override { return {}; } + void OnPresentationResponse( + const content::PresentationRequest& presentation_request, + mojom::RoutePresentationConnectionPtr connection, + const RouteRequestResult& result) override {} + + private: + absl::optional<content::PresentationRequest> default_presentation_request_; + base::WeakPtrFactory<TestWebContentsPresentationManager> weak_factory_{this}; +}; + +class MirroringToFlingingSwitcherTest : public testing::Test { + public: + MirroringToFlingingSwitcherTest() = default; + + ~MirroringToFlingingSwitcherTest() override { + media_router_factory_.ResetTestingFactory(&browser_context_); + } + + void SetUp() override { + media_router_ = static_cast<MockMediaRouter*>( + media_router_factory_.SetTestingFactoryAndUse( + &browser_context_, base::BindRepeating(&MockMediaRouter::Create))); + ASSERT_TRUE( + MediaRouterFactory::GetApiForBrowserContextIfExists(&browser_context_)); + + web_contents_ = content::WebContents::Create( + content::WebContents::CreateParams(&browser_context_)); + + presentation_manager_ = + std::make_unique<TestWebContentsPresentationManager>(); + media_router::WebContentsPresentationManager::SetTestInstance( + presentation_manager_.get()); + } + + int GetNewTabSource() { + return web_contents_->GetPrimaryMainFrame()->GetFrameTreeNodeId(); + } + + protected: + content::BrowserTaskEnvironment task_environment_; + content::TestBrowserContext browser_context_; + TestMediaRouterFactory media_router_factory_; + raw_ptr<MockMediaRouter> media_router_ = nullptr; + std::unique_ptr<content::WebContents> web_contents_; + std::unique_ptr<TestWebContentsPresentationManager> presentation_manager_; +}; + +TEST_F(MirroringToFlingingSwitcherTest, SwitchToFlingingFaliure) { + // No switch to flinging is expected as DefaultPresentationRequest is not set. + EXPECT_CALL(*media_router_, JoinRouteInternal).Times(0); + SwitchToFlingingIfPossible(GetNewTabSource()); + task_environment_.RunUntilIdle(); +} + +// This test checks if a request for switching to flinging is sent. It doesn't +// actually verify if the flinging session started. +TEST_F(MirroringToFlingingSwitcherTest, SwitchToFlinging) { + content::PresentationRequest presentation_request( + {0, 0}, {GURL("https://defaultpresentation.com/")}, + url::Origin::Create(GURL("http://origin/"))); + presentation_manager_->SetDefaultPresentationRequest(presentation_request); + + ASSERT_TRUE(presentation_manager_->HasDefaultPresentationRequest()); + const auto source_id = + MediaSource::ForPresentationUrl(presentation_request.presentation_urls[0]) + .id(); + bool incognito = web_contents_->GetBrowserContext()->IsOffTheRecord(); + EXPECT_CALL( + *media_router_, + JoinRouteInternal(source_id, kAutoJoinPresentationId, + presentation_request.frame_origin, web_contents_.get(), + _, base::TimeDelta(), incognito)); + + // Switch to flinging request is expected to be sent. + SwitchToFlingingIfPossible(GetNewTabSource()); + task_environment_.RunUntilIdle(); +} + +} // namespace media_router
diff --git a/components/media_router/browser/presentation/presentation_service_delegate_impl.cc b/components/media_router/browser/presentation/presentation_service_delegate_impl.cc index ec6677a1..7b9901d28 100644 --- a/components/media_router/browser/presentation/presentation_service_delegate_impl.cc +++ b/components/media_router/browser/presentation/presentation_service_delegate_impl.cc
@@ -528,7 +528,7 @@ std::move(error_cb), mojom::RoutePresentationConnectionPtr(), *result); } else { - // TODO(crbug.com/627655): Handle multiple URLs. + // TODO(crbug.com/1418744): Handle multiple URLs. const GURL& presentation_url = presentation_urls[0]; bool incognito = GetWebContents().GetBrowserContext()->IsOffTheRecord(); router_->JoinRoute(
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h index 88d1da5..180be803 100644 --- a/components/password_manager/core/browser/password_manager_metrics_util.h +++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -642,7 +642,9 @@ kUsernameCopyButtonClicked = 3, kPasswordCopyButtonClicked = 4, kPasswordShowButtonClicked = 5, - kMaxValue = kPasswordShowButtonClicked, + kUsernameEditButtonClicked = 6, + kUsernameAdded = 7, + kMaxValue = kUsernameAdded, }; std::string GetPasswordAccountStorageUsageLevelHistogramSuffix(
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index a18261e6..eed10891 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -114,6 +114,13 @@ BASE_FEATURE(kIOSShowPasswordStorageInSaveInfobar, "IOSShowPasswordStorageInSaveInfobar", base::FEATURE_DISABLED_BY_DEFAULT); + +// Enables password bottom sheet to be displayed (on iOS) when a user is +// signed-in and taps on a username or password field on a website that has at +// least one credential saved in their password manager. +BASE_FEATURE(kIOSPasswordBottomSheet, + "IOSPasswordBottomSheet", + base::FEATURE_DISABLED_BY_DEFAULT); #endif // IS_IOS // Enables memory mapping the word lists used in the zxcvbn library employed
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index 83fa4d5..0c3a7436 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -44,6 +44,7 @@ BASE_DECLARE_FEATURE(kIOSPasswordManagerCrossOriginIframeSupport); BASE_DECLARE_FEATURE(kIOSPasswordCheckup); BASE_DECLARE_FEATURE(kIOSShowPasswordStorageInSaveInfobar); +BASE_DECLARE_FEATURE(kIOSPasswordBottomSheet); #endif // IS_IOS #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop BASE_DECLARE_FEATURE(kMemoryMapWeaknessCheckDictionaries);
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc index 5dce00e..0e56c9b 100644 --- a/components/safe_browsing/core/common/features.cc +++ b/components/safe_browsing/core/common/features.cc
@@ -53,6 +53,14 @@ "SafeBrowsingComponentUpdaterAndroidProtegoAllowlist", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kConnectorsScanningAccessToken, + "ConnectorsScanningAccessToken", + base::FEATURE_ENABLED_BY_DEFAULT); + +BASE_FEATURE(kConnectorsScanningReportOnlyUI, + "ConnectorsScanningReportOnlyUI", + base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kDelayedWarnings, "SafeBrowsingDelayedWarnings", base::FEATURE_DISABLED_BY_DEFAULT); @@ -191,6 +199,14 @@ "SafeBrowsingCsbrrNewDownloadTrigger", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kSafeBrowsingDisableConsumerCsdForEnterprise, + "SafeBrowsingDisableConsumerCsdForEnterprise", + base::FEATURE_ENABLED_BY_DEFAULT); + +BASE_FEATURE(kSafeBrowsingEnterpriseCsd, + "SafeBrowsingEnterpriseCsd", + base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kSafeBrowsingLookupMechanismExperiment, "SafeBrowsingLookupMechanismExperiment", base::FEATURE_DISABLED_BY_DEFAULT); @@ -287,6 +303,8 @@ {&kClientSideDetectionReferrerChain, true}, {&kClientSideDetectionTypeForceRequest, true}, {&kComponentUpdaterAndroidProtegoAllowlist, true}, + {&kConnectorsScanningAccessToken, true}, + {&kConnectorsScanningReportOnlyUI, true}, {&kDelayedWarnings, true}, {&kDownloadBubble, true}, {&kDownloadBubbleV2, true}, @@ -307,6 +325,8 @@ {&kRealTimeUrlFilteringForEnterprise, true}, {&kRealTimeUrlLookupForEnterpriseAllowlistBypass, true}, {&kSafeBrowsingCsbrrNewDownloadTrigger, true}, + {&kSafeBrowsingDisableConsumerCsdForEnterprise, true}, + {&kSafeBrowsingEnterpriseCsd, true}, {&kSafeBrowsingLookupMechanismExperiment, true}, {&kSafeBrowsingRemoveCookiesInAuthRequests, true}, {&kSevenZipEvaluationEnabled, true},
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h index f5fe2f3..3d97640 100644 --- a/components/safe_browsing/core/common/features.h +++ b/components/safe_browsing/core/common/features.h
@@ -49,6 +49,16 @@ // Enables serving the Android Protego allowlist through the component updater. BASE_DECLARE_FEATURE(kComponentUpdaterAndroidProtegoAllowlist); +// Controls whether an access token is attached to scanning requests triggered +// by enterprise Connectors. +BASE_DECLARE_FEATURE(kConnectorsScanningAccessToken); + +// Controls the non-blocking scanning UI for Connectors scanning requests. If +// this is enabled, the downloaded file(s) will be renamed immediately and the +// scanning will take place without UI when the policy is set to "non-blocking" +// instead of just showing an "Open Now" button with the blocking UI. +BASE_DECLARE_FEATURE(kConnectorsScanningReportOnlyUI); + // Controls whether the delayed warning experiment is enabled. BASE_DECLARE_FEATURE(kDelayedWarnings); // True if mouse clicks should undelay the warnings immediately when delayed @@ -188,6 +198,14 @@ // new triggers BASE_DECLARE_FEATURE(kSafeBrowsingCsbrrNewDownloadTrigger); +// Controls whether we are disabling consumer download checks for users using +// the enterprise download checks. +BASE_DECLARE_FEATURE(kSafeBrowsingDisableConsumerCsdForEnterprise); + +// Controls whether we are performing enterprise download checks for users +// with the appropriate policies enabled. +BASE_DECLARE_FEATURE(kSafeBrowsingEnterpriseCsd); + // Controls whether the lookup mechanism experiment is enabled, which runs all // three lookup mechanisms instead of just real-time URL lookups for ESB users. // The other two lookup mechanisms are run in the background, and the results
diff --git a/components/viz/common/quads/texture_draw_quad.h b/components/viz/common/quads/texture_draw_quad.h index efce38d..694d33e 100644 --- a/components/viz/common/quads/texture_draw_quad.h +++ b/components/viz/common/quads/texture_draw_quad.h
@@ -93,7 +93,7 @@ // This optional damage is in target render pass coordinate space. absl::optional<gfx::Rect> damage_rect; - struct RoundedDisplayMasksInfo { + struct VIZ_COMMON_EXPORT RoundedDisplayMasksInfo { static constexpr size_t kMaxRoundedDisplayMasksCount = 2; static constexpr size_t kOriginRoundedDisplayMaskIndex = 0; static constexpr size_t kOtherRoundedDisplayMaskIndex = 1;
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc index 6c1b637..08a4429 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.cc +++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -24,6 +24,7 @@ #include "components/viz/common/quads/aggregated_render_pass.h" #include "components/viz/common/quads/quad_list.h" #include "components/viz/common/quads/solid_color_draw_quad.h" +#include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/service/debugger/viz_debugger.h" #include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/output_surface.h" @@ -36,8 +37,6 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/transform.h" -#include "components/viz/common/quads/texture_draw_quad.h" - namespace viz { namespace { @@ -62,6 +61,15 @@ "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysAttempted"; constexpr char kNumOverlaysFailedHistogramName[] = "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysFailed"; +constexpr char kWorkingScaleFactorHistogramName[] = + "Compositing.Display.OverlayProcessorUsingStrategy." + "WorkingScaleFactorForRequiredOverlays"; +constexpr char kFramesAttemptingRequiredOverlaysHistogramName[] = + "Compositing.Display.OverlayProcessorUsingStrategy." + "FramesAttemptingRequiredOverlays"; +constexpr char kFramesScalingRequiredOverlaysHistogramName[] = + "Compositing.Display.OverlayProcessorUsingStrategy." + "FramesScalingRequiredOverlays"; // Gets the minimum scaling amount used by either dimension for the src relative // to the dst. @@ -111,6 +119,29 @@ UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", strategy); } +static void LogFramesAttemptingRequiredCandidateBoolUMA( + const std::vector<OverlayProposedCandidate>& proposed_candidates) { + for (const auto& proposed_candidate : proposed_candidates) { + if (proposed_candidate.candidate.requires_overlay) { + UMA_HISTOGRAM_BOOLEAN(kFramesAttemptingRequiredOverlaysHistogramName, + true); + return; + } + } + UMA_HISTOGRAM_BOOLEAN(kFramesAttemptingRequiredOverlaysHistogramName, false); +} + +static void LogWorkingScaleFactorCountUMA(float scale_factor) { + UMA_HISTOGRAM_CUSTOM_COUNTS(kWorkingScaleFactorHistogramName, + scale_factor * 100, /*minimum=*/1, + /*maximum=*/201, /*bucket_count=*/50); +} + +static void LogFramesScalingRequiredCandidateBoolUMA(bool attempted_scaling) { + UMA_HISTOGRAM_BOOLEAN(kFramesScalingRequiredOverlaysHistogramName, + attempted_scaling); +} + OverlayProcessorUsingStrategy::OverlayProcessorUsingStrategy() : max_overlays_config_(features::MaxOverlaysConsidered()) {} @@ -562,6 +593,8 @@ : OverlayStrategy::kNoStrategyUsed); } + LogFramesAttemptingRequiredCandidateBoolUMA(proposed_candidates); + if (ShouldAttemptMultipleOverlays(proposed_candidates)) { auto* render_pass = render_pass_list->back().get(); return AttemptMultipleOverlays(proposed_candidates, primary_plane, @@ -569,14 +602,16 @@ } bool has_required_overlay = false; + bool attempted_scaling_required_overlays = false; for (auto&& candidate : proposed_candidates) { // Underlays change the material so we save it here to record proper UMA. DrawQuad::Material quad_material = candidate.strategy->GetUMAEnum() != OverlayStrategy::kUnknown ? candidate.quad_iter->material : DrawQuad::Material::kInvalid; - if (candidate.candidate.requires_overlay) + if (candidate.candidate.requires_overlay) { has_required_overlay = true; + } bool used_overlay = candidate.strategy->Attempt( output_color_matrix, render_pass_backdrop_filters, resource_provider, @@ -607,6 +642,7 @@ new_scale_factor < 1.0f; new_scale_factor += kScaleAdjust) { float zoom_scale = new_scale_factor / scale_factor; ScaleCandidateSrcRect(org_src_rect, zoom_scale, &candidate.candidate); + attempted_scaling_required_overlays = true; if (candidate.strategy->Attempt( output_color_matrix, render_pass_backdrop_filters, resource_provider, render_pass_list, surface_damage_rect_list, @@ -619,6 +655,7 @@ } } } + if (used_overlay) { // This function is used by underlay strategy to mark the primary plane as // enable_blending. @@ -634,11 +671,21 @@ if (scale_factor < 1.0f) { UpdateDownscalingCapabilities(scale_factor, /*success=*/true); } + LogWorkingScaleFactorCountUMA(scale_factor * 100); + LogFramesScalingRequiredCandidateBoolUMA( + attempted_scaling_required_overlays); } + RegisterOverlayRequirement(has_required_overlay); return true; } } + + if (has_required_overlay) { + LogFramesScalingRequiredCandidateBoolUMA( + attempted_scaling_required_overlays); + } + RegisterOverlayRequirement(has_required_overlay); if (proposed_candidates.size() != 0) {
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index e162b05..b96f876 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -336,24 +336,6 @@ return GetData().relative_bounds.bounds; } -gfx::Rect BrowserAccessibility::GetUnclippedRootFrameHypertextRangeBoundsRect( - const int start_offset, - const int end_offset, - ui::AXOffscreenResult* offscreen_result) const { - return GetHypertextRangeBoundsRect( - start_offset, end_offset, ui::AXCoordinateSystem::kRootFrame, - ui::AXClippingBehavior::kUnclipped, offscreen_result); -} - -gfx::Rect BrowserAccessibility::GetUnclippedScreenInnerTextRangeBoundsRect( - const int start_offset, - const int end_offset, - ui::AXOffscreenResult* offscreen_result) const { - return GetInnerTextRangeBoundsRect( - start_offset, end_offset, ui::AXCoordinateSystem::kScreenDIPs, - ui::AXClippingBehavior::kUnclipped, offscreen_result); -} - gfx::Rect BrowserAccessibility::GetUnclippedRootFrameInnerTextRangeBoundsRect( const int start_offset, const int end_offset,
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index fe52e274..977455b 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h
@@ -262,17 +262,7 @@ // for (const auto& child : AllChildren()) {}. AllChildrenRange AllChildren() const { return AllChildrenRange(this); } - // Derivative utils for AXPlatformNodeDelegate::GetHypertextRangeBoundsRect - gfx::Rect GetUnclippedRootFrameHypertextRangeBoundsRect( - const int start_offset, - const int end_offset, - ui::AXOffscreenResult* offscreen_result = nullptr) const; - // Derivative utils for AXPlatformNodeDelegate::GetInnerTextRangeBoundsRect - gfx::Rect GetUnclippedScreenInnerTextRangeBoundsRect( - const int start_offset, - const int end_offset, - ui::AXOffscreenResult* offscreen_result = nullptr) const; gfx::Rect GetUnclippedRootFrameInnerTextRangeBoundsRect( const int start_offset, const int end_offset,
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc index 60ef227..d4ffaf9 100644 --- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -21,6 +21,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/ax_common.h" #include "ui/accessibility/ax_tree.h" +#include "ui/accessibility/test_ax_tree_update.h" namespace content { @@ -637,30 +638,17 @@ #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK) TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) { - ui::AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - - ui::AXNodeData node2; - node2.id = 2; - root.child_ids.push_back(2); - - ui::AXNodeData node3; - node3.id = 3; - root.child_ids.push_back(3); - - ui::AXNodeData node4; - node4.id = 4; - node3.child_ids.push_back(4); - - ui::AXNodeData node5; - node5.id = 5; - root.child_ids.push_back(5); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kUnknown + ++++3 kUnknown + ++++++4 kUnknown + ++++5 kUnknown + )HTML")); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdateForTesting(root, node2, node3, node4, node5), - test_browser_accessibility_delegate_.get())); + update, test_browser_accessibility_delegate_.get())); BrowserAccessibility* root_accessible = manager->GetBrowserAccessibilityRoot(); @@ -741,30 +729,17 @@ } TEST_F(BrowserAccessibilityManagerTest, TestNextNonDescendantInTreeOrder) { - ui::AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - - ui::AXNodeData node2; - node2.id = 2; - root.child_ids.push_back(2); - - ui::AXNodeData node3; - node3.id = 3; - root.child_ids.push_back(3); - - ui::AXNodeData node4; - node4.id = 4; - node3.child_ids.push_back(4); - - ui::AXNodeData node5; - node5.id = 5; - root.child_ids.push_back(5); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kUnknown + ++++3 kUnknown + ++++++4 kUnknown + ++++5 kUnknown + )HTML")); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdateForTesting(root, node2, node3, node4, node5), - test_browser_accessibility_delegate_.get())); + update, test_browser_accessibility_delegate_.get())); BrowserAccessibility* root_accessible = manager->GetBrowserAccessibilityRoot(); @@ -791,57 +766,22 @@ } TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousTextOnlyObject) { - ui::AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - - ui::AXNodeData node2; - node2.id = 2; - root.child_ids.push_back(2); - - ui::AXNodeData text1; - text1.id = 3; - text1.role = ax::mojom::Role::kStaticText; - root.child_ids.push_back(3); - - ui::AXNodeData node3; - node3.id = 4; - root.child_ids.push_back(4); - - ui::AXNodeData text2; - text2.id = 5; - text2.role = ax::mojom::Role::kStaticText; - node3.child_ids.push_back(5); - - ui::AXNodeData node4; - node4.id = 6; - node3.child_ids.push_back(6); - - ui::AXNodeData text3; - text3.id = 7; - text3.role = ax::mojom::Role::kStaticText; - node3.child_ids.push_back(7); - - ui::AXNodeData node5; - node5.id = 8; - node5.role = ax::mojom::Role::kGenericContainer; - root.child_ids.push_back(8); - - ui::AXNodeData text4; - text4.id = 9; - text4.role = ax::mojom::Role::kLineBreak; - node5.child_ids.push_back(9); - - ui::AXNodeData link; - link.id = 10; - link.role = ax::mojom::Role::kLink; - node5.child_ids.push_back(10); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kUnknown + ++++3 kStaticText + ++++4 kUnknown + ++++++5 kStaticText + ++++++6 kUnknown + ++++++7 kStaticText + ++++8 kGenericContainer + ++++++9 kLineBreak + ++++++10 kLink + )HTML")); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdateForTesting(root, node2, node3, node4, node5, text1, - text2, text3, text4, link), - test_browser_accessibility_delegate_.get())); + update, test_browser_accessibility_delegate_.get())); BrowserAccessibility* root_accessible = manager->GetBrowserAccessibilityRoot(); @@ -902,60 +842,21 @@ // Linux and Windows. #if BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK) TEST_F(BrowserAccessibilityManagerTest, TestFindIndicesInCommonParent) { - ui::AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - - ui::AXNodeData div; - div.id = 2; - div.role = ax::mojom::Role::kGenericContainer; - root.child_ids.push_back(div.id); - - ui::AXNodeData button; - button.id = 3; - button.role = ax::mojom::Role::kButton; - div.child_ids.push_back(button.id); - - ui::AXNodeData button_text; - button_text.id = 4; - button_text.role = ax::mojom::Role::kStaticText; - button_text.SetName("Button"); - button.child_ids.push_back(button_text.id); - - ui::AXNodeData line_break; - line_break.id = 5; - line_break.role = ax::mojom::Role::kLineBreak; - line_break.SetName("\n"); - div.child_ids.push_back(line_break.id); - - ui::AXNodeData paragraph; - paragraph.id = 6; - paragraph.role = ax::mojom::Role::kParagraph; - root.child_ids.push_back(paragraph.id); - - ui::AXNodeData paragraph_text; - paragraph_text.id = 7; - paragraph_text.role = ax::mojom::Role::kStaticText; - paragraph.child_ids.push_back(paragraph_text.id); - - ui::AXNodeData paragraph_line1; - paragraph_line1.id = 8; - paragraph_line1.role = ax::mojom::Role::kInlineTextBox; - paragraph_line1.SetName("Hello "); - paragraph_text.child_ids.push_back(paragraph_line1.id); - - ui::AXNodeData paragraph_line2; - paragraph_line2.id = 9; - paragraph_line2.role = ax::mojom::Role::kInlineTextBox; - paragraph_line2.SetName("world."); - paragraph_text.child_ids.push_back(paragraph_line2.id); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kGenericContainer + ++++++3 kButton + ++++++++4 kStaticText name="Button" + ++++++5 kLineBreak name="\n" + ++++6 kParagraph + ++++++7 kStaticText + ++++++++8 kInlineTextBox name="Hello" + ++++++++9 kInlineTextBox name="world." + )HTML")); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdateForTesting(root, div, button, button_text, line_break, - paragraph, paragraph_text, paragraph_line1, - paragraph_line2), - test_browser_accessibility_delegate_.get())); + update, test_browser_accessibility_delegate_.get())); BrowserAccessibility* root_accessible = manager->GetBrowserAccessibilityRoot(); @@ -1475,31 +1376,19 @@ } TEST_F(BrowserAccessibilityManagerTest, TestShouldFireEventForNode) { - ui::AXNodeData inline_text; - inline_text.id = 1111; - inline_text.role = ax::mojom::Role::kInlineTextBox; - inline_text.SetName("One two three."); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++11 kParagraph + ++++++111 kStaticText + ++++++++1111 kInlineTextBox + )HTML")); - ui::AXNodeData text; - text.id = 111; - text.role = ax::mojom::Role::kStaticText; - text.SetName("One two three."); - text.child_ids = {inline_text.id}; - - ui::AXNodeData paragraph; - paragraph.id = 11; - paragraph.role = ax::mojom::Role::kParagraph; - paragraph.child_ids = {text.id}; - - ui::AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - root.child_ids = {paragraph.id}; + update.nodes[2].SetName("One two three."); + update.nodes[3].SetName("One two three."); std::unique_ptr<BrowserAccessibilityManager> manager( BrowserAccessibilityManager::Create( - MakeAXTreeUpdateForTesting(root, paragraph, text, inline_text), - test_browser_accessibility_delegate_.get())); + update, test_browser_accessibility_delegate_.get())); EXPECT_TRUE(manager->ShouldFireEventForNode(manager->GetFromID(1))); EXPECT_TRUE(manager->ShouldFireEventForNode(manager->GetFromID(11)));
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index f4214aa..d90ccc9 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -751,11 +751,6 @@ RunEventTest(FILE_PATH_LITERAL("input-type-text-value-changed.html")); } -IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, - AccessibilityEventsLangChanged) { - RunEventTest(FILE_PATH_LITERAL("lang-changed.html")); -} - // Flaky on Windows: https://crbug.com/1078490. #if BUILDFLAG(IS_WIN) #define MAYBE_AccessibilityEventsListboxFocus \
diff --git a/content/browser/attribution_reporting/attribution_internals.mojom b/content/browser/attribution_reporting/attribution_internals.mojom index dabd562f..f0a2c233 100644 --- a/content/browser/attribution_reporting/attribution_internals.mojom +++ b/content/browser/attribution_reporting/attribution_internals.mojom
@@ -42,14 +42,10 @@ uint32 value; }; -struct AttestationToken { - string value; -}; - // Contains aggregatable attribution data to be displayed. struct WebUIReportAggregatableAttributionData { array<AggregatableHistogramContribution> contributions; - AttestationToken? attestation_token; + string? attestation_token; string aggregation_coordinator; };
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc index 662cbe34..d85a2396 100644 --- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc +++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -166,15 +166,10 @@ contribution.value()); }); - ai_mojom::AttestationTokenPtr attestation_token = - aggregatable_data.attestation_token - ? ai_mojom::AttestationToken::New( - *aggregatable_data.attestation_token) - : nullptr; - return ai_mojom::WebUIReportData::NewAggregatableAttributionData( ai_mojom::WebUIReportAggregatableAttributionData::New( - std::move(contributions), std::move(attestation_token), + std::move(contributions), + aggregatable_data.attestation_token, aggregation_service::SerializeAggregationCoordinator( aggregatable_data.aggregation_coordinator))); },
diff --git a/content/browser/devtools/devtools_pipe_handler.cc b/content/browser/devtools/devtools_pipe_handler.cc index e533408..0450fda4 100644 --- a/content/browser/devtools/devtools_pipe_handler.cc +++ b/content/browser/devtools/devtools_pipe_handler.cc
@@ -8,6 +8,7 @@ #if BUILDFLAG(IS_WIN) #include <io.h> +#include <stdlib.h> #include <windows.h> #else #include <sys/socket.h> @@ -93,6 +94,34 @@ std::unique_ptr<base::Thread> thread_; base::AtomicFlag shutting_down_; }; + +#if BUILDFLAG(IS_WIN) +// Temporary CRT parameter validation error handler override that allows +// _get_osfhandle() to return INVALID_HANDLE_VALUE instead of crashing. +class ScopedInvalidParameterHandlerOverride { + public: + ScopedInvalidParameterHandlerOverride() { + prev_invalid_parameter_handler_ = + _set_thread_local_invalid_parameter_handler(InvalidParameterHandler); + } + + ~ScopedInvalidParameterHandlerOverride() { + _set_thread_local_invalid_parameter_handler( + prev_invalid_parameter_handler_); + } + + private: + static void InvalidParameterHandler(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, + unsigned int line, + uintptr_t reserved) {} + + _invalid_parameter_handler prev_invalid_parameter_handler_; +}; + +#endif // BUILDFLAG(IS_WIN) + } // namespace class PipeReaderBase : public PipeIOBase { @@ -100,11 +129,11 @@ PipeReaderBase(base::WeakPtr<DevToolsPipeHandler> devtools_handler, int read_fd) : PipeIOBase("DevToolsPipeHandlerReadThread"), - devtools_handler_(std::move(devtools_handler)) { + devtools_handler_(std::move(devtools_handler)), + read_fd_(read_fd) { #if BUILDFLAG(IS_WIN) + ScopedInvalidParameterHandlerOverride invalid_parameter_handler_override; read_handle_ = reinterpret_cast<HANDLE>(_get_osfhandle(read_fd)); -#else - read_fd_ = read_fd; #endif } @@ -120,7 +149,8 @@ #if BUILDFLAG(IS_WIN) // Cancel pending synchronous read. CancelIoEx(read_handle_, nullptr); - CloseHandle(read_handle_); + _close(read_fd_); + read_handle_ = INVALID_HANDLE_VALUE; #else shutdown(read_fd_, SHUT_RDWR); #endif @@ -174,21 +204,19 @@ } base::WeakPtr<DevToolsPipeHandler> devtools_handler_; + int read_fd_; #if BUILDFLAG(IS_WIN) HANDLE read_handle_; -#else - int read_fd_; #endif }; class PipeWriterBase : public PipeIOBase { public: explicit PipeWriterBase(int write_fd) - : PipeIOBase("DevToolsPipeHandlerWriteThread") { + : PipeIOBase("DevToolsPipeHandlerWriteThread"), write_fd_(write_fd) { #if BUILDFLAG(IS_WIN) + ScopedInvalidParameterHandlerOverride invalid_parameter_handler_override; write_handle_ = reinterpret_cast<HANDLE>(_get_osfhandle(write_fd)); -#else - write_fd_ = write_fd; #endif } @@ -203,7 +231,8 @@ protected: void ClosePipe() override { #if BUILDFLAG(IS_WIN) - CloseHandle(write_handle_); + _close(write_fd_); + write_handle_ = INVALID_HANDLE_VALUE; #else shutdown(write_fd_, SHUT_RDWR); #endif @@ -238,10 +267,9 @@ } private: + int write_fd_; #if BUILDFLAG(IS_WIN) HANDLE write_handle_; -#else - int write_fd_; #endif };
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc index 4f6e279..89b6e0d3 100644 --- a/content/browser/devtools/devtools_url_loader_interceptor.cc +++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -1702,7 +1702,8 @@ } // Since we're not forwarding OnComplete right now, make sure // we're in the proper state. The completion is due upon client response. - DCHECK(state_ == State::kResponseReceived || state_ == State::kResponseTaken); + DCHECK(state_ == State::kResponseReceived || state_ == State::kResponseTaken) + << "Unexpected state " << static_cast<int>(state_); DCHECK(waiting_for_resolution_); response_metadata_->status = status;
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc index 1488428..d9e3c15 100644 --- a/content/browser/preloading/preloading_decider.cc +++ b/content/browser/preloading/preloading_decider.cc
@@ -82,7 +82,7 @@ // otherwise try to preconnect to it. if (MaybePrerender(url)) { AddPreloadingPrediction(url, - preloading_predictor::kUrlPointerDownOnAnchor); + preloading_predictor::kUrlPointerHoverOnAnchor); return; } if (ShouldWaitForPrerenderResult(url))
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.ts b/content/browser/resources/attribution_reporting/attribution_internals.ts index 56ead81e..bc3c063 100644 --- a/content/browser/resources/attribution_reporting/attribution_internals.ts +++ b/content/browser/resources/attribution_reporting/attribution_internals.ts
@@ -525,9 +525,7 @@ ' '); this.attestationToken = - mojo.data.aggregatableAttributionData!.attestationToken ? - `${mojo.data.aggregatableAttributionData!.attestationToken.value}` : - ''; + mojo.data.aggregatableAttributionData!.attestationToken || ''; this.aggregationCoordinator = mojo.data.aggregatableAttributionData!.aggregationCoordinator;
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index e2111c3c..d2ec41d 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -926,13 +926,24 @@ // TODO(crbug.com/1418719): Replace exclude_iframe based on client metadata // response. - bool exclude_iframe = true; + bool exclude_iframe = net::registry_controlled_domains::SameDomainOrHost( + GetEmbeddingOrigin(), origin(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); absl::optional<std::string> iframe_url_for_display = absl::nullopt; std::string top_frame_url_for_display = FormatOriginForDisplay(GetEmbeddingOrigin()); - if (!exclude_iframe && GetEmbeddingOrigin() != origin()) { + if (!exclude_iframe) { iframe_url_for_display = FormatOriginForDisplay(origin()); + + // TODO(crbug.com/1422040): Decide what to do if we want to include iframe + // domain in the dialog but iframe_url_for_display is nullopt. + if (iframe_url_for_display->empty()) { + CompleteRequestWithError(FederatedAuthRequestResult::kError, + /*token_status=*/absl::nullopt, + /*should_delay_callback=*/false); + return; + } } // TODO(crbug.com/1383384): Handle auto_reauthn for multi IDP.
diff --git a/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc b/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc index 1bbda4c..740b625 100644 --- a/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_multiple_frames_unittest.cc
@@ -26,6 +26,7 @@ #include "content/common/content_navigation_policy.h" #include "content/public/browser/identity_request_dialog_controller.h" #include "content/public/common/content_features.h" +#include "content/public/test/navigation_simulator.h" #include "content/test/test_render_frame_host.h" #include "content/test/test_render_view_host.h" #include "content/test/test_web_contents.h" @@ -54,7 +55,7 @@ namespace { constexpr char kProviderUrlFull[] = "https://idp.example/fedcm.json"; -constexpr char kRpUrl[] = "https://rp.example/"; +constexpr char kTopFrameUrl[] = "https://top-frame.example/"; constexpr char kAccountsEndpoint[] = "https://idp.example/accounts"; constexpr char kTokenEndpoint[] = "https://idp.example/token"; constexpr char kClientId[] = "client_id_123"; @@ -122,6 +123,8 @@ public: struct State { bool did_show_accounts_dialog{false}; + std::string top_frame_for_display; + absl::optional<std::string> iframe_url_for_display; }; enum class AccountsDialogAction { @@ -149,6 +152,8 @@ IdentityRequestDialogController::DismissCallback dismiss_callback) override { state_->did_show_accounts_dialog = true; + state_->top_frame_for_display = top_frame_for_display; + state_->iframe_url_for_display = iframe_url_for_display; if (accounts_dialog_action_ == AccountsDialogAction::kSelectAccount) { std::move(on_selected) .Run(GURL(kProviderUrlFull), kAccountId, /*is_sign_in=*/true); @@ -186,7 +191,7 @@ std::make_unique<NiceMock<MockPermissionDelegate>>(); static_cast<TestWebContents*>(web_contents()) - ->NavigateAndCommit(GURL(kRpUrl), ui::PAGE_TRANSITION_LINK); + ->NavigateAndCommit(GURL(kTopFrameUrl), ui::PAGE_TRANSITION_LINK); } // Does token request and waits for result. @@ -260,9 +265,6 @@ // Test that test harness can execute successful FedCM flow for iframe. TEST_F(FederatedAuthRequestImplMultipleFramesTest, TestHarness) { - base::test::ScopedFeatureList list; - list.InitWithFeatures({features::kFedCm, features::kFedCmIframeSupport}, {}); - RenderFrameHost* iframe_rfh = content::RenderFrameHostTester::For(main_rfh()) ->AppendChild(/*frame_name=*/""); @@ -282,9 +284,6 @@ // Test that FedCM request fails on iframe if there is an in-progress FedCM // request for a different frame on the page. TEST_F(FederatedAuthRequestImplMultipleFramesTest, IframeTooManyRequests) { - base::test::ScopedFeatureList list; - list.InitWithFeatures({features::kFedCm, features::kFedCmIframeSupport}, {}); - mojo::Remote<blink::mojom::FederatedAuthRequest> main_frame_request_remote; TestDialogController::State main_frame_dialog_state; CreateFederatedAuthRequestImpl( @@ -310,4 +309,80 @@ EXPECT_FALSE(iframe_dialog_state.did_show_accounts_dialog); } +// Test that only top frame URL is available for display when FedCM is called +// within iframes which are same-origin with the top frame. +TEST_F(FederatedAuthRequestImplMultipleFramesTest, SameOriginIframe) { + const char kSameOriginIframeUrl[] = "https://top-frame.example/iframe.html"; + RenderFrameHost* same_origin_iframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSameOriginIframeUrl), + RenderFrameHostTester::For(web_contents()->GetPrimaryMainFrame()) + ->AppendChild("same_origin_iframe")); + + mojo::Remote<blink::mojom::FederatedAuthRequest> iframe_request_remote; + TestDialogController::State iframe_dialog_state; + CreateFederatedAuthRequestImpl( + *same_origin_iframe, iframe_request_remote, + TestDialogController::AccountsDialogAction::kSelectAccount, + &iframe_dialog_state); + + AuthRequestCallbackHelper iframe_callback_helper; + DoRequestTokenAndWait(iframe_request_remote, iframe_callback_helper); + EXPECT_EQ(RequestTokenStatus::kSuccess, iframe_callback_helper.status()); + EXPECT_TRUE(iframe_dialog_state.did_show_accounts_dialog); + EXPECT_EQ("top-frame.example", iframe_dialog_state.top_frame_for_display); + EXPECT_EQ(absl::nullopt, iframe_dialog_state.iframe_url_for_display); +} + +// Test that only top frame URL is available for display when FedCM is called +// within iframes which are same-site with the top frame. +TEST_F(FederatedAuthRequestImplMultipleFramesTest, SameSiteIframe) { + const char kSameSiteIframeUrl[] = + "https://subdomain.top-frame.example/iframe.html"; + RenderFrameHost* same_site_iframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kSameSiteIframeUrl), + RenderFrameHostTester::For(web_contents()->GetPrimaryMainFrame()) + ->AppendChild("same_site_iframe")); + + mojo::Remote<blink::mojom::FederatedAuthRequest> iframe_request_remote; + TestDialogController::State iframe_dialog_state; + CreateFederatedAuthRequestImpl( + *same_site_iframe, iframe_request_remote, + TestDialogController::AccountsDialogAction::kSelectAccount, + &iframe_dialog_state); + + AuthRequestCallbackHelper iframe_callback_helper; + DoRequestTokenAndWait(iframe_request_remote, iframe_callback_helper); + EXPECT_EQ(RequestTokenStatus::kSuccess, iframe_callback_helper.status()); + EXPECT_TRUE(iframe_dialog_state.did_show_accounts_dialog); + EXPECT_EQ("top-frame.example", iframe_dialog_state.top_frame_for_display); + EXPECT_EQ(absl::nullopt, iframe_dialog_state.iframe_url_for_display); +} + +// Test that both top frame and iframe URLs are available for display when FedCM +// is called within iframes which are cross-site with the top frame. +TEST_F(FederatedAuthRequestImplMultipleFramesTest, CrossSiteIframe) { + const char kCrossSiteIframeUrl[] = "https://cross-site.example/iframe.html"; + RenderFrameHost* cross_site_iframe = + NavigationSimulator::NavigateAndCommitFromDocument( + GURL(kCrossSiteIframeUrl), + RenderFrameHostTester::For(web_contents()->GetPrimaryMainFrame()) + ->AppendChild("cross_site_iframe")); + + mojo::Remote<blink::mojom::FederatedAuthRequest> iframe_request_remote; + TestDialogController::State iframe_dialog_state; + CreateFederatedAuthRequestImpl( + *cross_site_iframe, iframe_request_remote, + TestDialogController::AccountsDialogAction::kSelectAccount, + &iframe_dialog_state); + + AuthRequestCallbackHelper iframe_callback_helper; + DoRequestTokenAndWait(iframe_request_remote, iframe_callback_helper); + EXPECT_EQ(RequestTokenStatus::kSuccess, iframe_callback_helper.status()); + EXPECT_TRUE(iframe_dialog_state.did_show_accounts_dialog); + EXPECT_EQ("top-frame.example", iframe_dialog_state.top_frame_for_display); + EXPECT_EQ("cross-site.example", iframe_dialog_state.iframe_url_for_display); +} + } // namespace content
diff --git a/content/test/data/accessibility/event/lang-changed-expected-auralinux.txt b/content/test/data/accessibility/event/lang-changed-expected-auralinux.txt deleted file mode 100644 index 40c6e990..0000000 --- a/content/test/data/accessibility/event/lang-changed-expected-auralinux.txt +++ /dev/null
@@ -1,10 +0,0 @@ -PARENT-CHANGED PARENT:(role=ROLE_SECTION name='(null)') role=ROLE_CHECK_BOX name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,CHECKABLE -PARENT-CHANGED PARENT:(role=ROLE_SECTION name='(null)') role=ROLE_STATIC name='Gift' ENABLED,SENSITIVE,SHOWING,VISIBLE -=== Start Continuation === -STATE-CHANGE:CHECKED:TRUE role=ROLE_CHECK_BOX name='(null)' CHECKED,ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,CHECKABLE -=== Start Continuation === -STATE-CHANGE:CHECKED:FALSE role=ROLE_CHECK_BOX name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,CHECKABLE -=== Start Continuation === -PARENT-CHANGED PARENT:(role=ROLE_SECTION name='(null)') role=ROLE_CHECK_BOX name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE,CHECKABLE -PARENT-CHANGED PARENT:(role=ROLE_SECTION name='(null)') role=ROLE_STATIC name='Gift' ENABLED,SENSITIVE,SHOWING,VISIBLE -STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
diff --git a/content/test/data/accessibility/event/lang-changed.html b/content/test/data/accessibility/event/lang-changed.html deleted file mode 100644 index aa2b753e..0000000 --- a/content/test/data/accessibility/event/lang-changed.html +++ /dev/null
@@ -1,25 +0,0 @@ -<!DOCTYPE html> -<!-- Adding a lang will cause a normally ignored node to be included in the Blink tree, but it is still ignored on the platform layer. Adding an id causes it to be included n the platform layer as well --> -<div> - <div> - <span> - <input type="checkbox">Gift</input> - </span> - </div> -</div> -<script> - const span = document.querySelector('span'); - const cbox = document.querySelector('input'); - const go_passes = [ - () => span.setAttribute('lang', "de-DE"), - () => { span.id = 'xyz'; cbox.checked = true; }, - () => { span.removeAttribute('id'); cbox.checked = false; }, - () => span.removeAttribute('lang'), - ]; - - var current_pass = 0; - function go() { - go_passes[current_pass++].call(); - return current_pass < go_passes.length; - } -</script>
diff --git a/content/utility/services.cc b/content/utility/services.cc index 636cdea..e278440 100644 --- a/content/utility/services.cc +++ b/content/utility/services.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/command_line.h" +#include "base/lazy_instance.h" #include "base/task/single_thread_task_runner.h" #include "build/branding_buildflags.h" #include "build/build_config.h"
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc index 2cd1b30..581fc63e 100644 --- a/extensions/browser/api/management/management_api.cc +++ b/extensions/browser/api/management/management_api.cc
@@ -455,15 +455,12 @@ *target_extension, browser_context())) { // Either ask for parent permission or notify the child that their parent // has disabled this action. - auto parent_permission_callback = base::BindOnce( - &ManagementSetEnabledFunction::OnParentPermissionDialogDone, this); - auto error_callback = base::BindOnce( - &ManagementSetEnabledFunction::OnBlockedByParentDialogDone, this); - AddRef(); // Matched in OnParentPermissionDialogDone() or - // OnBlockedByParentDialogDone(). - supervised_user_extensions_delegate->PromptForParentPermissionOrShowError( + auto extension_approval_callback = base::BindOnce( + &ManagementSetEnabledFunction::OnExtensionApprovalDone, this); + AddRef(); // Matched in OnExtensionApprovalDone(). + supervised_user_extensions_delegate->RequestToEnableExtensionOrShowError( *target_extension, browser_context(), GetSenderWebContents(), - std::move(parent_permission_callback), std::move(error_callback)); + std::move(extension_approval_callback)); return RespondLater(); } #endif // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH) @@ -545,14 +542,13 @@ } } -void ManagementSetEnabledFunction::OnParentPermissionDialogDone( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result) { +void ManagementSetEnabledFunction::OnExtensionApprovalDone( + SupervisedUserExtensionsDelegate::ExtensionApprovalResult result) { // TODO(crbug.com/1320442): Investigate whether ENABLE_SUPERVISED_USERS can // be ported to //extensions. #if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH) switch (result) { - case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionReceived: { + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kApproved: { const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance() ->Get(browser_context()) @@ -562,26 +558,21 @@ break; } - case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionCanceled: { + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kCanceled: { Respond(Error(keys::kUserDidNotReEnableError)); break; } - case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: - kParentPermissionFailed: { + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kFailed: { Respond(Error(keys::kParentPermissionFailedError)); break; } - } - // Matches the AddRef in Run(). - Release(); -#endif // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH) -} -void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() { -#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH) - Respond(Error(keys::kUserCantModifyError, extension_id_)); + case SupervisedUserExtensionsDelegate::ExtensionApprovalResult::kBlocked: { + Respond(Error(keys::kUserCantModifyError, extension_id_)); + break; + } + } // Matches the AddRef in Run(). Release(); #endif // BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/extensions/browser/api/management/management_api.h b/extensions/browser/api/management/management_api.h index 8d79ccb..31cb3f2 100644 --- a/extensions/browser/api/management/management_api.h +++ b/extensions/browser/api/management/management_api.h
@@ -118,13 +118,9 @@ void OnRequirementsChecked(const PreloadCheck::Errors& errors); - // Called when the user dismisses the Parent Permission Dialog. - void OnParentPermissionDialogDone( - SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result); - - // Called when the user dismisses the Extension Install Blocked By Parent - // Dialog. - void OnBlockedByParentDialogDone(); + // Called when the extension approval flow is completed. + void OnExtensionApprovalDone( + SupervisedUserExtensionsDelegate::ExtensionApprovalResult result); std::string extension_id_;
diff --git a/extensions/browser/supervised_user_extensions_delegate.h b/extensions/browser/supervised_user_extensions_delegate.h index 6aa02b7..4395eae 100644 --- a/extensions/browser/supervised_user_extensions_delegate.h +++ b/extensions/browser/supervised_user_extensions_delegate.h
@@ -13,19 +13,24 @@ class WebContents; } // namespace content +namespace gfx { +class ImageSkia; +} // namespace gfx + namespace extensions { class SupervisedUserExtensionsDelegate { public: - // Result of the parent permission dialog invocation. - enum class ParentPermissionDialogResult { - kParentPermissionReceived, - kParentPermissionCanceled, - kParentPermissionFailed, + // Result of the extension approval flow. + enum class ExtensionApprovalResult { + kApproved, // Extension installation was approved. + kCanceled, // Extension approval flow was canceled. + kFailed, // Extension approval failed due to an error. + kBlocked, // Extension installation has been blocked by a parent. }; - using ParentPermissionDialogDoneCallback = - base::OnceCallback<void(ParentPermissionDialogResult)>; + using ExtensionApprovalDoneCallback = + base::OnceCallback<void(ExtensionApprovalResult)>; virtual ~SupervisedUserExtensionsDelegate() = default; @@ -39,16 +44,25 @@ // If the current user is a child, the child user has a custodian/parent, and // the parent has enabled the "Permissions for sites, apps and extensions" - // toggle, then display the Parent Permission Dialog and call - // |parent_permission_callback|. Otherwise, display the Extension Install - // Blocked by Parent Dialog and call |error_callback|. The two paths are - // mutually exclusive. - virtual void PromptForParentPermissionOrShowError( + // toggle, then display the Parent Permission Dialog. If the setting is + // disabled, the extension install blocked dialog is shown. When the flow is + // complete call |extension_approval_callback|. + // The icon must be supplied for installing new extensions because they are + // fetched via a network request. + virtual void RequestToAddExtensionOrShowError( const extensions::Extension& extension, content::BrowserContext* browser_context, content::WebContents* web_contents, - ParentPermissionDialogDoneCallback parent_permission_callback, - base::OnceClosure error_callback) = 0; + const gfx::ImageSkia& icon, + ExtensionApprovalDoneCallback extension_approval_callback) = 0; + + // Similar to RequestToAddExtensionOrShowError except for enabling already + // installed extensions. The icon is fetched from local resources. + virtual void RequestToEnableExtensionOrShowError( + const extensions::Extension& extension, + content::BrowserContext* browser_context, + content::WebContents* web_contents, + ExtensionApprovalDoneCallback extension_approval_callback) = 0; }; } // namespace extensions
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index 9a78352..44f7963 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -325,8 +325,6 @@ "manifest_handler_helpers.h", "manifest_handlers/app_display_info.cc", "manifest_handlers/app_display_info.h", - "manifest_handlers/app_isolation_info.cc", - "manifest_handlers/app_isolation_info.h", "manifest_handlers/automation.cc", "manifest_handlers/automation.h", "manifest_handlers/background_info.cc",
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 663cc92..604427a 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc
@@ -67,7 +67,6 @@ const char kIndicator[] = "indicator"; const char kInputComponents[] = "input_components"; const char kInputView[] = "input_view"; -const char kIsolation[] = "app.isolation"; const char kKey[] = "key"; const char kKiosk[] = "kiosk"; const char kKioskAlwaysUpdate[] = "kiosk.always_update";
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index f7430bd..654c9e9 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h
@@ -69,7 +69,6 @@ extern const char kIndicator[]; extern const char kInputComponents[]; extern const char kInputView[]; -extern const char kIsolation[]; extern const char kKey[]; extern const char kKiosk[]; extern const char kKioskAlwaysUpdate[];
diff --git a/extensions/common/manifest_handlers/app_isolation_info.cc b/extensions/common/manifest_handlers/app_isolation_info.cc deleted file mode 100644 index b5f8392..0000000 --- a/extensions/common/manifest_handlers/app_isolation_info.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "extensions/common/manifest_handlers/app_isolation_info.h" - -#include <stddef.h> - -#include <memory> -#include <string> - -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "extensions/common/error_utils.h" -#include "extensions/common/manifest_constants.h" -#include "extensions/common/manifest_handlers/permissions_parser.h" -#include "extensions/common/permissions/api_permission_set.h" - -namespace extensions { - -namespace keys = manifest_keys; - -AppIsolationInfo::AppIsolationInfo(bool isolated_storage) - : has_isolated_storage(isolated_storage) { -} - -AppIsolationInfo::~AppIsolationInfo() { -} - -// static -bool AppIsolationInfo::HasIsolatedStorage(const Extension* extension) { - AppIsolationInfo* info = static_cast<AppIsolationInfo*>( - extension->GetManifestData(keys::kIsolation)); - return info ? info->has_isolated_storage : false; -} - -AppIsolationHandler::AppIsolationHandler() { -} - -AppIsolationHandler::~AppIsolationHandler() { -} - -bool AppIsolationHandler::Parse(Extension* extension, std::u16string* error) { - // Platform apps always get isolated storage. - if (extension->is_platform_app()) { - extension->SetManifestData(keys::kIsolation, - std::make_unique<AppIsolationInfo>(true)); - return true; - } - - // No other apps get isolated storage, so no parsing is needed. - return true; -} - -bool AppIsolationHandler::AlwaysParseForType(Manifest::Type type) const { - return type == Manifest::TYPE_PLATFORM_APP; -} - -base::span<const char* const> AppIsolationHandler::Keys() const { - static constexpr const char* kKeys[] = {keys::kIsolation}; - return kKeys; -} - -} // namespace extensions
diff --git a/extensions/common/manifest_handlers/app_isolation_info.h b/extensions/common/manifest_handlers/app_isolation_info.h deleted file mode 100644 index 9a32418..0000000 --- a/extensions/common/manifest_handlers/app_isolation_info.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_COMMON_MANIFEST_HANDLERS_APP_ISOLATION_INFO_H_ -#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_APP_ISOLATION_INFO_H_ - -#include <string> -#include <vector> - -#include "extensions/common/extension.h" -#include "extensions/common/manifest.h" -#include "extensions/common/manifest_handler.h" - -namespace extensions { - -struct AppIsolationInfo : public Extension::ManifestData { - explicit AppIsolationInfo(bool isolated_storage); - ~AppIsolationInfo() override; - - static bool HasIsolatedStorage(const Extension* extension); - - // Whether this extension requests isolated storage. - bool has_isolated_storage; -}; - -// Parses the "isolation" manifest key. -class AppIsolationHandler : public ManifestHandler { - public: - AppIsolationHandler(); - - AppIsolationHandler(const AppIsolationHandler&) = delete; - AppIsolationHandler& operator=(const AppIsolationHandler&) = delete; - - ~AppIsolationHandler() override; - - bool Parse(Extension* extension, std::u16string* error) override; - bool AlwaysParseForType(Manifest::Type type) const override; - - private: - base::span<const char* const> Keys() const override; -}; - -} // namespace extensions - -#endif // EXTENSIONS_COMMON_MANIFEST_HANDLERS_APP_ISOLATION_INFO_H_
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 4117379..f69780f 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1099,6 +1099,10 @@ flags_ui::kOsIos, FEATURE_VALUE_TYPE(password_manager::features:: kIOSPasswordManagerCrossOriginIframeSupport)}, + {"ios-password-bottom-sheet", + flag_descriptions::kIOSPasswordBottomSheetName, + flag_descriptions::kIOSPasswordBottomSheetDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(password_manager::features::kIOSPasswordBottomSheet)}, {"ios-new-tab-page-retention", flag_descriptions::kNewTabPageRetentionName, flag_descriptions::kNewTabPageRetentionDescription, flags_ui::kOsIos, FEATURE_WITH_PARAMS_VALUE_TYPE(ntp_tiles::kNewTabPageRetention,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 815be5a7..c48aba3f 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -506,6 +506,10 @@ const char kIOSPasswordManagerCrossOriginIframeSupportDescription[] = "Enables password saving and filling in cross-origin iframes on IOS."; +const char kIOSPasswordBottomSheetName[] = "IOS Password Manager Bottom Sheet"; +const char kIOSPasswordBottomSheetDescription[] = + "Enables the display of the password bottom sheet on IOS."; + const char kNewTabPageRetentionName[] = "New tab page features that target new users"; const char kNewTabPageRetentionDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index a769b472..99c0bef8 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -440,6 +440,10 @@ extern const char kIOSPasswordManagerCrossOriginIframeSupportName[]; extern const char kIOSPasswordManagerCrossOriginIframeSupportDescription[]; +// Title and description for the flag to enable password bottom sheet on IOS. +extern const char kIOSPasswordBottomSheetName[]; +extern const char kIOSPasswordBottomSheetDescription[]; + // Title and description of the flag to enable client side new tab page // experiments aimed at improving user retention. extern const char kNewTabPageRetentionName[];
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn index 65e9429..053e409 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_checkup/BUILD.gn
@@ -33,8 +33,13 @@ deps = [ ":password_checkup_utils", "resources:password_checkup_header_background_color", + "resources:password_checkup_header_green", + "resources:password_checkup_header_loading", + "resources:password_checkup_header_red", + "resources:password_checkup_header_yellow", "//base", "//ios/chrome/app/strings", + "//ios/chrome/browser/shared/ui/util", "//ios/chrome/browser/ui/settings:settings_root", "//ui/base", ] @@ -83,8 +88,11 @@ "//components/password_manager/core/common:features", "//components/prefs:test_support", "//ios/chrome/browser/browser_state:test_support", + "//ios/chrome/browser/main:test_support", "//ios/chrome/browser/passwords", "//ios/chrome/browser/passwords:store_factory", + "//ios/chrome/browser/ui/table_view:test_support", + "//ios/chrome/browser/ui/table_view:utils", "//ios/web/public/test", "//testing/gtest", "//third_party/ocmock",
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h index 8fc1863..65df9de1 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h
@@ -29,12 +29,16 @@ // Struct used to obtain the password counts associated with the different // insecure types. struct InsecurePasswordCounts { - int compromisedCount; - int dismissedCount; - int reusedCount; - int weakCount; + int compromised_count; + int dismissed_count; + int reused_count; + int weak_count; }; +// Operator overload for the InsecurePasswordCounts struct. +bool operator==(const InsecurePasswordCounts& lhs, + const InsecurePasswordCounts& rhs); + // Returns the type of warning with the highest priority, the descending order // of priority being: // 1. Compromised password warnings
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.mm index 772620f9..2e66ddd 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.mm
@@ -26,6 +26,15 @@ namespace password_manager { +bool operator==(const InsecurePasswordCounts& lhs, + const InsecurePasswordCounts& rhs) { + std::tuple lhs_tuple = std::tie(lhs.compromised_count, lhs.dismissed_count, + lhs.reused_count, lhs.weak_count); + std::tuple rhs_tuple = std::tie(rhs.compromised_count, rhs.dismissed_count, + rhs.reused_count, rhs.weak_count); + return lhs_tuple == rhs_tuple; +} + WarningType GetWarningOfHighestPriority( const std::vector<password_manager::CredentialUIEntry>& insecure_credentials) { @@ -64,15 +73,15 @@ // If a compromised credential is muted, we don't want to take it into // account in the compromised count. if (credential.IsMuted()) { - counts.dismissedCount++; + counts.dismissed_count++; } else if (IsCompromised(credential)) { - counts.compromisedCount++; + counts.compromised_count++; } if (credential.IsReused()) { - counts.reusedCount++; + counts.reused_count++; } if (credential.IsWeak()) { - counts.weakCount++; + counts.weak_count++; } } return counts; @@ -86,13 +95,13 @@ CountInsecurePasswordsPerInsecureType(insecure_credentials); switch (warningType) { case WarningType::kCompromisedPasswordsWarning: - return counts.compromisedCount; + return counts.compromised_count; case WarningType::kReusedPasswordsWarning: - return counts.reusedCount; + return counts.reused_count; case WarningType::kWeakPasswordsWarning: - return counts.weakCount; + return counts.weak_count; case WarningType::kDismissedWarningsWarning: - return counts.dismissedCount; + return counts.dismissed_count; case WarningType::kNoInsecurePasswordsWarning: return 0; }
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.mm index 470ff7e42..5900496 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.h" #import "base/metrics/user_metrics.h" +#import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_commands.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_consumer.h" #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h" @@ -15,10 +16,54 @@ #error "This file requires ARC support." #endif +using password_manager::InsecurePasswordCounts; + +namespace { + +// Height of the image used as a header for the table view. +CGFloat const kHeaderImageHeight = 99; + +// Helper method to get the right trailing image for the Password Check cell +// depending on the check state. +UIImage* GetHeaderImage(PasswordCheckupHomepageState password_checkup_state, + InsecurePasswordCounts counts) { + bool has_compromised_passwords = counts.compromised_count > 0; + bool has_insecure_passwords = + counts.compromised_count > 0 || counts.dismissed_count > 0 || + counts.reused_count > 0 || counts.weak_count > 0; + switch (password_checkup_state) { + case PasswordCheckupHomepageStateDone: + if (has_compromised_passwords) { + return [UIImage imageNamed:@"password_checkup_header_red"]; + } else if (has_insecure_passwords) { + return [UIImage imageNamed:@"password_checkup_header_yellow"]; + } + return [UIImage imageNamed:@"password_checkup_header_green"]; + case PasswordCheckupHomepageStateRunning: + return [UIImage imageNamed:@"password_checkup_header_loading"]; + case PasswordCheckupHomepageStateError: + case PasswordCheckupHomepageStateDisabled: + return nil; + } +} + +} // namespace + @interface PasswordCheckupViewController () { // Whether Settings have been dismissed. BOOL _settingsAreDismissed; + + // Current PasswordCheckupHomepageState. + PasswordCheckupHomepageState _passwordCheckupState; + + // Password counts associated with the different insecure types. + InsecurePasswordCounts _insecurePasswordCounts; + + // Image view at the top of the screen, indicating the overall Password + // Checkup status. + UIImageView* _headerImageView; } + @end @implementation PasswordCheckupViewController @@ -29,18 +74,26 @@ [super viewDidLoad]; self.title = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECKUP); + + _headerImageView = [self createHeaderImageView]; + self.tableView.tableHeaderView = _headerImageView; + [self updateHeaderImage]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - self.navigationController.navigationBar.backgroundColor = - [UIColor colorNamed:@"password_checkup_header_background_color"]; + // Update the navigation bar background color as it is different for the + // PasswordCheckupViewController than for its parent. + [self updateNavigationBarBackgroundColorForDismissal:NO]; } - (void)willMoveToParentViewController:(UIViewController*)parent { [super willMoveToParentViewController:parent]; - // Set the navigation bar background color back to `nil`. - super.navigationController.navigationBar.backgroundColor = nil; + if (!parent) { + // Reset the navigation bar background color to what it was before getting + // to the PasswordCheckupViewController. + [self updateNavigationBarBackgroundColorForDismissal:YES]; + } } - (void)didMoveToParentViewController:(UIViewController*)parent { @@ -50,6 +103,15 @@ } } +- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + if (self.traitCollection.verticalSizeClass != + previousTraitCollection.verticalSizeClass) { + [self updateNavigationBarBackgroundColorForDismissal:NO]; + [self updateTableViewHeaderView]; + } +} + #pragma mark - SettingsControllerProtocol - (void)reportDismissalUserAction { @@ -72,13 +134,81 @@ - (void)setPasswordCheckupHomepageState:(PasswordCheckupHomepageState)state insecurePasswordCounts: - (password_manager::InsecurePasswordCounts) - insecurePasswordCounts { - // TODO(crbug.com/1406540): Add method's body. + (InsecurePasswordCounts)insecurePasswordCounts { + // If the state and the insecure password counts both haven't changed, there + // is no need to update anything. + if (_passwordCheckupState == state && + _insecurePasswordCounts == insecurePasswordCounts) { + return; + } + + // If state is PasswordCheckupHomepageStateDisabled, it means that there is no + // saved password to check, so we return to the Password Manager. + if (state == PasswordCheckupHomepageStateDisabled) { + [self.handler dismissPasswordCheckupViewController]; + } + + _passwordCheckupState = state; + _insecurePasswordCounts = insecurePasswordCounts; + [self updateHeaderImage]; } - (void)setAffiliatedGroupCount:(NSInteger)affiliatedGroupCount { // TODO(crbug.com/1406540): Add method's body. } +#pragma mark - Private + +// Creates the header image view. +- (UIImageView*)createHeaderImageView { + UIImageView* headerImageView = [[UIImageView alloc] init]; + headerImageView.contentMode = UIViewContentModeScaleAspectFill; + headerImageView.frame = CGRectMake(0, 0, 0, kHeaderImageHeight); + return headerImageView; +} + +// Updates the background color of the navigation bar. When iPhones are in +// landscape mode, we want to hide the header image, and so we want to update +// the background color of the navigation bar accordingly. We also want to set +// the background color back to `nil` when returning to the previous view +// controller to cleanup the color change made in this view controller. +- (void)updateNavigationBarBackgroundColorForDismissal: + (BOOL)viewControllerWillBeDismissed { + if (viewControllerWillBeDismissed || IsCompactHeight(self)) { + self.navigationController.navigationBar.backgroundColor = nil; + return; + } + self.navigationController.navigationBar.backgroundColor = + [UIColor colorNamed:@"password_checkup_header_background_color"]; +} + +// Updates the table view's header view depending on whether the header image +// view should be shown or not. When we're in iPhone landscape mode, we want to +// hide the image header view. +- (void)updateTableViewHeaderView { + if (IsCompactHeight(self)) { + self.tableView.tableHeaderView = nil; + } else { + self.tableView.tableHeaderView = _headerImageView; + } +} + +// Updates the header image according to the current +// PasswordCheckupHomepageState. +- (void)updateHeaderImage { + switch (_passwordCheckupState) { + case PasswordCheckupHomepageStateDone: + case PasswordCheckupHomepageStateRunning: { + UIImage* headerImage = + GetHeaderImage(_passwordCheckupState, _insecurePasswordCounts); + [_headerImageView setImage:headerImage]; + break; + } + case PasswordCheckupHomepageStateError: + case PasswordCheckupHomepageStateDisabled: + break; + } + [self.tableView layoutIfNeeded]; +} + @end
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller_unittest.mm index 25af389..34b8285 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller_unittest.mm
@@ -3,14 +3,206 @@ // found in the LICENSE file. #import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_view_controller.h" -#import "testing/platform_test.h" + +#import "components/keyed_service/core/service_access_type.h" +#import "components/password_manager/core/browser/password_form.h" +#import "components/password_manager/core/browser/password_manager_test_utils.h" +#import "components/password_manager/core/browser/test_password_store.h" +#import "components/password_manager/core/browser/ui/credential_ui_entry.h" +#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#import "ios/chrome/browser/main/test_browser.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" +#import "ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_utils.h" +#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h" +#import "ios/chrome/browser/ui/table_view/table_view_utils.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/gtest_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +using password_manager::CredentialUIEntry; +using password_manager::InsecureType; +using password_manager::PasswordForm; +using password_manager::TestPasswordStore; + // Test fixture for testing PasswordCheckupViewController class. -class PasswordCheckupViewControllerTest : public PlatformTest { +class PasswordCheckupViewControllerTest : public ChromeTableViewControllerTest { protected: - void SetUp() override { PlatformTest::SetUp(); } + PasswordCheckupViewControllerTest() = default; + + void SetUp() override { + ChromeTableViewControllerTest::SetUp(); + TestChromeBrowserState::Builder builder; + builder.AddTestingFactory( + IOSChromePasswordStoreFactory::GetInstance(), + base::BindRepeating( + &password_manager::BuildPasswordStore<web::BrowserState, + TestPasswordStore>)); + browser_state_ = builder.Build(); + browser_ = std::make_unique<TestBrowser>(browser_state_.get()); + + CreateController(); + } + + TestPasswordStore& GetTestStore() { + return *static_cast<TestPasswordStore*>( + IOSChromePasswordStoreFactory::GetForBrowserState( + browser_->GetBrowserState(), ServiceAccessType::EXPLICIT_ACCESS) + .get()); + } + + ChromeTableViewController* InstantiateController() override { + return [[PasswordCheckupViewController alloc] + initWithStyle:ChromeTableViewStyle()]; + } + + PasswordCheckupViewController* GetPasswordCheckupViewController() { + return static_cast<PasswordCheckupViewController*>(controller()); + } + + // Changes the PasswordCheckupHomepageState. + void ChangePasswordCheckupHomepageState(PasswordCheckupHomepageState state) { + PasswordCheckupViewController* view_controller = + GetPasswordCheckupViewController(); + + password_manager::InsecurePasswordCounts counts = {}; + for (const auto& signon_realm_forms : GetTestStore().stored_passwords()) { + for (const PasswordForm& form : signon_realm_forms.second) { + CredentialUIEntry credential = CredentialUIEntry(form); + if (credential.IsMuted()) { + counts.dismissed_count++; + } else if (IsCompromised(credential)) { + counts.compromised_count++; + } + if (credential.IsReused()) { + counts.reused_count++; + } + if (credential.IsWeak()) { + counts.weak_count++; + } + } + } + + [view_controller setPasswordCheckupHomepageState:state + insecurePasswordCounts:counts]; + } + + // Adds a form to the test password store. + void AddPasswordForm(std::unique_ptr<password_manager::PasswordForm> form) { + GetTestStore().AddLogin(*form); + RunUntilIdle(); + } + + // Creates and adds a saved insecure password form. + void AddSavedInsecureForm(InsecureType insecure_type, + bool is_muted = false, + std::string url = "http://www.example1.com/") { + auto form = std::make_unique<password_manager::PasswordForm>(); + form->url = GURL(url); + form->username_element = u"Email"; + form->username_value = u"test@egmail.com"; + form->password_element = u"Passwd"; + form->password_value = u"test"; + form->signon_realm = url; + form->scheme = password_manager::PasswordForm::Scheme::kHtml; + form->in_store = password_manager::PasswordForm::Store::kProfileStore; + form->password_issues = { + {insecure_type, + password_manager::InsecurityMetadata( + base::Time::Now(), password_manager::IsMuted(is_muted))}}; + AddPasswordForm(std::move(form)); + } + + void RunUntilIdle() { task_environment_.RunUntilIdle(); } + + web::WebTaskEnvironment task_environment_; + std::unique_ptr<TestChromeBrowserState> browser_state_; + std::unique_ptr<TestBrowser> browser_; }; + +// Tests the running state of the Password Checkup homepage. +TEST_F(PasswordCheckupViewControllerTest, PasswordCheckupHomepageStateRunning) { + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateRunning); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_loading"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +} + +// Tests the "done" state of the Password Checkup homepage with no insecure +// passwords. +TEST_F(PasswordCheckupViewControllerTest, PasswordCheckupHomepageStateSafe) { + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateDone); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_green"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +} + +// Tests the "done" state of the Password Checkup homepage with compromised +// passwords. +TEST_F(PasswordCheckupViewControllerTest, + PasswordCheckupHomepageStateWithCompromisedPasswords) { + AddSavedInsecureForm(InsecureType::kLeaked); + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateDone); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_red"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +} + +// Tests the "done" state of the Password Checkup homepage with muted +// compromised passwords. +TEST_F(PasswordCheckupViewControllerTest, + PasswordCheckupHomepageStateWithMutedCompromisedPasswords) { + AddSavedInsecureForm(InsecureType::kLeaked, /*is_muted=*/true); + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateDone); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_yellow"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +} + +// Tests the "done" state of the Password Checkup homepage with reused +// passwords. +TEST_F(PasswordCheckupViewControllerTest, + PasswordCheckupHomepageStateWithReusedPasswords) { + AddSavedInsecureForm(InsecureType::kReused); + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateDone); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_yellow"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +} + +// Tests the "done" state of the Password Checkup homepage with weak passwords. +TEST_F(PasswordCheckupViewControllerTest, + PasswordCheckupHomepageStateWithWeakPasswords) { + AddSavedInsecureForm(InsecureType::kWeak); + ChangePasswordCheckupHomepageState(PasswordCheckupHomepageStateDone); + + UIImageView* headerImageView = + (UIImageView*)GetPasswordCheckupViewController() + .tableView.tableHeaderView; + EXPECT_NSEQ([UIImage imageNamed:@"password_checkup_header_yellow"], + headerImageView.image); + [GetPasswordCheckupViewController() settingsWillBeDismissed]; +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_checkup/resources/BUILD.gn index 6496089..1c90e57 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/resources/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/BUILD.gn
@@ -8,3 +8,43 @@ sources = [ "password_checkup_header_background_color.colorset/Contents.json" ] } + +imageset("password_checkup_header_green") { + sources = [ + "password_checkup_header_green.imageset/Contents.json", + "password_checkup_header_green.imageset/password_checkup_header_green@2x.png", + "password_checkup_header_green.imageset/password_checkup_header_green@3x.png", + "password_checkup_header_green.imageset/password_checkup_header_green_dark@2x.png", + "password_checkup_header_green.imageset/password_checkup_header_green_dark@3x.png", + ] +} + +imageset("password_checkup_header_loading") { + sources = [ + "password_checkup_header_loading.imageset/Contents.json", + "password_checkup_header_loading.imageset/password_checkup_header_loading@2x.png", + "password_checkup_header_loading.imageset/password_checkup_header_loading@3x.png", + "password_checkup_header_loading.imageset/password_checkup_header_loading_dark@2x.png", + "password_checkup_header_loading.imageset/password_checkup_header_loading_dark@3x.png", + ] +} + +imageset("password_checkup_header_red") { + sources = [ + "password_checkup_header_red.imageset/Contents.json", + "password_checkup_header_red.imageset/password_checkup_header_red@2x.png", + "password_checkup_header_red.imageset/password_checkup_header_red@3x.png", + "password_checkup_header_red.imageset/password_checkup_header_red_dark@2x.png", + "password_checkup_header_red.imageset/password_checkup_header_red_dark@3x.png", + ] +} + +imageset("password_checkup_header_yellow") { + sources = [ + "password_checkup_header_yellow.imageset/Contents.json", + "password_checkup_header_yellow.imageset/password_checkup_header_yellow@2x.png", + "password_checkup_header_yellow.imageset/password_checkup_header_yellow@3x.png", + "password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@2x.png", + "password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@3x.png", + ] +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/Contents.json b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/Contents.json new file mode 100644 index 0000000..7dce599f --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/Contents.json
@@ -0,0 +1,40 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "password_checkup_header_green@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_green@3x.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_green_dark@2x.png", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_green_dark@3x.png", + "scale" : "3x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@2x.png new file mode 100644 index 0000000..dd8ad88 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@3x.png new file mode 100644 index 0000000..b4f4375 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@2x.png new file mode 100644 index 0000000..73ae3a2 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@3x.png new file mode 100644 index 0000000..f998b48 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_green.imageset/password_checkup_header_green_dark@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/Contents.json b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/Contents.json new file mode 100644 index 0000000..6b3760a --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/Contents.json
@@ -0,0 +1,40 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "password_checkup_header_loading@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_loading@3x.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_loading_dark@2x.png", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_loading_dark@3x.png", + "scale" : "3x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@2x.png new file mode 100644 index 0000000..6b9b36e --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@3x.png new file mode 100644 index 0000000..ef64d65 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@2x.png new file mode 100644 index 0000000..c7df5b8 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@3x.png new file mode 100644 index 0000000..6ebf7b7 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_loading.imageset/password_checkup_header_loading_dark@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/Contents.json b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/Contents.json new file mode 100644 index 0000000..34bd580 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/Contents.json
@@ -0,0 +1,40 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "password_checkup_header_red@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_red@3x.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_red_dark@2x.png", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_red_dark@3x.png", + "scale" : "3x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@2x.png new file mode 100644 index 0000000..5954805 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@3x.png new file mode 100644 index 0000000..3113c55 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@2x.png new file mode 100644 index 0000000..ec542e3 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@3x.png new file mode 100644 index 0000000..536f562 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_red.imageset/password_checkup_header_red_dark@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/Contents.json b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/Contents.json new file mode 100644 index 0000000..33a928e4 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/Contents.json
@@ -0,0 +1,40 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "password_checkup_header_yellow@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_yellow@3x.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_yellow_dark@2x.png", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "filename" : "password_checkup_header_yellow_dark@3x.png", + "scale" : "3x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@2x.png new file mode 100644 index 0000000..52e69b9 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@3x.png new file mode 100644 index 0000000..0a81ba0f --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@2x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@2x.png new file mode 100644 index 0000000..e37699b --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@3x.png b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@3x.png new file mode 100644 index 0000000..3281942 --- /dev/null +++ b/ios/chrome/browser/ui/settings/password/password_checkup/resources/password_checkup_header_yellow.imageset/password_checkup_header_yellow_dark@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm index 2016f80a..e9bde11 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_view_controller.mm
@@ -329,9 +329,6 @@ // Shared password auto-fill status manager that contains the most updated // status of password auto-fill for Chrome. PasswordAutoFillStatusManager* _sharedPasswordAutoFillStatusManager; - // Boolean containing whether `self` should be updated after dismissing - // the Search Controller. - BOOL _shouldUpdateAfterSearchControllerDismissed; // Whether the table view is in search mode. That is, it only has the search // bar potentially saved passwords and blocked sites. BOOL _tableIsInSearchMode; @@ -591,8 +588,7 @@ TableViewModel* model = self.tableViewModel; if (ShouldShowSettingsUI()) { - // Save passwords switch and manage account message. Only show this section - // when the searchController is not active. + // Don't show sections hidden when search controller is displayed. if (!_tableIsInSearchMode) { [model addSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch]; @@ -608,61 +604,64 @@ [model addItem:_savePasswordsItem toSectionWithIdentifier:SectionIdentifierSavePasswordsSwitch]; } + + // Passwords in other apps. + [model addSectionWithIdentifier:SectionIdentifierPasswordsInOtherApps]; + if (!_passwordsInOtherAppsItem) { + _passwordsInOtherAppsItem = [self passwordsInOtherAppsItem]; + } + [model addItem:_passwordsInOtherAppsItem + toSectionWithIdentifier:SectionIdentifierPasswordsInOtherApps]; + } + } + + // Don't show sections hidden when search controller is displayed. + if (!_tableIsInSearchMode) { + // Password check. + [model addSectionWithIdentifier:SectionIdentifierPasswordCheck]; + if (!_passwordProblemsItem) { + _passwordProblemsItem = [self passwordProblemsItem]; } - // Passwords in other apps. - [model addSectionWithIdentifier:SectionIdentifierPasswordsInOtherApps]; - if (!_passwordsInOtherAppsItem) { - _passwordsInOtherAppsItem = [self passwordsInOtherAppsItem]; - } - [model addItem:_passwordsInOtherAppsItem - toSectionWithIdentifier:SectionIdentifierPasswordsInOtherApps]; - } - - // Password check. - [model addSectionWithIdentifier:SectionIdentifierPasswordCheck]; - if (!_passwordProblemsItem) { - _passwordProblemsItem = [self passwordProblemsItem]; - } - - [self updatePasswordCheckStatusLabelWithState:_passwordCheckState]; - [model addItem:_passwordProblemsItem - toSectionWithIdentifier:SectionIdentifierPasswordCheck]; - - if (!_checkForProblemsItem) { - _checkForProblemsItem = [self checkForProblemsItem]; - } - - [self updatePasswordCheckButtonWithState:_passwordCheckState]; - - // Only add check button if kIOSPasswordCheckup is disabled, or if it is - // enabled and the current PasswordCheckUIState requires the button to be - // shown. - if (!IsPasswordCheckupEnabled() || self.shouldShowCheckButton) { - [model addItem:_checkForProblemsItem + [self updatePasswordCheckStatusLabelWithState:_passwordCheckState]; + [model addItem:_passwordProblemsItem toSectionWithIdentifier:SectionIdentifierPasswordCheck]; - } - // When the Password Checkup feature is enabled, this timestamp only appears - // in the detail text of the Password Checkup status cell. It is therefore - // managed in `updatePasswordCheckStatusLabelWithState`. - if (!IsPasswordCheckupEnabled()) { - [self updateLastCheckTimestampWithState:_passwordCheckState - fromState:_passwordCheckState - update:NO]; - } + if (!_checkForProblemsItem) { + _checkForProblemsItem = [self checkForProblemsItem]; + } - // On-device encryption. - [self updateOnDeviceEncryptionSessionWithUpdateTableView:NO - withRowAnimation: - UITableViewRowAnimationNone]; + [self updatePasswordCheckButtonWithState:_passwordCheckState]; - // Add Password button. - if (!ShouldShowSettingsUI() && [self allowsAddPassword]) { - [model addSectionWithIdentifier:SectionIdentifierAddPasswordButton]; - _addPasswordItem = [self addPasswordItem]; - [model addItem:_addPasswordItem - toSectionWithIdentifier:SectionIdentifierAddPasswordButton]; + // Only add check button if kIOSPasswordCheckup is disabled, or if it is + // enabled and the current PasswordCheckUIState requires the button to be + // shown. + if (!IsPasswordCheckupEnabled() || self.shouldShowCheckButton) { + [model addItem:_checkForProblemsItem + toSectionWithIdentifier:SectionIdentifierPasswordCheck]; + } + + // When the Password Checkup feature is enabled, this timestamp only appears + // in the detail text of the Password Checkup status cell. It is therefore + // managed in `updatePasswordCheckStatusLabelWithState`. + if (!IsPasswordCheckupEnabled()) { + [self updateLastCheckTimestampWithState:_passwordCheckState + fromState:_passwordCheckState + update:NO]; + } + + // On-device encryption. + [self updateOnDeviceEncryptionSessionWithUpdateTableView:NO + withRowAnimation: + UITableViewRowAnimationNone]; + + // Add Password button. + if (!ShouldShowSettingsUI() && [self allowsAddPassword]) { + [model addSectionWithIdentifier:SectionIdentifierAddPasswordButton]; + _addPasswordItem = [self addPasswordItem]; + [model addItem:_addPasswordItem + toSectionWithIdentifier:SectionIdentifierAddPasswordButton]; + } } // Saved passwords. @@ -695,14 +694,16 @@ toSectionWithIdentifier:SectionIdentifierExportPasswordsButton]; } - // Add the descriptive text at the top of the screen. Do this at the end to - // ensure the section to which it's being attached already exists. + // Add the descriptive text at the top of the screen. The section for this + // header is not visible in while in search mode. Adding it to the model only + // when not in search mode. _manageAccountLinkItem = [self manageAccountLinkItem]; - [model setHeader:_manageAccountLinkItem - forSectionWithIdentifier:[self sectionForManageAccountLinkHeader]]; + if (!_tableIsInSearchMode) { + [model setHeader:_manageAccountLinkItem + forSectionWithIdentifier:[self sectionForManageAccountLinkHeader]]; + } [self filterItems:self.searchTerm]; - _tableIsInSearchMode = NO; } // Returns YES if the array of index path contains a saved password. This is to @@ -1365,8 +1366,13 @@ _sharedPasswordAutoFillStatusManager.autoFillEnabled ? l10n_util::GetNSString(IDS_IOS_SETTING_ON) : l10n_util::GetNSString(IDS_IOS_SETTING_OFF); - [self reloadCellsForItems:@[ _passwordsInOtherAppsItem ] - withRowAnimation:UITableViewRowAnimationNone]; + + // Item is only visible when search is not active. + // Only update corresponding cell when visible. + if (!_tableIsInSearchMode) { + [self reloadCellsForItems:@[ _passwordsInOtherAppsItem ] + withRowAnimation:UITableViewRowAnimationNone]; + } } } @@ -1394,7 +1400,6 @@ self.navigationController.navigationBar.backgroundColor = [UIColor colorNamed:kGroupedPrimaryBackgroundColor]; - _shouldUpdateAfterSearchControllerDismissed = YES; [self showScrim]; // Remove save passwords switch section, password check section and // on device encryption. @@ -1432,14 +1437,9 @@ // No need to restore UI if the Password Manager is being dismissed or if a // previous call to `willDismissSearchController` already restored the UI. - if (self.navigationController.isBeingDismissed || - !_shouldUpdateAfterSearchControllerDismissed) { + if (self.navigationController.isBeingDismissed || !_tableIsInSearchMode) { return; } - // If `willDismissSearchController` is invoked again before the search - // controller is presented, we don't want to do any updates because they are - // only needed once the search controller is presented and dismissed again. - _shouldUpdateAfterSearchControllerDismissed = NO; [self hideScrim]; [self searchForTerm:@""];
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm index 51975018..a7ff237 100644 --- a/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm
@@ -701,6 +701,86 @@ })); } +// Tests that the password manager is updated when passwords change while in +// search mode. +TEST_F(PasswordManagerViewControllerTest, TestChangePasswordsWhileSearching) { + root_view_controller_ = [[UIViewController alloc] init]; + scoped_window_.Get().rootViewController = root_view_controller_; + + PasswordManagerViewController* passwords_controller = + GetPasswordManagerViewController(); + + // Present the view controller. + __block bool presentation_finished = NO; + UINavigationController* navigation_controller = + [[UINavigationController alloc] + initWithRootViewController:passwords_controller]; + [root_view_controller_ presentViewController:navigation_controller + animated:NO + completion:^{ + presentation_finished = YES; + }]; + EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( + base::test::ios::kWaitForUIElementTimeout, ^bool { + return presentation_finished; + })); + + EXPECT_EQ(4, NumberOfSections()); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierSavePasswordsSwitch]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierPasswordCheck]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierPasswordsInOtherApps]); + // TODO(crbug.com/1361357): Update test after Export button is moved to + // Password Settings. + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierExportPasswordsButton]); + + passwords_controller.navigationItem.searchController.active = YES; + + // Add a password update. + AddSavedForm1(); + + // Simulate an update to passwords in other apps button that shouldn't be + // visible while in search. + [passwords_controller updatePasswordsInOtherAppsDetailedText]; + + EXPECT_EQ(2, NumberOfSections()); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierSavedPasswords]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierExportPasswordsButton]); + EXPECT_EQ(1, NumberOfItemsInSection(0)); + + passwords_controller.navigationItem.searchController.active = NO; + + // Sections are restored after search is over. + EXPECT_EQ(5, NumberOfSections()); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierSavePasswordsSwitch]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierPasswordCheck]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierPasswordsInOtherApps]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierSavedPasswords]); + EXPECT_TRUE([passwords_controller.tableViewModel + hasSectionForSectionIdentifier:SectionIdentifierExportPasswordsButton]); + + // Dismiss `view_controller_` and waits for the dismissal to finish. + __block bool dismissal_finished = NO; + [passwords_controller settingsWillBeDismissed]; + [root_view_controller_ dismissViewControllerAnimated:NO + completion:^{ + dismissal_finished = YES; + }]; + EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( + base::test::ios::kWaitForUIElementTimeout, ^bool { + return dismissal_finished; + })); +} + // Tests that dismissing the Search Controller multiple times without presenting // it again doesn't cause a crash. TEST_F(PasswordManagerViewControllerTest,
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h index b16167ef..5fad381b 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h
@@ -7,8 +7,6 @@ #import <Foundation/Foundation.h> -#import "base/memory/weak_ptr.h" - @protocol InactiveTabsCountConsumer; class WebStateList; @@ -18,7 +16,7 @@ // Initializer with `consumer` as the receiver of `webStateList` count updates. - (instancetype)initWithConsumer:(id<InactiveTabsCountConsumer>)consumer - webStateList:(base::WeakPtr<WebStateList>)webStateList + webStateList:(WebStateList*)webStateList NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.mm index fc0c8837..131fbacf 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_button_mediator.h" #import "base/notreached.h" -#import "base/scoped_multi_source_observation.h" +#import "base/scoped_observation.h" #import "ios/chrome/browser/tabs/inactive_tabs/features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_count_consumer.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" @@ -16,14 +16,14 @@ #endif using ScopedWebStateListObservation = - base::ScopedMultiSourceObservation<WebStateList, WebStateListObserver>; + base::ScopedObservation<WebStateList, WebStateListObserver>; @interface InactiveTabsButtonMediator () <WebStateListObserving> { // The UI consumer to which updates are made. __weak id<InactiveTabsCountConsumer> _consumer; // The list of inactive tabs. - base::WeakPtr<WebStateList> _webStateList; - // Observers for WebStateList. + WebStateList* _webStateList; + // Observers of _webStateList. std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; std::unique_ptr<ScopedWebStateListObservation> _scopedWebStateListObservation; } @@ -33,10 +33,10 @@ @implementation InactiveTabsButtonMediator - (instancetype)initWithConsumer:(id<InactiveTabsCountConsumer>)consumer - webStateList:(base::WeakPtr<WebStateList>)webStateList { + webStateList:(WebStateList*)webStateList { DCHECK(IsInactiveTabsEnabled()); DCHECK(consumer); - DCHECK(webStateList.get()); + DCHECK(webStateList); self = [super init]; if (self) { _consumer = consumer; @@ -46,7 +46,7 @@ _scopedWebStateListObservation = std::make_unique<ScopedWebStateListObservation>( _webStateListObserverBridge.get()); - _scopedWebStateListObservation->AddObservation(_webStateList.get()); + _scopedWebStateListObservation->Observe(_webStateList); [_consumer advertizeInactiveTabsWithCount:_webStateList->count()]; } return self; @@ -78,17 +78,32 @@ - (void)webStateList:(WebStateList*)webStateList willDetachWebState:(web::WebState*)webState atIndex:(int)index { - DCHECK_EQ(_webStateList.get(), webStateList); + // No-op. `-webStateList:didDetachWebState:atIndex` will soon be called and + // will update the consumer with the new count. +} + +- (void)webStateList:(WebStateList*)webStateList + didDetachWebState:(web::WebState*)webState + atIndex:(int)atIndex { + DCHECK_EQ(_webStateList, webStateList); [_consumer advertizeInactiveTabsWithCount:_webStateList->count()]; } - (void)webStateList:(WebStateList*)webStateList + willCloseWebState:(web::WebState*)webState + atIndex:(int)atIndex + userAction:(BOOL)userAction { + // No-op. Closed tabs have previously been detached, which means the count has + // already been updated. +} + +- (void)webStateList:(WebStateList*)webStateList didChangeActiveWebState:(web::WebState*)newWebState oldWebState:(web::WebState*)oldWebState atIndex:(int)atIndex reason:(ActiveWebStateChangeReason)reason { - // Called when the selected web state is moved (closed and opened elsewhere) - // from inactive to active. No op. + // No-op. This is called when the selected web state is moved (closed and + // opened elsewhere) from inactive to active. } - (void)webStateList:(WebStateList*)webStateList @@ -105,4 +120,10 @@ NOTREACHED(); } +- (void)webStateListDestroyed:(WebStateList*)webStateList { + DCHECK_EQ(webStateList, _webStateList); + _scopedWebStateListObservation.reset(); + _webStateList = nullptr; +} + @end
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm index 4b4bf54..c597f59 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_coordinator.mm
@@ -7,10 +7,13 @@ #import <UIKit/UIKit.h> #import "base/notreached.h" +#import "ios/chrome/browser/main/browser.h" +#import "ios/chrome/browser/snapshots/snapshot_browser_agent.h" #import "ios/chrome/browser/tabs/inactive_tabs/features.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_view_controller.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -56,9 +59,12 @@ self.viewController.gridViewController.delegate = self; // Create the mediator. + SnapshotCache* snapshotCache = + SnapshotBrowserAgent::FromBrowser(self.browser)->snapshot_cache(); self.mediator = [[InactiveTabsMediator alloc] - initWithConsumer:self.viewController.gridViewController]; - self.mediator.inactiveBrowser = self.browser; + initWithConsumer:self.viewController.gridViewController + webStateList:self.browser->GetWebStateList() + snapshotCache:snapshotCache]; self.viewController.gridViewController.imageDataSource = self.mediator; // Add the view controller to the hierarchy.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h index 6b8d97e..14968ea 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.h
@@ -9,16 +9,18 @@ #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_image_data_source.h" -class Browser; +@class SnapshotCache; @protocol TabCollectionConsumer; +class WebStateList; +// This mediator provides data to the Inactive Tabs grid and handles +// interactions. @interface InactiveTabsMediator : NSObject <GridImageDataSource> -// The inactive browser reference. -@property(nonatomic, assign) Browser* inactiveBrowser; - -// Initializer with `consumer` as the receiver of model layer updates. +// Initializer with `consumer` as the receiver of `webStateList` updates. - (instancetype)initWithConsumer:(id<TabCollectionConsumer>)consumer + webStateList:(WebStateList*)webStateList + snapshotCache:(SnapshotCache*)snapshotCache NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm index f0c4781..a5d95d2 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/inactive_tabs/inactive_tabs_mediator.mm
@@ -6,8 +6,8 @@ #import "base/notreached.h" #import "base/scoped_multi_source_observation.h" +#import "base/scoped_observation.h" #import "components/favicon/ios/web_favicon_driver.h" -#import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/snapshots/snapshot_browser_agent.h" #import "ios/chrome/browser/snapshots/snapshot_cache.h" #import "ios/chrome/browser/snapshots/snapshot_cache_observer.h" @@ -26,48 +26,72 @@ #endif using ScopedWebStateListObservation = - base::ScopedMultiSourceObservation<WebStateList, WebStateListObserver>; + base::ScopedObservation<WebStateList, WebStateListObserver>; using ScopedWebStateObservation = base::ScopedMultiSourceObservation<web::WebState, web::WebStateObserver>; @interface InactiveTabsMediator () <CRWWebStateObserver, SnapshotCacheObserver, WebStateListObserving> { - // Observers for WebStateList. + // The UI consumer to which updates are made. + __weak id<TabCollectionConsumer> _consumer; + // The list of inactive tabs. + WebStateList* _webStateList; + // The snapshot cache of _webStateList. + __weak SnapshotCache* _snapshotCache; + // The observers of _webStateList. std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; std::unique_ptr<ScopedWebStateListObservation> _scopedWebStateListObservation; - // Observers for WebStates. + // The observers of web states from _webStateList. std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; std::unique_ptr<ScopedWebStateObservation> _scopedWebStateObservation; + // The short-term cache for grid thumbnails. + NSMutableDictionary<NSString*, UIImage*>* _appearanceCache; } -// The UI consumer to which updates are made. -@property(nonatomic, weak, readonly) id<TabCollectionConsumer> consumer; -// The list of inactive tabs. -@property(nonatomic, assign, readonly) WebStateList* webStateList; -// The snapshot cache of `webStateList`. -@property(nonatomic, weak, readonly) SnapshotCache* snapshotCache; -// The short-term cache for grid thumbnails. -@property(nonatomic, strong, readonly) - NSMutableDictionary<NSString*, UIImage*>* appearanceCache; - @end @implementation InactiveTabsMediator -- (instancetype)initWithConsumer:(id<TabCollectionConsumer>)consumer { +- (instancetype)initWithConsumer:(id<TabCollectionConsumer>)consumer + webStateList:(WebStateList*)webStateList + snapshotCache:(SnapshotCache*)snapshotCache { DCHECK(IsInactiveTabsEnabled()); - if (self = [super init]) { + DCHECK(consumer); + DCHECK(webStateList); + self = [super init]; + if (self) { _consumer = consumer; + _webStateList = webStateList; + + // Observe the web state list. _webStateListObserverBridge = std::make_unique<WebStateListObserverBridge>(self); _scopedWebStateListObservation = std::make_unique<ScopedWebStateListObservation>( _webStateListObserverBridge.get()); + _scopedWebStateListObservation->Observe(_webStateList); + + // Observe all web states from the list. _webStateObserverBridge = std::make_unique<web::WebStateObserverBridge>(self); _scopedWebStateObservation = std::make_unique<ScopedWebStateObservation>( _webStateObserverBridge.get()); + NSMutableArray* items = [[NSMutableArray alloc] init]; + for (int i = 0; i < _webStateList->count(); i++) { + web::WebState* webState = _webStateList->GetWebStateAt(i); + _scopedWebStateObservation->AddObservation(webState); + [items addObject:GetTabSwitcherItem(webState)]; + } + + // Push the tabs to the consumer. + [_consumer populateItems:items selectedItemID:nil]; + + // TODO(crbug.com/1421321): The snapshot cache never returns snapshots. + // Investigate why. + _snapshotCache = snapshotCache; + [_snapshotCache addObserver:self]; + _appearanceCache = [[NSMutableDictionary alloc] init]; } return self; @@ -77,25 +101,6 @@ [_snapshotCache removeObserver:self]; } -#pragma mark - Public properties - -- (void)setInactiveBrowser:(Browser*)inactiveBrowser { - [_snapshotCache removeObserver:self]; - _scopedWebStateListObservation->RemoveAllObservations(); - _scopedWebStateObservation->RemoveAllObservations(); - - _inactiveBrowser = inactiveBrowser; - _webStateList = - inactiveBrowser ? inactiveBrowser->GetWebStateList() : nullptr; - - [_snapshotCache addObserver:self]; - if (_webStateList) { - _scopedWebStateListObservation->AddObservation(_webStateList); - [self addWebStateObservations]; - [self populateConsumerItems]; - } -} - #pragma mark - CRWWebStateObserver - (void)webStateDidStartLoading:(web::WebState*)webState { @@ -158,7 +163,7 @@ - (void)preloadSnapshotsForVisibleGridItems: (NSSet<NSString*>*)visibleGridItems { - for (int i = 0; i <= self.webStateList->count() - 1; i++) { + for (int i = 0; i <= _webStateList->count() - 1; i++) { web::WebState* web_state = _webStateList->GetWebStateAt(i); NSString* identifier = web_state->GetStableIdentifier(); @@ -167,9 +172,9 @@ continue; } - __weak __typeof(self) weakSelf = self; + __weak __typeof(_appearanceCache) weakAppearanceCache = _appearanceCache; auto cacheImage = ^(UIImage* image) { - weakSelf.appearanceCache[identifier] = image; + weakAppearanceCache[identifier] = image; }; [self snapshotForIdentifier:identifier completion:cacheImage]; @@ -231,6 +236,19 @@ } - (void)webStateList:(WebStateList*)webStateList + didDetachWebState:(web::WebState*)webState + atIndex:(int)atIndex { + // No-op. +} + +- (void)webStateList:(WebStateList*)webStateList + willCloseWebState:(web::WebState*)webState + atIndex:(int)atIndex + userAction:(BOOL)userAction { + // No-op. +} + +- (void)webStateList:(WebStateList*)webStateList didChangeActiveWebState:(web::WebState*)newWebState oldWebState:(web::WebState*)oldWebState atIndex:(int)atIndex @@ -252,24 +270,10 @@ NOTREACHED(); } -#pragma mark - Private - -// Add observers to all web states from the list. -- (void)addWebStateObservations { - for (int i = 0; i < _webStateList->count(); i++) { - web::WebState* webState = _webStateList->GetWebStateAt(i); - _scopedWebStateObservation->AddObservation(webState); - } -} - -// Calls `-populateItems:selectedItemID:` on the consumer. -- (void)populateConsumerItems { - NSMutableArray* items = [[NSMutableArray alloc] init]; - for (int i = 0; i < _webStateList->count(); i++) { - web::WebState* webState = _webStateList->GetWebStateAt(i); - [items addObject:GetTabSwitcherItem(webState)]; - } - [_consumer populateItems:items selectedItemID:nil]; +- (void)webStateListDestroyed:(WebStateList*)webStateList { + DCHECK_EQ(webStateList, _webStateList); + _scopedWebStateListObservation.reset(); + _webStateList = nullptr; } @end
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm index b9822d7..e66ab50 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -681,7 +681,7 @@ if (IsInactiveTabsEnabled()) { self.inactiveTabsButtonMediator = [[InactiveTabsButtonMediator alloc] initWithConsumer:baseViewController.regularTabsConsumer - webStateList:_inactiveBrowser->GetWebStateList()->AsWeakPtr()]; + webStateList:_inactiveBrowser->GetWebStateList()]; } self.incognitoTabsMediator = [[TabGridMediator alloc]
diff --git a/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.cc b/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.cc index 023d5aba..d19c4745 100644 --- a/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.cc +++ b/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.cc
@@ -65,6 +65,13 @@ } } +absl::optional<bool> Transform(absl::optional<bool> in) { + if (!in.has_value()) { + return absl::nullopt; + } + return !in.value(); +} + absl::optional<uint8_t> Transform(absl::optional<uint8_t> in) { if (!in.has_value()) { return absl::nullopt; @@ -167,7 +174,9 @@ out_mapped_enum_value)); } - void MethodWithNumerics(bool has_u8_value, + void MethodWithNumerics(bool has_bool_value, + bool bool_value, + bool has_u8_value, uint8_t u8_value, bool has_u16_value, uint16_t u16_value, @@ -188,6 +197,8 @@ bool has_double_value, double double_value, MethodWithNumericsCallback callback) override { + auto [out_has_bool_value, out_bool_value] = + FromOpt(Transform(ToOpt(has_bool_value, bool_value))); auto [out_has_u8_value, out_u8_value] = FromOpt(Transform(ToOpt(has_u8_value, u8_value))); auto [out_has_u16_value, out_u16_value] = @@ -208,18 +219,20 @@ FromOpt(Transform(ToOpt(has_float_value, float_value))); auto [out_has_double_value, out_double_value] = FromOpt(Transform(ToOpt(has_double_value, double_value))); - std::move(callback).Run(out_has_u8_value, out_u8_value, out_has_u16_value, - out_u16_value, out_has_u32_value, out_u32_value, - out_has_u64_value, out_u64_value, out_has_i8_value, - out_i8_value, out_has_i16_value, out_i16_value, - out_has_i32_value, out_i32_value, out_has_i64_value, - out_i64_value, out_has_float_value, out_float_value, - out_has_double_value, out_double_value); + std::move(callback).Run( + out_has_bool_value, out_bool_value, out_has_u8_value, out_u8_value, + out_has_u16_value, out_u16_value, out_has_u32_value, out_u32_value, + out_has_u64_value, out_u64_value, out_has_i8_value, out_i8_value, + out_has_i16_value, out_i16_value, out_has_i32_value, out_i32_value, + out_has_i64_value, out_i64_value, out_has_float_value, out_float_value, + out_has_double_value, out_double_value); } void MethodWithStructWithNumerics( mojom::CompatibleStructWithNumericsPtr in, MethodWithStructWithNumericsCallback callback) override { + auto [out_has_bool_value, out_bool_value] = + FromOpt(Transform(ToOpt(in->has_bool_value, in->bool_value))); auto [out_has_u8_value, out_u8_value] = FromOpt(Transform(ToOpt(in->has_u8_value, in->u8_value))); auto [out_has_u16_value, out_u16_value] = @@ -241,12 +254,12 @@ auto [out_has_double_value, out_double_value] = FromOpt(Transform(ToOpt(in->has_double_value, in->double_value))); std::move(callback).Run(mojom::CompatibleStructWithNumerics::New( - out_has_u8_value, out_u8_value, out_has_u16_value, out_u16_value, - out_has_u32_value, out_u32_value, out_has_u64_value, out_u64_value, - out_has_i8_value, out_i8_value, out_has_i16_value, out_i16_value, - out_has_i32_value, out_i32_value, out_has_i64_value, out_i64_value, - out_has_float_value, out_float_value, out_has_double_value, - out_double_value)); + out_has_bool_value, out_bool_value, out_has_u8_value, out_u8_value, + out_has_u16_value, out_u16_value, out_has_u32_value, out_u32_value, + out_has_u64_value, out_u64_value, out_has_i8_value, out_i8_value, + out_has_i16_value, out_i16_value, out_has_i32_value, out_i32_value, + out_has_i64_value, out_i64_value, out_has_float_value, out_float_value, + out_has_double_value, out_double_value)); } void MethodWithVersionedArgs( @@ -291,7 +304,8 @@ Transform(in->enum_value), Transform(in->mapped_enum_value))); } - void MethodWithNumerics(absl::optional<uint8_t> u8_value, + void MethodWithNumerics(absl::optional<bool> bool_value, + absl::optional<uint8_t> u8_value, absl::optional<uint16_t> u16_value, absl::optional<uint32_t> u32_value, absl::optional<uint64_t> u64_value, @@ -302,25 +316,27 @@ absl::optional<float> float_value, absl::optional<double> double_value, MethodWithNumericsCallback callback) override { - std::move(callback).Run(Transform(u8_value), Transform(u16_value), - Transform(u32_value), Transform(u64_value), - Transform(i8_value), Transform(i16_value), - Transform(i32_value), Transform(i64_value), - Transform(float_value), Transform(double_value)); + std::move(callback).Run( + Transform(bool_value), Transform(u8_value), Transform(u16_value), + Transform(u32_value), Transform(u64_value), Transform(i8_value), + Transform(i16_value), Transform(i32_value), Transform(i64_value), + Transform(float_value), Transform(double_value)); } void MethodWithStructWithNumerics( mojom::StructWithNumericsPtr in, MethodWithStructWithNumericsCallback callback) override { std::move(callback).Run(mojom::StructWithNumerics::New( - Transform(in->u8_value), Transform(in->u16_value), - Transform(in->u32_value), Transform(in->u64_value), - Transform(in->i8_value), Transform(in->i16_value), - Transform(in->i32_value), Transform(in->i64_value), - Transform(in->float_value), Transform(in->double_value))); + Transform(in->bool_value), Transform(in->u8_value), + Transform(in->u16_value), Transform(in->u32_value), + Transform(in->u64_value), Transform(in->i8_value), + Transform(in->i16_value), Transform(in->i32_value), + Transform(in->i64_value), Transform(in->float_value), + Transform(in->double_value))); } void MethodWithVersionedArgs( + absl::optional<bool> bool_value, absl::optional<uint8_t> u8_value, absl::optional<uint16_t> u16_value, absl::optional<uint32_t> u32_value, @@ -338,6 +354,7 @@ case CallerVersion::kV1: // A caller using the V1 interface will not know about the new // arguments, so they should all equal absl::nullopt. + EXPECT_EQ(absl::nullopt, bool_value); EXPECT_EQ(absl::nullopt, u8_value); EXPECT_EQ(absl::nullopt, u16_value); EXPECT_EQ(absl::nullopt, u32_value); @@ -352,6 +369,7 @@ EXPECT_EQ(absl::nullopt, mapped_enum_value); break; case CallerVersion::kV2: + EXPECT_EQ(true, bool_value); EXPECT_EQ(uint8_t{1}, u8_value); EXPECT_EQ(uint16_t{2}, u16_value); EXPECT_EQ(uint32_t{4}, u32_value); @@ -367,8 +385,8 @@ break; } std::move(callback).Run( - uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, int8_t{-8}, - int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, + false, uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, + int8_t{-8}, int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, mojom::RegularEnum::kThatValue, TypemappedEnum::kValueOne); } @@ -379,6 +397,7 @@ case CallerVersion::kV1: // A caller using the V1 interface will not know about the new // arguments, so they should all equal absl::nullopt. + EXPECT_EQ(absl::nullopt, in->bool_value); EXPECT_EQ(absl::nullopt, in->u8_value); EXPECT_EQ(absl::nullopt, in->u16_value); EXPECT_EQ(absl::nullopt, in->u32_value); @@ -393,6 +412,7 @@ EXPECT_EQ(absl::nullopt, in->mapped_enum_value); break; case CallerVersion::kV2: + EXPECT_EQ(true, in->bool_value); EXPECT_EQ(uint8_t{1}, in->u8_value); EXPECT_EQ(uint16_t{2}, in->u16_value); EXPECT_EQ(uint32_t{4}, in->u32_value); @@ -408,8 +428,8 @@ break; } std::move(callback).Run(mojom::VersionedStructV2::New( - uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, int8_t{-8}, - int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, + false, uint8_t{128}, uint16_t{64}, uint32_t{32}, uint64_t{16}, + int8_t{-8}, int16_t{-4}, int32_t{-2}, int64_t{-1}, -0.5f, 0.25, mojom::RegularEnum::kThatValue, TypemappedEnum::kValueOne)); } @@ -747,6 +767,7 @@ TEST_F(NullableNumericsAndEnums, StructWithNumerics) { { auto input = mojom::StructWithNumerics::New(); + input->bool_value = true; input->u8_value = absl::nullopt; input->u16_value = 16; input->u32_value = absl::nullopt; @@ -762,20 +783,22 @@ ASSERT_TRUE( SerializeAndDeserialize<mojom::StructWithNumerics>(input, output)); - EXPECT_EQ(absl::nullopt, input->u8_value); - EXPECT_EQ(16u, input->u16_value); - EXPECT_EQ(absl::nullopt, input->u32_value); - EXPECT_EQ(64u, input->u64_value); - EXPECT_EQ(-8, input->i8_value); - EXPECT_EQ(absl::nullopt, input->i16_value); - EXPECT_EQ(-32, input->i32_value); - EXPECT_EQ(absl::nullopt, input->i64_value); - EXPECT_EQ(absl::nullopt, input->float_value); - EXPECT_EQ(-64.0, input->double_value); + EXPECT_EQ(true, output->bool_value); + EXPECT_EQ(absl::nullopt, output->u8_value); + EXPECT_EQ(16u, output->u16_value); + EXPECT_EQ(absl::nullopt, output->u32_value); + EXPECT_EQ(64u, output->u64_value); + EXPECT_EQ(-8, output->i8_value); + EXPECT_EQ(absl::nullopt, output->i16_value); + EXPECT_EQ(-32, output->i32_value); + EXPECT_EQ(absl::nullopt, output->i64_value); + EXPECT_EQ(absl::nullopt, output->float_value); + EXPECT_EQ(-64.0, output->double_value); } { auto input = mojom::StructWithNumerics::New(); + input->bool_value = absl::nullopt; input->u8_value = 8; input->u16_value = absl::nullopt; input->u32_value = 32; @@ -791,16 +814,17 @@ ASSERT_TRUE( SerializeAndDeserialize<mojom::StructWithNumerics>(input, output)); - EXPECT_EQ(8u, input->u8_value); - EXPECT_EQ(absl::nullopt, input->u16_value); - EXPECT_EQ(32u, input->u32_value); - EXPECT_EQ(absl::nullopt, input->u64_value); - EXPECT_EQ(absl::nullopt, input->i8_value); - EXPECT_EQ(-16, input->i16_value); - EXPECT_EQ(absl::nullopt, input->i32_value); - EXPECT_EQ(-64, input->i64_value); - EXPECT_EQ(-32.0f, input->float_value); - EXPECT_EQ(absl::nullopt, input->double_value); + EXPECT_EQ(absl::nullopt, output->bool_value); + EXPECT_EQ(8u, output->u8_value); + EXPECT_EQ(absl::nullopt, output->u16_value); + EXPECT_EQ(32u, output->u32_value); + EXPECT_EQ(absl::nullopt, output->u64_value); + EXPECT_EQ(absl::nullopt, output->i8_value); + EXPECT_EQ(-16, output->i16_value); + EXPECT_EQ(absl::nullopt, output->i32_value); + EXPECT_EQ(-64, output->i64_value); + EXPECT_EQ(-32.0f, output->float_value); + EXPECT_EQ(absl::nullopt, output->double_value); } } @@ -815,18 +839,22 @@ { base::RunLoop loop; remote->MethodWithNumerics( - false, /* ignored */ uint8_t{0}, true, uint16_t{16}, false, + true, true, false, /* ignored */ uint8_t{0}, true, uint16_t{16}, + false, /* ignored */ uint32_t{0}, true, uint64_t{64}, true, int8_t{-8}, false, /* ignored */ int16_t{0}, true, int32_t{-32}, false, int64_t{0}, false, /* ignored */ 0.0f, true, -64.0, base::BindLambdaForTesting( - [&](bool has_u8_value, uint8_t u8_value, bool has_u16_value, - uint16_t u16_value, bool has_u32_value, uint32_t u32_value, - bool has_u64_value, uint64_t u64_value, bool has_i8_value, - int8_t i8_value, bool has_i16_value, int16_t i16_value, - bool has_i32_value, int32_t i32_value, bool has_i64_value, - int64_t i64_value, bool has_float_value, float float_value, + [&](bool has_bool_value, bool bool_value, bool has_u8_value, + uint8_t u8_value, bool has_u16_value, uint16_t u16_value, + bool has_u32_value, uint32_t u32_value, bool has_u64_value, + uint64_t u64_value, bool has_i8_value, int8_t i8_value, + bool has_i16_value, int16_t i16_value, bool has_i32_value, + int32_t i32_value, bool has_i64_value, int64_t i64_value, + bool has_float_value, float float_value, bool has_double_value, double double_value) { + EXPECT_TRUE(has_bool_value); + EXPECT_EQ(false, bool_value); EXPECT_FALSE(has_u8_value); EXPECT_TRUE(has_u16_value); // Note: the seemingly more obvious ~uint16_t{16} is not used @@ -853,19 +881,22 @@ { base::RunLoop loop; remote->MethodWithNumerics( - true, uint8_t{8}, false, /* ignored */ uint16_t{0}, true, - uint32_t{32}, false, /* ignored */ uint64_t{0}, false, + false, /* ignored */ false, true, uint8_t{8}, false, + /* ignored */ uint16_t{0}, true, uint32_t{32}, false, + /* ignored */ uint64_t{0}, false, /* ignored */ int8_t{0}, true, int16_t{-16}, false, /* ignored */ int32_t{0}, true, int64_t{-64}, true, -32.0f, false, /* ignored */ -0.0, base::BindLambdaForTesting( - [&](bool has_u8_value, uint8_t u8_value, bool has_u16_value, - uint16_t u16_value, bool has_u32_value, uint32_t u32_value, - bool has_u64_value, uint64_t u64_value, bool has_i8_value, - int8_t i8_value, bool has_i16_value, int16_t i16_value, - bool has_i32_value, int32_t i32_value, bool has_i64_value, - int64_t i64_value, bool has_float_value, float float_value, + [&](bool has_bool_value, bool bool_value, bool has_u8_value, + uint8_t u8_value, bool has_u16_value, uint16_t u16_value, + bool has_u32_value, uint32_t u32_value, bool has_u64_value, + uint64_t u64_value, bool has_i8_value, int8_t i8_value, + bool has_i16_value, int16_t i16_value, bool has_i32_value, + int32_t i32_value, bool has_i64_value, int64_t i64_value, + bool has_float_value, float float_value, bool has_double_value, double double_value) { + EXPECT_FALSE(has_bool_value); EXPECT_TRUE(has_u8_value); // Note: the seemingly more obvious ~uint8_t{8} is not used // here because using ~ when sizeof(integer) < sizeof(int) @@ -900,9 +931,11 @@ { base::RunLoop loop; remote->MethodWithNumerics( - absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, int8_t{-8}, - absl::nullopt, int32_t{-32}, absl::nullopt, absl::nullopt, -64.0, - base::BindLambdaForTesting([&](absl::optional<uint8_t> u8_value, + true, absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, + int8_t{-8}, absl::nullopt, int32_t{-32}, absl::nullopt, absl::nullopt, + -64.0, + base::BindLambdaForTesting([&](absl::optional<bool> bool_value, + absl::optional<uint8_t> u8_value, absl::optional<uint16_t> u16_value, absl::optional<uint32_t> u32_value, absl::optional<uint64_t> u64_value, @@ -912,6 +945,7 @@ absl::optional<int64_t> i64_value, absl::optional<float> float_value, absl::optional<double> double_value) { + EXPECT_EQ(false, bool_value); EXPECT_EQ(absl::nullopt, u8_value); // Note: the seemingly more obvious ~uint16_t{16} is not used // here because using ~ when sizeof(integer) < sizeof(int) @@ -933,9 +967,11 @@ { base::RunLoop loop; remote->MethodWithNumerics( - uint8_t{8}, absl::nullopt, uint32_t{32}, absl::nullopt, absl::nullopt, - int16_t{-16}, absl::nullopt, int64_t{-64}, -32.0f, absl::nullopt, - base::BindLambdaForTesting([&](absl::optional<uint8_t> u8_value, + absl::nullopt, uint8_t{8}, absl::nullopt, uint32_t{32}, absl::nullopt, + absl::nullopt, int16_t{-16}, absl::nullopt, int64_t{-64}, -32.0f, + absl::nullopt, + base::BindLambdaForTesting([&](absl::optional<bool> bool_value, + absl::optional<uint8_t> u8_value, absl::optional<uint16_t> u16_value, absl::optional<uint32_t> u32_value, absl::optional<uint64_t> u64_value, @@ -945,6 +981,7 @@ absl::optional<int64_t> i64_value, absl::optional<float> float_value, absl::optional<double> double_value) { + EXPECT_EQ(absl::nullopt, bool_value); // Note: the seemingly more obvious ~uint8_t{8} is not used // here because using ~ when sizeof(integer) < sizeof(int) // automatically promotes to an int. 🙃 @@ -977,12 +1014,15 @@ base::RunLoop loop; remote->MethodWithStructWithNumerics( mojom::CompatibleStructWithNumerics::New( - false, /* ignored */ uint8_t{0}, true, uint16_t{16}, false, + true, true, false, /* ignored */ uint8_t{0}, true, uint16_t{16}, + false, /* ignored */ uint32_t{0}, true, uint64_t{64}, true, int8_t{-8}, false, /* ignored */ int16_t{0}, true, int32_t{-32}, false, int64_t{0}, false, /* ignored */ 0.0f, true, -64.0), base::BindLambdaForTesting( [&](mojom::CompatibleStructWithNumericsPtr out) { + EXPECT_TRUE(out->has_bool_value); + EXPECT_EQ(false, out->bool_value); EXPECT_FALSE(out->has_u8_value); EXPECT_TRUE(out->has_u16_value); // Note: the seemingly more obvious ~uint16_t{16} is not used @@ -1010,13 +1050,15 @@ base::RunLoop loop; remote->MethodWithStructWithNumerics( mojom::CompatibleStructWithNumerics::New( - true, uint8_t{8}, false, /* ignored */ uint16_t{0}, true, - uint32_t{32}, false, /* ignored */ uint64_t{0}, false, + false, /* ignored */ false, true, uint8_t{8}, false, + /* ignored */ uint16_t{0}, true, uint32_t{32}, false, + /* ignored */ uint64_t{0}, false, /* ignored */ int8_t{0}, true, int16_t{-16}, false, /* ignored */ int32_t{0}, true, int64_t{-64}, true, -32.0f, false, /* ignored */ -0.0), base::BindLambdaForTesting( [&](mojom::CompatibleStructWithNumericsPtr out) { + EXPECT_FALSE(out->has_bool_value); EXPECT_TRUE(out->has_u8_value); // Note: the seemingly more obvious ~uint8_t{8} is not used // here because using ~ when sizeof(integer) < sizeof(int) @@ -1052,10 +1094,11 @@ base::RunLoop loop; remote->MethodWithStructWithNumerics( mojom::StructWithNumerics::New( - absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, + true, absl::nullopt, uint16_t{16}, absl::nullopt, uint64_t{64}, int8_t{-8}, absl::nullopt, int32_t{-32}, absl::nullopt, absl::nullopt, -64.0), base::BindLambdaForTesting([&](mojom::StructWithNumericsPtr out) { + EXPECT_EQ(false, out->bool_value); EXPECT_EQ(absl::nullopt, out->u8_value); // Note: the seemingly more obvious ~uint16_t{16} is not used // here because using ~ when sizeof(integer) < sizeof(int) @@ -1078,10 +1121,11 @@ base::RunLoop loop; remote->MethodWithStructWithNumerics( mojom::StructWithNumerics::New( - uint8_t{8}, absl::nullopt, uint32_t{32}, absl::nullopt, - absl::nullopt, int16_t{-16}, absl::nullopt, int64_t{-64}, -32.0f, - absl::nullopt), + absl::nullopt, uint8_t{8}, absl::nullopt, uint32_t{32}, + absl::nullopt, absl::nullopt, int16_t{-16}, absl::nullopt, + int64_t{-64}, -32.0f, absl::nullopt), base::BindLambdaForTesting([&](mojom::StructWithNumericsPtr out) { + EXPECT_EQ(absl::nullopt, out->bool_value); // Note: the seemingly more obvious ~uint8_t{8} is not used // here because using ~ when sizeof(integer) < sizeof(int) // automatically promotes to an int. 🙃 @@ -1167,11 +1211,12 @@ { base::RunLoop loop; remote->MethodWithVersionedArgs( - uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, + true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo, base::BindLambdaForTesting( - [&](absl::optional<uint8_t> out_u8_value, + [&](absl::optional<bool> out_bool_value, + absl::optional<uint8_t> out_u8_value, absl::optional<uint16_t> out_u16_value, absl::optional<uint32_t> out_u32_value, absl::optional<uint64_t> out_u64_value, @@ -1186,6 +1231,7 @@ // An implementation based on the V1 interface will not know // about the new arguments, so they should all equal // absl::nullopt. + EXPECT_EQ(absl::nullopt, out_bool_value); EXPECT_EQ(absl::nullopt, out_u8_value); EXPECT_EQ(absl::nullopt, out_u16_value); EXPECT_EQ(absl::nullopt, out_u32_value); @@ -1207,13 +1253,15 @@ base::RunLoop loop; remote->MethodWithVersionedStruct( mojom::VersionedStructV2::New( - uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, - int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, - mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo), + true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, + int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, + -512.0, mojom::RegularEnum::kThisValue, + TypemappedEnum::kValueTwo), base::BindLambdaForTesting([&](mojom::VersionedStructV2Ptr out) { // An implementation based on the V1 interface will not know // about the new arguments, so they should all equal // absl::nullopt. + EXPECT_EQ(absl::nullopt, out->bool_value); EXPECT_EQ(absl::nullopt, out->u8_value); EXPECT_EQ(absl::nullopt, out->u16_value); EXPECT_EQ(absl::nullopt, out->u32_value); @@ -1242,11 +1290,12 @@ { base::RunLoop loop; remote->MethodWithVersionedArgs( - uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, + true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo, base::BindLambdaForTesting( - [&](absl::optional<uint8_t> out_u8_value, + [&](absl::optional<bool> out_bool_value, + absl::optional<uint8_t> out_u8_value, absl::optional<uint16_t> out_u16_value, absl::optional<uint32_t> out_u32_value, absl::optional<uint64_t> out_u64_value, @@ -1258,6 +1307,7 @@ absl::optional<double> out_double_value, absl::optional<mojom::RegularEnum> out_enum_value, absl::optional<TypemappedEnum> out_mapped_enum_value) { + EXPECT_EQ(false, out_bool_value); EXPECT_EQ(uint8_t{128}, out_u8_value); EXPECT_EQ(uint16_t{64}, out_u16_value); EXPECT_EQ(uint32_t{32}, out_u32_value); @@ -1279,10 +1329,12 @@ base::RunLoop loop; remote->MethodWithVersionedStruct( mojom::VersionedStructV2::New( - uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, int8_t{-16}, - int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, -512.0, - mojom::RegularEnum::kThisValue, TypemappedEnum::kValueTwo), + true, uint8_t{1}, uint16_t{2}, uint32_t{4}, uint64_t{8}, + int8_t{-16}, int16_t{-32}, int32_t{-64}, int64_t{-128}, 256.0f, + -512.0, mojom::RegularEnum::kThisValue, + TypemappedEnum::kValueTwo), base::BindLambdaForTesting([&](mojom::VersionedStructV2Ptr out) { + EXPECT_EQ(false, out->bool_value); EXPECT_EQ(uint8_t{128}, out->u8_value); EXPECT_EQ(uint16_t{64}, out->u16_value); EXPECT_EQ(uint32_t{32}, out->u32_value);
diff --git a/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.test-mojom b/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.test-mojom index dd7edfb7..01483a9 100644 --- a/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.test-mojom +++ b/mojo/public/cpp/bindings/tests/nullable_numerics_and_enums_unittest.test-mojom
@@ -28,7 +28,9 @@ }; struct StructWithNumerics { + bool? bool_value; uint8? u8_value; + uint16? u16_value; uint32? u32_value; uint64? u64_value; @@ -43,6 +45,9 @@ }; struct CompatibleStructWithNumerics { + bool has_bool_value; + bool bool_value; + bool has_u8_value; uint8 u8_value; bool has_u16_value; @@ -72,6 +77,8 @@ }; struct VersionedStructV2 { + [MinVersion=1] bool? bool_value; + [MinVersion=1] uint8? u8_value; [MinVersion=1] uint16? u16_value; [MinVersion=1] uint32? u32_value; @@ -102,6 +109,8 @@ => (CompatibleStructWithEnums out); MethodWithNumerics@3( + bool has_bool_value, + bool bool_value, bool has_u8_value, uint8 u8_value, bool has_u16_value, @@ -123,6 +132,8 @@ bool has_double_value, double double_value ) => ( + bool has_bool_value, + bool bool_value, bool has_u8_value, uint8 u8_value, bool has_u16_value, @@ -160,6 +171,7 @@ MethodWithStructWithEnums@2(StructWithEnums in) => (StructWithEnums out); MethodWithNumerics@3( + bool? bool_value, uint8? u8_value, uint16? u16_value, uint32? u32_value, @@ -171,6 +183,7 @@ float? float_value, double? double_value ) => ( + bool? bool_value, uint8? u8_value, uint16? u16_value, uint32? u32_value, @@ -187,6 +200,7 @@ => (StructWithNumerics out); MethodWithVersionedArgs@5( + [MinVersion=1] bool? bool_value, [MinVersion=1] uint8? u8_value, [MinVersion=1] uint16? u16_value, [MinVersion=1] uint32? u32_value, @@ -200,6 +214,7 @@ [MinVersion=1] RegularEnum? enum_value, [MinVersion=1] TypemappedEnum? mapped_enum_value ) => ( + [MinVersion=1] bool? bool_value, [MinVersion=1] uint8? u8_value, [MinVersion=1] uint16? u16_value, [MinVersion=1] uint32? u32_value,
diff --git a/mojo/public/rust/BUILD.gn b/mojo/public/rust/BUILD.gn index 5261f69f..092424d 100644 --- a/mojo/public/rust/BUILD.gn +++ b/mojo/public/rust/BUILD.gn
@@ -17,22 +17,11 @@ rust_unit_tests_group("mojo_rust_tests") { deps = [] if (can_build_rust_unit_tests) { - deps += [ ":mojo_rust_unittests" ] + deps += [ + "//mojo/public/rust/tests:mojo_rust_integration_tests", + "//mojo/public/rust/tests:mojo_rust_system_tests", + ] } - if (can_build_rust_unit_tests) { - deps += [ ":mojo_rust_extra_tests" ] - } -} - -static_library("c_test_support") { - testonly = true - sources = [ "test_support.cc" ] - deps = [ - "//base", - "//mojo/core/embedder", - "//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils", - ] - visibility = [ ":*" ] } source_set("mojo_c_system_wrapper") { @@ -47,33 +36,21 @@ visibility = [ ":*" ] } -rust_static_library("mojo_rust") { - crate_root = "lib.rs" - unit_test_target = - "mojo_rust_unittests" # avoids conflict with C++ target elsewhere - crate_name = "mojo" - edition = "2021" +rust_static_library("mojo_rust_system") { + crate_root = "system/lib.rs" + crate_name = "mojo_system" - # TODO(danakj): Move to a gtest target. - build_native_rust_unit_tests = true sources = [ - "bindings/decoding.rs", - "bindings/encoding.rs", - "bindings/macros.rs", - "bindings/message.rs", - "bindings/mod.rs", - "bindings/mojom.rs", - "bindings/run_loop.rs", - "lib.rs", "system/core.rs", "system/data_pipe.rs", "system/ffi.rs", "system/handle.rs", + "system/lib.rs", "system/message_pipe.rs", - "system/mod.rs", "system/mojo_types.rs", "system/shared_buffer.rs", "system/trap.rs", + "system/util/run_loop.rs", "system/wait.rs", "system/wait_set.rs", ] @@ -81,6 +58,7 @@ deps = [ ":mojo_c_system_binding", ":mojo_c_system_wrapper", + "//mojo/public/c/system", "//third_party/rust/bitflags/v1:lib", ] @@ -89,20 +67,31 @@ rustenv = [ "BINDGEN_RS_FILE=" + rebase_path(bindgen_output[0]) ] } -if (can_build_rust_unit_tests) { - rust_unit_test("mojo_rust_extra_tests") { - testonly = true - crate_root = "tests/lib.rs" - edition = "2018" - sources = [ - "tests/integration.rs", - "tests/lib.rs", - ] - deps = [ - ":c_test_support", - ":mojo_rust", - "//mojo/public/c/system", - "//third_party/rust/lazy_static/v1:test_support", - ] - } +rust_static_library("mojo_rust_bindings") { + crate_root = "bindings/lib.rs" + crate_name = "mojo_bindings" + + sources = [ + "bindings/decoding.rs", + "bindings/encoding.rs", + "bindings/lib.rs", + "bindings/macros.rs", + "bindings/message.rs", + "bindings/mojom.rs", + ] + + deps = [ ":mojo_rust_system" ] +} + +# Convenience target to link both Mojo Rust components and reexport them under a +# single `mojo` name. +rust_static_library("mojo_rust") { + crate_root = "lib.rs" + crate_name = "mojo" + + sources = [ "lib.rs" ] + deps = [ + ":mojo_rust_bindings", + ":mojo_rust_system", + ] }
diff --git a/mojo/public/rust/bindings/decoding.rs b/mojo/public/rust/bindings/decoding.rs index acef06a..de611d4 100644 --- a/mojo/public/rust/bindings/decoding.rs +++ b/mojo/public/rust/bindings/decoding.rs
@@ -2,17 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::bindings::encoding::{ +use crate::encoding::{ Bits, Context, DataHeader, DataHeaderValue, MojomPrimitive, DATA_HEADER_SIZE, }; -use crate::bindings::mojom::{MojomEncodable, MOJOM_NULL_POINTER, UNION_SIZE}; +use crate::mojom::{MojomEncodable, MOJOM_NULL_POINTER, UNION_SIZE}; use std::mem; use std::ptr; use std::vec::Vec; -use crate::system; -use crate::system::{CastHandle, Handle, UntypedHandle}; +use system::{self, CastHandle, Handle, UntypedHandle}; #[derive(Debug, Eq, PartialEq)] pub enum ValidationError {
diff --git a/mojo/public/rust/bindings/encoding.rs b/mojo/public/rust/bindings/encoding.rs index 45d319b..18774e2 100644 --- a/mojo/public/rust/bindings/encoding.rs +++ b/mojo/public/rust/bindings/encoding.rs
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::bindings::mojom::MOJOM_NULL_POINTER; +use crate::mojom::MOJOM_NULL_POINTER; use std::mem; use std::ops::{Add, AddAssign, Mul}; use std::ptr; use std::vec::Vec; -use crate::system::UntypedHandle; +use system::UntypedHandle; /// Represents some count of bits. ///
diff --git a/mojo/public/rust/bindings/lib.rs b/mojo/public/rust/bindings/lib.rs new file mode 100644 index 0000000..d1fee52 --- /dev/null +++ b/mojo/public/rust/bindings/lib.rs
@@ -0,0 +1,19 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#![feature(int_roundings)] +// Require unsafe blocks for unsafe operations even in an unsafe fn. +#![deny(unsafe_op_in_unsafe_fn)] + +/// `pub` since a macro refers to `$crate::system`. +pub extern crate mojo_system as system; + +pub mod macros; + +pub mod decoding; +pub mod encoding; +pub mod message; +pub mod mojom; + +pub use system::util::run_loop;
diff --git a/mojo/public/rust/bindings/macros.rs b/mojo/public/rust/bindings/macros.rs index 3d66e02b..54223f11 100644 --- a/mojo/public/rust/bindings/macros.rs +++ b/mojo/public/rust/bindings/macros.rs
@@ -13,28 +13,25 @@ #[macro_export] macro_rules! impl_encodable_for_pointer { () => { - const MOJOM_TYPE: $crate::bindings::mojom::MojomType = - $crate::bindings::mojom::MojomType::Pointer; - fn embed_size( - _context: &$crate::bindings::encoding::Context, - ) -> $crate::bindings::encoding::Bits { - $crate::bindings::mojom::POINTER_BIT_SIZE + const MOJOM_TYPE: $crate::mojom::MojomType = $crate::mojom::MojomType::Pointer; + fn embed_size(_context: &$crate::encoding::Context) -> $crate::encoding::Bits { + $crate::mojom::POINTER_BIT_SIZE } fn encode( self, - encoder: &mut $crate::bindings::encoding::Encoder, - state: &mut $crate::bindings::encoding::EncodingState, - context: $crate::bindings::encoding::Context, + encoder: &mut $crate::encoding::Encoder, + state: &mut $crate::encoding::EncodingState, + context: $crate::encoding::Context, ) { state.encode_pointer(self.encode_new(encoder, context)); } fn decode( - decoder: &mut $crate::bindings::decoding::Decoder, - context: $crate::bindings::encoding::Context, + decoder: &mut $crate::decoding::Decoder, + context: $crate::encoding::Context, ) -> Result<Self, ValidationError> { let state = decoder.get_mut(&context); let ptr = state.decode_pointer()?; - if ptr == $crate::bindings::mojom::MOJOM_NULL_POINTER { + if ptr == $crate::mojom::MOJOM_NULL_POINTER { Err(ValidationError::UnexpectedNullPointer) } else { Self::decode_new(decoder, context, ptr) @@ -54,27 +51,24 @@ #[macro_export] macro_rules! impl_encodable_for_union { () => { - const MOJOM_TYPE: $crate::bindings::mojom::MojomType = - $crate::bindings::mojom::MojomType::Union; - fn embed_size( - context: &$crate::bindings::encoding::Context, - ) -> $crate::bindings::encoding::Bits { + const MOJOM_TYPE: $crate::mojom::MojomType = $crate::mojom::MojomType::Union; + fn embed_size(context: &$crate::encoding::Context) -> $crate::encoding::Bits { if context.is_union() { - $crate::bindings::mojom::UNION_NESTED_EMBED_SIZE + $crate::mojom::UNION_NESTED_EMBED_SIZE } else { - $crate::bindings::mojom::UNION_INLINE_EMBED_SIZE + $crate::mojom::UNION_INLINE_EMBED_SIZE } } fn encode( self, - encoder: &mut $crate::bindings::encoding::Encoder, - state: &mut $crate::bindings::encoding::EncodingState, - context: $crate::bindings::encoding::Context, + encoder: &mut $crate::encoding::Encoder, + state: &mut $crate::encoding::EncodingState, + context: $crate::encoding::Context, ) { if context.is_union() { - $crate::bindings::mojom::encode_union_nested(self, encoder, state, context); + $crate::mojom::encode_union_nested(self, encoder, state, context); } else { - $crate::bindings::mojom::encode_union_inline( + $crate::mojom::encode_union_inline( self, encoder, state, @@ -83,13 +77,13 @@ } } fn decode( - decoder: &mut $crate::bindings::decoding::Decoder, - context: $crate::bindings::encoding::Context, + decoder: &mut $crate::decoding::Decoder, + context: $crate::encoding::Context, ) -> Result<Self, ValidationError> { if context.is_union() { - $crate::bindings::mojom::decode_union_nested(decoder, context) + $crate::mojom::decode_union_nested(decoder, context) } else { - $crate::bindings::mojom::decode_union_inline(decoder, context.set_is_union(true)) + $crate::mojom::decode_union_inline(decoder, context.set_is_union(true)) } } }; @@ -106,22 +100,19 @@ #[macro_export] macro_rules! impl_encodable_for_interface { () => { - const MOJOM_TYPE: $crate::bindings::mojom::MojomType = - $crate::bindings::mojom::MojomType::Interface; - fn embed_size( - _context: &$crate::bindings::encoding::Context, - ) -> $crate::bindings::encoding::Bits { + const MOJOM_TYPE: $crate::mojom::MojomType = $crate::mojom::MojomType::Interface; + fn embed_size(_context: &$crate::encoding::Context) -> $crate::encoding::Bits { use std::mem; - $crate::bindings::encoding::Bits(2 * 8 * mem::size_of::<u32>()) + $crate::encoding::Bits(2 * 8 * mem::size_of::<u32>()) } - fn compute_size(&self, _context: $crate::bindings::encoding::Context) -> usize { + fn compute_size(&self, _context: $crate::encoding::Context) -> usize { 0 // Indicates that this type is inlined and it adds nothing external to the size } fn encode( self, - encoder: &mut $crate::bindings::encoding::Encoder, - state: &mut $crate::bindings::encoding::EncodingState, - context: $crate::bindings::encoding::Context, + encoder: &mut $crate::encoding::Encoder, + state: &mut $crate::encoding::EncodingState, + context: $crate::encoding::Context, ) { let version = self.version(); let pos = encoder.add_handle(self.as_untyped()); @@ -129,8 +120,8 @@ state.encode(version as u32); } fn decode( - decoder: &mut $crate::bindings::decoding::Decoder, - context: $crate::bindings::encoding::Context, + decoder: &mut $crate::decoding::Decoder, + context: $crate::encoding::Context, ) -> Result<Self, ValidationError> { let state = decoder.get_mut(&context); let handle_index: i32 = state.decode();
diff --git a/mojo/public/rust/bindings/message.rs b/mojo/public/rust/bindings/message.rs index d529fcb..ccf0c68 100644 --- a/mojo/public/rust/bindings/message.rs +++ b/mojo/public/rust/bindings/message.rs
@@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::bindings::decoding::{Decoder, ValidationError}; -use crate::bindings::encoding; -use crate::bindings::encoding::{ - Context, DataHeaderValue, Encoder, EncodingState, DATA_HEADER_SIZE, -}; -use crate::bindings::mojom::{MojomEncodable, MojomPointer, MojomStruct}; +use crate::decoding::{Decoder, ValidationError}; +use crate::encoding; +use crate::encoding::{Context, DataHeaderValue, Encoder, EncodingState, DATA_HEADER_SIZE}; +use crate::impl_encodable_for_pointer; +use crate::mojom::{MojomEncodable, MojomPointer, MojomStruct}; /// A flag for the message header indicating that no flag has been set. pub const MESSAGE_HEADER_NO_FLAG: u32 = 0;
diff --git a/mojo/public/rust/bindings/mod.rs b/mojo/public/rust/bindings/mod.rs deleted file mode 100644 index 9832c1b..0000000 --- a/mojo/public/rust/bindings/mod.rs +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2016 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#[macro_use] -mod macros; - -pub mod decoding; -pub mod encoding; -pub mod message; -pub mod mojom; -pub mod run_loop;
diff --git a/mojo/public/rust/bindings/mojom.rs b/mojo/public/rust/bindings/mojom.rs index 24a9e44b..495a567 100644 --- a/mojo/public/rust/bindings/mojom.rs +++ b/mojo/public/rust/bindings/mojom.rs
@@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::bindings::decoding::{Decoder, DecodingState, ValidationError}; -use crate::bindings::encoding; -use crate::bindings::encoding::{ +use crate::decoding::{Decoder, DecodingState, ValidationError}; +use crate::encoding; +use crate::encoding::{ Bits, Context, DataHeader, DataHeaderValue, Encoder, EncodingState, DATA_HEADER_SIZE, }; -use crate::bindings::message::MessageHeader; +use crate::impl_encodable_for_pointer; +use crate::message::MessageHeader; use std::cmp::Eq; use std::collections::HashMap; @@ -15,10 +16,10 @@ use std::mem; use std::vec::Vec; -use crate::system::data_pipe; -use crate::system::message_pipe; -use crate::system::shared_buffer; -use crate::system::{CastHandle, Handle, MojoResult, UntypedHandle}; +use system::data_pipe; +use system::message_pipe; +use system::shared_buffer; +use system::{CastHandle, Handle, MojoResult, UntypedHandle}; /// The size of a Mojom map plus header in bytes. const MAP_SIZE: usize = 24;
diff --git a/mojo/public/rust/lib.rs b/mojo/public/rust/lib.rs index 77094e53..b27b1a8 100644 --- a/mojo/public/rust/lib.rs +++ b/mojo/public/rust/lib.rs
@@ -2,46 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#![feature(int_roundings)] -#![feature(maybe_uninit_slice)] -#![feature(new_uninit)] -// Require unsafe blocks for unsafe operations even in an unsafe fn. -#![deny(unsafe_op_in_unsafe_fn)] +pub use mojo_bindings as bindings; +pub use mojo_system as system; -#[macro_use] -mod macros { - /// This macro must be used at the top-level in any - /// Rust Mojo application. It defines and abstracts away the - /// hook needed by Mojo in order to set up the basic - /// functionality (see mojo::system::ffi). It must take the - /// name of a function who returns a MojoResult and takes - /// exactly one argument: a mojo::handle::Handle, or on in - /// other words, an untyped handle. - #[macro_export] - macro_rules! set_mojo_main { - ( $fn_main:ident ) => { - #[allow(bad_style)] - #[no_mangle] - pub fn MojoMain(app_request_handle: mojo::system::MojoHandle) -> mojo::MojoResult { - use mojo::system::CastHandle; - use std::panic; - let handle = unsafe { - mojo::system::message_pipe::MessageEndpoint::from_untyped( - mojo::system::acquire(app_request_handle), - ) - }; - let result = panic::catch_unwind(|| $fn_main(handle)); - match result { - Ok(value) => value, - Err(_) => mojo::MojoResult::Aborted, - } - } - }; - } -} - -#[macro_use] -pub mod bindings; -pub mod system; - -pub use crate::system::MojoResult; +pub use system::MojoResult;
diff --git a/mojo/public/rust/system/core.rs b/mojo/public/rust/system/core.rs index dba1d09..b196043 100644 --- a/mojo/public/rust/system/core.rs +++ b/mojo/public/rust/system/core.rs
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::system::ffi; -use crate::system::mojo_types::MojoTimeTicks; +use crate::ffi; +use crate::mojo_types::MojoTimeTicks; /// Get the time ticks now according to the Mojo IPC. As /// can be seen in the documentation for the Mojo C API,
diff --git a/mojo/public/rust/system/data_pipe.rs b/mojo/public/rust/system/data_pipe.rs index 09ad04c..d897eed 100644 --- a/mojo/public/rust/system/data_pipe.rs +++ b/mojo/public/rust/system/data_pipe.rs
@@ -9,9 +9,9 @@ use std::slice; use std::vec; -use crate::system::ffi; -use crate::system::handle::{self, CastHandle, Handle, UntypedHandle}; -use crate::system::mojo_types::*; +use crate::ffi; +use crate::handle::{self, CastHandle, Handle, UntypedHandle}; +use crate::mojo_types::*; bitflags::bitflags! { #[derive(Default)] @@ -319,13 +319,13 @@ impl<T> CastHandle for Consumer<T> { /// Generates a Consumer from an untyped handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { Consumer::<T> { handle: handle, _elem_type: marker::PhantomData } } /// Consumes this object and produces a plain handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed fn as_untyped(self) -> handle::UntypedHandle { self.handle } @@ -334,7 +334,7 @@ impl<T> Handle for Consumer<T> { /// Returns the native handle wrapped by this structure. /// - /// See mojo::system::handle for information on handle wrappers + /// See crate::handle for information on handle wrappers fn get_native_handle(&self) -> MojoHandle { self.handle.get_native_handle() } @@ -394,13 +394,13 @@ impl<T> CastHandle for Producer<T> { /// Generates a Consumer from an untyped handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { Producer::<T> { handle: handle, _elem_type: marker::PhantomData } } /// Consumes this object and produces a plain handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed fn as_untyped(self) -> handle::UntypedHandle { self.handle } @@ -409,7 +409,7 @@ impl<T> Handle for Producer<T> { /// Returns the native handle wrapped by this structure. /// - /// See mojo::system::handle for information on handle wrappers + /// See crate::handle for information on handle wrappers fn get_native_handle(&self) -> MojoHandle { self.handle.get_native_handle() }
diff --git a/mojo/public/rust/system/ffi.rs b/mojo/public/rust/system/ffi.rs index e701c966..8704a0d 100644 --- a/mojo/public/rust/system/ffi.rs +++ b/mojo/public/rust/system/ffi.rs
@@ -61,7 +61,7 @@ pub type MojoResultCode = raw_ffi::MojoResult; } -use crate::system::ffi::types::*; +use crate::ffi::types::*; #[allow(non_camel_case_types)] pub type c_void = std::ffi::c_void;
diff --git a/mojo/public/rust/system/handle.rs b/mojo/public/rust/system/handle.rs index 8008a61..11a6712f 100644 --- a/mojo/public/rust/system/handle.rs +++ b/mojo/public/rust/system/handle.rs
@@ -13,12 +13,12 @@ //! data pipes, and shared buffers. Typed handles wrap untyped handles //! but act much the same as untyped handles. -use crate::system::ffi; -use crate::system::wait::*; +use crate::ffi; +use crate::wait::*; // This full import is intentional; nearly every type in mojo_types needs to be // used. -use crate::system::mojo_types::*; +use crate::mojo_types::*; /// The CastHandle trait defines an interface to convert between /// typed and untyped handles. These are only used internally for
diff --git a/mojo/public/rust/system/lib.rs b/mojo/public/rust/system/lib.rs new file mode 100644 index 0000000..fd107e22 --- /dev/null +++ b/mojo/public/rust/system/lib.rs
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#![feature(maybe_uninit_slice)] +// Require unsafe blocks for unsafe operations even in an unsafe fn. +#![deny(unsafe_op_in_unsafe_fn)] + +mod ffi; +mod handle; +mod mojo_types; + +pub mod core; +pub mod data_pipe; +pub mod message_pipe; +pub mod shared_buffer; +pub mod trap; +pub mod wait; +pub mod wait_set; + +/// Provides extra utilities that don't directly wrap Mojo APIs, but build on +/// top of them and may be generally useful. +pub mod util { + pub mod run_loop; +} + +// In order to keep the interface clean, we re-export basic Mojo and handle +// types and traits here in the system module. +pub use crate::handle::*; +pub use crate::mojo_types::*;
diff --git a/mojo/public/rust/system/message_pipe.rs b/mojo/public/rust/system/message_pipe.rs index 8e5a4ab0..48e597ad 100644 --- a/mojo/public/rust/system/message_pipe.rs +++ b/mojo/public/rust/system/message_pipe.rs
@@ -7,12 +7,12 @@ use std::convert::TryInto; -use crate::system::ffi; -use crate::system::handle; -use crate::system::handle::{CastHandle, Handle}; +use crate::ffi; +use crate::handle; +use crate::handle::{CastHandle, Handle}; // This full import is intentional; nearly every type in mojo_types needs to be // used. -use crate::system::mojo_types::*; +use crate::mojo_types::*; use ffi::c_void; @@ -239,13 +239,13 @@ impl CastHandle for MessageEndpoint { /// Generates a MessageEndpoint from an untyped handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { MessageEndpoint { handle: handle } } /// Consumes this object and produces a plain handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed fn as_untyped(self) -> handle::UntypedHandle { self.handle } @@ -254,7 +254,7 @@ impl Handle for MessageEndpoint { /// Returns the native handle wrapped by this structure. /// - /// See mojo::system::handle for information on handle wrappers + /// See crate::handle for information on handle wrappers fn get_native_handle(&self) -> MojoHandle { self.handle.get_native_handle() }
diff --git a/mojo/public/rust/system/mod.rs b/mojo/public/rust/system/mod.rs deleted file mode 100644 index 9934639..0000000 --- a/mojo/public/rust/system/mod.rs +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2016 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -mod ffi; -mod handle; -mod mojo_types; - -pub mod core; -pub mod data_pipe; -pub mod message_pipe; -pub mod shared_buffer; -pub mod trap; -pub mod wait; -pub mod wait_set; - -// In order to keep the interface clean, we re-export basic Mojo and handle -// types and traits here in the system module. -pub use crate::system::handle::*; -pub use crate::system::mojo_types::*;
diff --git a/mojo/public/rust/system/mojo_types.rs b/mojo/public/rust/system/mojo_types.rs index 8ee85338..d87532c8 100644 --- a/mojo/public/rust/system/mojo_types.rs +++ b/mojo/public/rust/system/mojo_types.rs
@@ -14,7 +14,7 @@ //! a whole because it is intended to be used that way. It contains //! all of the basic types needed by all system-level Mojo bindings. -use crate::system::ffi::types::{self, *}; +use crate::ffi::types::{self, *}; use std::fmt; use std::u64; @@ -26,7 +26,7 @@ pub type MojoDeadline = u64; pub static MOJO_INDEFINITE: MojoDeadline = u64::MAX; -pub use crate::system::wait_set::WaitSetResult; +pub use crate::wait_set::WaitSetResult; /// MojoResult represents anything that can happen /// as a result of performing some operation in Mojo.
diff --git a/mojo/public/rust/system/shared_buffer.rs b/mojo/public/rust/system/shared_buffer.rs index d0277f42..025b428 100644 --- a/mojo/public/rust/system/shared_buffer.rs +++ b/mojo/public/rust/system/shared_buffer.rs
@@ -5,12 +5,12 @@ use std::ptr; use std::slice; -use crate::system::ffi; +use crate::ffi; // This full import is intentional; nearly every type in mojo_types needs to be // used. -use crate::system::handle; -use crate::system::handle::{CastHandle, Handle}; -use crate::system::mojo_types::*; +use crate::handle; +use crate::handle::{CastHandle, Handle}; +use crate::mojo_types::*; use super::UntypedHandle; @@ -182,13 +182,13 @@ impl CastHandle for SharedBuffer { /// Generates a SharedBuffer from an untyped handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed unsafe fn from_untyped(handle: handle::UntypedHandle) -> Self { SharedBuffer { handle: handle } } /// Consumes this object and produces a plain handle wrapper - /// See mojo::system::handle for information on untyped vs. typed + /// See crate::handle for information on untyped vs. typed fn as_untyped(self) -> handle::UntypedHandle { self.handle } @@ -197,7 +197,7 @@ impl Handle for SharedBuffer { /// Returns the native handle wrapped by this structure. /// - /// See mojo::system::handle for information on handle wrappers + /// See crate::handle for information on handle wrappers fn get_native_handle(&self) -> MojoHandle { self.handle.get_native_handle() }
diff --git a/mojo/public/rust/system/trap.rs b/mojo/public/rust/system/trap.rs index e370b75..cfaa42c2 100644 --- a/mojo/public/rust/system/trap.rs +++ b/mojo/public/rust/system/trap.rs
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use crate::system::ffi::{self, raw_ffi, types::MojoTriggerCondition}; -use crate::system::handle::*; -use crate::system::mojo_types::*; +use crate::ffi::{self, raw_ffi, types::MojoTriggerCondition}; +use crate::handle::*; +use crate::mojo_types::*; use std::collections::HashMap; use std::convert::TryFrom;
diff --git a/mojo/public/rust/bindings/run_loop.rs b/mojo/public/rust/system/util/run_loop.rs similarity index 93% rename from mojo/public/rust/bindings/run_loop.rs rename to mojo/public/rust/system/util/run_loop.rs index b3c9ab1..ab64d0f 100644 --- a/mojo/public/rust/bindings/run_loop.rs +++ b/mojo/public/rust/system/util/run_loop.rs
@@ -19,6 +19,8 @@ //! another thread's run-loop, this is as-of-yet unsupported, and //! Rust should complain loudly when you try to do any threading here. +use crate::*; + use std::cell::RefCell; use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::collections::BinaryHeap; @@ -26,13 +28,8 @@ use std::i64; use std::vec::Vec; -use crate::system; -use crate::system::core; -use crate::system::wait_set; -use crate::system::{Handle, MojoResult, MOJO_INDEFINITE}; - /// Define the equivalent of MOJO_INDEFINITE for absolute deadlines -const MOJO_INDEFINITE_ABSOLUTE: system::MojoTimeTicks = 0; +const MOJO_INDEFINITE_ABSOLUTE: MojoTimeTicks = 0; // TODO(mknyszek): The numbers below are arbitrary and come from the C++ // bindings, and should probably be changed at some point @@ -89,7 +86,7 @@ /// The handle for which we are waiting. /// /// We keep this handle around so that we may easily re-register. - handle: system::MojoHandle, + handle: MojoHandle, /// The handler, boxed up. /// @@ -104,7 +101,7 @@ /// This is the most recently updated deadline that /// we should be watching out for. All others for this /// token may be considered "stale". - deadline: system::MojoTimeTicks, + deadline: MojoTimeTicks, } /// A wrapper struct for carrying the task as well as some information about @@ -118,7 +115,7 @@ /// This is the most recently updated deadline that /// we should be watching out for. All others for this /// token may be considered "stale". - deadline: system::MojoTimeTicks, + deadline: MojoTimeTicks, } impl<'t> TaskInfo<'t> { @@ -129,7 +126,7 @@ } /// Getter for the current absolute deadline held inside. - pub fn deadline(&self) -> system::MojoTimeTicks { + pub fn deadline(&self) -> MojoTimeTicks { self.deadline } } @@ -172,7 +169,7 @@ token: Token, /// An absolute deadline in terms of time ticks. - deadline: system::MojoTimeTicks, + deadline: MojoTimeTicks, } impl DeadlineInfo { @@ -182,7 +179,7 @@ } /// Getter for the absolute deadline inside. - pub fn deadline(&self) -> system::MojoTimeTicks { + pub fn deadline(&self) -> MojoTimeTicks { self.deadline } } @@ -218,16 +215,16 @@ /// Convert a mojo deadline (which is a relative deadline to "now") to /// an absolute deadline based on time ticks. -fn absolute_deadline(deadline: system::MojoDeadline) -> system::MojoTimeTicks { +fn absolute_deadline(deadline: MojoDeadline) -> MojoTimeTicks { if deadline == MOJO_INDEFINITE { return MOJO_INDEFINITE_ABSOLUTE; } let mut converted = MOJO_INDEFINITE_ABSOLUTE; - let max_time_ticks = i64::MAX as system::MojoDeadline; + let max_time_ticks = i64::MAX as MojoDeadline; if deadline <= max_time_ticks { let now = core::get_time_ticks_now(); if deadline <= (max_time_ticks - (now as u64)) { - converted = (deadline as system::MojoTimeTicks) + now + converted = (deadline as MojoTimeTicks) + now } } converted @@ -294,8 +291,8 @@ pub fn register<H>( &mut self, handle: &dyn Handle, - signals: system::HandleSignals, - deadline: system::MojoDeadline, + signals: HandleSignals, + deadline: MojoDeadline, handler: H, ) -> Token where @@ -326,8 +323,8 @@ pub fn reregister( &mut self, token: &Token, - signals: system::HandleSignals, - deadline: system::MojoDeadline, + signals: HandleSignals, + deadline: MojoDeadline, ) -> bool { match self.handlers.get_mut(&token) { Some(info) => { @@ -346,7 +343,7 @@ // It's perfectly okay for the handle to be invalid, so although this // is all unsafe, the whole system should just call the handler with an // error. - let mut dummy = unsafe { system::acquire(info.handle) }; + let mut dummy = unsafe { acquire(info.handle) }; let result = self.handle_set.add(&dummy, signals, token.to_cookie()); assert_eq!(result, MojoResult::Okay); dummy.invalidate(); @@ -376,7 +373,7 @@ /// Adds a task to be run by the runloop after some delay. /// /// Returns a token if the delay is valid, otherwise returns None. - pub fn post_task<F>(&mut self, task: F, delay: system::MojoTimeTicks) -> Result<(), ()> + pub fn post_task<F>(&mut self, task: F, delay: MojoTimeTicks) -> Result<(), ()> where F: FnOnce(&mut RunLoop) + 't, { @@ -393,7 +390,7 @@ /// /// Removes stale deadline entries as they are found, but /// does not otherwise modify the heap of deadlines. - fn get_next_deadline(&mut self) -> system::MojoTimeTicks { + fn get_next_deadline(&mut self) -> MojoTimeTicks { debug_assert!(!self.handlers.is_empty()); let top_task_deadline = match self.tasks.peek() { Some(info) => info.deadline(), @@ -421,7 +418,7 @@ /// owners of the results by calling their given callbacks. /// /// We do NOT dequeue notified handles. - fn notify_of_results(&mut self, results: &[system::WaitSetResult]) { + fn notify_of_results(&mut self, results: &[WaitSetResult]) { assert!(!self.handlers.is_empty()); for wait_set_result in results { let token = Token(wait_set_result.cookie.0); @@ -477,7 +474,7 @@ /// owners of the expiration by calling their given callbacks. /// /// We do NOT dequeue notified handles. - fn notify_of_expired(&mut self, expired_deadline: system::MojoTimeTicks) { + fn notify_of_expired(&mut self, expired_deadline: MojoTimeTicks) { assert!(!self.handlers.is_empty()); let mut top = match self.deadlines.peek() { Some(info) => info.clone(), @@ -554,7 +551,7 @@ /// handles this thread has registered. This method returns immediately as /// soon as any one handle has its signals satisfied, fails to ever have its /// signals satisfied, or reaches its deadline. - fn wait(&mut self, results_buffer: &mut Vec<system::WaitSetResult>) { + fn wait(&mut self, results_buffer: &mut Vec<WaitSetResult>) { assert!(!(self.handlers.is_empty() && self.tasks.is_empty())); self.execute_ready_tasks(); // If after executing a task we quit or there are no handles, @@ -610,8 +607,7 @@ } self.running = true; self.should_quit = false; - let mut buffer: Vec<system::WaitSetResult> = - Vec::with_capacity(INITIAL_WAIT_SET_NUM_RESULTS); + let mut buffer: Vec<WaitSetResult> = Vec::with_capacity(INITIAL_WAIT_SET_NUM_RESULTS); // Loop while we haven't been signaled to quit, and there's something to // run or wait on. while !self.should_quit && !(self.handlers.is_empty() && self.tasks.is_empty()) {
diff --git a/mojo/public/rust/system/wait.rs b/mojo/public/rust/system/wait.rs index c2fa45f4..e9a2215 100644 --- a/mojo/public/rust/system/wait.rs +++ b/mojo/public/rust/system/wait.rs
@@ -4,8 +4,8 @@ use std::sync::{Arc, Condvar, Mutex}; -use crate::system::mojo_types::{HandleSignals, MojoHandle, MojoResult, SignalsState}; -use crate::system::trap::{Trap, TrapEvent, TriggerCondition}; +use crate::mojo_types::{HandleSignals, MojoHandle, MojoResult, SignalsState}; +use crate::trap::{Trap, TrapEvent, TriggerCondition}; /// The result of `wait`ing on a handle. There are three possible outcomes: /// * A requested signal was satisfied
diff --git a/mojo/public/rust/system/wait_set.rs b/mojo/public/rust/system/wait_set.rs index a9e643a..1ae5691 100644 --- a/mojo/public/rust/system/wait_set.rs +++ b/mojo/public/rust/system/wait_set.rs
@@ -5,10 +5,10 @@ use std::collections::{hash_map, HashMap}; use std::sync::{Arc, Condvar, Mutex}; -use crate::system::handle::Handle; -use crate::system::mojo_types; -use crate::system::mojo_types::{MojoResult, SignalsState}; -use crate::system::trap::{Trap, TrapEvent, TriggerCondition, TriggerId}; +use crate::handle::Handle; +use crate::mojo_types; +use crate::mojo_types::{MojoResult, SignalsState}; +use crate::trap::{Trap, TrapEvent, TriggerCondition, TriggerId}; /// Identifies a handle added to `WaitSet`. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
diff --git a/mojo/public/rust/tests/BUILD.gn b/mojo/public/rust/tests/BUILD.gn new file mode 100644 index 0000000..a3ab4c3 --- /dev/null +++ b/mojo/public/rust/tests/BUILD.gn
@@ -0,0 +1,61 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/rust.gni") +import("//build/rust/rust_static_library.gni") +import("//build/rust/rust_unit_test.gni") +import("//build/rust/rust_unit_tests_group.gni") + +assert(can_build_rust_unit_tests) + +rust_unit_test("mojo_rust_system_tests") { + testonly = true + crate_root = "system/lib.rs" + sources = [ + "system/lib.rs", + "system/run_loop.rs", + ] + deps = [ + ":c_test_support", + ":test_util", + "//mojo/public/rust:mojo_rust", + "//third_party/rust/lazy_static/v1:test_support", + ] +} + +rust_unit_test("mojo_rust_integration_tests") { + testonly = true + crate_root = "integration/lib.rs" + sources = [ + "integration/encoding.rs", + "integration/integration.rs", + "integration/lib.rs", + "integration/mojom_validation.rs", + "integration/regression.rs", + "integration/validation.rs", + ] + deps = [ + ":c_test_support", + ":test_util", + "//mojo/public/rust:mojo_rust", + ] +} + +rust_static_library("test_util") { + testonly = true + crate_root = "util/lib.rs" + edition = "2021" + sources = [ "util/lib.rs" ] +} + +static_library("c_test_support") { + testonly = true + sources = [ "test_support.cc" ] + deps = [ + "//base", + "//mojo/core/embedder", + "//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils", + ] + visibility = [ ":*" ] +}
diff --git a/mojo/public/rust/tests/encoding.rs b/mojo/public/rust/tests/integration/encoding.rs similarity index 99% rename from mojo/public/rust/tests/encoding.rs rename to mojo/public/rust/tests/integration/encoding.rs index 497e132b..9b53a42d 100644 --- a/mojo/public/rust/tests/encoding.rs +++ b/mojo/public/rust/tests/integration/encoding.rs
@@ -8,6 +8,8 @@ //! and the result being caught in the test! macro. If a test function //! returns without panicking, it is assumed to pass. +use crate::mojom_validation::*; + use mojo::bindings::encoding::Context; use mojo::bindings::message::MessageHeader; use mojo::bindings::mojom::{MojomInterface, MojomPointer, MojomStruct}; @@ -17,9 +19,6 @@ use std::collections::HashMap; -use crate::util; -use crate::util::mojom_validation::*; - /// This macro is a wrapper for the tests! macro as it takes advantage of the /// shared code between tests. /// @@ -41,7 +40,7 @@ ($($name:ident { MessageHeader => $header_cls:expr, $req_type:ident => $cls:expr } )*) => { $( mojo_test!($name, { - let data = include_str!(concat!("../../interfaces/bindings/tests/data/validation/", + let data = include_str!(concat!("../../../interfaces/bindings/tests/data/validation/", stringify!($name), ".data")); match util::parse_validation_test(data) {
diff --git a/mojo/public/rust/tests/integration.rs b/mojo/public/rust/tests/integration/integration.rs similarity index 97% rename from mojo/public/rust/tests/integration.rs rename to mojo/public/rust/tests/integration/integration.rs index a934202..426364fc 100644 --- a/mojo/public/rust/tests/integration.rs +++ b/mojo/public/rust/tests/integration/integration.rs
@@ -8,14 +8,14 @@ //! and the result being caught in the test! macro. If a test function //! returns without panicking, it is assumed to pass. +use crate::mojom_validation::*; + use mojo::bindings::mojom::{MojomInterface, MojomInterfaceRecv, MojomInterfaceSend}; use mojo::system::message_pipe; use mojo::system::{Handle, HandleSignals}; use std::thread; -use crate::util::mojom_validation::*; - // Tests basic client and server interaction over a thread mojo_test!(send_and_recv, { let (endpt0, endpt1) = message_pipe::create().unwrap();
diff --git a/mojo/public/rust/tests/integration/lib.rs b/mojo/public/rust/tests/integration/lib.rs new file mode 100644 index 0000000..63346de --- /dev/null +++ b/mojo/public/rust/tests/integration/lib.rs
@@ -0,0 +1,12 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#[macro_use] +extern crate test_util as util; + +mod encoding; +mod integration; +mod mojom_validation; +mod regression; +mod validation;
diff --git a/mojo/public/rust/tests/util/mojom_validation.rs b/mojo/public/rust/tests/integration/mojom_validation.rs similarity index 99% rename from mojo/public/rust/tests/util/mojom_validation.rs rename to mojo/public/rust/tests/integration/mojom_validation.rs index 1ab28eac..e43b64bf5 100644 --- a/mojo/public/rust/tests/util/mojom_validation.rs +++ b/mojo/public/rust/tests/integration/mojom_validation.rs
@@ -8,23 +8,21 @@ #![allow(unused_variables)] #![allow(dead_code)] -use mojo::bindings::decoding; -use mojo::bindings::decoding::{Decoder, ValidationError}; -use mojo::bindings::encoding; +use mojo::bindings::decoding::{self, Decoder, ValidationError}; use mojo::bindings::encoding::{ - Context, DataHeaderValue, Encoder, EncodingState, DATA_HEADER_SIZE, + self, Context, DataHeaderValue, Encoder, EncodingState, DATA_HEADER_SIZE, }; -use mojo::bindings::message; -use mojo::bindings::message::MessageHeader; -use mojo::bindings::mojom; +use mojo::bindings::message::{self, MessageHeader}; use mojo::bindings::mojom::{ - MojomEncodable, MojomInterface, MojomInterfaceRecv, MojomInterfaceSend, MojomMessage, + self, MojomEncodable, MojomInterface, MojomInterfaceRecv, MojomInterfaceSend, MojomMessage, MojomMessageOption, MojomPointer, MojomStruct, MojomUnion, UNION_SIZE, }; -use mojo::system; -use mojo::system::message_pipe; -use mojo::system::{CastHandle, UntypedHandle}; +use mojo::bindings::{ + impl_encodable_for_interface, impl_encodable_for_pointer, impl_encodable_for_union, +}; + +use mojo::system::{self, message_pipe, CastHandle, UntypedHandle}; use std::collections::HashMap; use std::vec::Vec;
diff --git a/mojo/public/rust/tests/regression.rs b/mojo/public/rust/tests/integration/regression.rs similarity index 95% rename from mojo/public/rust/tests/regression.rs rename to mojo/public/rust/tests/integration/regression.rs index 8ddbd40..e9c6b5d 100644 --- a/mojo/public/rust/tests/regression.rs +++ b/mojo/public/rust/tests/integration/regression.rs
@@ -9,11 +9,10 @@ //! returns without panicking, it is assumed to pass. use mojo::bindings::decoding::{Decoder, ValidationError}; -use mojo::bindings::encoding; -use mojo::bindings::encoding::{Context, DataHeaderValue, Encoder, EncodingState}; +use mojo::bindings::encoding::{self, Context, DataHeaderValue, Encoder, EncodingState}; +use mojo::bindings::impl_encodable_for_pointer; use mojo::bindings::mojom::{MojomEncodable, MojomPointer, MojomStruct}; -use mojo::system; -use mojo::system::UntypedHandle; +use mojo::system::{self, UntypedHandle}; const STRUCT_A_VERSIONS: [(u32, u32); 1] = [(0, 16)];
diff --git a/mojo/public/rust/tests/validation.rs b/mojo/public/rust/tests/integration/validation.rs similarity index 96% rename from mojo/public/rust/tests/validation.rs rename to mojo/public/rust/tests/integration/validation.rs index 154fb43..0fa5ad3 100644 --- a/mojo/public/rust/tests/validation.rs +++ b/mojo/public/rust/tests/integration/validation.rs
@@ -8,12 +8,11 @@ //! and the result being caught in the test! macro. If a test function //! returns without panicking, it is assumed to pass. +use crate::mojom_validation::*; + use mojo::bindings::mojom::MojomMessageOption; use mojo::system; -use crate::util; -use crate::util::mojom_validation::*; - /// This macro is a wrapper for the tests! macro as it takes advantage of the /// shared code between tests. /// @@ -26,10 +25,10 @@ ($($name:ident => $req_type:ident;)*) => { $( mojo_test!($name, { - let data = include_str!(concat!("../../interfaces/bindings/tests/data/validation/", + let data = include_str!(concat!("../../../interfaces/bindings/tests/data/validation/", stringify!($name), ".data")); - let expected = include_str!(concat!("../../interfaces/bindings/tests/data/validation/", + let expected = include_str!(concat!("../../../interfaces/bindings/tests/data/validation/", stringify!($name), ".expected")).trim(); match util::parse_validation_test(data) {
diff --git a/mojo/public/rust/tests/lib.rs b/mojo/public/rust/tests/lib.rs deleted file mode 100644 index 63e016ff..0000000 --- a/mojo/public/rust/tests/lib.rs +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#![feature(assert_matches)] -#![feature(maybe_uninit_write_slice)] - -#[macro_use] -extern crate mojo; - -#[macro_use] -mod util; - -// These test suites work more or less. They still rely on some old Mojo -// behavior such as wait sets (see https://codereview.chromium.org/2744943002). -// These are temporarily replaced in support.cc. -mod integration; -mod run_loop; -mod system; - -// Has one broken test that panics during a panic. It's disabled for now. -mod regression; - -// These tests have two problems: -// * lots of test data from the Mojo SDK doesn't exist / has changed -// * the mojom encoding has changed since this code was written -// -// The code in crate/bindings/{encoding,decoding}.rs needs to be updated and -// the tests must be updated to use the available test data -// -mod encoding; -mod validation;
diff --git a/mojo/public/rust/tests/system.rs b/mojo/public/rust/tests/system/lib.rs similarity index 98% rename from mojo/public/rust/tests/system.rs rename to mojo/public/rust/tests/system/lib.rs index db680cb4..25f944cfc 100644 --- a/mojo/public/rust/tests/system.rs +++ b/mojo/public/rust/tests/system/lib.rs
@@ -1,4 +1,4 @@ -// Copyright 2016 The Chromium Authors +// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,14 @@ //! and the result being caught in the test! macro. If a test function //! returns without panicking, it is assumed to pass. +#![feature(assert_matches)] +#![feature(maybe_uninit_write_slice)] + +#[macro_use] +extern crate test_util as util; + +mod run_loop; + use mojo::system::data_pipe; use mojo::system::message_pipe; use mojo::system::shared_buffer::{self, SharedBuffer};
diff --git a/mojo/public/rust/tests/run_loop.rs b/mojo/public/rust/tests/system/run_loop.rs similarity index 100% rename from mojo/public/rust/tests/run_loop.rs rename to mojo/public/rust/tests/system/run_loop.rs
diff --git a/mojo/public/rust/test_support.cc b/mojo/public/rust/tests/test_support.cc similarity index 100% rename from mojo/public/rust/test_support.cc rename to mojo/public/rust/tests/test_support.cc
diff --git a/mojo/public/rust/tests/util/mod.rs b/mojo/public/rust/tests/util/lib.rs similarity index 97% rename from mojo/public/rust/tests/util/mod.rs rename to mojo/public/rust/tests/util/lib.rs index 161add8..ca4b72c 100644 --- a/mojo/public/rust/tests/util/mod.rs +++ b/mojo/public/rust/tests/util/lib.rs
@@ -4,8 +4,6 @@ //! This module contains useful functions and macros for testing. -pub mod mojom_validation; - use std::env; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -18,6 +16,7 @@ /// Note: this macro is quite delicate because of rustmt's inconsistent handling /// of macro invocations. Slight changes to macro syntax can make rustfmt ignore /// the inside of an invocation, which is not what we want. +#[macro_export] macro_rules! mojo_test { {$i: ident, $(#[$attr:meta])* $b:block} => { #[test] @@ -25,7 +24,7 @@ #[ $attr ] )* fn $i() { - $crate::util::init(); + $crate::init(); $b } }
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl index 5372abc..16520fef 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
@@ -64,8 +64,9 @@ return absl::nullopt; } {%- endif %} + return data_->{{has_value_pf.field.name}} - ? absl::make_optional(data_->{{value_pf.field.name}}) + ? absl::make_optional({{ "!!" if kind|is_bool_kind }}data_->{{value_pf.field.name}}) : absl::nullopt; }
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 0193b40..6bf0de1 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -408,6 +408,7 @@ "should_inline": ShouldInlineStruct, "should_inline_union": ShouldInlineUnion, "is_array_kind": mojom.IsArrayKind, + "is_bool_kind": mojom.IsBoolKind, "is_enum_kind": mojom.IsEnumKind, "is_nullable_value_kind_packed_field": pack.IsNullableValueKindPackedField,
diff --git a/net/base/network_anonymization_key.cc b/net/base/network_anonymization_key.cc index 0f5c5e61..d182b97 100644 --- a/net/base/network_anonymization_key.cc +++ b/net/base/network_anonymization_key.cc
@@ -35,7 +35,8 @@ NetworkAnonymizationKey NetworkAnonymizationKey::CreateFromNetworkIsolationKey( const net::NetworkIsolationKey& network_isolation_key) { // If NIK is double-keyed, a 2.5-keyed NAK cannot be constructed from it. - DCHECK(NetworkIsolationKey::IsFrameSiteEnabled()); + DCHECK_EQ(NetworkIsolationKey::GetMode(), + NetworkIsolationKey::Mode::kFrameSiteEnabled); // We cannot create a valid NetworkAnonymizationKey from a NetworkIsolationKey // that is not fully populated.
diff --git a/net/base/network_isolation_key.cc b/net/base/network_isolation_key.cc index 0fbd7e68..d74601b 100644 --- a/net/base/network_isolation_key.cc +++ b/net/base/network_isolation_key.cc
@@ -36,7 +36,7 @@ SchemefulSite&& frame_site, const base::UnguessableToken* nonce) : top_frame_site_(std::move(top_frame_site)), - frame_site_(IsFrameSiteEnabled() + frame_site_((GetMode() == Mode::kFrameSiteEnabled) ? absl::make_optional(std::move(frame_site)) : absl::nullopt), nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt) { @@ -82,9 +82,9 @@ if (IsTransient()) return absl::nullopt; - std::string frame_site_str = - " " + (IsFrameSiteEnabled() ? frame_site_->Serialize() - : top_frame_site_->Serialize()); + std::string frame_site_str = " " + ((GetMode() == Mode::kFrameSiteEnabled) + ? frame_site_->Serialize() + : top_frame_site_->Serialize()); return top_frame_site_->Serialize() + frame_site_str; } @@ -102,8 +102,13 @@ } bool NetworkIsolationKey::IsFullyPopulated() const { - return top_frame_site_.has_value() && - (!IsFrameSiteEnabled() || frame_site_.has_value()); + if (!top_frame_site_.has_value()) { + return false; + } + if (GetMode() == Mode::kFrameSiteEnabled && !frame_site_.has_value()) { + return false; + } + return true; } bool NetworkIsolationKey::IsTransient() const { @@ -112,9 +117,16 @@ return IsOpaque(); } +// static +NetworkIsolationKey::Mode NetworkIsolationKey::GetMode() { + // NIKs are currently always triple-keyed, but we will experiment with + // 2.5-keying in crbug.com/1414808. + return Mode::kFrameSiteEnabled; +} + const absl::optional<SchemefulSite>& NetworkIsolationKey::GetFrameSite() const { // Frame site will be empty if double-keying is enabled. - CHECK(NetworkIsolationKey::IsFrameSiteEnabled()); + CHECK(GetMode() == Mode::kFrameSiteEnabled); return frame_site_; } @@ -122,15 +134,10 @@ return !top_frame_site_.has_value() && !frame_site_.has_value(); } -bool NetworkIsolationKey::IsFrameSiteEnabled() { - // NIKs are currently always triple-keyed, but we will experiment with - // 2.5-keying in crbug.com/1414808. - return true; -} - bool NetworkIsolationKey::IsOpaque() const { return top_frame_site_->opaque() || - (IsFrameSiteEnabled() && frame_site_->opaque()) || nonce_.has_value(); + (GetMode() == Mode::kFrameSiteEnabled && frame_site_->opaque()) || + nonce_.has_value(); } } // namespace net
diff --git a/net/base/network_isolation_key.h b/net/base/network_isolation_key.h index 647ae89..c506084 100644 --- a/net/base/network_isolation_key.h +++ b/net/base/network_isolation_key.h
@@ -119,7 +119,21 @@ return top_frame_site_; } - // Note: This will CHECK if `IsFrameSiteEnabled()` returns false. + enum class Mode { + // This scheme indicates that "triple-key" NetworkIsolationKeys are used to + // partition the HTTP cache. This key will have the following properties: + // `top_frame_site` -> the schemeful site of the top level page. + // `frame_site ` -> the schemeful site of the frame. + // `is_cross_site` -> absl::nullopt. + kFrameSiteEnabled, + // TODO(awillia): Add `kIsCrossSiteEnabled` here to experiment with + // 2.5-keying. + }; + + // Returns the cache key scheme currently in use. + static Mode GetMode(); + + // Note: This will CHECK if `GetScheme()` does not return `kFrameSiteEnabled`. const absl::optional<SchemefulSite>& GetFrameSite() const; // Do not use outside of testing. Returns the `frame_site_`. @@ -152,10 +166,6 @@ // Returns true if all parts of the key are empty. bool IsEmpty() const; - // Returns true if the NetworkIsolationKey has a triple keyed scheme. This - // means both `frame_site_` and `top_frame_site_` will be used. - static bool IsFrameSiteEnabled(); - private: // Whether this key has opaque origins or a nonce. bool IsOpaque() const;
diff --git a/net/base/network_isolation_key_unittest.cc b/net/base/network_isolation_key_unittest.cc index 0015b95..c9f2fce3 100644 --- a/net/base/network_isolation_key_unittest.cc +++ b/net/base/network_isolation_key_unittest.cc
@@ -18,8 +18,9 @@ namespace { const char kDataUrl[] = "data:text/html,<body>Hello World</body>"; -TEST(NetworkIsolationKeyTest, IsFrameSiteEnabled) { - EXPECT_TRUE(NetworkIsolationKey::IsFrameSiteEnabled()); +TEST(NetworkIsolationKeyTest, GetMode) { + EXPECT_EQ(NetworkIsolationKey::GetMode(), + NetworkIsolationKey::Mode::kFrameSiteEnabled); } TEST(NetworkIsolationKeyTest, EmptyKey) {
diff --git a/services/device/generic_sensor/platform_sensor_accelerometer_mac.cc b/services/device/generic_sensor/platform_sensor_accelerometer_mac.cc index f85f59b..55871b2 100644 --- a/services/device/generic_sensor/platform_sensor_accelerometer_mac.cc +++ b/services/device/generic_sensor/platform_sensor_accelerometer_mac.cc
@@ -42,14 +42,14 @@ // operations. class PlatformSensorAccelerometerMac::BlockingTaskRunnerHelper final { public: - explicit BlockingTaskRunnerHelper( - base::WeakPtr<PlatformSensorAccelerometerMac> platform_sensor); + BlockingTaskRunnerHelper( + base::WeakPtr<PlatformSensorAccelerometerMac> platform_sensor, + scoped_refptr<base::SequencedTaskRunner> task_runner); ~BlockingTaskRunnerHelper(); BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete; BlockingTaskRunnerHelper& operator=(const BlockingTaskRunnerHelper&) = delete; - void Init(); void StartPolling(double frequency); void StopPolling(); @@ -77,28 +77,17 @@ PlatformSensorAccelerometerMac::BlockingTaskRunnerHelper:: BlockingTaskRunnerHelper( - base::WeakPtr<PlatformSensorAccelerometerMac> platform_sensor) + base::WeakPtr<PlatformSensorAccelerometerMac> platform_sensor, + scoped_refptr<base::SequencedTaskRunner> task_runner) : platform_sensor_(platform_sensor), - owner_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) { - // Detaches from the sequence on which this object was created. It will be - // bound to another sequence when Init() is called. - DETACH_FROM_SEQUENCE(sequence_checker_); -} + owner_task_runner_(std::move(task_runner)), + sudden_motion_sensor_(SuddenMotionSensor::Create()) {} PlatformSensorAccelerometerMac::BlockingTaskRunnerHelper:: ~BlockingTaskRunnerHelper() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -void PlatformSensorAccelerometerMac::BlockingTaskRunnerHelper::Init() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (sudden_motion_sensor_) - return; - - sudden_motion_sensor_.reset(SuddenMotionSensor::Create()); -} - void PlatformSensorAccelerometerMac::BlockingTaskRunnerHelper::StartPolling( double frequency) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -143,19 +132,13 @@ PlatformSensorAccelerometerMac::PlatformSensorAccelerometerMac( SensorReadingSharedBuffer* reading_buffer, PlatformSensorProvider* provider) - : PlatformSensor(SensorType::ACCELEROMETER, reading_buffer, provider), - blocking_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( + : PlatformSensor(SensorType::ACCELEROMETER, reading_buffer, provider) { + blocking_task_helper_ = base::SequenceBound<BlockingTaskRunnerHelper>( + base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::USER_VISIBLE, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})), - blocking_task_helper_(nullptr, - base::OnTaskRunnerDeleter(blocking_task_runner_)) { - // We need to properly initialize |blocking_task_helper_| here because we need - // |weak_factory_| to be created first. - blocking_task_helper_.reset( - new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr())); - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Init, - base::Unretained(blocking_task_helper_.get()))); + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}), + weak_factory_.GetWeakPtr(), + base::SequencedTaskRunner::GetCurrentDefault()); } PlatformSensorAccelerometerMac::~PlatformSensorAccelerometerMac() = default; @@ -182,18 +165,14 @@ if (is_reading_active_) StopSensor(); is_reading_active_ = true; - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StartPolling, - base::Unretained(blocking_task_helper_.get()), - configuration.frequency())); + blocking_task_helper_.AsyncCall(&BlockingTaskRunnerHelper::StartPolling) + .WithArgs(configuration.frequency()); return true; } void PlatformSensorAccelerometerMac::StopSensor() { is_reading_active_ = false; - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StopPolling, - base::Unretained(blocking_task_helper_.get()))); + blocking_task_helper_.AsyncCall(&BlockingTaskRunnerHelper::StopPolling); } void PlatformSensorAccelerometerMac::OnReadingAvailable(SensorReading reading) {
diff --git a/services/device/generic_sensor/platform_sensor_accelerometer_mac.h b/services/device/generic_sensor/platform_sensor_accelerometer_mac.h index baa967d..6fadaf5 100644 --- a/services/device/generic_sensor/platform_sensor_accelerometer_mac.h +++ b/services/device/generic_sensor/platform_sensor_accelerometer_mac.h
@@ -5,10 +5,8 @@ #ifndef SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_ACCELEROMETER_MAC_H_ #define SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_ACCELEROMETER_MAC_H_ -#include <memory> - #include "base/memory/weak_ptr.h" -#include "base/task/sequenced_task_runner.h" +#include "base/threading/sequence_bound.h" #include "base/timer/timer.h" #include "services/device/generic_sensor/platform_sensor.h" #include "services/device/public/cpp/generic_sensor/sensor_reading.h" @@ -48,9 +46,7 @@ void OnReadingAvailable(SensorReading reading); - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; - std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter> - blocking_task_helper_; + base::SequenceBound<BlockingTaskRunnerHelper> blocking_task_helper_; SensorReading reading_;
diff --git a/services/device/generic_sensor/platform_sensor_reader_linux.cc b/services/device/generic_sensor/platform_sensor_reader_linux.cc index 52873317..b0b9a044 100644 --- a/services/device/generic_sensor/platform_sensor_reader_linux.cc +++ b/services/device/generic_sensor/platform_sensor_reader_linux.cc
@@ -13,6 +13,7 @@ #include "base/strings/string_util.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" +#include "base/threading/sequence_bound.h" #include "base/timer/timer.h" #include "services/device/generic_sensor/linux/sensor_data_linux.h" #include "services/device/generic_sensor/platform_sensor_linux.h" @@ -43,6 +44,7 @@ public: BlockingTaskRunnerHelper( base::WeakPtr<PollingSensorReader> polling_sensor_reader, + scoped_refptr<base::SequencedTaskRunner> task_runner, const SensorInfoLinux& sensor_info); BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete; @@ -91,27 +93,18 @@ // called on the right thread. SEQUENCE_CHECKER(sequence_checker_); - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_ = - base::ThreadPool::CreateSequencedTaskRunner( - {base::MayBlock(), base::TaskPriority::USER_VISIBLE, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}); - - std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter> - blocking_task_helper_; + base::SequenceBound<BlockingTaskRunnerHelper> blocking_task_helper_; base::WeakPtrFactory<PollingSensorReader> weak_factory_{this}; }; PollingSensorReader::BlockingTaskRunnerHelper::BlockingTaskRunnerHelper( base::WeakPtr<PollingSensorReader> polling_sensor_reader, + scoped_refptr<base::SequencedTaskRunner> task_runner, const SensorInfoLinux& sensor_info) : polling_sensor_reader_(polling_sensor_reader), - owner_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()), - sensor_info_(sensor_info) { - // Detaches from the sequence on which this object was created. It will be - // bound to its owning sequence when StartPolling() is called. - DETACH_FROM_SEQUENCE(sequence_checker_); -} + owner_task_runner_(std::move(task_runner)), + sensor_info_(sensor_info) {} PollingSensorReader::BlockingTaskRunnerHelper::~BlockingTaskRunnerHelper() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -177,13 +170,13 @@ PollingSensorReader::PollingSensorReader( const SensorInfoLinux& sensor_info, base::WeakPtr<PlatformSensorLinux> sensor) - : SensorReader(sensor), - blocking_task_helper_(nullptr, - base::OnTaskRunnerDeleter(blocking_task_runner_)) { - // We need to properly initialize |blocking_task_helper_| here because we need - // |weak_factory_| to be created first. - blocking_task_helper_.reset( - new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr(), sensor_info)); + : SensorReader(sensor) { + blocking_task_helper_ = base::SequenceBound<BlockingTaskRunnerHelper>( + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}), + weak_factory_.GetWeakPtr(), + base::SequencedTaskRunner::GetCurrentDefault(), sensor_info); } PollingSensorReader::~PollingSensorReader() { @@ -196,18 +189,14 @@ if (is_reading_active_) StopFetchingData(); is_reading_active_ = true; - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StartPolling, - base::Unretained(blocking_task_helper_.get()), - configuration.frequency())); + blocking_task_helper_.AsyncCall(&BlockingTaskRunnerHelper::StartPolling) + .WithArgs(configuration.frequency()); } void PollingSensorReader::StopFetchingData() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); is_reading_active_ = false; - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::StopPolling, - base::Unretained(blocking_task_helper_.get()))); + blocking_task_helper_.AsyncCall(&BlockingTaskRunnerHelper::StopPolling); } void PollingSensorReader::OnReadingAvailable(SensorReading reading) {
diff --git a/services/device/hid/hid_connection_linux.cc b/services/device/hid/hid_connection_linux.cc index 1947e28..9b68928 100644 --- a/services/device/hid/hid_connection_linux.cc +++ b/services/device/hid/hid_connection_linux.cc
@@ -10,6 +10,7 @@ #include <memory> #include <string> +#include <tuple> #include <utility> #include "base/files/file_descriptor_watcher_posix.h" @@ -35,14 +36,21 @@ public: BlockingTaskRunnerHelper(base::ScopedFD fd, scoped_refptr<HidDeviceInfo> device_info, - base::WeakPtr<HidConnectionLinux> connection) + base::WeakPtr<HidConnectionLinux> connection, + scoped_refptr<base::SequencedTaskRunner> task_runner) : fd_(std::move(fd)), connection_(connection), - origin_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) { - DETACH_FROM_SEQUENCE(sequence_checker_); + origin_task_runner_(std::move(task_runner)) { // Report buffers must always have room for the report ID. report_buffer_size_ = device_info->max_input_report_size() + 1; has_report_id_ = device_info->has_report_id(); + + // Starts the FileDescriptorWatcher that reads input events from the device. + // Must be called on a thread that has a base::MessageLoopForIO. + file_watcher_ = base::FileDescriptorWatcher::WatchReadable( + fd_.get(), base::BindRepeating( + &BlockingTaskRunnerHelper::OnFileCanReadWithoutBlocking, + base::Unretained(this))); } BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete; @@ -52,19 +60,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - // Starts the FileDescriptorWatcher that reads input events from the device. - // Must be called on a thread that has a base::MessageLoopForIO. - void Start() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - file_watcher_ = base::FileDescriptorWatcher::WatchReadable( - fd_.get(), base::BindRepeating( - &BlockingTaskRunnerHelper::OnFileCanReadWithoutBlocking, - base::Unretained(this))); - } - - void Write(scoped_refptr<base::RefCountedBytes> buffer, - WriteCallback callback) { + bool Write(scoped_refptr<base::RefCountedBytes> buffer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); @@ -73,21 +69,19 @@ HANDLE_EINTR(write(fd_.get(), buffer->front(), buffer->size())); if (result < 0) { HID_PLOG(EVENT) << "Write failed"; - origin_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), false)); + return false; } else { if (static_cast<size_t>(result) != buffer->size()) { HID_LOG(EVENT) << "Incomplete HID write: " << result << " != " << buffer->size(); } - origin_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), true)); + return true; } } - void GetFeatureReport(uint8_t report_id, - scoped_refptr<base::RefCountedBytes> buffer, - ReadCallback callback) { + std::tuple<bool, scoped_refptr<base::RefCountedBytes>, int> GetFeatureReport( + uint8_t report_id, + scoped_refptr<base::RefCountedBytes> buffer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); @@ -96,28 +90,22 @@ ioctl(fd_.get(), HIDIOCGFEATURE(buffer->size()), buffer->front())); if (result < 0) { HID_PLOG(EVENT) << "Failed to get feature report"; - origin_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), false, nullptr, 0)); + return std::make_tuple(false, nullptr, 0); } else if (result == 0) { HID_LOG(EVENT) << "Get feature result too short."; - origin_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), false, nullptr, 0)); + return std::make_tuple(false, nullptr, 0); } else if (report_id == 0) { // Linux adds a 0 to the beginning of the data received from the device. auto copied_buffer = base::MakeRefCounted<base::RefCountedBytes>(result - 1); memcpy(copied_buffer->front(), buffer->front() + 1, result - 1); - origin_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), true, copied_buffer, result - 1)); + return std::make_tuple(true, std::move(copied_buffer), result - 1); } else { - origin_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true, buffer, result)); + return std::make_tuple(true, std::move(buffer), result); } } - void SendFeatureReport(scoped_refptr<base::RefCountedBytes> buffer, - WriteCallback callback) { + bool SendFeatureReport(scoped_refptr<base::RefCountedBytes> buffer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); @@ -126,11 +114,9 @@ ioctl(fd_.get(), HIDIOCSFEATURE(buffer->size()), buffer->front())); if (result < 0) { HID_PLOG(EVENT) << "Failed to send feature report"; - origin_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), false)); + return false; } else { - origin_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), true)); + return true; } } @@ -187,14 +173,11 @@ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, bool allow_protected_reports, bool allow_fido_reports) - : HidConnection(device_info, allow_protected_reports, allow_fido_reports), - helper_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner)), - blocking_task_runner_(std::move(blocking_task_runner)) { - helper_.reset(new BlockingTaskRunnerHelper(std::move(fd), device_info, - weak_factory_.GetWeakPtr())); - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start, - base::Unretained(helper_.get()))); + : HidConnection(device_info, allow_protected_reports, allow_fido_reports) { + helper_ = base::SequenceBound<BlockingTaskRunnerHelper>( + std::move(blocking_task_runner), std::move(fd), device_info, + weak_factory_.GetWeakPtr(), + base::SequencedTaskRunner::GetCurrentDefault()); } HidConnectionLinux::~HidConnectionLinux() {} @@ -204,7 +187,7 @@ // base::ScopedFD is destroyed on a thread where I/O is allowed is satisfied // and 2) any tasks posted to this task runner that refer to this file will // complete before it is closed. - helper_.reset(); + helper_.Reset(); } void HidConnectionLinux::PlatformWrite( @@ -212,10 +195,9 @@ WriteCallback callback) { // Linux expects the first byte of the buffer to always be a report ID so the // buffer can be used directly. - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Write, - base::Unretained(helper_.get()), buffer, - std::move(callback))); + helper_.AsyncCall(&BlockingTaskRunnerHelper::Write) + .WithArgs(std::move(buffer)) + .Then(std::move(callback)); } void HidConnectionLinux::PlatformGetFeatureReport(uint8_t report_id, @@ -227,10 +209,16 @@ device_info()->max_feature_report_size() + 1); buffer->data()[0] = report_id; - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::GetFeatureReport, - base::Unretained(helper_.get()), report_id, - buffer, std::move(callback))); + auto callback_wrapper = base::BindOnce( + [](ReadCallback callback, + std::tuple<bool, scoped_refptr<base::RefCountedBytes>, int> result) { + std::move(callback).Run(get<0>(result), get<1>(result), get<2>(result)); + }, + std::move(callback)); + + helper_.AsyncCall(&BlockingTaskRunnerHelper::GetFeatureReport) + .WithArgs(report_id, std::move(buffer)) + .Then(std::move(callback_wrapper)); } void HidConnectionLinux::PlatformSendFeatureReport( @@ -238,10 +226,9 @@ WriteCallback callback) { // Linux expects the first byte of the buffer to always be a report ID so the // buffer can be used directly. - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::SendFeatureReport, - base::Unretained(helper_.get()), buffer, - std::move(callback))); + helper_.AsyncCall(&BlockingTaskRunnerHelper::SendFeatureReport) + .WithArgs(std::move(buffer)) + .Then(std::move(callback)); } } // namespace device
diff --git a/services/device/hid/hid_connection_linux.h b/services/device/hid/hid_connection_linux.h index cab8d31..e0c5fea5 100644 --- a/services/device/hid/hid_connection_linux.h +++ b/services/device/hid/hid_connection_linux.h
@@ -10,7 +10,7 @@ #include "base/files/scoped_file.h" #include "base/memory/weak_ptr.h" -#include "base/task/sequenced_task_runner.h" +#include "base/threading/sequence_bound.h" #include "services/device/hid/hid_connection.h" namespace base { @@ -45,12 +45,7 @@ void PlatformSendFeatureReport(scoped_refptr<base::RefCountedBytes> buffer, WriteCallback callback) override; - // |helper_| lives on the sequence to which |blocking_task_runner_| posts - // tasks so all calls must be posted there including this object's - // destruction. - std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter> helper_; - - const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; + base::SequenceBound<BlockingTaskRunnerHelper> helper_; base::WeakPtrFactory<HidConnectionLinux> weak_factory_{this}; };
diff --git a/services/device/hid/hid_service_linux.cc b/services/device/hid/hid_service_linux.cc index b58223d..30ffb7e 100644 --- a/services/device/hid/hid_service_linux.cc +++ b/services/device/hid/hid_service_linux.cc
@@ -213,10 +213,14 @@ class HidServiceLinux::BlockingTaskRunnerHelper : public UdevWatcher::Observer { public: - BlockingTaskRunnerHelper(base::WeakPtr<HidServiceLinux> service) - : service_(std::move(service)), - task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) { - DETACH_FROM_SEQUENCE(sequence_checker_); + BlockingTaskRunnerHelper(base::WeakPtr<HidServiceLinux> service, + scoped_refptr<base::SequencedTaskRunner> task_runner) + : service_(std::move(service)), task_runner_(std::move(task_runner)) { + watcher_ = UdevWatcher::StartWatching(this); + watcher_->EnumerateExistingDevices(); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&HidServiceLinux::FirstEnumerationComplete, service_)); } BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete; @@ -226,16 +230,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - void Start() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - watcher_ = UdevWatcher::StartWatching(this); - watcher_->EnumerateExistingDevices(); - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&HidServiceLinux::FirstEnumerationComplete, service_)); - } - private: // UdevWatcher::Observer void OnDeviceAdded(ScopedUdevDevicePtr device) override { @@ -350,16 +344,11 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; }; -HidServiceLinux::HidServiceLinux() - : blocking_task_runner_( - base::ThreadPool::CreateSequencedTaskRunner(kBlockingTaskTraits)), - helper_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)) { - // We need to properly initialize |blocking_task_helper_| here because we need - // |weak_factory_| to be created first. - helper_.reset(new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr())); - blocking_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::Start, - base::Unretained(helper_.get()))); +HidServiceLinux::HidServiceLinux() { + helper_ = base::SequenceBound<BlockingTaskRunnerHelper>( + base::ThreadPool::CreateSequencedTaskRunner(kBlockingTaskTraits), + weak_factory_.GetWeakPtr(), + base::SequencedTaskRunner::GetCurrentDefault()); } HidServiceLinux::~HidServiceLinux() = default;
diff --git a/services/device/hid/hid_service_linux.h b/services/device/hid/hid_service_linux.h index 91e40ed..c5e60c5 100644 --- a/services/device/hid/hid_service_linux.h +++ b/services/device/hid/hid_service_linux.h
@@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "base/files/scoped_file.h" #include "base/memory/weak_ptr.h" -#include "base/task/sequenced_task_runner.h" +#include "base/threading/sequence_bound.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "services/device/hid/hid_device_info.h" @@ -52,11 +52,8 @@ #endif static void FinishOpen(std::unique_ptr<ConnectParams> params); - const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; + base::SequenceBound<BlockingTaskRunnerHelper> helper_; - // |helper_| lives on the sequence |blocking_task_runner_| posts to and holds - // a weak reference back to the service that owns it. - std::unique_ptr<BlockingTaskRunnerHelper, base::OnTaskRunnerDeleter> helper_; base::WeakPtrFactory<HidServiceLinux> weak_factory_{this}; };
diff --git a/services/device/serial/serial_device_enumerator_win.cc b/services/device/serial/serial_device_enumerator_win.cc index 1f8a3871..9a08e84 100644 --- a/services/device/serial/serial_device_enumerator_win.cc +++ b/services/device/serial/serial_device_enumerator_win.cc
@@ -150,9 +150,16 @@ class SerialDeviceEnumeratorWin::UiThreadHelper : public DeviceMonitorWin::Observer { public: - UiThreadHelper() - : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) { - DETACH_FROM_SEQUENCE(sequence_checker_); + UiThreadHelper(base::WeakPtr<SerialDeviceEnumeratorWin> enumerator, + scoped_refptr<base::SequencedTaskRunner> task_runner) + : enumerator_(std::move(enumerator)), + task_runner_(std::move(task_runner)) { + // Note that this uses GUID_DEVINTERFACE_COMPORT even though we use + // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR for enumeration because it + // doesn't seem to make a difference and ports which aren't enumerable by + // device interface don't generate WM_DEVICECHANGE events. + device_observation_.Observe( + DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_COMPORT)); } // Disallow copy and assignment. @@ -163,17 +170,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } - void Initialize(base::WeakPtr<SerialDeviceEnumeratorWin> enumerator) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - enumerator_ = std::move(enumerator); - // Note that this uses GUID_DEVINTERFACE_COMPORT even though we use - // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR for enumeration because it - // doesn't seem to make a difference and ports which aren't enumerable by - // device interface don't generate WM_DEVICECHANGE events. - device_observation_.Observe( - DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_COMPORT)); - } - void OnDeviceAdded(const GUID& class_guid, const std::wstring& device_path) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -203,14 +199,10 @@ }; SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) - : helper_(new UiThreadHelper(), base::OnTaskRunnerDeleter(ui_task_runner)) { - // Passing a raw pointer to |helper_| is safe here because this task will - // reach the UI thread before any task to delete |helper_|. - ui_task_runner->PostTask(FROM_HERE, - base::BindOnce(&UiThreadHelper::Initialize, - base::Unretained(helper_.get()), - weak_factory_.GetWeakPtr())); + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { + helper_ = base::SequenceBound<UiThreadHelper>( + std::move(ui_task_runner), weak_factory_.GetWeakPtr(), + base::SequencedTaskRunner::GetCurrentDefault()); DoInitialEnumeration(); }
diff --git a/services/device/serial/serial_device_enumerator_win.h b/services/device/serial/serial_device_enumerator_win.h index 3499e16..c387aef 100644 --- a/services/device/serial/serial_device_enumerator_win.h +++ b/services/device/serial/serial_device_enumerator_win.h
@@ -6,6 +6,7 @@ #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_ #include "base/task/single_thread_task_runner.h" +#include "base/threading/sequence_bound.h" #include "base/win/windows_types.h" #include "device/base/device_monitor_win.h" #include "services/device/serial/serial_device_enumerator.h" @@ -40,7 +41,7 @@ std::map<base::FilePath, base::UnguessableToken> paths_; - std::unique_ptr<UiThreadHelper, base::OnTaskRunnerDeleter> helper_; + base::SequenceBound<UiThreadHelper> helper_; base::WeakPtrFactory<SerialDeviceEnumeratorWin> weak_factory_{this}; };
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom index 8b6f799..ec57ac27 100644 --- a/services/media_session/public/mojom/media_session.mojom +++ b/services/media_session/public/mojom/media_session.mojom
@@ -132,14 +132,13 @@ [Stable] struct RemotePlaybackMetadata { - string video_codec; - string audio_codec; - bool remote_playback_disabled; - [MinVersion=17] bool remote_playback_started; - // TODO(crbug.com/1420103): `remoting_device_friendly_name` is no longer - // needed, to be removed. - [MinVersion=17] string? remoting_device_friendly_name; - [MinVersion=18] bool is_encrypted_media; + string video_codec@0; + string audio_codec@1; + bool remote_playback_disabled@2; + [MinVersion=17] bool remote_playback_started@3; + // Deprecated, was remoting_device_friendly_name + [MinVersion=17] string? unused_field@4; + [MinVersion=18] bool is_encrypted_media@5; }; // Contains state information about a MediaSession.
diff --git a/services/network/public/cpp/network_isolation_key_mojom_traits.cc b/services/network/public/cpp/network_isolation_key_mojom_traits.cc index 2993c45..dc994c8 100644 --- a/services/network/public/cpp/network_isolation_key_mojom_traits.cc +++ b/services/network/public/cpp/network_isolation_key_mojom_traits.cc
@@ -21,9 +21,12 @@ } // A key is either fully empty or fully populated. - if (net::NetworkIsolationKey::IsFrameSiteEnabled() && - (top_frame_site.has_value() != frame_site.has_value())) { - return false; + switch (net::NetworkIsolationKey::GetMode()) { + case net::NetworkIsolationKey::Mode::kFrameSiteEnabled: + if (top_frame_site.has_value() != frame_site.has_value()) { + return false; + } + break; } absl::optional<base::UnguessableToken> nonce; @@ -36,12 +39,9 @@ return false; *out = net::NetworkIsolationKey(); } else { - *out = - net::NetworkIsolationKey(std::move(top_frame_site.value()), - net::NetworkIsolationKey::IsFrameSiteEnabled() - ? std::move(frame_site.value()) - : net::SchemefulSite(), - nonce ? &nonce.value() : nullptr); + *out = net::NetworkIsolationKey(std::move(top_frame_site.value()), + std::move(frame_site.value()), + nonce ? &nonce.value() : nullptr); } return true;
diff --git a/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc b/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc index 7d81fb46..573aae7e8 100644 --- a/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc +++ b/services/network/public/cpp/network_isolation_key_mojom_traits_unittest.cc
@@ -38,7 +38,8 @@ network::mojom::NetworkIsolationKey>(original, copied)); EXPECT_EQ(original, copied); EXPECT_EQ(original.GetTopFrameSite(), copied.GetTopFrameSite()); - if (net::NetworkIsolationKey::IsFrameSiteEnabled()) { + if (net::NetworkIsolationKey::GetMode() == + net::NetworkIsolationKey::Mode::kFrameSiteEnabled) { EXPECT_EQ(original.GetFrameSite(), copied.GetFrameSite()); } EXPECT_EQ(original.IsTransient(), copied.IsTransient()); @@ -49,7 +50,8 @@ std::vector<uint8_t> serialized; net::NetworkIsolationKey deserialized; - if (net::NetworkIsolationKey::IsFrameSiteEnabled()) { + if (net::NetworkIsolationKey::GetMode() == + net::NetworkIsolationKey::Mode::kFrameSiteEnabled) { auto empty_top_level_site = network::mojom::NetworkIsolationKey::New( /*top_frame_site=*/absl::nullopt, net::SchemefulSite(url::Origin::Create(GURL("http://a.test/"))),
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc index e934013..4c351d3 100644 --- a/services/network/url_loader_unittest.cc +++ b/services/network/url_loader_unittest.cc
@@ -4882,10 +4882,35 @@ ExpectedCookieSettingOverridesForCrossSiteRedirect())); } -// TODO(crbug.com/1401089): Add test case for two-time redirects with the first -// redirect cross-site and the second redirect same-site, to verify the enum -// gets removed for the first redirect and added for the second. +TEST_P(URLLoaderCookieSettingOverridesTest, + CookieSettingOverrides_OnCrossSiteToSameSite) { + GURL cross_site_to_same_site_redirect_url = test_server()->GetURL( + kHostnameWithAliases, + "/server-redirect?" + test_server()->GetURL("/empty.html").spec()); + base::RunLoop delete_run_loop; + ResourceRequest request = + CreateResourceRequest("GET", cross_site_to_same_site_redirect_url); + request.request_initiator = test_server()->GetOrigin(); + SetUpRequest(request); + + mojo::Remote<mojom::URLLoader> loader; + std::unique_ptr<URLLoader> url_loader; + context().mutable_factory_params().process_id = mojom::kBrowserProcessId; + url_loader = URLLoaderOptions().MakeURLLoader( + context(), DeleteLoaderCallback(&delete_run_loop, &url_loader), + loader.BindNewPipeAndPassReceiver(), request, client()->CreateRemote()); + + client()->RunUntilRedirectReceived(); + loader->FollowRedirect({}, {}, {}, absl::nullopt); + client()->RunUntilComplete(); + delete_run_loop.Run(); + EXPECT_THAT(test_network_delegate()->cookie_setting_overrides_records(), + ElementsAre(ExpectedCookieSettingOverridesForCrossSiteRedirect(), + ExpectedCookieSettingOverridesForCrossSiteRedirect(), + ExpectedCookieSettingOverrides(), + ExpectedCookieSettingOverrides())); +} INSTANTIATE_TEST_SUITE_P(All, URLLoaderCookieSettingOverridesTest, testing::Combine(testing::Bool(),
diff --git a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc index 1451f4585..cefb615 100644 --- a/services/viz/public/cpp/compositing/mojom_traits_unittest.cc +++ b/services/viz/public/cpp/compositing/mojom_traits_unittest.cc
@@ -14,6 +14,7 @@ #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/quads/debug_border_draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" +#include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/resources/resource_format.h" #include "components/viz/common/resources/resource_settings.h" #include "components/viz/common/resources/returned_resource.h" @@ -1046,16 +1047,40 @@ const gfx::Rect rect6(321, 765, 11109, 151413); const bool needs_blending6 = false; const ResourceId resource_id6(1234); - const gfx::Size resource_size_in_pixels(1234, 5678); + const gfx::Size resource_size_in_pixels6(1234, 5678); const float stream_draw_quad_opacity[] = {1, 1, 1, 1}; TextureDrawQuad* stream_video_draw_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); stream_video_draw_quad->SetAll( - sqs, rect6, rect6, needs_blending6, resource_id6, resource_size_in_pixels, - false, uv_top_left, uv_bottom_right, SkColors::kTransparent, - stream_draw_quad_opacity, false, false, false, protected_video_type); + sqs, rect6, rect6, needs_blending6, resource_id6, + resource_size_in_pixels6, false, uv_top_left, uv_bottom_right, + SkColors::kTransparent, stream_draw_quad_opacity, false, false, false, + protected_video_type); stream_video_draw_quad->is_stream_video = true; + // Create a TextureDrawQuad with rounded-display masks. + const gfx::Rect rect7(421, 865, 11109, 151413); + const bool needs_blending7 = false; + const ResourceId resource_id7(4834); + const gfx::Size resource_size_in_pixels7(12894, 8878); + const float rounded_display_mask_quad_opacity[] = {1.0, 1.5, 1.8, 1.1}; + const int origin_rounded_display_mask_radius = 10; + const int other_rounded_display_mask_radius = 15; + const bool is_horizontally_positioned = false; + + TextureDrawQuad* rounded_display_mask_quad = + render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); + rounded_display_mask_quad->SetAll( + sqs, rect7, rect7, needs_blending7, resource_id7, + resource_size_in_pixels7, false, uv_top_left, uv_bottom_right, + SkColors::kTransparent, rounded_display_mask_quad_opacity, false, false, + false, protected_video_type); + + rounded_display_mask_quad->rounded_display_masks_info = + TextureDrawQuad::RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo( + origin_rounded_display_mask_radius, other_rounded_display_mask_radius, + is_horizontally_positioned); + std::unique_ptr<CompositorRenderPass> output; mojo::test::SerializeAndDeserialize<mojom::CompositorRenderPass>(render_pass, output); @@ -1137,10 +1162,33 @@ EXPECT_EQ(rect6, out_stream_video_draw_quad->visible_rect); EXPECT_EQ(needs_blending6, out_stream_video_draw_quad->needs_blending); EXPECT_EQ(resource_id6, out_stream_video_draw_quad->resource_id()); - EXPECT_EQ(resource_size_in_pixels, + EXPECT_EQ(resource_size_in_pixels6, out_stream_video_draw_quad->resource_size_in_pixels()); EXPECT_EQ(uv_top_left, out_stream_video_draw_quad->uv_top_left); EXPECT_EQ(uv_bottom_right, out_stream_video_draw_quad->uv_bottom_right); + + const TextureDrawQuad* out_rounded_display_mask_quad = + TextureDrawQuad::MaterialCast(output->quad_list.ElementAt(6)); + EXPECT_FALSE(out_rounded_display_mask_quad->is_stream_video); + EXPECT_EQ(rect7, out_rounded_display_mask_quad->rect); + EXPECT_EQ(rect7, out_rounded_display_mask_quad->visible_rect); + EXPECT_EQ(needs_blending7, out_rounded_display_mask_quad->needs_blending); + EXPECT_EQ(resource_id7, out_rounded_display_mask_quad->resource_id()); + EXPECT_EQ(resource_size_in_pixels7, + out_rounded_display_mask_quad->resource_size_in_pixels()); + EXPECT_EQ(uv_top_left, out_rounded_display_mask_quad->uv_top_left); + EXPECT_EQ(uv_bottom_right, out_rounded_display_mask_quad->uv_bottom_right); + EXPECT_EQ(origin_rounded_display_mask_radius, + out_rounded_display_mask_quad->rounded_display_masks_info + .radii[TextureDrawQuad::RoundedDisplayMasksInfo:: + kOriginRoundedDisplayMaskIndex]); + EXPECT_EQ(other_rounded_display_mask_radius, + out_rounded_display_mask_quad->rounded_display_masks_info + .radii[TextureDrawQuad::RoundedDisplayMasksInfo:: + kOtherRoundedDisplayMaskIndex]); + EXPECT_EQ(is_horizontally_positioned, + out_rounded_display_mask_quad->rounded_display_masks_info + .is_horizontally_positioned); } TEST_F(StructTraitsTest, SurfaceId) {
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.cc b/services/viz/public/cpp/compositing/quads_mojom_traits.cc index e2667795..b0e2b973 100644 --- a/services/viz/public/cpp/compositing/quads_mojom_traits.cc +++ b/services/viz/public/cpp/compositing/quads_mojom_traits.cc
@@ -64,6 +64,22 @@ } // static +bool StructTraits<viz::mojom::RoundedDisplayMasksInfoDataView, + viz::TextureDrawQuad::RoundedDisplayMasksInfo>:: + Read(viz::mojom::RoundedDisplayMasksInfoDataView data, + viz::TextureDrawQuad::RoundedDisplayMasksInfo* out) { + viz::TextureDrawQuad::RoundedDisplayMasksInfo* info = + static_cast<viz::TextureDrawQuad::RoundedDisplayMasksInfo*>(out); + base::span<uint8_t> radii_array(info->radii); + if (!data.ReadRadii(&radii_array)) { + return false; + } + + info->is_horizontally_positioned = data.is_horizontally_positioned(); + return true; +} + +// static bool StructTraits<viz::mojom::DebugBorderQuadStateDataView, viz::DrawQuad>:: Read(viz::mojom::DebugBorderQuadStateDataView data, viz::DrawQuad* out) { viz::DebugBorderDrawQuad* quad = static_cast<viz::DebugBorderDrawQuad*>(out); @@ -150,7 +166,8 @@ !data.ReadProtectedVideoType(&protected_video_type) || !data.ReadHdrMode(&quad->hdr_mode) || !data.ReadHdrMetadata(&quad->hdr_metadata) || - !data.ReadOverlayPriorityHint(&overlay_priority_hint)) { + !data.ReadOverlayPriorityHint(&overlay_priority_hint) || + !data.ReadRoundedDisplayMasksInfo(&quad->rounded_display_masks_info)) { return false; } quad->protected_video_type = protected_video_type;
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.h b/services/viz/public/cpp/compositing/quads_mojom_traits.h index 39794cd..f7bd112e 100644 --- a/services/viz/public/cpp/compositing/quads_mojom_traits.h +++ b/services/viz/public/cpp/compositing/quads_mojom_traits.h
@@ -111,6 +111,23 @@ }; template <> +struct StructTraits<viz::mojom::RoundedDisplayMasksInfoDataView, + viz::TextureDrawQuad::RoundedDisplayMasksInfo> { + static bool is_horizontally_positioned( + const viz::TextureDrawQuad::RoundedDisplayMasksInfo& input) { + return input.is_horizontally_positioned; + } + + static base::span<const uint8_t> radii( + const viz::TextureDrawQuad::RoundedDisplayMasksInfo& input) { + return input.radii; + } + + static bool Read(viz::mojom::RoundedDisplayMasksInfoDataView data, + viz::TextureDrawQuad::RoundedDisplayMasksInfo* out); +}; + +template <> struct UnionTraits<viz::mojom::DrawQuadStateDataView, viz::DrawQuad> { static viz::mojom::DrawQuadStateDataView::Tag GetTag( const viz::DrawQuad& quad) { @@ -396,6 +413,13 @@ return quad->resource_size_in_pixels(); } + static viz::TextureDrawQuad::RoundedDisplayMasksInfo + rounded_display_masks_info(const viz::DrawQuad& input) { + const viz::TextureDrawQuad* quad = + viz::TextureDrawQuad::MaterialCast(&input); + return quad->rounded_display_masks_info; + } + static bool premultiplied_alpha(const viz::DrawQuad& input) { const viz::TextureDrawQuad* quad = viz::TextureDrawQuad::MaterialCast(&input);
diff --git a/services/viz/public/mojom/compositing/quads.mojom b/services/viz/public/mojom/compositing/quads.mojom index 8d4b472..abbccd5 100644 --- a/services/viz/public/mojom/compositing/quads.mojom +++ b/services/viz/public/mojom/compositing/quads.mojom
@@ -28,6 +28,11 @@ kRequired }; +struct RoundedDisplayMasksInfo { + bool is_horizontally_positioned; + array<uint8, 2> radii; +}; + struct DebugBorderQuadState { // Debug border color. skia.mojom.SkColor4f color; @@ -96,6 +101,7 @@ gfx.mojom.HDRMetadata? hdr_metadata; gfx.mojom.Rect? damage_rect; OverlayPriority overlay_priority_hint; + RoundedDisplayMasksInfo rounded_display_masks_info; }; struct TileQuadState {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index cd7243bd..cbc4870 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5490,7 +5490,8 @@ "--dont-restore-color-profile-after-test", "--test-machine-name", "${buildername}", - "--git-revision=${got_revision}" + "--git-revision=${got_revision}", + "--service-account=/creds/service_accounts/skylab-drone.json" ], "autotest_name": "chromium_GPU", "bucket": "chromiumos-image-archive", @@ -5561,7 +5562,8 @@ "--dont-restore-color-profile-after-test", "--test-machine-name", "${buildername}", - "--git-revision=${got_revision}" + "--git-revision=${got_revision}", + "--service-account=/creds/service_accounts/skylab-drone.json" ], "autotest_name": "chromium_GPU", "bucket": "chromiumos-image-archive",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 279dd49b..ade4858d 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2920,6 +2920,13 @@ '--extra-browser-args=--disable-wcg-for-test', ], }, + 'ChromeOS FYI Release Skylab (kevin)': { + 'args': [ + # Skylab currently doesn't support use of LUCI_CONTEXT, so Gold cannot + # automatically get the service account to authenticate with. + '--service-account=/creds/service_accounts/skylab-drone.json', + ], + }, 'android_optional_gpu_tests_rel': { 'args': [ # See above. @@ -3405,6 +3412,13 @@ '--extra-browser-args=--disable-wcg-for-test', ], }, + 'ChromeOS FYI Release Skylab (kevin)': { + 'args': [ + # Skylab currently doesn't support use of LUCI_CONTEXT, so Gold cannot + # automatically get the service account to authenticate with. + '--service-account=/creds/service_accounts/skylab-drone.json', + ], + }, 'android_optional_gpu_tests_rel': { 'args': [ # See above.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index e4d4ad1f..3d304ad 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1302,32 +1302,6 @@ ] } ], - "AutofillServerCommunication": [ - { - "platforms": [ - "android", - "android_weblayer", - "android_webview", - "chromeos", - "chromeos_lacros", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "//0": "This is to effectively disable the", - "//1": "AutofillDownloadManager in browser tests", - "//2": "It is not an ongoing Finch experiment.", - "name": "AutofillServerCommunication", - "disable_features": [ - "AutofillServerCommunication" - ] - } - ] - } - ], "AutofillSurveys": [ { "platforms": [ @@ -6452,6 +6426,21 @@ ] } ], + "IOSPasswordBottomSheet": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "IOSPasswordBottomSheet" + ] + } + ] + } + ], "IOSPasswordManagerCrossOriginIframeSupport": [ { "platforms": [ @@ -10744,6 +10733,29 @@ ] } ], + "SafeBrowsingEsbPromotionFlowImprovements": [ + { + "platforms": [ + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "EnabledWithBoth", + "params": { + "EnableEsbIphBubble": "true", + "EnableEsbSettingCollapse": "true" + }, + "enable_features": [ + "EsbIphBubbleAndCollapseSettings" + ] + } + ] + } + ], "SafeBrowsingLookupMechanismExperiment": [ { "platforms": [
diff --git a/third_party/blink/renderer/build/scripts/core/css/css_properties.py b/third_party/blink/renderer/build/scripts/core/css/css_properties.py index 3dae8a38..e6d9b7e 100755 --- a/third_party/blink/renderer/build/scripts/core/css/css_properties.py +++ b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
@@ -166,6 +166,22 @@ and not self.runtime_flag \ and not self.alternative + @property + def ultimate_property(self): + """Returns the ultimate property, which is the final property + in the alternative_of chain.""" + if self.alternative_of: + return self.alternative_of.ultimate_property + return self + + @property + def css_sample_id(self): + """Returns the CSSSampleId to use for this property.""" + # Alternative properties use the same use-counter as the + # corresponding ultimate main property. In other words, alternative + # properties are use-counted the same way as their main properties. + return self.ultimate_property.enum_key + def generate_property_field(default): # Must use 'default_factory' rather than 'default' for list/dict.
diff --git a/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py b/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py index 8853973f..fc6ca04 100755 --- a/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py +++ b/third_party/blink/renderer/build/scripts/core/css/make_css_property_names.py
@@ -85,10 +85,8 @@ for property_ in self._css_properties.gperf_properties ] - # Variants use the same use-counter as the corresponding main property. css_sample_id_pairs = [ - (property_.enum_key, (property_.alternative_of - or property_).enum_key) + (property_.enum_key, property_.css_sample_id) for property_ in self._css_properties.properties_including_aliases ]
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl index 0e3f25a..1db8f13 100644 --- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl +++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_properties.cc.tmpl
@@ -33,7 +33,7 @@ {% for property in properties %} {% set class_name = property.name.to_upper_camel_case() %} {% set is_alias = property.alias_for %} -{% set exposed_property = property.alternative_of or property %} +{% set exposed_property = property.ultimate_property %} // {{property.name}} {% macro return_none_if_alternative_exposed(alternative) %}
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc index 9b3ae5f5..91faecb 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.cc +++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -2586,7 +2586,8 @@ bool CSSAnimations::IsAnimationAffectingProperty(const CSSProperty& property) { switch (property.PropertyID()) { case CSSPropertyID::kAnimation: - case CSSPropertyID::kAlternativeAnimation: + case CSSPropertyID::kAlternativeAnimationWithTimeline: + case CSSPropertyID::kAlternativeAnimationWithDelayStartEnd: case CSSPropertyID::kAnimationDelay: case CSSPropertyID::kAlternativeAnimationDelay: case CSSPropertyID::kAnimationComposition:
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_interpolation_type.cc index a76e550..d9fb328 100644 --- a/third_party/blink/renderer/core/animation/css_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
@@ -336,24 +336,8 @@ const CSSValue* css_value = CreateCSSValue(interpolable_value, non_interpolable_value, state); DCHECK(!css_value->IsCustomPropertyDeclaration()); - - // TODO(alancutter): Defer tokenization of the CSSValue until it is needed. - String string_value = css_value->CssText(); - CSSTokenizer tokenizer(string_value); - const auto tokens = tokenizer.TokenizeToEOF(); - bool is_animation_tainted = true; - bool needs_variable_resolution = false; - scoped_refptr<CSSVariableData> variable_data = CSSVariableData::Create( - {CSSParserTokenRange(tokens), StringView(string_value)}, - is_animation_tainted, needs_variable_resolution); - const PropertyHandle property = GetProperty(); - - // TODO(andruud): Avoid making the CSSCustomPropertyDeclaration by allowing - // any CSSValue in CustomProperty::ApplyValue. - const CSSValue* value = MakeGarbageCollected<CSSCustomPropertyDeclaration>( - std::move(variable_data), /* parser_context */ nullptr); StyleBuilder::ApplyProperty(GetProperty().GetCSSPropertyName(), state, - *value); + *css_value, StyleBuilder::ValueMode::kAnimated); } } // namespace blink
diff --git a/third_party/blink/renderer/core/annotation/annotation_agent_impl.cc b/third_party/blink/renderer/core/annotation/annotation_agent_impl.cc index 374f1430..5f32992b 100644 --- a/third_party/blink/renderer/core/annotation/annotation_agent_impl.cc +++ b/third_party/blink/renderer/core/annotation/annotation_agent_impl.cc
@@ -80,8 +80,12 @@ } bool AnnotationAgentImpl::IsAttached() const { + // An attached range may have !IsCollapsed but converting to EphemeralRange + // results in IsCollapsed. For an example, see + // AnnotationAgentImplTest.ScrollIntoViewCollapsedRange. return attached_range_ && attached_range_->IsConnected() && - !attached_range_->IsCollapsed(); + !attached_range_->IsCollapsed() && + !attached_range_->ToEphemeralRange().IsCollapsed(); } bool AnnotationAgentImpl::IsBoundForTesting() const { @@ -128,13 +132,7 @@ return; EphemeralRangeInFlatTree range = attached_range_->ToEphemeralRange(); - - // TODO(bokan): This should be checked in IsAttached. - bool range_has_nodes = range.Nodes().begin() != range.Nodes().end(); - if (!range_has_nodes) { - return; - } - + CHECK(range.Nodes().begin() != range.Nodes().end()); Node& first_node = *range.Nodes().begin(); Document& document = *owning_container_->GetSupplementable();
diff --git a/third_party/blink/renderer/core/annotation/annotation_agent_impl_test.cc b/third_party/blink/renderer/core/annotation/annotation_agent_impl_test.cc index 8f6bdd7..86b8272 100644 --- a/third_party/blink/renderer/core/annotation/annotation_agent_impl_test.cc +++ b/third_party/blink/renderer/core/annotation/annotation_agent_impl_test.cc
@@ -780,6 +780,10 @@ host.BindToAgent(*agent); agent->Attach(); + // Attachment should fail for this collapsed range. + EXPECT_FALSE(agent->IsAttached()); + host.FlushForTesting(); + // Ensure calling ScrollIntoView doesn't crash. host.agent_->ScrollIntoView(); host.FlushForTesting();
diff --git a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc index 71a6189..0ab6e719 100644 --- a/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc +++ b/third_party/blink/renderer/core/css/css_computed_style_declaration_test.cc
@@ -219,6 +219,7 @@ TEST_F(CSSComputedStyleDeclarationTest, UseCountComputedAlternativeAnimationDelayZero) { ScopedCSSScrollTimelineForTest scroll_timeline_feature(true); + ScopedCSSAnimationDelayStartEndForTest delay_start_end_feature(false); GetDocument().body()->setInnerHTML(R"HTML( <style> @@ -237,7 +238,8 @@ // There is no animation property specified at all, so getting the computed // value should not trigger the counter. - EXPECT_TRUE(style->GetPropertyCSSValue(CSSPropertyID::kAlternativeAnimation)); + EXPECT_TRUE(style->GetPropertyCSSValue( + CSSPropertyID::kAlternativeAnimationWithTimeline)); EXPECT_TRUE( style->GetPropertyCSSValue(CSSPropertyID::kAlternativeAnimationDelay)); EXPECT_FALSE(GetDocument().IsUseCounted( @@ -247,12 +249,13 @@ // -alternative-animation[-delay], because those properties are only in // use when 'CSSScrollTimeline' is enabled (which is the feature that would // ship the change that this use-counter is for in the first place). - div->SetInlineStyleProperty(CSSPropertyID::kAlternativeAnimation, + div->SetInlineStyleProperty(CSSPropertyID::kAlternativeAnimationWithTimeline, "anim linear"); UpdateAllLifecyclePhasesForTest(); EXPECT_FALSE(GetDocument().IsUseCounted( WebFeature::kCSSGetComputedAnimationDelayZero)); - EXPECT_TRUE(style->GetPropertyCSSValue(CSSPropertyID::kAlternativeAnimation)); + EXPECT_TRUE(style->GetPropertyCSSValue( + CSSPropertyID::kAlternativeAnimationWithTimeline)); EXPECT_TRUE( style->GetPropertyCSSValue(CSSPropertyID::kAlternativeAnimationDelay)); EXPECT_FALSE(GetDocument().IsUseCounted(
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index d951318..3ab1ff55 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -771,7 +771,7 @@ ], property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"], valid_for_keyframe: false, - runtime_flag: "CSSScrollTimeline", + runtime_flag: "CSSAnimationDelayStartEnd", }, { name: "animation-delay-start", @@ -785,7 +785,7 @@ valid_for_marker: true, is_animation_property: true, valid_for_keyframe: false, - runtime_flag: "CSSScrollTimeline", + runtime_flag: "CSSAnimationDelayStartEnd", }, { name: "animation-delay-end", @@ -799,7 +799,7 @@ valid_for_marker: true, is_animation_property: true, valid_for_keyframe: false, - runtime_flag: "CSSScrollTimeline", + runtime_flag: "CSSAnimationDelayStartEnd", }, { name: "animation-direction", @@ -6595,13 +6595,27 @@ valid_for_keyframe: false, }, { - // Variant of the "animation" shorthand which includes new longhands from - // Scroll-Linked Animations. - // https://drafts.csswg.org/scroll-animations-1/ - name: "-alternative-animation", + // Variant of the "animation" shorthand which includes the + // animation-timeline longhand. + name: "-alternative-animation-with-timeline", alternative_of: "animation", longhands: [ "animation-duration", "animation-timing-function", + "animation-delay", "animation-iteration-count", "animation-direction", + "animation-fill-mode", "animation-play-state", "animation-name", + "animation-timeline" + ], + property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"], + valid_for_keyframe: false, + runtime_flag: 'CSSScrollTimeline', + }, + { + // Variant of the "animation" shorthand which includes the + // animation-delay-start and animation-delay-end longhands. + name: "-alternative-animation-with-delay-start-end", + alternative_of: "-alternative-animation-with-timeline", + longhands: [ + "animation-duration", "animation-timing-function", "animation-delay-start", "animation-delay-end", "animation-iteration-count", "animation-direction", "animation-fill-mode", "animation-play-state", "animation-name", @@ -6609,7 +6623,7 @@ ], property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"], valid_for_keyframe: false, - runtime_flag: 'CSSScrollTimeline', + runtime_flag: 'CSSAnimationDelayStartEnd', }, { name: "animation-range", @@ -7719,12 +7733,18 @@ // -webkit-animation directly to animation's alternative, because we have // to remember the -webkit-ness of the property to enable legacy parsing // behavior. (See CSSParserLocalContext::UseAliasParsing). - name: "-webkit-alternative-animation", - alias_for: "-alternative-animation", + name: "-webkit-alternative-animation-with-timeline", + alias_for: "-alternative-animation-with-timeline", alternative_of: "-webkit-animation", runtime_flag: "CSSScrollTimeline", }, { + name: "-webkit-alternative-animation-with-delay-start-end", + alias_for: "-alternative-animation-with-delay-start-end", + alternative_of: "-webkit-alternative-animation-with-timeline", + runtime_flag: "CSSAnimationDelayStartEnd", + }, + { name: "-webkit-animation-delay", alias_for: "animation-delay", }, @@ -7732,7 +7752,7 @@ name: "-webkit-alternative-animation-delay", alias_for: "-alternative-animation-delay", alternative_of: "-webkit-animation-delay", - runtime_flag: "CSSScrollTimeline", + runtime_flag: "CSSAnimationDelayStartEnd", }, { name: "-webkit-animation-direction",
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc index 379b4ae8..2063e7e3 100644 --- a/third_party/blink/renderer/core/css/css_property_equality.cc +++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -878,8 +878,9 @@ case CSSPropertyID::kAliasWebkitAlignContent: case CSSPropertyID::kAliasWebkitAlignItems: case CSSPropertyID::kAliasWebkitAlignSelf: - case CSSPropertyID::kAliasWebkitAlternativeAnimation: case CSSPropertyID::kAliasWebkitAlternativeAnimationDelay: + case CSSPropertyID::kAliasWebkitAlternativeAnimationWithDelayStartEnd: + case CSSPropertyID::kAliasWebkitAlternativeAnimationWithTimeline: case CSSPropertyID::kAliasWebkitAnimation: case CSSPropertyID::kAliasWebkitAnimationDelay: case CSSPropertyID::kAliasWebkitAnimationDirection: @@ -1183,8 +1184,9 @@ return true; // Non-animateable properties - case CSSPropertyID::kAlternativeAnimation: case CSSPropertyID::kAlternativeAnimationDelay: + case CSSPropertyID::kAlternativeAnimationWithDelayStartEnd: + case CSSPropertyID::kAlternativeAnimationWithTimeline: case CSSPropertyID::kAnimation: case CSSPropertyID::kAnimationComposition: case CSSPropertyID::kAnimationDelay:
diff --git a/third_party/blink/renderer/core/css/css_property_names_test.cc b/third_party/blink/renderer/core/css/css_property_names_test.cc index 0a44e803..acc92d5 100644 --- a/third_party/blink/renderer/core/css/css_property_names_test.cc +++ b/third_party/blink/renderer/core/css/css_property_names_test.cc
@@ -9,32 +9,53 @@ namespace blink { -TEST(CSSPropertyNamesTest, AlternativeAnimation) { +TEST(CSSPropertyNamesTest, AlternativeAnimationWithTimeline) { + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(false); + { - ScopedCSSScrollTimelineForTest scoped_feature(false); + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(false); EXPECT_EQ( CSSPropertyID::kAnimation, UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation")); } { - ScopedCSSScrollTimelineForTest scoped_feature(true); + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(true); EXPECT_EQ( - CSSPropertyID::kAlternativeAnimation, + CSSPropertyID::kAlternativeAnimationWithTimeline, + UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation")); + } +} + +TEST(CSSPropertyNamesTest, AlternativeAnimationWithDelayStartEnd) { + // CSSAnimationDelayStartEnd depends on CSSScrollTimeline. + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(true); + + { + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(false); + EXPECT_EQ( + CSSPropertyID::kAlternativeAnimationWithTimeline, + UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation")); + } + + { + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(true); + EXPECT_EQ( + CSSPropertyID::kAlternativeAnimationWithDelayStartEnd, UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation")); } } TEST(CSSPropertyNamesTest, AlternativeAnimationDelay) { { - ScopedCSSScrollTimelineForTest scoped_feature(false); + ScopedCSSAnimationDelayStartEndForTest scoped_feature(false); EXPECT_EQ(CSSPropertyID::kAnimationDelay, UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation-delay")); } { - ScopedCSSScrollTimelineForTest scoped_feature(true); + ScopedCSSAnimationDelayStartEndForTest scoped_feature(true); EXPECT_EQ(CSSPropertyID::kAlternativeAnimationDelay, UnresolvedCSSPropertyID(/* execution_context */ nullptr, "animation-delay"));
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 03ce05b0..aeaf21e2 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -4317,7 +4317,7 @@ CSSValue* ConsumeAnimationDelay(CSSParserTokenRange& range, const CSSParserContext& context) { - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return ConsumeTime(range, context, CSSPrimitiveValue::ValueRange::kAll); }
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc index 1cf29821..fb26618 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -128,18 +128,34 @@ return; } - const auto& declaration = To<CSSCustomPropertyDeclaration>(value); - bool is_inherited_property = IsInherited(); - scoped_refptr<CSSVariableData> data = &declaration.Value(); - DCHECK(!data->NeedsVariableResolution()); + const auto* declaration = DynamicTo<CSSCustomPropertyDeclaration>(value); - builder.SetVariableData(name_, data, is_inherited_property); + // Unregistered custom properties can only accept + // CSSCustomPropertyDeclaration objects. + if (!registration_) { + // We can reach here without a CSSCustomPropertyDeclaration + // if we're removing a property registration while animating. + // TODO(andruud): Cancel animations if the registration changed. + if (declaration) { + CSSVariableData& data = declaration->Value(); + DCHECK(!data.NeedsVariableResolution()); + builder.SetVariableData(name_, &data, is_inherited_property); + } + return; + } - if (registration_) { - const CSSParserContext* context = declaration.ParserContext(); + // Registered custom properties can accept either + // - A CSSCustomPropertyDeclaration, in which case we produce the + // `registered_value` value from that, or: + // - Some other value (typically an interpolated value), which we'll use + // as the `registered_value` directly. + const CSSParserContext* context = + declaration ? declaration->ParserContext() : nullptr; + + if (!context) { // There is no "originating" CSSParserContext associated with the // declaration if it represents a "synthetic" token sequence such as those // constructed to represent interpolated (registered) custom properties. [1] @@ -149,35 +165,39 @@ // // [1] // https://drafts.css-houdini.org/css-properties-values-api-1/#equivalent-token-sequence - if (!context) { - context = StrictCSSParserContext( - state.GetDocument().GetExecutionContext()->GetSecureContextMode()); - } - const CSSValue* registered_value = - Parse(CSSTokenizedValue{data->TokenRange(), data->OriginalText()}, - *context, CSSParserLocalContext()); - if (!registered_value) { - if (is_inherited_property) { - ApplyInherit(state); - } else { - ApplyInitial(state); - } - return; - } - - // TODO(andruud): Eventually only `value_mode` should decide if we're - // animation-tainted or not. - bool is_animation_tainted = - data->IsAnimationTainted() || (value_mode == ValueMode::kAnimated); - - registered_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue( - state, *registered_value, context); - data = StyleBuilderConverter::ConvertRegisteredPropertyVariableData( - *registered_value, is_animation_tainted); - - builder.SetVariableData(name_, data, is_inherited_property); - builder.SetVariableValue(name_, registered_value, is_inherited_property); + context = StrictCSSParserContext( + state.GetDocument().GetExecutionContext()->GetSecureContextMode()); } + + const CSSValue* registered_value = declaration ? nullptr : &value; + + if (!registered_value) { + DCHECK(declaration); + CSSVariableData& data = declaration->Value(); + registered_value = + Parse(CSSTokenizedValue{data.TokenRange(), data.OriginalText()}, + *context, CSSParserLocalContext()); + } + + if (!registered_value) { + if (is_inherited_property) { + ApplyInherit(state); + } else { + ApplyInitial(state); + } + return; + } + + bool is_animation_tainted = value_mode == ValueMode::kAnimated; + + registered_value = &StyleBuilderConverter::ConvertRegisteredPropertyValue( + state, *registered_value, context); + scoped_refptr<CSSVariableData> data = + StyleBuilderConverter::ConvertRegisteredPropertyVariableData( + *registered_value, is_animation_tainted); + + builder.SetVariableData(name_, data, is_inherited_property); + builder.SetVariableValue(name_, registered_value, is_inherited_property); } const CSSValue* CustomProperty::ParseSingleValue(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index f761bd46..094bb72 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -261,10 +261,10 @@ const ComputedStyle& style, const LayoutObject*, bool allow_visited_style) const { - // When CSSScrollTimeline is enabled, animation-delay is a shorthand - // which expands to animation-delay-start/end, therefore this should not - // be reachable without that feature. - DCHECK(!RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + // When CSSAnimationDelayStartEndEnabled is enabled, animation-delay is a + // shorthand which expands to animation-delay-start/end, therefore this should + // not be reachable without that feature. + DCHECK(!RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return ComputedStyleUtils::ValueForAnimationDelayStartList( style.Animations()); } @@ -280,7 +280,7 @@ CSSParserTokenRange& range, const CSSParserContext& context, const CSSParserLocalContext&) const { - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return css_parsing_utils::ConsumeCommaSeparatedList( css_parsing_utils::ConsumeAnimationDelay, range, context); } @@ -302,7 +302,7 @@ CSSParserTokenRange& range, const CSSParserContext& context, const CSSParserLocalContext&) const { - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return css_parsing_utils::ConsumeCommaSeparatedList( css_parsing_utils::ConsumeAnimationDelay, range, context); }
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc index 7af84ca..5d00dee 100644 --- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -46,11 +46,11 @@ bool use_legacy_parsing) { switch (property) { case CSSPropertyID::kAnimationDelay: - DCHECK(!RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(!RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return css_parsing_utils::ConsumeTime( range, context, CSSPrimitiveValue::ValueRange::kAll); case CSSPropertyID::kAnimationDelayStart: - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return css_parsing_utils::ConsumeAnimationDelay(range, context); case CSSPropertyID::kAnimationDelayEnd: // New animation-* properties are "reset only": @@ -58,7 +58,7 @@ // // Returning nullptr here means that AnimationDelayEnd::InitialValue will // be used. - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); return nullptr; case CSSPropertyID::kAnimationDirection: return css_parsing_utils::ConsumeIdent< @@ -202,22 +202,44 @@ style.Animations()); } -bool AlternativeAnimation::ParseShorthand( +bool AlternativeAnimationWithTimeline::ParseShorthand( bool important, CSSParserTokenRange& range, const CSSParserContext& context, const CSSParserLocalContext& local_context, HeapVector<CSSPropertyValue, 64>& properties) const { - return ParseAnimationShorthand(alternativeAnimationShorthand(), important, - range, context, local_context, properties); + return ParseAnimationShorthand(alternativeAnimationWithTimelineShorthand(), + important, range, context, local_context, + properties); } -const CSSValue* AlternativeAnimation::CSSValueFromComputedStyleInternal( +const CSSValue* +AlternativeAnimationWithTimeline::CSSValueFromComputedStyleInternal( const ComputedStyle& style, const LayoutObject*, bool allow_visited_style) const { - return CSSValueFromComputedAnimation(alternativeAnimationShorthand(), - style.Animations()); + return CSSValueFromComputedAnimation( + alternativeAnimationWithTimelineShorthand(), style.Animations()); +} + +bool AlternativeAnimationWithDelayStartEnd::ParseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext& local_context, + HeapVector<CSSPropertyValue, 64>& properties) const { + return ParseAnimationShorthand( + alternativeAnimationWithDelayStartEndShorthand(), important, range, + context, local_context, properties); +} + +const CSSValue* +AlternativeAnimationWithDelayStartEnd::CSSValueFromComputedStyleInternal( + const ComputedStyle& style, + const LayoutObject*, + bool allow_visited_style) const { + return CSSValueFromComputedAnimation( + alternativeAnimationWithDelayStartEndShorthand(), style.Animations()); } namespace { @@ -317,7 +339,7 @@ const CSSParserContext& context, const CSSParserLocalContext& local_context, HeapVector<CSSPropertyValue, 64>& properties) const { - DCHECK(RuntimeEnabledFeatures::CSSScrollTimelineEnabled()); + DCHECK(RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); using css_parsing_utils::AddProperty; using css_parsing_utils::ConsumeCommaIncludingWhitespace;
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index ce184be..4a04f382c 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -5915,6 +5915,107 @@ EXPECT_EQ(3u, after_count - before_count); } +TEST_F(StyleEngineTest, AnimationDelayShorthandFlags) { + String css = "animation-delay:1s"; + { + ScopedCSSAnimationDelayStartEndForTest enabled(false); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(1u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelay)); + } + { + ScopedCSSAnimationDelayStartEndForTest enabled(true); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(2u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayStart)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayEnd)); + } +} + +TEST_F(StyleEngineTest, AnimationDelayStartEndFlags) { + String css = "animation-delay-start:1s;animation-delay-end:1s"; + { + ScopedCSSAnimationDelayStartEndForTest enabled(false); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(0u, set->PropertyCount()); + } + { + ScopedCSSAnimationDelayStartEndForTest enabled(true); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(2u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayStart)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayEnd)); + } +} + +TEST_F(StyleEngineTest, AnimationShorthandFlags) { + String css = "animation: foo 1s"; + { + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(false); + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(false); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(8u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDuration)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationTimingFunction)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelay)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationIterationCount)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDirection)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationFillMode)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationPlayState)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationName)); + } + { + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(true); + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(false); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(9u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDuration)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationTimingFunction)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelay)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationIterationCount)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDirection)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationFillMode)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationPlayState)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationName)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationTimeline)); + } + { + ScopedCSSScrollTimelineForTest scroll_timeline_enabled(true); + ScopedCSSAnimationDelayStartEndForTest start_end_enabled(true); + const CSSPropertyValueSet* set = + css_test_helpers::ParseDeclarationBlock(css); + ASSERT_TRUE(set); + EXPECT_EQ(10u, set->PropertyCount()); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDuration)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationTimingFunction)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayStart)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDelayEnd)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationIterationCount)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationDirection)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationFillMode)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationPlayState)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationName)); + EXPECT_TRUE(set->HasProperty(CSSPropertyID::kAnimationTimeline)); + } + // Note that the combination CSSScrollTimeline=false and + // CSSAnimationDelayStartEnd=true is not supported, via 'depends_on' + // in runtime_enabled_features.json5. + EXPECT_FALSE(!RuntimeEnabledFeatures::CSSScrollTimelineEnabled() && + RuntimeEnabledFeatures::CSSAnimationDelayStartEndEnabled()); +} + TEST_F(StyleEngineTest, InitialStyle_Recalc) { GetDocument().body()->setInnerHTML(R"HTML( <style>
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc index dfc97b34..fd37849 100644 --- a/third_party/blink/renderer/core/css/style_property_serializer.cc +++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -471,8 +471,12 @@ switch (property_id) { case CSSPropertyID::kAnimation: return GetLayeredShorthandValue(animationShorthand()); - case CSSPropertyID::kAlternativeAnimation: - return GetLayeredShorthandValue(alternativeAnimationShorthand()); + case CSSPropertyID::kAlternativeAnimationWithTimeline: + return GetLayeredShorthandValue( + alternativeAnimationWithTimelineShorthand()); + case CSSPropertyID::kAlternativeAnimationWithDelayStartEnd: + return GetLayeredShorthandValue( + alternativeAnimationWithDelayStartEndShorthand()); case CSSPropertyID::kAlternativeAnimationDelay: return AnimationDelayShorthandValue(); case CSSPropertyID::kAnimationRange:
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index c1ee4bcd..8ee4be4 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2836,6 +2836,7 @@ if (UNLIKELY(HasUndoStack())) { frame->GetEditor().GetUndoStack().ElementRemoved(this); } + frame->GetEditor().ElementRemoved(this); frame->GetEventHandler().ElementRemoved(this); } }
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc index 8be6be2..1648ab9 100644 --- a/third_party/blink/renderer/core/editing/editor.cc +++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -948,6 +948,16 @@ InputEvent::InputType::kInsertReplacementText); } +void Editor::ElementRemoved(Element* element) { + if (!RuntimeEnabledFeatures::DontLeakDetachedInputEnabled()) { + return; + } + if (last_edit_command_ && + last_edit_command_->EndingSelection().RootEditableElement() == element) { + last_edit_command_ = nullptr; + } +} + void Editor::Trace(Visitor* visitor) const { visitor->Trace(frame_); visitor->Trace(last_edit_command_);
diff --git a/third_party/blink/renderer/core/editing/editor.h b/third_party/blink/renderer/core/editing/editor.h index e5f9571..20141e8 100644 --- a/third_party/blink/renderer/core/editing/editor.h +++ b/third_party/blink/renderer/core/editing/editor.h
@@ -147,6 +147,8 @@ void SetStartNewKillRingSequence(bool); + void ElementRemoved(Element* element); + void Clear(); SelectionInDOMTree SelectionForCommand(Event*);
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc index 727c8e6f..456dc77 100644 --- a/third_party/blink/renderer/core/testing/internals.cc +++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2133,6 +2133,18 @@ .ForceInvocationForTesting(); } +bool Internals::hasLastEditCommand(Document* document, + ExceptionState& exception_state) { + if (!document || !document->GetFrame()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidAccessError, + "No frame can be obtained from the provided document."); + return false; + } + + return document->GetFrame()->GetEditor().LastEditCommand(); +} + Vector<AtomicString> Internals::userPreferredLanguages() const { return blink::UserPreferredLanguages(); }
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h index 75d2205..d72743d 100644 --- a/third_party/blink/renderer/core/testing/internals.h +++ b/third_party/blink/renderer/core/testing/internals.h
@@ -292,6 +292,8 @@ String idleTimeSpellCheckerState(Document*, ExceptionState&); void runIdleTimeSpellChecker(Document*, ExceptionState&); + bool hasLastEditCommand(Document*, ExceptionState&); + Vector<AtomicString> userPreferredLanguages() const; void setUserPreferredLanguages(const Vector<String>&); void setSystemTimeZone(const String&);
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl index 2b21f09..e607475 100644 --- a/third_party/blink/renderer/core/testing/internals.idl +++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -148,6 +148,8 @@ [RaisesException] DOMString idleTimeSpellCheckerState(Document document); [RaisesException] void runIdleTimeSpellChecker(Document document); + [RaisesException] boolean hasLastEditCommand(Document document); + sequence<DOMString> userPreferredLanguages(); void setUserPreferredLanguages(sequence<DOMString> languages); void setSystemTimeZone(DOMString timezone);
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc index 22c22e0..05f6b0e9 100644 --- a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc +++ b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
@@ -378,9 +378,16 @@ VectorOf<Element>& elements, VectorOf<AtomicString>& transition_names, absl::optional<RootData>& root_data) { - // If the root element doesn't generate a layout object then there can't be - // any elements participating in the transition since no element can generate - // a box. This is a valid state for things like entry or exit animations. + // Fail if the document element does not exist, since that's the place where + // we attach pseudo elements, and if it's not there, we can't do a transition. + if (!document_->documentElement()) { + return false; + } + + // If the root element exists but doesn't generate a layout object then there + // can't be any elements participating in the transition since no element can + // generate a box. This is a valid state for things like entry or exit + // animations. if (!document_->documentElement()->GetLayoutObject()) { return true; } @@ -809,6 +816,10 @@ bool ViewTransitionStyleTracker::RunPostPrePaintSteps() { DCHECK_GE(document_->Lifecycle().GetState(), DocumentLifecycle::kPrePaintClean); + // Abort if the document element is not there. + if (!document_->documentElement()) { + return false; + } if (!document_->documentElement()->GetLayoutObject()) { // If we have any view transition elements, while having no @@ -832,6 +843,7 @@ // Use the document element's effective zoom, since that's what the parent // effective zoom would be. + DCHECK(document_->documentElement()); float device_pixel_ratio = document_->documentElement() ->GetLayoutObject() ->StyleRef() @@ -850,6 +862,7 @@ if (!element_data->target_element) continue; + DCHECK(document_->documentElement()); DCHECK_NE(element_data->target_element, document_->documentElement()); auto* layout_object = element_data->target_element->GetLayoutObject(); // TODO(khushalsagar): Verify that skipping a transition when things become @@ -951,6 +964,7 @@ PseudoId live_content_element = HasLiveNewContent() ? kPseudoIdViewTransitionNew : kPseudoIdViewTransitionOld; + DCHECK(document_->documentElement()); if (auto* pseudo_element = document_->documentElement()->GetNestedPseudoElement( live_content_element, entry.key)) { @@ -1242,10 +1256,11 @@ ua_style_sheet_.reset(); document_->GetStyleEngine().InvalidateUAViewTransitionStyle(); - auto* originating_element = document_->documentElement(); - originating_element->SetNeedsStyleRecalc( - kLocalStyleChange, StyleChangeReasonForTracing::Create( - style_change_reason::kViewTransition)); + if (auto* originating_element = document_->documentElement()) { + originating_element->SetNeedsStyleRecalc( + kLocalStyleChange, StyleChangeReasonForTracing::Create( + style_change_reason::kViewTransition)); + } auto invalidate_style = [](PseudoElement* pseudo_element) { pseudo_element->SetNeedsStyleRecalc(
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_utils.h b/third_party/blink/renderer/core/view_transition/view_transition_utils.h index 8118213..0b8fc212 100644 --- a/third_party/blink/renderer/core/view_transition/view_transition_utils.h +++ b/third_party/blink/renderer/core/view_transition/view_transition_utils.h
@@ -18,6 +18,10 @@ public: template <typename Functor> static void ForEachTransitionPseudo(Document& document, Functor& func) { + if (!document.documentElement()) { + return; + } + auto* transition_pseudo = document.documentElement()->GetPseudoElement(kPseudoIdViewTransition); if (!transition_pseudo) @@ -56,6 +60,10 @@ template <typename Functor> static PseudoElement* FindPseudoIf(const Document& document, const Functor& condition) { + if (!document.documentElement()) { + return nullptr; + } + auto* transition_pseudo = document.documentElement()->GetPseudoElement(kPseudoIdViewTransition); if (!transition_pseudo) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index 4076ca5..c8c55672 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -604,6 +604,12 @@ role_(ax::mojom::blink::Role::kUnknown), explicit_container_id_(0), last_modification_count_(-1), + cached_is_ignored_(false), + cached_is_ignored_but_included_in_tree_(false), + cached_is_inert_(false), + cached_is_aria_hidden_(false), + cached_is_descendant_of_disabled_node_(false), + cached_can_set_focus_attribute_(false), cached_live_region_root_(nullptr), cached_aria_column_index_(0), cached_aria_row_index_(0), @@ -2925,9 +2931,19 @@ is_ignored && ComputeAccessibilityIsIgnoredButIncludedInTree(); bool included_in_tree_changed = false; - bool is_included_in_tree = !is_ignored || is_ignored_but_included_in_tree; - if (is_included_in_tree != LastKnownIsIncludedInTreeValue()) { - included_in_tree_changed = true; + // If the child's "included in tree" state changes, we will be notifying the + // parent to recompute it's children. + // Exceptions: + // - Caller passes in |notify_parent_of_ignored_changes = false| -- this + // occurs when this is a new child, or when a parent is in the middle of + // adding this child, and doing this would be redundant. + // - Inline text boxes: their "included in tree" state is entirely dependent + // on their static text parent. + if (notify_parent_of_ignored_changes && + RoleValue() != ax::mojom::blink::Role::kInlineTextBox) { + bool is_included_in_tree = !is_ignored || is_ignored_but_included_in_tree; + if (is_included_in_tree != LastKnownIsIncludedInTreeValue()) + included_in_tree_changed = true; } // Presence of inline text children depends on ignored state. @@ -2937,19 +2953,11 @@ SetNeedsToUpdateChildren(); } - // If the child's "included in tree" state changes, we will be notifying the - // parent to recompute it's children. - // Exceptions: - // - Caller passes in |notify_parent_of_ignored_changes = false| -- this - // occurs when this is a new child, or when a parent is in the middle of - // adding this child, and doing this would be redundant. - // - Inline text boxes: their "included in tree" state is entirely dependent - // on their static text parent. + // Call children changed on included ancestor. // This must be called before cached_is_ignored_* are updated, otherwise a // performance optimization depending on LastKnownIsIncludedInTreeValue() // may misfire. - if (included_in_tree_changed && notify_parent_of_ignored_changes && - RoleValue() != ax::mojom::blink::Role::kInlineTextBox) { + if (included_in_tree_changed) { if (AXObject* parent = CachedParentObject()) { // Defers a ChildrenChanged() on the first included ancestor. // Must defer it, otherwise it can cause reentry into @@ -2983,12 +2991,6 @@ cached_local_bounding_box_rect_for_accessibility_ = GetLayoutObject()->LocalBoundingBoxRectForAccessibility(); } - -#if DCHECK_IS_ON() - if (included_in_tree_changed) { - AXObjectCache().UpdateIncludedNodeCount(this); - } -#endif } bool AXObject::ComputeAccessibilityIsIgnored( @@ -7039,11 +7041,8 @@ } } - if (!GetDocument()) { + if (!GetDocument()) string_builder = string_builder + " missingDocument"; - } else if (!GetDocument()->GetFrame()) { - string_builder = string_builder + " closedDocument"; - } // Add properties of interest that often contribute to errors: if (HasARIAOwns(GetElement())) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h index e045f5d..602e248 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -1462,20 +1462,16 @@ mutable int last_modification_count_; - // The following cached attribute values (the ones starting with cached_**) + // The following cached attribute values (the ones starting with m_cached*) // are only valid if last_modification_count_ matches // AXObjectCacheImpl::ModificationCount(). - // Objects are marked ignored at construction time (and thus by default they - // not included in the tree), so that if object becomes included in Init() - // or in a future page update, the included node count will be incremented via - // AXObjectCacheImpl::UpdateIncludedNodeCount(). - mutable bool cached_is_ignored_ : 1 = true; - mutable bool cached_is_ignored_but_included_in_tree_ : 1 = false; - mutable bool cached_is_inert_ : 1 = false; - mutable bool cached_is_aria_hidden_ : 1 = false; - mutable bool cached_is_hidden_via_style_ : 1 = false; - mutable bool cached_is_descendant_of_disabled_node_ : 1 = false; - mutable bool cached_can_set_focus_attribute_ : 1 = false; + mutable bool cached_is_ignored_ : 1; + mutable bool cached_is_ignored_but_included_in_tree_ : 1; + mutable bool cached_is_inert_ : 1; + mutable bool cached_is_aria_hidden_ : 1; + mutable bool cached_is_hidden_via_style_ : 1; + mutable bool cached_is_descendant_of_disabled_node_ : 1; + mutable bool cached_can_set_focus_attribute_ : 1; // Focusability can change in response to a new style (e.g. content-visibility // added/removed), new dom (e.g. tabindex set/unset), or new AXCache
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 59a098b..d65f6ae 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -678,6 +678,7 @@ const ui::AXMode& ax_mode) : document_(document), ax_mode_(ax_mode), + modification_count_(0), validation_message_axid_(0), active_aria_modal_dialog_(nullptr), relation_cache_(std::make_unique<AXRelationCache>(this)), @@ -1506,12 +1507,6 @@ if (!obj) return; -#if DCHECK_IS_ON() - if (obj->LastKnownIsIncludedInTreeValue()) { - --included_node_count_; - } -#endif - if (notify_parent && !has_been_disposed_) { ChildrenChangedOnAncestorOf(obj); } @@ -2555,11 +2550,6 @@ RemoveIncludedSubtree(current, /* remove_root */ false); } -#if DCHECK_IS_ON() - if (current->LastKnownIsIncludedInTreeValue()) { - --included_node_count_; - } -#endif AXID retained_axid = current->AXObjectID(); // Remove from relevant maps, but not from relation cache, as the relations // between AXIDs will still be the same. @@ -3984,10 +3974,8 @@ DCHECK_GT(update.nodes.size(), 0U); for (auto& node_data : update.nodes) { - AXID id = node_data.id; - DCHECK(id); - VLOG(1) << "*** Serialize: " << ObjectFromAXID(id)->ToString(true); - already_serialized_ids.insert(id); + DCHECK(node_data.id); + already_serialized_ids.insert(node_data.id); } DCHECK(already_serialized_ids.Contains(obj->AXObjectID())) @@ -4047,88 +4035,8 @@ VLOG(1) << "AXEvent: " << event.event_type << " on " << ObjectFromAXID(event.id); } - -#if DCHECK_IS_ON() - if (!HasDirtyObjects()) { - CheckTreeConsistency(); - } -#endif } -#if DCHECK_IS_ON() -void AXObjectCacheImpl::CheckTreeConsistency() { - // If all serializations are complete, check that the number of included nodes - // being serialized is the same as the number of included nodes according to - // the AXObjectCache. - if (included_node_count_ != ax_tree_serializer_->ClientTreeNodeCount()) { - // There was an inconsistency in the node count: provide a helpful message - // to facilitate debugging. - std::ostringstream msg; - msg << "AXTreeSerializer should have the expected number of included nodes:" - << "\n* AXObjectCache: " << included_node_count_ - << "\n* Serializer: " << ax_tree_serializer_->ClientTreeNodeCount(); - for (const auto& id_to_object_entry : objects_) { - AXObject* obj = id_to_object_entry.value; - if (obj->LastKnownIsIncludedInTreeValue()) { - if (!ax_tree_serializer_->IsInClientTree(obj)) { - if (obj->IsMissingParent()) { - msg << "\n* Included node not serialized, is missing parent: " - << obj->ToString(true, true); - } else if (!obj->GetDocument()->GetFrame()) { - msg << "\n* Included node not serialized, in closed document: " - << obj->ToString(true, true); - } else { - bool included_state_stale = !obj->AccessibilityIsIncludedInTree(); - msg << "\n* Included node not serialized: " << obj->ToString(true); - if (included_state_stale) { - msg << "\n Included state was stale."; - } - msg << "\n Parent: " << obj->CachedParentObject()->ToString(true); - } - } - } - } - for (AXID id : ax_tree_serializer_->ClientTreeNodeIds()) { - AXObject* obj = ObjectFromAXID(id); - if (!obj) { - msg << "\n* Serialized node does not exist: " << id; - if (AXObject* parent = ax_tree_serializer_->ParentOf(id)) { - msg << "\n* Parent = " << parent->ToString(true); - } - } else if (!obj->LastKnownIsIncludedInTreeValue()) { - msg << "\n* Serialized an unincluded node: " << obj->ToString(true); - } - } - DCHECK(false) << msg.str(); - } - - constexpr size_t kMaxNodesForDeepSlowConsistencyCheck = 100; - if (included_node_count_ > kMaxNodesForDeepSlowConsistencyCheck) { - return; - } - - DCHECK_EQ(included_node_count_, RecursiveIncludedNodeCount(Root())); -} - -size_t AXObjectCacheImpl::RecursiveIncludedNodeCount(AXObject* subtree) { - size_t count = 1; // For |subtree| itself. - for (const auto& child : subtree->ChildrenIncludingIgnored()) { - count += RecursiveIncludedNodeCount(child); - } - return count; -} -#endif - -#if DCHECK_IS_ON() -void AXObjectCacheImpl::UpdateIncludedNodeCount(const AXObject* obj) { - if (obj->LastKnownIsIncludedInTreeValue()) { - ++included_node_count_; - } else { - --included_node_count_; - } -} -#endif - bool AXObjectCacheImpl::AddPendingEvent(const ui::AXEvent& event, bool insert_at_beginning) { if (insert_at_beginning)
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index aa7e93c..6702044 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -511,13 +511,6 @@ void UpdateAXForAllDocuments() override; -#if DCHECK_IS_ON() - // This is called after a node's included status changes, to update the - // included_node_count_ which is used to debug tree mismatches between the the - // AXObjectCache and AXTreeSerializer. - void UpdateIncludedNodeCount(const AXObject* obj); -#endif - protected: void PostPlatformNotification( AXObject* obj, @@ -679,13 +672,6 @@ // in which case there is nothing to be serialized. AXObject* GetSerializationTarget(AXObject* obj); -#if DCHECK_IS_ON() - // Check that the number of nodes known by the serializer is the same as the - // current number of included objects. - void CheckTreeConsistency(); - size_t RecursiveIncludedNodeCount(AXObject*); -#endif - // Helper that clears children up to the first included ancestor and returns // the ancestor if a children changed notification should be fired on it. AXObject* InvalidateChildren(AXObject* obj); @@ -701,10 +687,7 @@ HeapHashMap<Member<const LayoutObject>, AXID> layout_object_mapping_; HeapHashMap<Member<const Node>, AXID> node_object_mapping_; HashMap<AbstractInlineTextBox*, AXID> inline_text_box_object_mapping_; - int modification_count_ = 0; -#if DCHECK_IS_ON() - size_t included_node_count_ = 0; -#endif + int modification_count_; // Used for a mock AXObject representing the message displayed in the // validation message bubble.
diff --git a/third_party/blink/renderer/modules/canvas/OWNERS b/third_party/blink/renderer/modules/canvas/OWNERS index ded0a72..2d58b15 100644 --- a/third_party/blink/renderer/modules/canvas/OWNERS +++ b/third_party/blink/renderer/modules/canvas/OWNERS
@@ -1,6 +1,5 @@ fserb@chromium.org aaronhk@chromium.org jpgravel@chromium.org -juanmihd@chromium.org junov@chromium.org yiyix@chromium.org
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc index 818c640..5f665bf 100644 --- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc +++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_processor_test.cc
@@ -168,7 +168,7 @@ EXPECT_EQ(config.noise_suppression.level, webrtc::AudioProcessing::Config::NoiseSuppression::kHigh); -#if BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) // Android uses echo cancellation optimized for mobiles, and does not // support keytap suppression. EXPECT_TRUE(config.echo_canceller.mobile_mode);
diff --git a/third_party/blink/renderer/modules/webgpu/external_texture_helper.cc b/third_party/blink/renderer/modules/webgpu/external_texture_helper.cc index 4525faa..209ed1b 100644 --- a/third_party/blink/renderer/modules/webgpu/external_texture_helper.cc +++ b/third_party/blink/renderer/modules/webgpu/external_texture_helper.cc
@@ -242,10 +242,12 @@ WGPUExternalTextureDescriptor external_texture_desc = {}; - // Set ExternalTexture visibleSize and visibleOrigin + // Set ExternalTexture visibleSize and visibleOrigin. 0-copy path + // uses this metadata. gfx::Rect visible_rect = media_video_frame->visible_rect(); DCHECK(visible_rect.x() >= 0 && visible_rect.y() >= 0 && visible_rect.width() >= 0 && visible_rect.height() >= 0); + external_texture_desc.visibleOrigin = { static_cast<uint32_t>(visible_rect.x()), static_cast<uint32_t>(visible_rect.y())}; @@ -335,7 +337,19 @@ context_provider_wrapper->ContextProvider()->IsContextLost()) return external_texture; - const auto intrinsic_size = media_video_frame->natural_size(); + // In 0-copy path, uploading shares the whole frame into dawn and apply + // visible rect and sample from it. For 1-copy path, we should obey the + // same behaviour by: + // - Get recycle cache with video frame visible size. + // - Draw video frame visible rect into recycle cache, uses visible size. + // - Reset origin of visible rect in ExternalTextureDesc and use internal + // shader to + // handle visible rect. + const auto intrinsic_size = + gfx::Size(media_video_frame->visible_rect().width(), + media_video_frame->visible_rect().height()); + + external_texture_desc.visibleOrigin = {}; // Try to workaround crbug.com/1407112 by keeping no color space conversion // DrawVideoFrameIntoResourceProvider by setting the canvas resource's @@ -375,7 +389,7 @@ // DrawVideoFrameIntoResourceProvider() creates local_video_renderer always. // This might affect performance, maybe a cache local_video_renderer could // help. - const auto dest_rect = gfx::Rect(media_video_frame->natural_size()); + const auto dest_rect = gfx::Rect(intrinsic_size); if (!DrawVideoFrameIntoResourceProvider( std::move(media_video_frame), resource_provider, raster_context_provider, dest_rect, video_renderer)) {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc index 209b0b9..f00cc61 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
@@ -23,6 +23,7 @@ X(maxStorageBuffersPerShaderStage) \ X(maxStorageTexturesPerShaderStage) \ X(maxUniformBuffersPerShaderStage) \ + X(maxFragmentCombinedOutputResources) \ X(maxUniformBufferBindingSize) \ X(maxStorageBufferBindingSize) \ X(minUniformBufferOffsetAlignment) \
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h index f617ac0..5139529 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h +++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
@@ -42,6 +42,7 @@ unsigned maxStorageBuffersPerShaderStage() const; unsigned maxStorageTexturesPerShaderStage() const; unsigned maxUniformBuffersPerShaderStage() const; + unsigned maxFragmentCombinedOutputResources() const; uint64_t maxUniformBufferBindingSize() const; uint64_t maxStorageBufferBindingSize() const; unsigned minUniformBufferOffsetAlignment() const;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl index 01e9683a7..6c1f0f5c 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl +++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
@@ -21,6 +21,7 @@ readonly attribute unsigned long maxStorageBuffersPerShaderStage; readonly attribute unsigned long maxStorageTexturesPerShaderStage; readonly attribute unsigned long maxUniformBuffersPerShaderStage; + readonly attribute unsigned long maxFragmentCombinedOutputResources; readonly attribute unsigned long long maxUniformBufferBindingSize; readonly attribute unsigned long long maxStorageBufferBindingSize; readonly attribute unsigned long minUniformBufferOffsetAlignment;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index 3584ab68..f66ce17 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -629,6 +629,9 @@ DCHECK(!use_oop_rasterization_); if (ShouldReplaceTargetBuffer()) resource_ = NewOrRecycledResource(); + if (!resource() || !GetSkSurface()) { + return; + } resource()->CopyRenderingResultsToGpuMemoryBuffer( GetSkSurface()->makeImageSnapshot()); }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 14520930..5275971 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -699,6 +699,16 @@ base_feature: "none", }, { + // Support for the animation-delay-start and animation-delay-end + // properties. + // + // Additionally, animation-delay becomes a shorthand which expands + // to those properties. + name: "CSSAnimationDelayStartEnd", + depends_on: ["CSSScrollTimeline"], + status: "test", + }, + { // Whether <image> values are allowed as counter style <symbol> name: "CSSAtRuleCounterStyleImageSymbols", base_feature: "none", @@ -1352,6 +1362,12 @@ base_feature: "none", }, { + // Kill-switch for fixes to a bug that detached input elements are retained. + // See crbug.com/1413100 + name: "DontLeakDetachedInput", + status: "stable", + }, + { name: "EarlyHintsPreloadForNavigationOptIn", origin_trial_feature_name: "EarlyHintsPreloadForNavigation", status: "stable",
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests index 5c3cb07..7cfe093 100644 --- a/third_party/blink/web_tests/SlowTests +++ b/third_party/blink/web_tests/SlowTests
@@ -1459,6 +1459,3 @@ crbug.com/1404951 external/wpt/credential-management/fedcm-network-requests.https.html [ Slow ] crbug.com/1404951 external/wpt/credential-management/fedcm-iframe.https.html [ Slow ] - -crbug.com/1422630 external/wpt/long-animation-frame/tentative/loaf-promise.html [ Slow ] -crbug.com/1422630 external/wpt/long-animation-frame/tentative/loaf-script-block.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index c586c4b5..41c530c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2910,6 +2910,8 @@ crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html [ Failure ] +crbug.com/626703 virtual/threaded/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html [ Failure ] crbug.com/626703 [ Linux ] virtual/shared-storage-fenced-frame-mparch-selecturl-limit/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit-multiple-origins.https.html [ Timeout ] crbug.com/626703 [ Mac12 ] virtual/shared-storage-fenced-frame-mparch-selecturl-limit/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit-multiple-origins.https.html [ Timeout ] crbug.com/626703 external/wpt/css/css-rhythm/block-step-size-establishes-independent-formatting-context-list-item.html [ Failure ] @@ -6872,5 +6874,5 @@ crbug.com/1409713 virtual/view-transition-wide-gamut/external/wpt/css/css-view-transitions/content-with-clip-max-texture-size.html [ Failure ] # Sheriff 2023-02-08 -crbug.com/1404951 external/wpt/credential-management/fedcm-network-requests.https.html [ Failure ] -crbug.com/1404951 external/wpt/credential-management/fedcm-iframe.https.html [ Failure ] +crbug.com/1422630 external/wpt/long-animation-frame/tentative/loaf-promise.html [ Failure ] +crbug.com/1422630 external/wpt/long-animation-frame/tentative/loaf-script-block.html [ Failure ]
diff --git a/third_party/blink/web_tests/editing/inserting/typing-leaks-detached-input.html b/third_party/blink/web_tests/editing/inserting/typing-leaks-detached-input.html new file mode 100644 index 0000000..20373df2 --- /dev/null +++ b/third_party/blink/web_tests/editing/inserting/typing-leaks-detached-input.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<title>Tests that typing should not retain detached subtree</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + +<div id="root"></div> + +<script> +const n = 50; + +function createSubtree() { + let last = document.createElement('div'); + last.spellcheck = false; + last.contentEditable = true; + last.id = 'target'; + for (let i = 0; i < n; ++i) { + let div = document.createElement('div'); + div.appendChild(last); + last = div; + } + root.appendChild(last); +} + +function raf() { + return new Promise(resolve => requestAnimationFrame(resolve)); +} + +promise_setup(async () => { + assert_own_property(window, 'internals', 'This test requires internals') +}) + +promise_test(async () => { + gc(); + let nodesBefore = internals.numberOfLiveNodes(); + + createSubtree(); + document.getElementById('target').focus(); + document.execCommand('insertText', false, 'foo'); + assert_true(internals.hasLastEditCommand(document)); + + root.firstChild.remove(); + + await raf(); + await raf(); + + gc(); + let nodesAfter = internals.numberOfLiveNodes(); + + assert_less_than_equal(nodesAfter, nodesBefore); + assert_false(internals.hasLastEditCommand(document)); +}, 'Typing should not retain detached subtree'); + +promise_test(async () => { + createSubtree(); + document.getElementById('target').focus(); + document.execCommand('insertText', false, 'foo'); + document.getElementById('target').blur(); + assert_true(internals.hasLastEditCommand(document)); + + await raf(); + await raf(); + + gc(); + assert_true(internals.hasLastEditCommand(document)); +}, 'Last edit command should be retained if node is still connected'); +</script> + +</body>
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 d5325ac..0a31819 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
@@ -17095,149 +17095,6 @@ {} ] ], - "fixedpos-001-print.html": [ - "04feb96e8474bb638254bc0babc22fa378178f48", - [ - null, - [ - [ - "/css/css-break/fixedpos-001-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-002-print.html": [ - "c23c6be7d2a3bd2416b7c2765cd7654869918d54", - [ - null, - [ - [ - "/css/css-break/fixedpos-002-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-003-print.html": [ - "1b06257175fe3bc93a9205bbaa4c6ee38a778e9f", - [ - null, - [ - [ - "/css/css-break/fixedpos-003-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-004-print.html": [ - "c138e9cd6aa591657f65cd80859a8e9e4f33e132", - [ - null, - [ - [ - "/css/css-break/fixedpos-004-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-005-print.html": [ - "0a2edc71788aaa76305f1d17951e5499418709bd", - [ - null, - [ - [ - "/css/css-break/fixedpos-005-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-006-print.html": [ - "2386c166c81363a904c3e11dfac7dec4e0241029", - [ - null, - [ - [ - "/css/css-break/fixedpos-006-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-007-print.html": [ - "8dcb700b96d89c508f9e6696292c79a382a472a2", - [ - null, - [ - [ - "/css/css-break/fixedpos-007-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-008-print.html": [ - "02b5d63cc7cd500e8dafa2d7a7e966d2dc90c521", - [ - null, - [ - [ - "/css/css-break/fixedpos-008-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-with-abspos-with-link-print.html": [ - "057ddc91460264bbef9bb36fa7be8d89f6d6458e", - [ - null, - [ - [ - "/css/css-break/fixedpos-with-abspos-with-link-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-with-iframe-print.html": [ - "5102d045c4202e4bc22c6c876fd3bbbcf620c4b0", - [ - null, - [ - [ - "/css/css-break/fixedpos-with-iframe-print-ref.html", - "==" - ] - ], - {} - ] - ], - "fixedpos-with-link-with-inline-child-print.html": [ - "694e5376cbfab7ee52c1f27b9bf0fd23a2a91375", - [ - null, - [ - [ - "/css/css-break/fixedpos-with-link-with-inline-child-print-ref.html", - "==" - ] - ], - {} - ] - ], "flexbox": { "multi-line-row-flex-fragmentation-063-print.html": [ "1225792abac5a223be7c98cb298e979c1ceda3d7", @@ -17357,19 +17214,6 @@ {} ] ], - "page-name-001-print.html": [ - "56281bb4ed5f8b3e34401420b10504ed6c0e00fd", - [ - null, - [ - [ - "/css/css-break/page-name-001-print-ref.html", - "==" - ] - ], - {} - ] - ], "table": { "repeated-section": { "fixedpos-in-footer-forced-break-print.html": [ @@ -17677,6 +17521,149 @@ {} ] ], + "fixedpos-001-print.html": [ + "04feb96e8474bb638254bc0babc22fa378178f48", + [ + null, + [ + [ + "/css/printing/fixedpos-001-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-002-print.html": [ + "c23c6be7d2a3bd2416b7c2765cd7654869918d54", + [ + null, + [ + [ + "/css/printing/fixedpos-002-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-003-print.html": [ + "1b06257175fe3bc93a9205bbaa4c6ee38a778e9f", + [ + null, + [ + [ + "/css/printing/fixedpos-003-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-004-print.html": [ + "c138e9cd6aa591657f65cd80859a8e9e4f33e132", + [ + null, + [ + [ + "/css/printing/fixedpos-004-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-005-print.html": [ + "0a2edc71788aaa76305f1d17951e5499418709bd", + [ + null, + [ + [ + "/css/printing/fixedpos-005-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-006-print.html": [ + "2386c166c81363a904c3e11dfac7dec4e0241029", + [ + null, + [ + [ + "/css/printing/fixedpos-006-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-007-print.html": [ + "8dcb700b96d89c508f9e6696292c79a382a472a2", + [ + null, + [ + [ + "/css/printing/fixedpos-007-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-008-print.html": [ + "02b5d63cc7cd500e8dafa2d7a7e966d2dc90c521", + [ + null, + [ + [ + "/css/printing/fixedpos-008-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-with-abspos-with-link-print.html": [ + "057ddc91460264bbef9bb36fa7be8d89f6d6458e", + [ + null, + [ + [ + "/css/printing/fixedpos-with-abspos-with-link-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-with-iframe-print.html": [ + "5102d045c4202e4bc22c6c876fd3bbbcf620c4b0", + [ + null, + [ + [ + "/css/printing/fixedpos-with-iframe-print-ref.html", + "==" + ] + ], + {} + ] + ], + "fixedpos-with-link-with-inline-child-print.html": [ + "694e5376cbfab7ee52c1f27b9bf0fd23a2a91375", + [ + null, + [ + [ + "/css/printing/fixedpos-with-link-with-inline-child-print-ref.html", + "==" + ] + ], + {} + ] + ], "fragmented-inline-block-001-print.html": [ "848635431ecfc5ae3835cdc1f8398b1c04c95ed9", [ @@ -17724,6 +17711,19 @@ {} ] ], + "page-name-001-print.html": [ + "56281bb4ed5f8b3e34401420b10504ed6c0e00fd", + [ + null, + [ + [ + "/css/printing/page-name-001-print-ref.html", + "==" + ] + ], + {} + ] + ], "page-name-002-print.html": [ "060b93b0bf9ac4fbe380810f3e5dc981faa645a2", [ @@ -76267,6 +76267,19 @@ {} ] ], + "background-clip-padding-box-with-border-radius.html": [ + "8595caec7bb2d751dd87aebc777be84de6233af7", + [ + null, + [ + [ + "/css/css-backgrounds/reference/background-clip-padding-box-with-border-radius-ref.html", + "==" + ] + ], + {} + ] + ], "background-clip_padding-box.html": [ "354cbba90759471f886961d3b0e1a5202618d577", [ @@ -265650,11 +265663,11 @@ "support": { ".cache": { "gitignore2.json": [ - "ddaf6314467c922b9f2003184bfb637c6f9a337b", + "0fcc592c012d275cccf4ff6821f6bc3f3d5179e8", [] ], "mtime.json": [ - "e6cda80cd01d09cac42aa70ca4965b0f7044736c", + "17c2e6c03bfd81433d941bd6e02b8304856c89db", [] ] }, @@ -281700,6 +281713,10 @@ "81e95173e8ac9117215d1a1e4911c94cff586cdb", [] ], + "background-clip-padding-box-with-border-radius.html.ini": [ + "b3a742716a129bc32e4966baf739f6e84a76a94c", + [] + ], "background-color-body-propagation-ref.html": [ "1a138740de91c7aca95757c0b8daef0feef0b9d2", [] @@ -282627,6 +282644,10 @@ "dc6d9a00d53495e17f21adc8915176dd8c681e1e", [] ], + "background-clip-padding-box-with-border-radius-ref.html": [ + "545b80d35163b43e136d21f7584082b3b9401b38", + [] + ], "background-color-clip.html": [ "18e80a92586f241dbbe9d2a73991d78c98141071", [] @@ -283864,50 +283885,6 @@ "5c96f31a6ba193f6d86c7a66267581edd65260d2", [] ], - "fixedpos-001-print-ref.html": [ - "3d66305db0e7497f76dd6aa5a42217eb0931a87a", - [] - ], - "fixedpos-002-print-ref.html": [ - "3d66305db0e7497f76dd6aa5a42217eb0931a87a", - [] - ], - "fixedpos-003-print-ref.html": [ - "3d66305db0e7497f76dd6aa5a42217eb0931a87a", - [] - ], - "fixedpos-004-print-ref.html": [ - "3e3473bcb8e41ce1c4ac6aaf0006b25622b24bc3", - [] - ], - "fixedpos-005-print-ref.html": [ - "e692ff8db3764e05601348acfc2d4ce8314f41b5", - [] - ], - "fixedpos-006-print-ref.html": [ - "b03e1d78d003f33d1ad7810bcacf9cf407b95acb", - [] - ], - "fixedpos-007-print-ref.html": [ - "f576c9377153c3e48ce58d8fcd5428da0d705b23", - [] - ], - "fixedpos-008-print-ref.html": [ - "6ed2528115ae3a5634df6a2968a71fcd81424471", - [] - ], - "fixedpos-with-abspos-with-link-print-ref.html": [ - "000c05350b54885c47ea74a7336e02ed857d55ea", - [] - ], - "fixedpos-with-iframe-print-ref.html": [ - "5c1714045083dfc22272b0522273e7a7235cde6f", - [] - ], - "fixedpos-with-link-with-inline-child-print-ref.html": [ - "f12d31acd9d077a24a4ba47bcdbb5b2a3029faf3", - [] - ], "flexbox": { "flex-container-fragmentation-005.html.ini": [ "68711ec142d48cf8df22a5fc0bc61123fda79acf", @@ -284172,10 +284149,6 @@ "cf345b59638f28ddf423ed343a269178ab47f1b9", [] ], - "page-name-001-print-ref.html": [ - "69c5c37b5a3cc4ed47fab1f8105e5f2351e2d07b", - [] - ], "parallel-flow-trailing-margin-002.html.ini": [ "221f52f483a7a4465291e3ff8ae2cc1069ab29c1", [] @@ -321429,6 +321402,10 @@ "f57dc9971a753fc62dbe453c8256c6e759225333", [] ], + "kind-of-widget-fallback-input-search-text-border-bottom-style-001.html.ini": [ + "97d3e9abbd45580da8e8d11ceb56891c87c8ee75", + [] + ], "kind-of-widget-fallback-input-search-text-border-image-source-001.html.ini": [ "e19e35b9221c3f106b1db29f46c18acbd5e10c3a", [] @@ -321525,6 +321502,10 @@ "d6750fc55d3c62468cdf996e42b3ec95c92a26ee", [] ], + "kind-of-widget-fallback-input-text-border-bottom-left-radius-001.html.ini": [ + "bb2e69c02ea8b7f588e74283aea4c7209583362e", + [] + ], "kind-of-widget-fallback-input-text-border-bottom-right-radius-001.html.ini": [ "8cf94321dc1df346f82158550e4cd2ad2b5b6e3d", [] @@ -329834,6 +329815,50 @@ "305aa2fce2f490ef161c803558cc7a17bf7aa117", [] ], + "fixedpos-001-print-ref.html": [ + "3d66305db0e7497f76dd6aa5a42217eb0931a87a", + [] + ], + "fixedpos-002-print-ref.html": [ + "3d66305db0e7497f76dd6aa5a42217eb0931a87a", + [] + ], + "fixedpos-003-print-ref.html": [ + "3d66305db0e7497f76dd6aa5a42217eb0931a87a", + [] + ], + "fixedpos-004-print-ref.html": [ + "3e3473bcb8e41ce1c4ac6aaf0006b25622b24bc3", + [] + ], + "fixedpos-005-print-ref.html": [ + "e692ff8db3764e05601348acfc2d4ce8314f41b5", + [] + ], + "fixedpos-006-print-ref.html": [ + "b03e1d78d003f33d1ad7810bcacf9cf407b95acb", + [] + ], + "fixedpos-007-print-ref.html": [ + "f576c9377153c3e48ce58d8fcd5428da0d705b23", + [] + ], + "fixedpos-008-print-ref.html": [ + "6ed2528115ae3a5634df6a2968a71fcd81424471", + [] + ], + "fixedpos-with-abspos-with-link-print-ref.html": [ + "000c05350b54885c47ea74a7336e02ed857d55ea", + [] + ], + "fixedpos-with-iframe-print-ref.html": [ + "5c1714045083dfc22272b0522273e7a7235cde6f", + [] + ], + "fixedpos-with-link-with-inline-child-print-ref.html": [ + "f12d31acd9d077a24a4ba47bcdbb5b2a3029faf3", + [] + ], "fragmented-inline-block-002-print-ref.html": [ "dcfa3a1385628a90cb2d1be17e8bf6da09cde20e", [] @@ -329850,6 +329875,10 @@ "f4ea262fa5b4de4a0e30bdf9d89ed76f1da41242", [] ], + "page-name-001-print-ref.html": [ + "69c5c37b5a3cc4ed47fab1f8105e5f2351e2d07b", + [] + ], "page-name-002-print-ref.html": [ "17ecc93e57aee6910a524e3fa6b14ecc026f9b52", [] @@ -344196,6 +344225,10 @@ "f6468a026208668b3407234247731b85bdacec1d", [] ], + "open-features-non-integer-width.html.ini": [ + "7641fc2eee0a2798a057a7a6f2676aba8a3d060d", + [] + ], "open-features-tokenization-innerheight-innerwidth.html.ini": [ "0689c5196416b1c98615f0c6bf76f2b368d9d9a9", [] @@ -347570,6 +347603,10 @@ "d8bd3cb3a11dda94b9baf9340e83db21c6f01cae", [] ], + "navigate-to-aboutblank.https.html.ini": [ + "3cc4743616d9ae07387b3130e8e721687ae2379d", + [] + ], "navigate-top-to-aboutblank.https.html.ini": [ "7402249077ebcc4c12ced89498b38738ab3d3bd0", [] @@ -363400,7 +363437,7 @@ [] ], "cross-origin-iframe.sub.html.ini": [ - "cfa2645bf05abfe2f64fb4ad33b62c484f62cc60", + "004f0b64c9b047e6dcbba796907f0ca31bef0a7e", [] ], "idlharness.window-expected.txt": [ @@ -387349,6 +387386,10 @@ "10cfd651554a259817cd34521ab44556063f4f44", [] ], + "RTCRtpTransceiver-headerExtensionControl.html.ini": [ + "9b46e02b534528c26b52f463ca5d665ae0db1922", + [] + ], "transfer-datachannel-service-worker.https.html.ini": [ "e40f8621775d777dacb34fa2a3b75ad6191e1a29", [] @@ -388092,7 +388133,7 @@ [] ], "close.any.js.ini": [ - "a460aa08f08362ca69f1cbea86b33b7eba6b393f", + "330bbab903effe601fb6260df8229148d6b4f5de", [] ], "constructor.any.js.ini": [ @@ -658568,13 +658609,6 @@ {} ] ], - "background-clip-padding-box-with-border-radius.html": [ - "ee98dababbcce0d7fbee2f6b7eaff18bb78341e9", - [ - null, - {} - ] - ], "background-clip-root.html": [ "8f9f5f3ebd50137939e6f006e7cb068aa120863c", [
diff --git a/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-presentation.html b/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-presentation.html deleted file mode 100644 index 138625a1..0000000 --- a/third_party/blink/web_tests/external/wpt/accessibility/crashtests/aria-owns-presentation.html +++ /dev/null
@@ -1,3 +0,0 @@ -<!DOCTYPE html> -<div id="parent" aria-owns="owned"></div> -<div id="owned" role="none"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html index ee98dab..8595cae 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html
@@ -7,6 +7,7 @@ <link rel="author" title="Lea Verou" href="http://lea.verou.me" /> <link rel="help" href="http://www.w3.org/TR/css3-background/#the-background-clip" /> <link rel="help" href="http://www.w3.org/TR/css3-background/#corner-shaping" /> +<link rel="match" href="reference/background-clip-padding-box-with-border-radius-ref.html" /> <meta name="assert" content="Backgrounds clipped to the padding box should follow the padding box curve, which should be equal to the outer border radius minus the corresponding border thickness." /> <style> div {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html.ini b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html.ini new file mode 100644 index 0000000..b3a74271 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-clip-padding-box-with-border-radius.html.ini
@@ -0,0 +1,5 @@ +[background-clip-padding-box-with-border-radius.html] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == "highdpi"): PASS + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS + FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-clip-padding-box-with-border-radius-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-clip-padding-box-with-border-radius-ref.html new file mode 100644 index 0000000..545b80d3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-clip-padding-box-with-border-radius-ref.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference File</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + background-color: green; + border-radius: 30px; + height: 144px; + margin-left: 18px; + margin-top: 24px; + width: 144px; + } + + div + div + { + margin-top: 6px; + } + </style> + + <p>Test passes if there are two filled green rounded squares and <strong>no red</strong>. + + <div></div> + + <div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-style-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-style-001.html.ini new file mode 100644 index 0000000..97d3e9a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-bottom-style-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-search-text-border-bottom-style-001.html] + expected: + if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-bottom-left-radius-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-bottom-left-radius-001.html.ini new file mode 100644 index 0000000..bb2e69c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-text-border-bottom-left-radius-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-text-border-bottom-left-radius-001.html] + expected: + if (product == "content_shell") and (os == "mac"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/document-element-detatched-crash.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/document-element-detatched-crash.html new file mode 100644 index 0000000..3c5419a8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/document-element-detatched-crash.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<title>View transitions: documentElement.remove</title> +<link rel="help" href="https://github.com/WICG/view-transitions"> +<link rel="author" href="mailto:vmpstr@chromium.org"> + +<style> +html { + display: none; +} +</style> + +<script> +async function runTest() { + document.startViewTransition(() => { + requestAnimationFrame(() => document.documentElement.remove()); + }) + +} +onload = () => requestAnimationFrame(runTest); +</script> +
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-width.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-width.html.ini new file mode 100644 index 0000000..7641fc2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-width.html.ini
@@ -0,0 +1,3 @@ +[open-features-non-integer-width.html] + expected: + if product == "chrome": [TIMEOUT, OK, ERROR]
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html.ini b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html.ini new file mode 100644 index 0000000..3cc47436 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html.ini
@@ -0,0 +1,3 @@ +[navigate-to-aboutblank.https.html] + expected: + if product == "chrome": ERROR
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini b/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini index cfa2645..004f0b6 100644 --- a/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini +++ b/third_party/blink/web_tests/external/wpt/intersection-observer/cross-origin-iframe.sub.html.ini
@@ -1,21 +1,22 @@ [cross-origin-iframe.sub.html] [First rAF] expected: - if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS] + if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL + if (product == "content_shell") and (os == "mac"): FAIL [iframeDocument.scrollingElement.scrollTop = 250] expected: - if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS] - if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL if (product == "content_shell") and (os == "linux") and (flag_specific == ""): FAIL - if (product == "content_shell") and (os == "mac"): FAIL + if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL + if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL + if (product == "content_shell") and (os == "mac"): [FAIL, PASS] [topDocument.scrollingElement.scrollTop = 100] expected: if (product == "content_shell") and (os == "win"): FAIL - if (product == "content_shell") and (os == "mac"): FAIL + if (product == "content_shell") and (os == "mac"): [FAIL, PASS] [topDocument.scrollingElement.scrollTop = 200] expected: - if (product == "content_shell") and (os == "win") and (port == "win11"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac"): [FAIL, PASS] FAIL
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouse-pointer-preventdefault-passive.html b/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouse-pointer-preventdefault-passive.html new file mode 100644 index 0000000..57da0968 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/pointerevents/compat/pointerevent_mouse-pointer-preventdefault-passive.html
@@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<title>Canceling passive pointerevents does not affect compat mouseevents</title> +<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="/resources/testdriver-actions.js"></script> +<script src="../pointerevent_support.js"></script> +<style> + div { + margin: 20px; + padding: 20px; + background-color: green; + user-select: none; // Prevents text selection on drag. + } +</style> +<div id="logger" draggable="false"></div> +<div id="done"></div> + +<script> + 'use strict'; + + const logger = document.getElementById("logger"); + const done = document.getElementById("done"); + + let received_events = []; + + const logged_pointer_events = ["pointerdown", "pointermove", "pointerup", + "pointerenter", "pointerleave", "pointerover", "pointerout"]; + const logged_mouse_events = ["mousedown", "mousemove", "mouseup", + "mouseenter", "mouseleave", "mouseover", "mouseout"]; + + const expected_pointer_events = [ + "pointerover", "pointerenter", + "pointermove", "pointerdown", "pointermove", "pointerup", + "pointerout", "pointerleave" + ]; + + const expected_mouse_events = [ + "mouseover", "mouseenter", + "mousemove", "mousedown", "mousemove", "mouseup", + "mouseout", "mouseleave" + ]; + + logged_pointer_events.forEach(ename => logger.addEventListener(ename, e => { + received_events.push(e.type); + e.preventDefault(); + }, { passive: true })); + + logged_mouse_events.forEach(ename => logger.addEventListener(ename, e => + received_events.push(e.type))); + + promise_test(async () => { + received_events = []; + + let click_on_done = getEvent("click", done); + + let actions = new test_driver.Actions() + // Start outside all event listeners + .pointerMove(0, 0) + .pointerDown() + .pointerUp() + // Drag within "logger" + .pointerMove(0, 0, { origin: logger }) + .pointerDown() + .pointerMove(15, 15, { origin: logger }) + .pointerUp() + // Click "done" + .pointerMove(0, 0, { origin: done }) + .pointerDown() + .pointerUp() + .send(); + + await actions; + await click_on_done; + + assert_array_equals(received_events.filter(isPointerEvent), + expected_pointer_events, "expected pointer events"); + assert_array_equals(received_events.filter(isMouseEvent), + expected_mouse_events, "expected mouse events"); + assert_true(arePointerEventsBeforeCompatMouseEvents(received_events), + "pairing of pointer/mouse events"); + }, "Canceling passive pointerevents does not affect compat mouseevents"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html.ini b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html.ini new file mode 100644 index 0000000..9b46e02 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webrtc-extensions/RTCRtpTransceiver-headerExtensionControl.html.ini
@@ -0,0 +1,5 @@ +[RTCRtpTransceiver-headerExtensionControl.html] + [setHeaderExtensionsToNegotiate throws NotSupported on encountering unknown URI] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == "highdpi"): PASS + FAIL
diff --git a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/close.any.js.ini b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/close.any.js.ini index a460aa0..330bbab 100644 --- a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/close.any.js.ini +++ b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/close.any.js.ini
@@ -1,5 +1,13 @@ [close.any.html?wpt_flags=h2] expected: TIMEOUT +[close.any.serviceworker.html?wpt_flags=h2] + expected: + if (product == "content_shell") and (os == "mac"): [TIMEOUT, OK] + +[close.any.sharedworker.html?wpt_flags=h2] + expected: + if (product == "content_shell") and (os == "mac"): [TIMEOUT, OK] + [close.any.worker.html?wpt_flags=h2] expected: [TIMEOUT, OK]
diff --git a/third_party/blink/web_tests/fast/reflections/reflection-masks-expected.png b/third_party/blink/web_tests/fast/reflections/reflection-masks-expected.png index 04bbf03..173f521 100644 --- a/third_party/blink/web_tests/fast/reflections/reflection-masks-expected.png +++ b/third_party/blink/web_tests/fast/reflections/reflection-masks-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png b/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png index 6bed6aa..a494426 100644 --- a/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png +++ b/third_party/blink/web_tests/fast/reflections/reflection-masks-opacity-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/fast/borders/border-image-outset-expected.png b/third_party/blink/web_tests/flag-specific/highdpi/fast/borders/border-image-outset-expected.png index b466166..e9d4c83ce 100644 --- a/third_party/blink/web_tests/flag-specific/highdpi/fast/borders/border-image-outset-expected.png +++ b/third_party/blink/web_tests/flag-specific/highdpi/fast/borders/border-image-outset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/mix-blend-mode-isolated-group-3-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/mix-blend-mode-isolated-group-3-expected.png index 5dc934d..3b5f425 100644 --- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/mix-blend-mode-isolated-group-3-expected.png +++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/css3/blending/mix-blend-mode-isolated-group-3-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/color-profile-border-image-expected.png index 34808d7..031475f2 100644 --- a/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/flag-specific/skia-vulkan-swiftshader/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/images/color-profile-border-image-expected.png index a7cd2e4..26e56443 100644 --- a/third_party/blink/web_tests/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-expected.png index 483017c..e546284 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png index 34808d7..031475f2 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png deleted file mode 100644 index 5a68b73..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/sprite-no-bleed-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/borders/border-image-repeat-round-expected.png b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/borders/border-image-repeat-round-expected.png index 560b83da..c6dcaf8 100644 --- a/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/borders/border-image-repeat-round-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac11-arm64/fast/borders/border-image-repeat-round-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/borders/border-image-repeat-round-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/borders/border-image-repeat-round-expected.png index 560b83da..c6dcaf8 100644 --- a/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/borders/border-image-repeat-round-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/fast/borders/border-image-repeat-round-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/gpu-rasterization/images/color-profile-border-image-expected.png new file mode 100644 index 0000000..cda8a9e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac12-arm64/virtual/gpu-rasterization/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-expected.png b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-expected.png index 64aa8bbcf..2081e5d 100644 --- a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-expected.png +++ b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png index 64aa8bbcf..2081e5d 100644 --- a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png +++ b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-repeat-round-expected.png b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-repeat-round-expected.png index b5568c7..3e01f71 100644 --- a/third_party/blink/web_tests/platform/mac/fast/borders/border-image-repeat-round-expected.png +++ b/third_party/blink/web_tests/platform/mac/fast/borders/border-image-repeat-round-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-expected.png b/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-expected.png index f5cfbce0..7e0e2b2 100644 --- a/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png index f5cfbce0..7e0e2b2 100644 --- a/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/borders/border-image-repeat-round-expected.png b/third_party/blink/web_tests/platform/win/fast/borders/border-image-repeat-round-expected.png index 8096eb4..69bbdb9f 100644 --- a/third_party/blink/web_tests/platform/win/fast/borders/border-image-repeat-round-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/borders/border-image-repeat-round-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/exotic-color-space/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/virtual/exotic-color-space/images/color-profile-border-image-expected.png index 73b9425d..d60aa69 100644 --- a/third_party/blink/web_tests/virtual/exotic-color-space/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/virtual/exotic-color-space/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png index d46c751..6a62101 100644 --- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png +++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-border-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini index d0ce9d2..87ac3f5 100644 --- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini +++ b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini
@@ -1,4 +1,2 @@ [root-element-transition.html] - expected: - if product == "chrome": ERROR - FAIL + expected: FAIL
diff --git a/tools/android/build_speed/benchmark.py b/tools/android/build_speed/benchmark.py index 1ae20915..5debd89 100755 --- a/tools/android/build_speed/benchmark.py +++ b/tools/android/build_speed/benchmark.py
@@ -206,6 +206,7 @@ finally: if file_path.exists(): file_path.unlink() + return file_backup_path = file_path.with_suffix('.backup') logging.info('Creating %s for backup', file_backup_path) # Move the original file and copy back to preserve metadata. @@ -408,13 +409,6 @@ return result -def _get_benchmark_for_name(name: str) -> Benchmark: - for benchmark in _BENCHMARKS: - if benchmark.name == name: - return benchmark - assert False, f'{name} is not a valid name.' - - def _parse_benchmarks(benchmarks: List[str]) -> Iterator[Benchmark]: for name in benchmarks: if name in _SUITES:
diff --git a/tools/cast3p/runtime.version b/tools/cast3p/runtime.version index 9e713e8..084044d 100644 --- a/tools/cast3p/runtime.version +++ b/tools/cast3p/runtime.version
@@ -1 +1 @@ -348205 +348461
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index e6505eea9..2e06bcc7 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py
@@ -710,7 +710,6 @@ .Append('Params& Params::operator=(Params&& rhs) = default;') .Append() .Cblock(self._GenerateFunctionParamsCreate(function)) - .Cblock(self._GenerateFunctionParamsCreateDeprecated(function)) ) # Results::Create function @@ -906,58 +905,6 @@ return c - def _GenerateFunctionParamsCreateDeprecated(self, function): - """Generate function to create an instance of Params. The generated - function takes a const base::Value::List& of arguments. - - E.g for function "Bar", generate Bar::Params::CreateDeprecated() - """ - c = Code() - - (c.Append('// static') - .Sblock('std::unique_ptr<Params> Params::CreateDeprecated(%s) {' % - self._GenerateParams([ - 'const base::Value::List& args'])) - ) - if self._generate_error_messages: - c.Append('DCHECK(error);') - - failure_value = 'nullptr' - (c.Concat(self._GenerateParamsCheck(function, 'args', failure_value)) - .Append('std::unique_ptr<Params> params(new Params());') - ) - - for param in function.params: - c.Concat(self._InitializePropertyToDefault(param, 'params')) - - for i, param in enumerate(function.params): - # Any failure will cause this function to return. If any argument is - # incorrect or missing, those following it are not processed. Note that - # for optional arguments, we allow missing arguments and proceed because - # there may be other arguments following it. - c.Append() - value_var = param.unix_name + '_value' - (c.Append('if (%(i)s < args.size() &&') - .Sblock(' !args[%(i)s].is_none()) {') - .Append('const base::Value& %(value_var)s = args[%(i)s];') - .Concat(self._GeneratePopulatePropertyFromValue( - param, value_var, 'params', failure_value)) - .Eblock('}') - ) - if not param.optional: - (c.Sblock('else {') - .Concat(self._AppendError16('u"\'%%(key)s\' is required"')) - .Append('return %s;' % failure_value) - .Eblock('}')) - c.Substitute({'value_var': value_var, 'i': i, 'key': param.name}) - (c.Append() - .Append('return params;') - .Eblock('}') - .Append() - ) - - return c - def _GeneratePopulatePropertyFromValue(self, prop, src_var,
diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py index 9fb02d1..7c71a7ef 100644 --- a/tools/json_schema_compiler/h_generator.py +++ b/tools/json_schema_compiler/h_generator.py
@@ -337,9 +337,6 @@ c = Code() (c.Sblock('struct Params {') - .Append('static std::unique_ptr<Params> CreateDeprecated(%s);' % - self._GenerateParams( - ('const base::Value::List& args',))) .Append('static absl::optional<Params> Create(%s);' % self._GenerateParams( ('const base::Value::List& args',)))
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index f8c11a8..f2c6b964 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -3496,6 +3496,12 @@ <int value="2" label="Federated service not connected"/> </enum> +<enum name="AppListFederatedSearchSessionConclusion"> + <int value="0" label="Quit"/> + <int value="1" label="Launch"/> + <int value="2" label="AnswerCardSeen"/> +</enum> + <enum name="AppListFolderOpened"> <int value="0" label="Original Folder Design"/> <int value="1" label="Peeking App List Folder Design"/> @@ -79166,6 +79172,8 @@ <int value="3" label="Username copied"/> <int value="4" label="Password copied"/> <int value="5" label="Password revealed"/> + <int value="6" label="Username edit button clicked"/> + <int value="7" label="Username added"/> </enum> <enum name="PasswordManager.AssistantStoppedBubble.CloseReason">
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml index d9e6bf0..d9f4486e 100644 --- a/tools/metrics/histograms/metadata/apps/histograms.xml +++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -989,6 +989,27 @@ </summary> </histogram> +<histogram name="Apps.AppList.Search.Federated.SearchSessionConclusion" + enum="AppListFederatedSearchSessionConclusion" expires_after="2023-09-01"> + <owner>amandadeacon@chromium.org</owner> + <owner>tby@chromium.org</owner> + <summary> + Tracks the conclusion of each search session starting from the search box. + Records launcher dismissals ("quit"), launches, and viewings of + answer card results, for the query list view when federated analytics is + enabled. + + Quit. Emitted if the user dismisses search without launching a result or + seeing an answer card. + + Launch. Emitted if the user launches a search result. + + AnswerCardSeen. Emitted if an answer card is displayed for some threshold + period of time, and the user then dismisses the launcher without launching a + result. + </summary> +</histogram> + <histogram name="Apps.AppList.Search.Session2.Error" enum="AppListUserEventError" expires_after="2024-01-31"> <owner>yulunwu@chromium.org</owner> @@ -2785,15 +2806,6 @@ </summary> </histogram> -<histogram name="Apps.RestoreNoGhostWindowReason" enum="ArcNoWindowReason" - expires_after="2023-04-16"> - <owner>nancylingwang@chromium.org</owner> - <owner>sstan@chromium.org</owner> - <summary> - Records the reason of ARC app launched without ghost window on ARC VM. - </summary> -</histogram> - <histogram name="Apps.RestoreNotification" enum="RestoreAction" expires_after="2023-08-20"> <owner>nancylingwang@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 6ef5f6d..d3afa364 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -3691,6 +3691,16 @@ </summary> </histogram> +<histogram name="Ash.NotificationView.ImageDrag.Start" + enum="NotificationCatalogName" expires_after="M121"> + <owner>andrewxu@chromium.org</owner> + <owner>cros-status-area-eng@google.com</owner> + <summary> + Records the notification catalog name when the notification image drag + starts. + </summary> +</histogram> + <histogram name="Ash.NotificationView.NotificationAdded.Type" enum="NotificationViewType" expires_after="2023-06-18"> <owner>leandre@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml index 6434db44..76eb718 100644 --- a/tools/metrics/histograms/metadata/compositing/histograms.xml +++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -438,6 +438,28 @@ </histogram> <histogram + name="Compositing.Display.OverlayProcessorUsingStrategy.FramesAttemptingRequiredOverlays" + units="boolean" expires_after="2023-06-30"> + <owner>zoraiznaeem@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Records once per frame, whether we will attempt to promote any required + overlay or not in that frame. + </summary> +</histogram> + +<histogram + name="Compositing.Display.OverlayProcessorUsingStrategy.FramesScalingRequiredOverlays" + units="boolean" expires_after="2023-06-30"> + <owner>zoraiznaeem@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Records zero or once per frame, whether we attempted scaling any required + overlay. + </summary> +</histogram> + +<histogram name="Compositing.Display.OverlayProcessorUsingStrategy.NumOverlays{Counted}" units="overlay candidates" expires_after="2022-11-30"> <owner>khaslett@chromium.org</owner> @@ -476,6 +498,18 @@ </summary> </histogram> +<histogram + name="Compositing.Display.OverlayProcessorUsingStrategy.WorkingScaleFactorForRequiredOverlays" + units="scale_factor" expires_after="2023-06-30"> + <owner>zoraiznaeem@chromium.org</owner> + <owner>graphics-dev@chromium.org</owner> + <summary> + Records the scale factor that is used to downscale successfully promoted + required candidates. It is only logged once per frame if a required overlay + is promoted. Note: The scale factor value is logged as `scale_factor * 100`. + </summary> +</histogram> + <histogram name="Compositing.Display.VizDependencyResolvedToGpuStartedDrawUs" units="microseconds" expires_after="2022-12-18"> <owner>vasilyt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 3020d43..afd0c98 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -800,7 +800,7 @@ </histogram> <histogram name="Media.Audio.Processing.CaptureDelayMs" units="ms" - expires_after="2023-08-20"> + expires_after="2023-09-07"> <owner>saza@google.com</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner> @@ -812,7 +812,7 @@ </histogram> <histogram name="Media.Audio.Processing.CaptureDelayVarianceMs" - units="ms squared" expires_after="2023-04-16"> + units="ms squared" expires_after="2023-09-07"> <owner>saza@chromium.org</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner> @@ -824,7 +824,7 @@ </histogram> <histogram name="Media.Audio.Processing.RenderDelayMs" units="ms" - expires_after="2023-08-20"> + expires_after="2023-09-07"> <owner>saza@chromium.org</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner> @@ -836,7 +836,7 @@ </histogram> <histogram name="Media.Audio.Processing.RenderDelayVarianceMs" - units="ms squared" expires_after="2023-04-16"> + units="ms squared" expires_after="2023-09-07"> <owner>saza@chromium.org</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner> @@ -848,7 +848,7 @@ </histogram> <histogram name="Media.Audio.Processing.TotalDelayMs" units="ms" - expires_after="2023-09-03"> + expires_after="2023-09-07"> <owner>saza@chromium.org</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner> @@ -859,7 +859,7 @@ </histogram> <histogram name="Media.Audio.Processing.TotalDelayVarianceMs" - units="ms squared" expires_after="2023-08-20"> + units="ms squared" expires_after="2023-09-07"> <owner>saza@chromium.org</owner> <owner>olka@chromium.org</owner> <owner>webrtc-audio-uma@google.com</owner>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 647593c..58bc181 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -52,9 +52,9 @@ power.desktop,brucedawson@chromium.org,,https://bit.ly/power-benchmarks, power.mobile,chrometto-team@google.com,,https://goto.google.com/power-mobile-benchmark,"2018,2019,2021,health_check,infinite_scroll,javascript_heavy" rasterize_and_record_micro.top_25,"pdr@chromium.org, wangxianzhu@chromium.org, vmpstr@chromium.org",Internals>Compositing>Rasterization,https://bit.ly/rasterize-and-record-benchmark, -rendering.desktop,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"backdrop_filter,gpu_rasterization,image_decoding,key_desktop_move,maps,motionmark,motionmark_ramp,repaint_desktop,representative_mac_desktop,representative_mobile,representative_win_desktop,required_webgl,simple_canvas,throughput_test,top_real_world_desktop,tough_animation,tough_canvas,tough_compositor,tough_filters,tough_path_rendering,tough_pinch_zoom,tough_scheduling,tough_scrollbar_scrolling,tough_scrolling,tough_texture_upload,tough_webgl,use_fake_camera_device" +rendering.desktop,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"backdrop_filter,gpu_rasterization,image_decoding,key_desktop_move,maps,motionmark,motionmark_fixed_2_seconds,motionmark_ramp,repaint_desktop,representative_mac_desktop,representative_mobile,representative_win_desktop,required_webgl,simple_canvas,throughput_test,top_real_world_desktop,tough_animation,tough_canvas,tough_compositor,tough_filters,tough_path_rendering,tough_pinch_zoom,tough_scheduling,tough_scrollbar_scrolling,tough_scrolling,tough_texture_upload,tough_webgl,use_fake_camera_device" rendering.desktop.notracing,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"motionmark,motionmark_ramp" -rendering.mobile,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"backdrop_filter,fastpath,gpu_rasterization,image_decoding,key_idle_power,key_noop,key_silk,maps,motionmark,motionmark_ramp,pathological_mobile_sites,representative_mac_desktop,representative_mobile,representative_win_desktop,required_webgl,simple_canvas,simple_mobile_sites,throughput_test,top_real_world_desktop,top_real_world_mobile,tough_animation,tough_canvas,tough_compositor,tough_filters,tough_path_rendering,tough_pinch_zoom_mobile,tough_scheduling,tough_scrollbar_scrolling,tough_scrolling,tough_texture_upload,tough_webgl,use_fake_camera_device" +rendering.mobile,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"backdrop_filter,fastpath,gpu_rasterization,image_decoding,key_idle_power,key_noop,key_silk,maps,motionmark,motionmark_fixed_2_seconds,motionmark_ramp,pathological_mobile_sites,representative_mac_desktop,representative_mobile,representative_win_desktop,required_webgl,simple_canvas,simple_mobile_sites,throughput_test,top_real_world_desktop,top_real_world_mobile,tough_animation,tough_canvas,tough_compositor,tough_filters,tough_path_rendering,tough_pinch_zoom_mobile,tough_scheduling,tough_scrollbar_scrolling,tough_scrolling,tough_texture_upload,tough_webgl,use_fake_camera_device" rendering.mobile.notracing,"jonross@chromium.org, chrome-gpu-metrics@google.com",Internals>GPU>Metrics,https://bit.ly/rendering-benchmarks,"motionmark,motionmark_ramp" resource_sizes_chromecast,"juke@chromium.org, eliribble@chromium.org",Chromecast,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py, resource_sizes_lacros_chrome,"erikchen@chromium.org, huangs@chromium.org",OS>LaCrOS,https://chromium.googlesource.com/chromium/src/+/HEAD/tools/binary_size/README.md#resource_sizes_py,
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 454070a..3159eeb 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -711,6 +711,9 @@ # Benchmark: system_health_smoke_test crbug.com/1354513 [ win ] system_health.memory_desktop/load:media:imgur:2018 [ Skip ] +# Skipped for everything except for PGO purposes. +crbug.com/1402260 rendering.desktop/motionmark_fixed* [ Skip ] + ##### Perf FYI benchmarks go after here ##### # Benchmark: loading.desktop_layout_ng crbug.com/879833 [ linux ] loading.desktop_layout_ng/Walgreens_cold [ Skip ]
diff --git a/tools/perf/page_sets/data/rendering_desktop.json b/tools/perf/page_sets/data/rendering_desktop.json index fc9fda7b4..b3f0942 100644 --- a/tools/perf/page_sets/data/rendering_desktop.json +++ b/tools/perf/page_sets/data/rendering_desktop.json
@@ -279,6 +279,33 @@ "motionmark_ramp_suits": { "DEFAULT": "rendering_common_c95200764f.wprgo" }, + "motionmark_fixed_2_seconds_canvas_arcs": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_canvas_lines": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_composite": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_design": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_images": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_leaves": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_multiply": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_paths": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, + "motionmark_fixed_2_seconds_suits": { + "DEFAULT": "rendering_common_c95200764f.wprgo" + }, "new_tilings": { "DEFAULT": "rendering_desktop_010.wprgo" },
diff --git a/tools/perf/page_sets/rendering/motionmark.py b/tools/perf/page_sets/rendering/motionmark.py index 705ab45f..476d0a92 100644 --- a/tools/perf/page_sets/rendering/motionmark.py +++ b/tools/perf/page_sets/rendering/motionmark.py
@@ -371,3 +371,85 @@ def WillStartTracing(self, chrome_trace_config): chrome_trace_config.record_mode = 'record-until-full' + + +class MotionMarkFixed2SecondsPage(MotionMarkPage): + ABSTRACT_STORY = True + TAGS = [story_tags.MOTIONMARK, story_tags.MOTIONMARK_FIXED_2_SECONDS] + SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS + + def RunPageInteractions(self, action_runner): + with action_runner.CreateInteraction('Filter'): + action_runner.Wait(2) + + # Navigate to about:blank to stop rendering frames and let the device + # cool down while the trace data for the story is processed. + action_runner.Navigate('about:blank') + + @classmethod + def GetFixed2SecondsUrl(cls, suite_name, test_name, complexity): + # Strip unwanted characters from names + for ch in [' ', '.', ',']: + suite_name = suite_name.replace(ch, '') + test_name = test_name.replace(ch, '') + + return ('https://browserbench.org/MotionMark1.2/developer.html' + '?suite-name=%s' + '&test-name=%s' + '&complexity=%d' + '&test-interval=1' + '&display=minimal' + '&tiles=big' + '&controller=fixed' + '&kalman-process-error=1' + '&kalman-measurement-error=4' + '&time-measurement=raf') % (suite_name, test_name, complexity) + + +#Numbers for complexity based on MotionMark score for chrome build without PGO +class MotionMarkFixed2SecondsMultiply(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_multiply' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', + 'Multiply', 1396) + + +class MotionMarkFixed2SecondsCanvasArcs(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_canvas_arcs' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', + 'Canvas Arcs', 6194) + + +class MotionMarkFixed2SecondsLeaves(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_leaves' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', 'Leaves', + 1377) + + +class MotionMarkFixed2SecondsPaths(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_paths' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', 'Paths', + 29172) + + +class MotionMarkFixed2SecondsCanvasLines(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_canvas_lines' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', + 'Canvas Lines', 16520) + + +class MotionMarkFixed2SecondsImages(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_images' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', 'Images', + 102) + + +class MotionMarkFixed2SecondsDesign(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_design' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', 'Design', + 213) + + +class MotionMarkFixed2SecondsSuits(MotionMarkFixed2SecondsPage): + BASE_NAME = 'motionmark_fixed_2_seconds_suits' + URL = MotionMarkFixed2SecondsPage.GetFixed2SecondsUrl('MotionMark', 'Suits', + 1299)
diff --git a/tools/perf/page_sets/rendering/story_tags.py b/tools/perf/page_sets/rendering/story_tags.py index 3da9adb..ddd1a1d 100644 --- a/tools/perf/page_sets/rendering/story_tags.py +++ b/tools/perf/page_sets/rendering/story_tags.py
@@ -41,6 +41,9 @@ 'Motionmark benchmark stories (fixed complexity)') MOTIONMARK_RAMP = Tag('motionmark_ramp', 'Motionmark benchmark stories (ramped complexity)') +MOTIONMARK_FIXED_2_SECONDS = Tag( + 'motionmark_fixed_2_seconds', + 'Motionmark benchmark stories running with fixed complexity for 2 seconds') PATHOLOGICAL_MOBILE_SITES = Tag( 'pathological_mobile_sites', 'Pathological mobile sites') REPAINT_DESKTOP = Tag(
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index b8ee318..02e2d4c 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -398,7 +398,7 @@ <item id="wallpaper_online_downloader" added_in_milestone="110" content_hash_code="07abedad" os_list="chromeos" file_path="ash/wallpaper/wallpaper_controller_impl.cc" /> <item id="fenced_frame_reporting_beacon" added_in_milestone="110" content_hash_code="03fd07f7" os_list="linux,windows,android,chromeos" file_path="content/browser/fenced_frame/fenced_frame_reporter.cc" /> <item id="password_sync_token_fetcher" added_in_milestone="110" content_hash_code="0268c983" os_list="chromeos" file_path="chrome/browser/ash/login/saml/password_sync_token_fetcher.cc" /> - <item id="projector_xhr_loader" added_in_milestone="110" content_hash_code="071c4ac5" os_list="chromeos" file_path="ash/webui/projector_app/projector_xhr_sender.cc" /> + <item id="projector_xhr_loader" added_in_milestone="110" content_hash_code="07e102c2" os_list="chromeos" file_path="ash/webui/projector_app/projector_xhr_sender.cc" /> <item id="cloud_speech_recognition" added_in_milestone="110" content_hash_code="00d56fd8" os_list="linux,windows,chromeos" file_path="components/live_caption/live_translate_controller.cc" /> <item id="bruschetta_installer_download" added_in_milestone="110" content_hash_code="073f0263" os_list="chromeos" file_path="chrome/browser/ash/bruschetta/bruschetta_installer_impl.cc" /> <item id="quick_start_session_auth_requester" added_in_milestone="110" content_hash_code="08353e70" os_list="chromeos" file_path="chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc" /> @@ -419,4 +419,5 @@ <item id="safe_browsing_hashprefix_realtime_lookup" added_in_milestone="111" content_hash_code="00aa24b2" os_list="linux,windows,chromeos,android" file_path="components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc" /> <item id="android_feedback_connectivity_checker" added_in_milestone="111" content_hash_code="0011753d" os_list="android" file_path="chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java" /> <item id="printer_config_fetch" added_in_milestone="111" content_hash_code="042f8883" os_list="chromeos" file_path="chromeos/printing/printer_config_cache.cc" /> + <item id="projector_xhr_loader_allow_cookie" added_in_milestone="112" content_hash_code="04a2140d" os_list="chromeos" file_path="ash/webui/projector_app/projector_xhr_sender.cc" /> </annotations>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml index 7d78e5c3..de88d5fe 100644 --- a/tools/traffic_annotation/summary/grouping.xml +++ b/tools/traffic_annotation/summary/grouping.xml
@@ -284,6 +284,7 @@ <annotation id="network_portal_detector"/> <annotation id="android_feedback_connectivity_checker"/> <annotation id="printer_config_fetch"/> + <annotation id="projector_xhr_loader_allow_cookie"/> </sender> </group> <group name="Admin Features" hidden="true">
diff --git a/tools/win/DebugVisualizers/chrome.natvis b/tools/win/DebugVisualizers/chrome.natvis index 3b30580..406d1691 100644 --- a/tools/win/DebugVisualizers/chrome.natvis +++ b/tools/win/DebugVisualizers/chrome.natvis
@@ -225,43 +225,79 @@ </Expand> </Type> <Type Name="base::Value" > - <DisplayString Condition="data_.index_==base::Value::NONE">None</DisplayString> - <DisplayString Condition="data_.index_==base::Value::BOOLEAN">Boolean {data_.state_.tail.head}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::INTEGER">Integer {data_.state_.tail.tail.head}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::DOUBLE">Double {*(double*)data_.state_.tail.tail.tail.head.v}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::STRING">String {data_.state_.tail.tail.tail.tail.head,na}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::BINARY">Binary</DisplayString> - <DisplayString Condition="data_.index_==base::Value::DICTIONARY">Dictionary {data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::LIST">List {data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_}</DisplayString> - <DisplayString Condition="data_.index_==base::Value::DEAD">Dead</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::NONE" Optional="true">None</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::BOOLEAN" Optional="true">Boolean {data_.state_.tail.head}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::INTEGER" Optional="true">Integer {data_.state_.tail.tail.head}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::DOUBLE" Optional="true">Double {*(double*)data_.state_.tail.tail.tail.head.v_}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::STRING" Optional="true">String {data_.state_.tail.tail.tail.tail.head,na}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::BINARY" Optional="true">Binary {data_.state_.tail.tail.tail.tail.tail.head}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::DICT" Optional="true">Dictionary {data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_}</DisplayString> + <DisplayString Condition="data_.index_ == base::Value::Type::LIST" Optional="true">List {data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_}</DisplayString> <DisplayString>Unknown type</DisplayString> <Expand > - <Item Condition="data_.index_==base::Value::BOOLEAN" Name="[Value]">data_.state_.tail.head</Item> - <Item Condition="data_.index_==base::Value::INTEGER" Name="[Value]">data_.state_.tail.tail.head</Item> - <Item Condition="data_.index_==base::Value::DOUBLE" Name="[Value]">*(double*)data_.state_.tail.tail.tail.head.v</Item> - <Item Condition="data_.index_==base::Value::STRING" Name="[String]">data_.state_.tail.tail.tail.tail.head,na</Item> + <Item Condition="data_.index_ == base::Value::Type::BOOLEAN" Name="[value]" Optional="true"> + data_.state_.tail.head + </Item> + <Item Condition="data_.index_ == base::Value::Type::INTEGER" Name="[value]" Optional="true"> + data_.state_.tail.tail.head + </Item> + <Item Condition="data_.index_ == base::Value::Type::DOUBLE" Name="[value]" Optional="true"> + *(double*)data_.state_.tail.tail.tail.head.v_ + </Item> + <Item Condition="data_.index_ == base::Value::Type::STRING" Name="[value]" Optional="true"> + data_.state_.tail.tail.tail.tail.head,na + </Item> + <Item Condition="data_.index_ == base::Value::Type::BINARY" Name="[value]" Optional="true"> + data_.state_.tail.tail.tail.tail.tail.head + </Item> <!-- Dictionary --> - <Item Condition="data_.index_==base::Value::DICTIONARY" Name="[size]"> - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__end_ - - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_ </Item> - <ArrayItems Condition="data_.index_==base::Value::DICTIONARY"> + <Item Condition="data_.index_ == base::Value::Type::DICT" Name="[size]" Optional="true"> + data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_.__end_ - + data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_.__begin_ + </Item> + <ArrayItems Condition="data_.index_ == base::Value::Type::DICT" Optional="true"> <Size> - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__end_ - - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_ + data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_.__end_ - + data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_.__begin_ </Size> - <ValuePointer>data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_</ValuePointer> + <ValuePointer> + data_.state_.tail.tail.tail.tail.tail.tail.head.storage_.body_.__begin_ + </ValuePointer> </ArrayItems> <!-- List --> - <Item Condition="data_.index_==base::Value::LIST" Name="[size]"> - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__end_ - - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_ </Item> - <ArrayItems Condition="data_.index_==base::Value::LIST"> + <Item Condition="data_.index_ == base::Value::Type::LIST" Name="[size]" Optional="true"> + data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_.__end_ - + data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_.__begin_ + </Item> + <ArrayItems Condition="data_.index_ == base::Value::Type::LIST" Optional="true"> <Size> - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__end_ - - data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_ + data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_.__end_ - + data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_.__begin_ </Size> - <ValuePointer>(base::Value*)data_.state_.tail.tail.tail.tail.tail.tail.head.impl_.body_.__begin_</ValuePointer> + <ValuePointer> + data_.state_.tail.tail.tail.tail.tail.tail.tail.head.storage_.__begin_ + </ValuePointer> </ArrayItems> </Expand> </Type> + <Type Name="base::Value::Dict" > + <DisplayString>Dictionary {storage_.body_}</DisplayString> + <Expand > + <Item Name="[size]">storage_.body_.__end_ - storage_.body_.__begin_</Item> + <ArrayItems> + <Size>storage_.body_.__end_ - storage_.body_.__begin_</Size> + <ValuePointer>storage_.body_.__begin_</ValuePointer> + </ArrayItems> + </Expand> + </Type> + <Type Name="base::Value::List" > + <DisplayString>List {storage_}</DisplayString> + <Expand > + <Item Name="[size]">storage_.__end_ - storage_.__begin_</Item> + <ArrayItems> + <Size>storage_.__end_ - storage_.__begin_</Size> + <ValuePointer>storage_.__begin_</ValuePointer> + </ArrayItems> + </Expand> + </Type> </AutoVisualizer>
diff --git a/ui/accessibility/ax_enum_util.cc b/ui/accessibility/ax_enum_util.cc index 41f0ff4..f6e87799 100644 --- a/ui/accessibility/ax_enum_util.cc +++ b/ui/accessibility/ax_enum_util.cc
@@ -561,6 +561,434 @@ return ""; } +ax::mojom::Role StringToRole(const std::string& role) { + if (role == "kNone") { + return ax::mojom::Role::kNone; + } else if (role == "kAbbr") { + return ax::mojom::Role::kAbbr; + } else if (role == "kAlertDialog") { + return ax::mojom::Role::kAlertDialog; + } else if (role == "kAlert") { + return ax::mojom::Role::kAlert; + } else if (role == "kApplication") { + return ax::mojom::Role::kApplication; + } else if (role == "kArticle") { + return ax::mojom::Role::kArticle; + } else if (role == "kAudio") { + return ax::mojom::Role::kAudio; + } else if (role == "kBanner") { + return ax::mojom::Role::kBanner; + } else if (role == "kBlockquote") { + return ax::mojom::Role::kBlockquote; + } else if (role == "kButton") { + return ax::mojom::Role::kButton; + } else if (role == "kCanvas") { + return ax::mojom::Role::kCanvas; + } else if (role == "kCaption") { + return ax::mojom::Role::kCaption; + } else if (role == "kCaret") { + return ax::mojom::Role::kCaret; + } else if (role == "kCell") { + return ax::mojom::Role::kCell; + } else if (role == "kCheckBox") { + return ax::mojom::Role::kCheckBox; + } else if (role == "kClient") { + return ax::mojom::Role::kClient; + } else if (role == "kCode") { + return ax::mojom::Role::kCode; + } else if (role == "kColorWell") { + return ax::mojom::Role::kColorWell; + } else if (role == "kColumnHeader") { + return ax::mojom::Role::kColumnHeader; + } else if (role == "kColumn") { + return ax::mojom::Role::kColumn; + } else if (role == "kComboBoxGrouping") { + return ax::mojom::Role::kComboBoxGrouping; + } else if (role == "kComboBoxMenuButton") { + return ax::mojom::Role::kComboBoxMenuButton; + } else if (role == "kComboBoxSelect") { + return ax::mojom::Role::kComboBoxSelect; + } else if (role == "kComment") { + return ax::mojom::Role::kComment; + } else if (role == "kComplementary") { + return ax::mojom::Role::kComplementary; + } else if (role == "kContentDeletion") { + return ax::mojom::Role::kContentDeletion; + } else if (role == "kContentInsertion") { + return ax::mojom::Role::kContentInsertion; + } else if (role == "kContentInfo") { + return ax::mojom::Role::kContentInfo; + } else if (role == "kDate") { + return ax::mojom::Role::kDate; + } else if (role == "kDateTime") { + return ax::mojom::Role::kDateTime; + } else if (role == "kDefinition") { + return ax::mojom::Role::kDefinition; + } else if (role == "kDescriptionListDetail") { + return ax::mojom::Role::kDescriptionListDetail; + } else if (role == "kDescriptionList") { + return ax::mojom::Role::kDescriptionList; + } else if (role == "kDescriptionListTerm") { + return ax::mojom::Role::kDescriptionListTerm; + } else if (role == "kDesktop") { + return ax::mojom::Role::kDesktop; + } else if (role == "kDetails") { + return ax::mojom::Role::kDetails; + } else if (role == "kDialog") { + return ax::mojom::Role::kDialog; + } else if (role == "kDirectory") { + return ax::mojom::Role::kDirectory; + } else if (role == "kDisclosureTriangle") { + return ax::mojom::Role::kDisclosureTriangle; + } else if (role == "kDocAbstract") { + return ax::mojom::Role::kDocAbstract; + } else if (role == "kDocAcknowledgments") { + return ax::mojom::Role::kDocAcknowledgments; + } else if (role == "kDocAfterword") { + return ax::mojom::Role::kDocAfterword; + } else if (role == "kDocAppendix") { + return ax::mojom::Role::kDocAppendix; + } else if (role == "kDocBackLink") { + return ax::mojom::Role::kDocBackLink; + } else if (role == "kDocBiblioEntry") { + return ax::mojom::Role::kDocBiblioEntry; + } else if (role == "kDocBibliography") { + return ax::mojom::Role::kDocBibliography; + } else if (role == "kDocBiblioRef") { + return ax::mojom::Role::kDocBiblioRef; + } else if (role == "kDocChapter") { + return ax::mojom::Role::kDocChapter; + } else if (role == "kDocColophon") { + return ax::mojom::Role::kDocColophon; + } else if (role == "kDocConclusion") { + return ax::mojom::Role::kDocConclusion; + } else if (role == "kDocCover") { + return ax::mojom::Role::kDocCover; + } else if (role == "kDocCredit") { + return ax::mojom::Role::kDocCredit; + } else if (role == "kDocCredits") { + return ax::mojom::Role::kDocCredits; + } else if (role == "kDocDedication") { + return ax::mojom::Role::kDocDedication; + } else if (role == "kDocEndnote") { + return ax::mojom::Role::kDocEndnote; + } else if (role == "kDocEndnotes") { + return ax::mojom::Role::kDocEndnotes; + } else if (role == "kDocEpigraph") { + return ax::mojom::Role::kDocEpigraph; + } else if (role == "kDocEpilogue") { + return ax::mojom::Role::kDocEpilogue; + } else if (role == "kDocErrata") { + return ax::mojom::Role::kDocErrata; + } else if (role == "kDocExample") { + return ax::mojom::Role::kDocExample; + } else if (role == "kDocFootnote") { + return ax::mojom::Role::kDocFootnote; + } else if (role == "kDocForeword") { + return ax::mojom::Role::kDocForeword; + } else if (role == "kDocGlossary") { + return ax::mojom::Role::kDocGlossary; + } else if (role == "kDocGlossRef") { + return ax::mojom::Role::kDocGlossRef; + } else if (role == "kDocIndex") { + return ax::mojom::Role::kDocIndex; + } else if (role == "kDocIntroduction") { + return ax::mojom::Role::kDocIntroduction; + } else if (role == "kDocNoteRef") { + return ax::mojom::Role::kDocNoteRef; + } else if (role == "kDocNotice") { + return ax::mojom::Role::kDocNotice; + } else if (role == "kDocPageBreak") { + return ax::mojom::Role::kDocPageBreak; + } else if (role == "kDocPageFooter") { + return ax::mojom::Role::kDocPageFooter; + } else if (role == "kDocPageHeader") { + return ax::mojom::Role::kDocPageHeader; + } else if (role == "kDocPageList") { + return ax::mojom::Role::kDocPageList; + } else if (role == "kDocPart") { + return ax::mojom::Role::kDocPart; + } else if (role == "kDocPreface") { + return ax::mojom::Role::kDocPreface; + } else if (role == "kDocPrologue") { + return ax::mojom::Role::kDocPrologue; + } else if (role == "kDocPullquote") { + return ax::mojom::Role::kDocPullquote; + } else if (role == "kDocQna") { + return ax::mojom::Role::kDocQna; + } else if (role == "kDocSubtitle") { + return ax::mojom::Role::kDocSubtitle; + } else if (role == "kDocTip") { + return ax::mojom::Role::kDocTip; + } else if (role == "kDocToc") { + return ax::mojom::Role::kDocToc; + } else if (role == "kDocument") { + return ax::mojom::Role::kDocument; + } else if (role == "kEmbeddedObject") { + return ax::mojom::Role::kEmbeddedObject; + } else if (role == "kEmphasis") { + return ax::mojom::Role::kEmphasis; + } else if (role == "kFeed") { + return ax::mojom::Role::kFeed; + } else if (role == "kFigcaption") { + return ax::mojom::Role::kFigcaption; + } else if (role == "kFigure") { + return ax::mojom::Role::kFigure; + } else if (role == "kFooter") { + return ax::mojom::Role::kFooter; + } else if (role == "kFooterAsNonLandmark") { + return ax::mojom::Role::kFooterAsNonLandmark; + } else if (role == "kForm") { + return ax::mojom::Role::kForm; + } else if (role == "kGenericContainer") { + return ax::mojom::Role::kGenericContainer; + } else if (role == "kGraphicsDocument") { + return ax::mojom::Role::kGraphicsDocument; + } else if (role == "kGraphicsObject") { + return ax::mojom::Role::kGraphicsObject; + } else if (role == "kGraphicsSymbol") { + return ax::mojom::Role::kGraphicsSymbol; + } else if (role == "kGrid") { + return ax::mojom::Role::kGrid; + } else if (role == "kGroup") { + return ax::mojom::Role::kGroup; + } else if (role == "kHeader") { + return ax::mojom::Role::kHeader; + } else if (role == "kHeaderAsNonLandmark") { + return ax::mojom::Role::kHeaderAsNonLandmark; + } else if (role == "kHeading") { + return ax::mojom::Role::kHeading; + } else if (role == "kIframe") { + return ax::mojom::Role::kIframe; + } else if (role == "kIframePresentational") { + return ax::mojom::Role::kIframePresentational; + } else if (role == "kImage") { + return ax::mojom::Role::kImage; + } else if (role == "kImeCandidate") { + return ax::mojom::Role::kImeCandidate; + } else if (role == "kInlineTextBox") { + return ax::mojom::Role::kInlineTextBox; + } else if (role == "kInputTime") { + return ax::mojom::Role::kInputTime; + } else if (role == "kKeyboard") { + return ax::mojom::Role::kKeyboard; + } else if (role == "kLabelText") { + return ax::mojom::Role::kLabelText; + } else if (role == "kLayoutTable") { + return ax::mojom::Role::kLayoutTable; + } else if (role == "kLayoutTableCell") { + return ax::mojom::Role::kLayoutTableCell; + } else if (role == "kLayoutTableRow") { + return ax::mojom::Role::kLayoutTableRow; + } else if (role == "kLegend") { + return ax::mojom::Role::kLegend; + } else if (role == "kLineBreak") { + return ax::mojom::Role::kLineBreak; + } else if (role == "kLink") { + return ax::mojom::Role::kLink; + } else if (role == "kList") { + return ax::mojom::Role::kList; + } else if (role == "kListBoxOption") { + return ax::mojom::Role::kListBoxOption; + } else if (role == "kListBox") { + return ax::mojom::Role::kListBox; + } else if (role == "kListGrid") { + return ax::mojom::Role::kListGrid; + } else if (role == "kListItem") { + return ax::mojom::Role::kListItem; + } else if (role == "kListMarker") { + return ax::mojom::Role::kListMarker; + } else if (role == "kLog") { + return ax::mojom::Role::kLog; + } else if (role == "kMain") { + return ax::mojom::Role::kMain; + } else if (role == "kMark") { + return ax::mojom::Role::kMark; + } else if (role == "kMarquee") { + return ax::mojom::Role::kMarquee; + } else if (role == "kMath") { + return ax::mojom::Role::kMath; + } else if (role == "kMathMLFraction") { + return ax::mojom::Role::kMathMLFraction; + } else if (role == "kMathMLIdentifier") { + return ax::mojom::Role::kMathMLIdentifier; + } else if (role == "kMathMLMath") { + return ax::mojom::Role::kMathMLMath; + } else if (role == "kMathMLMultiscripts") { + return ax::mojom::Role::kMathMLMultiscripts; + } else if (role == "kMathMLNoneScript") { + return ax::mojom::Role::kMathMLNoneScript; + } else if (role == "kMathMLNumber") { + return ax::mojom::Role::kMathMLNumber; + } else if (role == "kMathMLOperator") { + return ax::mojom::Role::kMathMLOperator; + } else if (role == "kMathMLOver") { + return ax::mojom::Role::kMathMLOver; + } else if (role == "kMathMLPrescriptDelimiter") { + return ax::mojom::Role::kMathMLPrescriptDelimiter; + } else if (role == "kMathMLRoot") { + return ax::mojom::Role::kMathMLRoot; + } else if (role == "kMathMLRow") { + return ax::mojom::Role::kMathMLRow; + } else if (role == "kMathMLSquareRoot") { + return ax::mojom::Role::kMathMLSquareRoot; + } else if (role == "kMathMLStringLiteral") { + return ax::mojom::Role::kMathMLStringLiteral; + } else if (role == "kMathMLSub") { + return ax::mojom::Role::kMathMLSub; + } else if (role == "kMathMLSubSup") { + return ax::mojom::Role::kMathMLSubSup; + } else if (role == "kMathMLSup") { + return ax::mojom::Role::kMathMLSup; + } else if (role == "kMathMLTable") { + return ax::mojom::Role::kMathMLTable; + } else if (role == "kMathMLTableCell") { + return ax::mojom::Role::kMathMLTableCell; + } else if (role == "kMathMLTableRow") { + return ax::mojom::Role::kMathMLTableRow; + } else if (role == "kMathMLText") { + return ax::mojom::Role::kMathMLText; + } else if (role == "kMathMLUnder") { + return ax::mojom::Role::kMathMLUnder; + } else if (role == "kMathMLUnderOver") { + return ax::mojom::Role::kMathMLUnderOver; + } else if (role == "kMenu") { + return ax::mojom::Role::kMenu; + } else if (role == "kMenuBar") { + return ax::mojom::Role::kMenuBar; + } else if (role == "kMenuItem") { + return ax::mojom::Role::kMenuItem; + } else if (role == "kMenuItemCheckBox") { + return ax::mojom::Role::kMenuItemCheckBox; + } else if (role == "kMenuItemRadio") { + return ax::mojom::Role::kMenuItemRadio; + } else if (role == "kMenuListOption") { + return ax::mojom::Role::kMenuListOption; + } else if (role == "kMenuListPopup") { + return ax::mojom::Role::kMenuListPopup; + } else if (role == "kMeter") { + return ax::mojom::Role::kMeter; + } else if (role == "kNavigation") { + return ax::mojom::Role::kNavigation; + } else if (role == "kNote") { + return ax::mojom::Role::kNote; + } else if (role == "kPane") { + return ax::mojom::Role::kPane; + } else if (role == "kParagraph") { + return ax::mojom::Role::kParagraph; + } else if (role == "kPdfActionableHighlight") { + return ax::mojom::Role::kPdfActionableHighlight; + } else if (role == "kPdfRoot") { + return ax::mojom::Role::kPdfRoot; + } else if (role == "kPluginObject") { + return ax::mojom::Role::kPluginObject; + } else if (role == "kPopUpButton") { + return ax::mojom::Role::kPopUpButton; + } else if (role == "kPortal") { + return ax::mojom::Role::kPortal; + } else if (role == "kPre") { + return ax::mojom::Role::kPre; + } else if (role == "kProgressIndicator") { + return ax::mojom::Role::kProgressIndicator; + } else if (role == "kRadioButton") { + return ax::mojom::Role::kRadioButton; + } else if (role == "kRadioGroup") { + return ax::mojom::Role::kRadioGroup; + } else if (role == "kRegion") { + return ax::mojom::Role::kRegion; + } else if (role == "kRootWebArea") { + return ax::mojom::Role::kRootWebArea; + } else if (role == "kRow") { + return ax::mojom::Role::kRow; + } else if (role == "kRowGroup") { + return ax::mojom::Role::kRowGroup; + } else if (role == "kRowHeader") { + return ax::mojom::Role::kRowHeader; + } else if (role == "kRuby") { + return ax::mojom::Role::kRuby; + } else if (role == "kRubyAnnotation") { + return ax::mojom::Role::kRubyAnnotation; + } else if (role == "kSection") { + return ax::mojom::Role::kSection; + } else if (role == "kStrong") { + return ax::mojom::Role::kStrong; + } else if (role == "kSubscript") { + return ax::mojom::Role::kSubscript; + } else if (role == "kSuggestion") { + return ax::mojom::Role::kSuggestion; + } else if (role == "kSuperscript") { + return ax::mojom::Role::kSuperscript; + } else if (role == "kSvgRoot") { + return ax::mojom::Role::kSvgRoot; + } else if (role == "kScrollBar") { + return ax::mojom::Role::kScrollBar; + } else if (role == "kScrollView") { + return ax::mojom::Role::kScrollView; + } else if (role == "kSearch") { + return ax::mojom::Role::kSearch; + } else if (role == "kSearchBox") { + return ax::mojom::Role::kSearchBox; + } else if (role == "kSlider") { + return ax::mojom::Role::kSlider; + } else if (role == "kSpinButton") { + return ax::mojom::Role::kSpinButton; + } else if (role == "kSplitter") { + return ax::mojom::Role::kSplitter; + } else if (role == "kStaticText") { + return ax::mojom::Role::kStaticText; + } else if (role == "kStatus") { + return ax::mojom::Role::kStatus; + } else if (role == "kSwitch") { + return ax::mojom::Role::kSwitch; + } else if (role == "kTabList") { + return ax::mojom::Role::kTabList; + } else if (role == "kTabPanel") { + return ax::mojom::Role::kTabPanel; + } else if (role == "kTab") { + return ax::mojom::Role::kTab; + } else if (role == "kTable") { + return ax::mojom::Role::kTable; + } else if (role == "kTableHeaderContainer") { + return ax::mojom::Role::kTableHeaderContainer; + } else if (role == "kTerm") { + return ax::mojom::Role::kTerm; + } else if (role == "kTextField") { + return ax::mojom::Role::kTextField; + } else if (role == "kTextFieldWithComboBox") { + return ax::mojom::Role::kTextFieldWithComboBox; + } else if (role == "kTime") { + return ax::mojom::Role::kTime; + } else if (role == "kTimer") { + return ax::mojom::Role::kTimer; + } else if (role == "kTitleBar") { + return ax::mojom::Role::kTitleBar; + } else if (role == "kToggleButton") { + return ax::mojom::Role::kToggleButton; + } else if (role == "kToolbar") { + return ax::mojom::Role::kToolbar; + } else if (role == "kTreeGrid") { + return ax::mojom::Role::kTreeGrid; + } else if (role == "kTreeItem") { + return ax::mojom::Role::kTreeItem; + } else if (role == "kTree") { + return ax::mojom::Role::kTree; + } else if (role == "kUnknown") { + return ax::mojom::Role::kUnknown; + } else if (role == "kTooltip") { + return ax::mojom::Role::kTooltip; + } else if (role == "kVideo") { + return ax::mojom::Role::kVideo; + } else if (role == "kWebView") { + return ax::mojom::Role::kWebView; + } else if (role == "kWindow") { + return ax::mojom::Role::kWindow; + } + + // We should never pass in an invalid role. + NOTREACHED() << "Invalid role was provided: " << role; + return ax::mojom::Role::kUnknown; +} + const char* ToString(ax::mojom::State state) { switch (state) { case ax::mojom::State::kNone: @@ -606,6 +1034,52 @@ return ""; } +ax::mojom::State StringToState(const std::string& str) { + if (str == "kNone") { + return ax::mojom::State::kNone; + } else if (str == "kAutofillAvailable") { + return ax::mojom::State::kAutofillAvailable; + } else if (str == "kCollapsed") { + return ax::mojom::State::kCollapsed; + } else if (str == "kDefault") { + return ax::mojom::State::kDefault; + } else if (str == "kEditable") { + return ax::mojom::State::kEditable; + } else if (str == "kExpanded") { + return ax::mojom::State::kExpanded; + } else if (str == "kFocusable") { + return ax::mojom::State::kFocusable; + } else if (str == "kHorizontal") { + return ax::mojom::State::kHorizontal; + } else if (str == "kHovered") { + return ax::mojom::State::kHovered; + } else if (str == "kIgnored") { + return ax::mojom::State::kIgnored; + } else if (str == "kInvisible") { + return ax::mojom::State::kInvisible; + } else if (str == "kLinked") { + return ax::mojom::State::kLinked; + } else if (str == "kMultiline") { + return ax::mojom::State::kMultiline; + } else if (str == "kMultiselectable") { + return ax::mojom::State::kMultiselectable; + } else if (str == "kProtected") { + return ax::mojom::State::kProtected; + } else if (str == "kRequired") { + return ax::mojom::State::kRequired; + } else if (str == "kRichlyEditable") { + return ax::mojom::State::kRichlyEditable; + } else if (str == "kVertical") { + return ax::mojom::State::kVertical; + } else if (str == "kVisited") { + return ax::mojom::State::kVisited; + } + + // We should never pass in an invalid state. + NOTREACHED() << "An invalid state was provided: " << str; + return ax::mojom::State::kNone; +} + const char* ToString(ax::mojom::Action action) { switch (action) { case ax::mojom::Action::kNone: @@ -852,6 +1326,85 @@ return ""; } +ax::mojom::StringAttribute StringToStringAttribute( + const std::string& string_attribute) { + if (string_attribute == "kNone") { + return ax::mojom::StringAttribute::kNone; + } else if (string_attribute == "kAccessKey") { + return ax::mojom::StringAttribute::kAccessKey; + } else if (string_attribute == "kAriaInvalidValue") { + return ax::mojom::StringAttribute::kAriaInvalidValue; + } else if (string_attribute == "kAutoComplete") { + return ax::mojom::StringAttribute::kAutoComplete; + } else if (string_attribute == "kAriaBrailleLabel") { + return ax::mojom::StringAttribute::kAriaBrailleLabel; + } else if (string_attribute == "kAriaBrailleRoleDescription") { + return ax::mojom::StringAttribute::kAriaBrailleRoleDescription; + } else if (string_attribute == "kCheckedStateDescription") { + return ax::mojom::StringAttribute::kCheckedStateDescription; + } else if (string_attribute == "kChildTreeId") { + return ax::mojom::StringAttribute::kChildTreeId; + } else if (string_attribute == "kChildTreeNodeAppId") { + return ax::mojom::StringAttribute::kChildTreeNodeAppId; + } else if (string_attribute == "kClassName") { + return ax::mojom::StringAttribute::kClassName; + } else if (string_attribute == "kContainerLiveRelevant") { + return ax::mojom::StringAttribute::kContainerLiveRelevant; + } else if (string_attribute == "kContainerLiveStatus") { + return ax::mojom::StringAttribute::kContainerLiveStatus; + } else if (string_attribute == "kDescription") { + return ax::mojom::StringAttribute::kDescription; + } else if (string_attribute == "kDisplay") { + return ax::mojom::StringAttribute::kDisplay; + } else if (string_attribute == "kDoDefaultLabel") { + return ax::mojom::StringAttribute::kDoDefaultLabel; + } else if (string_attribute == "kFontFamily") { + return ax::mojom::StringAttribute::kFontFamily; + } else if (string_attribute == "kHtmlTag") { + return ax::mojom::StringAttribute::kHtmlTag; + } else if (string_attribute == "kImageAnnotation") { + return ax::mojom::StringAttribute::kImageAnnotation; + } else if (string_attribute == "kImageDataUrl") { + return ax::mojom::StringAttribute::kImageDataUrl; + } else if (string_attribute == "kInnerHtml") { + return ax::mojom::StringAttribute::kInnerHtml; + } else if (string_attribute == "kInputType") { + return ax::mojom::StringAttribute::kInputType; + } else if (string_attribute == "kKeyShortcuts") { + return ax::mojom::StringAttribute::kKeyShortcuts; + } else if (string_attribute == "kLanguage") { + return ax::mojom::StringAttribute::kLanguage; + } else if (string_attribute == "kName") { + return ax::mojom::StringAttribute::kName; + } else if (string_attribute == "kLiveRelevant") { + return ax::mojom::StringAttribute::kLiveRelevant; + } else if (string_attribute == "kLiveStatus") { + return ax::mojom::StringAttribute::kLiveStatus; + } else if (string_attribute == "kApp") { + return ax::mojom::StringAttribute::kAppId; + } else if (string_attribute == "kPlaceholder") { + return ax::mojom::StringAttribute::kPlaceholder; + } else if (string_attribute == "kRole") { + return ax::mojom::StringAttribute::kRole; + } else if (string_attribute == "kRoleDescription") { + return ax::mojom::StringAttribute::kRoleDescription; + } else if (string_attribute == "kLongClickLabel") { + return ax::mojom::StringAttribute::kLongClickLabel; + } else if (string_attribute == "kToolTip") { + return ax::mojom::StringAttribute::kTooltip; + } else if (string_attribute == "kUrl") { + return ax::mojom::StringAttribute::kUrl; + } else if (string_attribute == "kValue") { + return ax::mojom::StringAttribute::kUrl; + } else if (string_attribute == "kVirtualContent") { + return ax::mojom::StringAttribute::kVirtualContent; + } else { + NOTREACHED() << "An invalid StringAttribute was provided: " + << string_attribute; + return ax::mojom::StringAttribute::kNone; + } +} + const char* ToString(ax::mojom::IntAttribute int_attribute) { switch (int_attribute) { case ax::mojom::IntAttribute::kNone: @@ -987,6 +1540,141 @@ return ""; } +ax::mojom::IntAttribute StringToIntAttribute(const std::string& int_attribute) { + if (int_attribute == "kNone") { + return ax::mojom::IntAttribute::kNone; + } else if (int_attribute == "kDefaultActionVerb") { + return ax::mojom::IntAttribute::kDefaultActionVerb; + } else if (int_attribute == "kDropeffect") { + return ax::mojom::IntAttribute::kDropeffect; + } else if (int_attribute == "kScrollX") { + return ax::mojom::IntAttribute::kScrollX; + } else if (int_attribute == "kScrollXMin") { + return ax::mojom::IntAttribute::kScrollXMin; + } else if (int_attribute == "kScrollXMax") { + return ax::mojom::IntAttribute::kScrollXMax; + } else if (int_attribute == "kScrollY") { + return ax::mojom::IntAttribute::kScrollY; + } else if (int_attribute == "kScrollYMin") { + return ax::mojom::IntAttribute::kScrollYMin; + } else if (int_attribute == "kScrollYMax") { + return ax::mojom::IntAttribute::kScrollYMax; + } else if (int_attribute == "kTextSelStart") { + return ax::mojom::IntAttribute::kTextSelStart; + } else if (int_attribute == "kTextSelEnd") { + return ax::mojom::IntAttribute::kTextSelEnd; + } else if (int_attribute == "kAriaColumnCount") { + return ax::mojom::IntAttribute::kAriaColumnCount; + } else if (int_attribute == "kAriaCellColumnIndex") { + return ax::mojom::IntAttribute::kAriaCellColumnIndex; + } else if (int_attribute == "kAriaCellColumnSpan") { + return ax::mojom::IntAttribute::kAriaCellColumnSpan; + } else if (int_attribute == "kAriaRowCount") { + return ax::mojom::IntAttribute::kAriaRowCount; + } else if (int_attribute == "kAriaCellRowIndex") { + return ax::mojom::IntAttribute::kAriaCellRowIndex; + } else if (int_attribute == "kAriaCellRowSpan") { + return ax::mojom::IntAttribute::kAriaCellRowSpan; + } else if (int_attribute == "kTableRowCount") { + return ax::mojom::IntAttribute::kTableRowCount; + } else if (int_attribute == "kTableColumnCount") { + return ax::mojom::IntAttribute::kTableColumnCount; + } else if (int_attribute == "kTableHeaderId") { + return ax::mojom::IntAttribute::kTableHeaderId; + } else if (int_attribute == "kTableRowIndex") { + return ax::mojom::IntAttribute::kTableRowIndex; + } else if (int_attribute == "kTableRowHeaderId") { + return ax::mojom::IntAttribute::kTableRowHeaderId; + } else if (int_attribute == "kTableColumnIndex") { + return ax::mojom::IntAttribute::kTableColumnIndex; + } else if (int_attribute == "kTableColumnHeaderId") { + return ax::mojom::IntAttribute::kTableColumnHeaderId; + } else if (int_attribute == "kTableCellColumnIndex") { + return ax::mojom::IntAttribute::kTableCellColumnIndex; + } else if (int_attribute == "kTableCellColumnSpan") { + return ax::mojom::IntAttribute::kTableCellColumnSpan; + } else if (int_attribute == "kTableCellRowIndex") { + return ax::mojom::IntAttribute::kTableCellRowIndex; + } else if (int_attribute == "kTableCellRowSpan") { + return ax::mojom::IntAttribute::kTableCellRowSpan; + } else if (int_attribute == "kSortDirection") { + return ax::mojom::IntAttribute::kSortDirection; + } else if (int_attribute == "kHierarchicalLevel") { + return ax::mojom::IntAttribute::kHierarchicalLevel; + } else if (int_attribute == "kNameFrom") { + return ax::mojom::IntAttribute::kNameFrom; + } else if (int_attribute == "kDescriptionFrom") { + return ax::mojom::IntAttribute::kDescriptionFrom; + } else if (int_attribute == "kActivedescendantId") { + return ax::mojom::IntAttribute::kActivedescendantId; + } else if (int_attribute == "kErrormessageId") { + return ax::mojom::IntAttribute::kErrormessageId; + } else if (int_attribute == "kInPageLinkTargetId") { + return ax::mojom::IntAttribute::kInPageLinkTargetId; + } else if (int_attribute == "kMemberOfId") { + return ax::mojom::IntAttribute::kMemberOfId; + } else if (int_attribute == "kNextOnLineId") { + return ax::mojom::IntAttribute::kNextOnLineId; + } else if (int_attribute == "kPopupForId") { + return ax::mojom::IntAttribute::kPopupForId; + } else if (int_attribute == "kPreviousOnLineId") { + return ax::mojom::IntAttribute::kPreviousOnLineId; + } else if (int_attribute == "kRestriction") { + return ax::mojom::IntAttribute::kRestriction; + } else if (int_attribute == "kSetSize") { + return ax::mojom::IntAttribute::kSetSize; + } else if (int_attribute == "kPosInSet") { + return ax::mojom::IntAttribute::kPosInSet; + } else if (int_attribute == "kColorValue") { + return ax::mojom::IntAttribute::kColorValue; + } else if (int_attribute == "kAriaCurrentState") { + return ax::mojom::IntAttribute::kAriaCurrentState; + } else if (int_attribute == "kBackgroundColor") { + return ax::mojom::IntAttribute::kBackgroundColor; + } else if (int_attribute == "kColor") { + return ax::mojom::IntAttribute::kColor; + } else if (int_attribute == "kHasPopup") { + return ax::mojom::IntAttribute::kHasPopup; + } else if (int_attribute == "kIsPopup") { + return ax::mojom::IntAttribute::kIsPopup; + } else if (int_attribute == "kInvalidState") { + return ax::mojom::IntAttribute::kInvalidState; + } else if (int_attribute == "kCheckedState") { + return ax::mojom::IntAttribute::kCheckedState; + } else if (int_attribute == "kListStyle") { + return ax::mojom::IntAttribute::kListStyle; + } else if (int_attribute == "kTextAlign") { + return ax::mojom::IntAttribute::kTextAlign; + } else if (int_attribute == "kTextDirection") { + return ax::mojom::IntAttribute::kTextDirection; + } else if (int_attribute == "kTextPosition") { + return ax::mojom::IntAttribute::kTextPosition; + } else if (int_attribute == "kTextStyle") { + return ax::mojom::IntAttribute::kTextStyle; + } else if (int_attribute == "kTextOverlineStyle") { + return ax::mojom::IntAttribute::kTextOverlineStyle; + } else if (int_attribute == "kTextStrikethroughStyle") { + return ax::mojom::IntAttribute::kTextStrikethroughStyle; + } else if (int_attribute == "kTextUnderlineStyle") { + return ax::mojom::IntAttribute::kTextUnderlineStyle; + } else if (int_attribute == "kPreviousFocusId") { + return ax::mojom::IntAttribute::kPreviousFocusId; + } else if (int_attribute == "kNextFocusId") { + return ax::mojom::IntAttribute::kNextFocusId; + } else if (int_attribute == "kImageAnnotationStatus") { + return ax::mojom::IntAttribute::kImageAnnotationStatus; + } else if (int_attribute == "kDomNodeId") { + return ax::mojom::IntAttribute::kDOMNodeId; + } else if (int_attribute == "kNextWindowFocusId") { + return ax::mojom::IntAttribute::kNextWindowFocusId; + } else if (int_attribute == "kPreviousWindowFocusId") { + return ax::mojom::IntAttribute::kPreviousWindowFocusId; + } + + NOTREACHED() << "An invalid IntAttribute was provided: " << int_attribute; + return ax::mojom::IntAttribute::kNone; +} + const char* ToString(ax::mojom::FloatAttribute float_attribute) { switch (float_attribute) { case ax::mojom::FloatAttribute::kNone: @@ -1063,6 +1751,58 @@ return ""; } +ax::mojom::BoolAttribute StringToBoolAttribute( + const std::string& bool_attribute) { + if (bool_attribute == "kNone") { + return ax::mojom::BoolAttribute::kNone; + } else if (bool_attribute == "kBusy") { + return ax::mojom::BoolAttribute::kBusy; + } else if (bool_attribute == "kNonAtomicTextFieldRoot") { + return ax::mojom::BoolAttribute::kNonAtomicTextFieldRoot; + } else if (bool_attribute == "kContainerLiveAtomic") { + return ax::mojom::BoolAttribute::kContainerLiveAtomic; + } else if (bool_attribute == "kContainerLiveBusy") { + return ax::mojom::BoolAttribute::kContainerLiveBusy; + } else if (bool_attribute == "kGrabbed") { + return ax::mojom::BoolAttribute::kGrabbed; + } else if (bool_attribute == "kLiveAtomic") { + return ax::mojom::BoolAttribute::kLiveAtomic; + } else if (bool_attribute == "kModal") { + return ax::mojom::BoolAttribute::kModal; + } else if (bool_attribute == "kUpdateLocationOnly") { + return ax::mojom::BoolAttribute::kUpdateLocationOnly; + } else if (bool_attribute == "kCanvasHasFallback") { + return ax::mojom::BoolAttribute::kCanvasHasFallback; + } else if (bool_attribute == "kScrollable") { + return ax::mojom::BoolAttribute::kScrollable; + } else if (bool_attribute == "kClickable") { + return ax::mojom::BoolAttribute::kClickable; + } else if (bool_attribute == "kClipsChildren") { + return ax::mojom::BoolAttribute::kClipsChildren; + } else if (bool_attribute == "kNotUserSelectableStyle") { + return ax::mojom::BoolAttribute::kNotUserSelectableStyle; + } else if (bool_attribute == "kSelected") { + return ax::mojom::BoolAttribute::kSelected; + } else if (bool_attribute == "kSelectedFromFocus") { + return ax::mojom::BoolAttribute::kSelectedFromFocus; + } else if (bool_attribute == "kSupportsTextLocation") { + return ax::mojom::BoolAttribute::kSupportsTextLocation; + } else if (bool_attribute == "kIsLineBreakingObject") { + return ax::mojom::BoolAttribute::kIsLineBreakingObject; + } else if (bool_attribute == "kIsPageBreakingObject") { + return ax::mojom::BoolAttribute::kIsPageBreakingObject; + } else if (bool_attribute == "kHasAriaAttribute") { + return ax::mojom::BoolAttribute::kHasAriaAttribute; + } else if (bool_attribute == "kTouchPassthrough") { + return ax::mojom::BoolAttribute::kTouchPassthrough; + } else if (bool_attribute == "kLongClickable") { + return ax::mojom::BoolAttribute::kLongClickable; + } else { + NOTREACHED() << "An invalid BoolAttribute was provided: " << bool_attribute; + return ax::mojom::BoolAttribute::kNone; + } +} + const char* ToString(ax::mojom::IntListAttribute int_list_attribute) { switch (int_list_attribute) { case ax::mojom::IntListAttribute::kNone:
diff --git a/ui/accessibility/ax_enum_util.h b/ui/accessibility/ax_enum_util.h index 60125fec..cb416a7 100644 --- a/ui/accessibility/ax_enum_util.h +++ b/ui/accessibility/ax_enum_util.h
@@ -22,9 +22,11 @@ // ax::mojom::Role AX_BASE_EXPORT const char* ToString(ax::mojom::Role role); +AX_BASE_EXPORT ax::mojom::Role StringToRole(const std::string& role); // ax::mojom::State AX_BASE_EXPORT const char* ToString(ax::mojom::State state); +AX_BASE_EXPORT ax::mojom::State StringToState(const std::string& state); // ax::mojom::Action AX_BASE_EXPORT const char* ToString(ax::mojom::Action action); @@ -42,15 +44,21 @@ // ax::mojom::StringAttribute AX_BASE_EXPORT const char* ToString( ax::mojom::StringAttribute string_attribute); +AX_BASE_EXPORT ax::mojom::StringAttribute StringToStringAttribute( + const std::string& string_attribute); // ax::mojom::IntAttribute AX_BASE_EXPORT const char* ToString(ax::mojom::IntAttribute int_attribute); +AX_BASE_EXPORT ax::mojom::IntAttribute StringToIntAttribute( + const std::string& int_attribute); // ax::mojom::FloatAttribute AX_BASE_EXPORT const char* ToString(ax::mojom::FloatAttribute float_attribute); // ax::mojom::BoolAttribute AX_BASE_EXPORT const char* ToString(ax::mojom::BoolAttribute bool_attribute); +AX_BASE_EXPORT ax::mojom::BoolAttribute StringToBoolAttribute( + const std::string& bool_attribute); // ax::mojom::IntListAttribute AX_BASE_EXPORT const char* ToString(
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index a91865f..fb5e6bf3 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc
@@ -5,6 +5,7 @@ #include "ui/accessibility/ax_tree.h" #include <stddef.h> + #include <numeric> #include <utility> @@ -23,6 +24,7 @@ #include "base/observer_list.h" #include "base/strings/stringprintf.h" #include "base/timer/elapsed_timer.h" +#include "components/crash/core/common/crash_key.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_event.h" @@ -2761,9 +2763,27 @@ if (is_fatal && !disallow_fail_fast_) { LOG(FATAL) << verbose_error.str(); - } else { - LOG(ERROR) << verbose_error.str(); } + + // If this is the first error, will dump without crashing in + // RenderAccessibilityImpl::OnFatalError(). + static auto* const ax_tree_error_key = base::debug::AllocateCrashKeyString( + "ax_tree_error", base::debug::CrashKeySize::Size256); + static auto* const ax_tree_update_key = base::debug::AllocateCrashKeyString( + "ax_tree_update", base::debug::CrashKeySize::Size256); + static auto* const ax_tree_key = base::debug::AllocateCrashKeyString( + "ax_tree", base::debug::CrashKeySize::Size256); + static auto* const ax_tree_data_key = base::debug::AllocateCrashKeyString( + "ax_tree_data", base::debug::CrashKeySize::Size256); + + // Log additional crash keys so we can debug bad tree updates. + base::debug::SetCrashKeyString(ax_tree_error_key, new_error); + base::debug::SetCrashKeyString(ax_tree_update_key, + update_state.pending_tree_update->ToString()); + base::debug::SetCrashKeyString(ax_tree_key, + TreeToStringHelper(root_, 0, false)); + base::debug::SetCrashKeyString(ax_tree_data_key, data_.ToString()); + LOG(ERROR) << verbose_error.str(); } } // namespace ui
diff --git a/ui/accessibility/ax_tree_manager.cc b/ui/accessibility/ax_tree_manager.cc index 1c5bb8df..0eac978 100644 --- a/ui/accessibility/ax_tree_manager.cc +++ b/ui/accessibility/ax_tree_manager.cc
@@ -164,31 +164,38 @@ #if defined(AX_FAIL_FAST_BUILD) static auto* const ax_crash_key_focus = base::debug::AllocateCrashKeyString( "ax_focus", base::debug::CrashKeySize::Size256); +#endif static auto* const ax_crash_key_focus_top_frame = base::debug::AllocateCrashKeyString("ax_focus_top_frame", base::debug::CrashKeySize::Size256); static auto* const ax_crash_key_focus_frame = base::debug::AllocateCrashKeyString("ax_focus_frame", base::debug::CrashKeySize::Size256); -#endif if (node) { -#if defined(AX_FAIL_FAST_BUILD) std::ostringstream node_info_focus, node_info_top_frame, node_info_frame; + + // Only set specific focused node info in fail fast builds, in order to + // avoid extra processing for every focus move. +#if defined(AX_FAIL_FAST_BUILD) node_info_focus << node; - if (node->GetManager() && node->GetManager()->GetRootManager()) { - node_info_top_frame << node->GetManager()->GetRootManager()->GetRoot(); - if (!node->GetManager()->IsRoot()) { - // There is a parent manager, so provide frame root info as well. - node_info_frame << node->GetManager()->GetRoot(); + base::debug::SetCrashKeyString(ax_crash_key_focus, node_info_focus.str()); +#endif + + // Only set frame url crash keys if the tree id has changed. + DCHECK(node->GetManager()); + if (node->GetManager()->GetTreeID() != last_focused_node_tree_id_) { + if (node->GetManager() && node->GetManager()->GetRootManager()) { + node_info_top_frame << node->GetManager()->GetRootManager()->GetRoot(); + base::debug::SetCrashKeyString(ax_crash_key_focus_top_frame, + node_info_top_frame.str()); + if (!node->GetManager()->IsRoot()) { + // There is a parent manager, so provide frame root info as well. + node_info_frame << node->GetManager()->GetRoot(); + base::debug::SetCrashKeyString(ax_crash_key_focus_frame, + node_info_frame.str()); + } } } - base::debug::SetCrashKeyString(ax_crash_key_focus, node_info_focus.str()); - base::debug::SetCrashKeyString(ax_crash_key_focus_top_frame, - node_info_top_frame.str()); - base::debug::SetCrashKeyString(ax_crash_key_focus_frame, - node_info_frame.str()); -#endif - DCHECK(node->GetManager()); last_focused_node_id_ = node->id(); last_focused_node_tree_id_ = node->GetManager()->GetTreeID(); @@ -197,9 +204,9 @@ } else { #if defined(AX_FAIL_FAST_BUILD) base::debug::ClearCrashKeyString(ax_crash_key_focus); +#endif base::debug::ClearCrashKeyString(ax_crash_key_focus_top_frame); base::debug::ClearCrashKeyString(ax_crash_key_focus_frame); -#endif last_focused_node_id_.reset(); last_focused_node_tree_id_.reset(); }
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h index 48292fb..987459b5 100644 --- a/ui/accessibility/ax_tree_serializer.h +++ b/ui/accessibility/ax_tree_serializer.h
@@ -134,12 +134,6 @@ // as explored by the serializer. size_t ClientTreeNodeCount() const; -#if DCHECK_IS_ON() - std::vector<AXNodeID> ClientTreeNodeIds() const; - - AXSourceNode ParentOf(AXNodeID id); -#endif - private: // Return the least common ancestor of a node in the source tree // and a node in the client tree, or nullptr if there is no such node. @@ -313,27 +307,6 @@ return client_id_map_.size(); } -#if DCHECK_IS_ON() -template <typename AXSourceNode> -std::vector<AXNodeID> AXTreeSerializer<AXSourceNode>::ClientTreeNodeIds() - const { - std::vector<AXNodeID> keys; - std::transform( - client_id_map_.begin(), client_id_map_.end(), std::back_inserter(keys), - [](std::pair<AXNodeID, ClientTreeNode*> item) { return item.first; }); - return keys; -} - -template <typename AXSourceNode> -AXSourceNode AXTreeSerializer<AXSourceNode>::ParentOf(AXNodeID id) { - ClientTreeNode* node = ClientTreeNodeById(id); - if (!node || !node->parent) { - return nullptr; - } - return tree_->GetFromId(node->parent->id); -} -#endif - template <typename AXSourceNode> AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( AXSourceNode node,
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index 8be32b9..24cf204 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -2131,42 +2131,14 @@ } TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkSelectionInterface) { - AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kListBox; - root.AddState(ax::mojom::State::kFocusable); - root.AddState(ax::mojom::State::kMultiselectable); - root.child_ids.push_back(2); - root.child_ids.push_back(3); - root.child_ids.push_back(4); - root.child_ids.push_back(5); + ui::TestAXTreeUpdate update(std::string(R"HTML( + ++1 kListBox states=kFocusable,kMultiselectable + ++++2 kListBoxOption + ++++3 kListBoxOption + ++++4 kListBoxOption + ++++5 kListItem + )HTML")); - AXNodeData item_1; - item_1.id = 2; - item_1.role = ax::mojom::Role::kListBoxOption; - - AXNodeData item_2; - item_2.id = 3; - item_2.role = ax::mojom::Role::kListBoxOption; - - AXNodeData item_3; - item_3.id = 4; - item_3.role = ax::mojom::Role::kListBoxOption; - - // Add a final item which is not selectable. - AXNodeData item_4; - item_4.id = 5; - item_4.role = ax::mojom::Role::kListItem; - - AXTreeUpdate update; - update.root_id = 1; - update.nodes.push_back(root); - update.nodes.push_back(item_1); - update.nodes.push_back(item_2); - update.nodes.push_back(item_3); - update.nodes.push_back(item_4); - update.has_tree_data = true; - update.tree_data.tree_id = AXTreeID::CreateNewAXTreeID(); Init(update); AtkObject* root_atk_object(GetRootAtkObject());
diff --git a/ui/accessibility/platform/ax_platform_node_unittest.h b/ui/accessibility/platform/ax_platform_node_unittest.h index 17a262d0..69ebae6 100644 --- a/ui/accessibility/platform/ax_platform_node_unittest.h +++ b/ui/accessibility/platform/ax_platform_node_unittest.h
@@ -13,6 +13,7 @@ #include "ui/accessibility/ax_tree_update.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/accessibility/test_ax_tree_manager.h" +#include "ui/accessibility/test_ax_tree_update.h" namespace ui {
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index c300063..22b1b34b 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -4169,74 +4169,21 @@ } TEST_F(AXPlatformNodeWinTest, IsUIAControlColorWellInsideTable) { - // ++1 kRootWebArea - // ++++2 kTable - // ++++++3 kLayoutTableCell - // ++++++++4 kColorWell - // ++++++++++5 kStaticText - // ++++++6 kColumnHeader - // ++++++++7 kColorWell - // ++++++++++8 kStaticText - // ++++++9 kRowHeader - // ++++++++10 kColorWell - // ++++++++++11 kStaticText + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kTable + ++++++3 kLayoutTableCell + ++++++++4 kColorWell + ++++++++++5 kStaticText + ++++++6 kColumnHeader + ++++++++7 kColorWell + ++++++++++8 kStaticText + ++++++9 kRowHeader + ++++++++10 kColorWell + ++++++++++11 kStaticText + )HTML")); - AXNodeData root_1; - AXNodeData table_2; - AXNodeData cell_3; - AXNodeData color_4; - AXNodeData st_5; - AXNodeData column_header_6; - AXNodeData color_7; - AXNodeData st_8; - AXNodeData row_header_9; - AXNodeData color_10; - AXNodeData st_11; - - root_1.id = 1; - table_2.id = 2; - cell_3.id = 3; - color_4.id = 4; - st_5.id = 5; - column_header_6.id = 6; - color_7.id = 7; - st_8.id = 8; - row_header_9.id = 9; - color_10.id = 10; - st_11.id = 11; - - root_1.role = ax::mojom::Role::kRootWebArea; - root_1.child_ids = {table_2.id}; - - table_2.role = ax::mojom::Role::kTable; - table_2.child_ids = {cell_3.id, column_header_6.id, row_header_9.id}; - - cell_3.role = ax::mojom::Role::kLayoutTableCell; - cell_3.child_ids = {color_4.id}; - - color_4.role = ax::mojom::Role::kColorWell; - color_4.child_ids = {st_5.id}; - - st_5.role = ax::mojom::Role::kStaticText; - - column_header_6.role = ax::mojom::Role::kColumnHeader; - column_header_6.child_ids = {color_7.id}; - - color_7.role = ax::mojom::Role::kColorWell; - color_7.child_ids = {st_8.id}; - - st_8.role = ax::mojom::Role::kStaticText; - - row_header_9.role = ax::mojom::Role::kRowHeader; - row_header_9.child_ids = {color_10.id}; - - color_10.role = ax::mojom::Role::kColorWell; - color_10.child_ids = {st_11.id}; - - st_11.role = ax::mojom::Role::kStaticText; - - Init(root_1, table_2, cell_3, color_4, st_5, column_header_6, color_7, st_8, - row_header_9, color_10, st_11); + Init(update); // Turn on web content mode for the AXTree. TestAXNodeWrapper::SetGlobalIsWebContent(true); @@ -4261,52 +4208,16 @@ } TEST_F(AXPlatformNodeWinTest, IsUIAControlForTextNodes) { - // ++1 root - // ++++2 kGenericContainer - // ++++++3 kStaticText "text" - // ++++4 kGroup - // ++++++5 kStaticText "text" - // ++++6 kHeading - // ++++++7 kStaticText "text" - - AXNodeData root_1; - AXNodeData gc_2; - AXNodeData text_3; - AXNodeData group_4; - AXNodeData text_5; - AXNodeData heading_6; - AXNodeData text_7; - - root_1.id = 1; - gc_2.id = 2; - text_3.id = 3; - group_4.id = 4; - text_5.id = 5; - heading_6.id = 6; - text_7.id = 7; - - root_1.role = ax::mojom::Role::kRootWebArea; - root_1.child_ids = {gc_2.id, group_4.id, heading_6.id}; - - gc_2.role = ax::mojom::Role::kGenericContainer; - gc_2.child_ids = {text_3.id}; - - text_3.role = ax::mojom::Role::kStaticText; - text_3.SetName("text"); - - group_4.role = ax::mojom::Role::kGroup; - group_4.child_ids = {text_5.id}; - - text_5.role = ax::mojom::Role::kStaticText; - text_5.SetName("text"); - - heading_6.role = ax::mojom::Role::kHeading; - heading_6.child_ids = {text_7.id}; - - text_7.role = ax::mojom::Role::kStaticText; - text_7.SetName("text"); - - Init(root_1, gc_2, text_3, group_4, text_5, heading_6, text_7); + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kGenericContainer + ++++++3 kStaticText name="text" + ++++4 kGroup + ++++++5 kStaticText name="text" + ++++6 kHeading + ++++++7 kStaticText name="text" + )HTML")); + Init(update); // Turn on web content mode for the AXTree. TestAXNodeWrapper::SetGlobalIsWebContent(true); @@ -4330,21 +4241,11 @@ } TEST_F(AXPlatformNodeWinTest, IsUIAControlForNonFocusableNodesInViews) { - // ++1 kUnknown - // ++++2 kButton - - AXNodeData root_1; - AXNodeData button_2; - - root_1.id = 1; - button_2.id = 2; - - root_1.role = ax::mojom::Role::kUnknown; - root_1.child_ids = {button_2.id}; - - button_2.role = ax::mojom::Role::kButton; - - Init(root_1, button_2); + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kUnknown + ++++2 kButton + )HTML")); + Init(update); // Set web content mode to false for the AXTree since we're testing for Views. TestAXNodeWrapper::SetGlobalIsWebContent(false); @@ -4409,20 +4310,12 @@ } TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueIsDialog) { - AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - root.child_ids = {2, 3}; - - AXNodeData alert_dialog; - alert_dialog.id = 2; - alert_dialog.role = ax::mojom::Role::kAlertDialog; - - AXNodeData dialog; - dialog.id = 3; - dialog.role = ax::mojom::Role::kDialog; - - Init(root, alert_dialog, dialog); + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kAlertDialog + ++++3 kDialog + )HTML")); + Init(update); EXPECT_UIA_BOOL_EQ(GetRootIRawElementProviderSimple(), UIA_IsDialogPropertyId, false); @@ -4434,53 +4327,17 @@ TEST_F(AXPlatformNodeWinTest, UIAGetPropertyValueIsControlElementIgnoredInvisible) { - AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; - root.child_ids = {2, 3, 4, 5, 6, 7, 8}; - - AXNodeData normal_button; - normal_button.id = 2; - normal_button.role = ax::mojom::Role::kButton; - - AXNodeData ignored_button; - ignored_button.id = 3; - ignored_button.role = ax::mojom::Role::kButton; - ignored_button.AddState(ax::mojom::State::kIgnored); - - AXNodeData invisible_button; - invisible_button.id = 4; - invisible_button.role = ax::mojom::Role::kButton; - invisible_button.AddState(ax::mojom::State::kInvisible); - - AXNodeData invisible_focusable_button; - invisible_focusable_button.id = 5; - invisible_focusable_button.role = ax::mojom::Role::kButton; - invisible_focusable_button.AddState(ax::mojom::State::kInvisible); - invisible_focusable_button.AddState(ax::mojom::State::kFocusable); - - AXNodeData focusable_generic_container; - focusable_generic_container.id = 6; - focusable_generic_container.role = ax::mojom::Role::kGenericContainer; - focusable_generic_container.AddState(ax::mojom::State::kFocusable); - - AXNodeData ignored_focusable_generic_container; - ignored_focusable_generic_container.id = 7; - ignored_focusable_generic_container.role = ax::mojom::Role::kGenericContainer; - ignored_focusable_generic_container.AddState(ax::mojom::State::kIgnored); - focusable_generic_container.AddState(ax::mojom::State::kFocusable); - - AXNodeData invisible_focusable_generic_container; - invisible_focusable_generic_container.id = 8; - invisible_focusable_generic_container.role = - ax::mojom::Role::kGenericContainer; - invisible_focusable_generic_container.AddState(ax::mojom::State::kInvisible); - invisible_focusable_generic_container.AddState(ax::mojom::State::kFocusable); - - Init(root, normal_button, ignored_button, invisible_button, - invisible_focusable_button, focusable_generic_container, - ignored_focusable_generic_container, - invisible_focusable_generic_container); + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kButton + ++++3 kButton states=kIgnored + ++++4 kButton states=kInvisible + ++++5 kButton states=kInvisible,kFocusable + ++++6 kGenericContainer states=kFocusable + ++++7 kGenericContainer states=kIgnored,kFocusable + ++++8 kGenericContainer states=kInvisible,kFocusable + )HTML")); + Init(update); // Turn on web content mode for the AXTree. TestAXNodeWrapper::SetGlobalIsWebContent(true); @@ -4975,65 +4832,32 @@ } TEST_F(AXPlatformNodeWinTest, GetPropertyValue_HelpText) { - AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kRootWebArea; + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kTextField name="name-from-title" state=kEditable stringAttribute=kPlaceholder,placeholder + ++++3 kTextField state=kEditable name="name-from-title" + ++++4 kTextField name="name-from-placeholder" state=kEditable + ++++5 kTextField state=kEditable name="name-from-attribute" stringAttribute=kToolTip,tooltip + ++++6 kTextField state=kEditable name="name-from-attribute" + )HTML")); - // Test Placeholder StringAttribute is exposed - AXNodeData input1; - input1.id = 2; - input1.role = ax::mojom::Role::kTextField; - input1.AddState(ax::mojom::State::kEditable); - input1.SetName("name-from-title"); - input1.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, - static_cast<int>(ax::mojom::NameFrom::kTitle)); - input1.AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder, - "placeholder"); - root.child_ids.push_back(input1.id); + update.nodes[1].AddIntAttribute( + ax::mojom::IntAttribute::kNameFrom, + static_cast<int>(ax::mojom::NameFrom::kTitle)); + update.nodes[2].AddIntAttribute( + ax::mojom::IntAttribute::kNameFrom, + static_cast<int>(ax::mojom::NameFrom::kTitle)); + update.nodes[3].AddIntAttribute( + ax::mojom::IntAttribute::kNameFrom, + static_cast<int>(ax::mojom::NameFrom::kPlaceholder)); + update.nodes[4].AddIntAttribute( + ax::mojom::IntAttribute::kNameFrom, + static_cast<int>(ax::mojom::NameFrom::kAttribute)); + update.nodes[5].AddIntAttribute( + ax::mojom::IntAttribute::kNameFrom, + static_cast<int>(ax::mojom::NameFrom::kAttribute)); - // Test NameFrom Title is exposed - AXNodeData input2; - input2.id = 3; - input2.role = ax::mojom::Role::kTextField; - input2.AddState(ax::mojom::State::kEditable); - input2.SetName("name-from-title"); - input2.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, - static_cast<int>(ax::mojom::NameFrom::kTitle)); - root.child_ids.push_back(input2.id); - - // Test NameFrom Placeholder is exposed - AXNodeData input3; - input3.id = 4; - input3.role = ax::mojom::Role::kTextField; - input3.AddState(ax::mojom::State::kEditable); - input3.SetName("name-from-placeholder"); - input3.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, - static_cast<int>(ax::mojom::NameFrom::kPlaceholder)); - root.child_ids.push_back(input3.id); - - // Test Title StringAttribute is exposed - AXNodeData input4; - input4.id = 5; - input4.role = ax::mojom::Role::kTextField; - input4.AddState(ax::mojom::State::kEditable); - input4.SetName("name-from-attribute"); - input4.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, - static_cast<int>(ax::mojom::NameFrom::kAttribute)); - input4.AddStringAttribute(ax::mojom::StringAttribute::kTooltip, "tooltip"); - root.child_ids.push_back(input4.id); - - // Test NameFrom (other), without explicit - // Title / Placeholder StringAttribute is not exposed - AXNodeData input5; - input5.id = 6; - input5.role = ax::mojom::Role::kTextField; - input5.AddState(ax::mojom::State::kEditable); - input5.SetName("name-from-attribute"); - input5.AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, - static_cast<int>(ax::mojom::NameFrom::kAttribute)); - root.child_ids.push_back(input5.id); - - Init(root, input1, input2, input3, input4, input5); + Init(update); auto* root_node = GetRoot(); EXPECT_UIA_BSTR_EQ(QueryInterfaceFromNode<IRawElementProviderSimple>( @@ -5054,99 +4878,57 @@ } TEST_F(AXPlatformNodeWinTest, GetPropertyValue_LocalizedControlType) { - AXNodeData root; - root.role = ax::mojom::Role::kUnknown; - root.id = 1; - root.AddStringAttribute(ax::mojom::StringAttribute::kRoleDescription, - "root role description"); + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kUnknown stringAttribute=kRoleDescription,rootRoleDescription + ++++2 kSearchBox stringAttribute=kRoleDescription,child1RoleDescription + ++++3 kButton + )HTML")); - AXNodeData child1; - child1.id = 2; - child1.role = ax::mojom::Role::kSearchBox; - child1.AddStringAttribute(ax::mojom::StringAttribute::kRoleDescription, - "child1 role description"); - root.child_ids.push_back(2); - - AXNodeData child2; - child2.id = 3; - child2.role = ax::mojom::Role::kButton; - root.child_ids.push_back(3); - - Init(root, child1, child2); + Init(update); ComPtr<IRawElementProviderSimple> root_node = GetRootIRawElementProviderSimple(); EXPECT_UIA_BSTR_EQ(root_node, UIA_LocalizedControlTypePropertyId, - L"root role description"); + L"rootRoleDescription"); EXPECT_UIA_BSTR_EQ(QueryInterfaceFromNode<IRawElementProviderSimple>( GetRoot()->children()[0]), UIA_LocalizedControlTypePropertyId, - L"child1 role description"); + L"child1RoleDescription"); EXPECT_UIA_EMPTY(QueryInterfaceFromNode<IRawElementProviderSimple>( GetRoot()->children()[1]), UIA_LocalizedControlTypePropertyId); } TEST_F(AXPlatformNodeWinTest, GetPropertyValue_IsControlElement) { - AXTreeUpdate update; + TestAXTreeUpdate update(std::string(R"HTML( + ++1 kRootWebArea + ++++2 kButton + ++++++3 kStaticText name="someText" + ++++4 kGenericContainer + ++++++5 kStaticText name="moreText" + ++++6 kTable + ++++7 kList + ++++8 kForm + ++++9 kImage + ++++10 kImage + ++++11 kArticle + ++++12 kGenericContainer boolAttribute=kHasAriaAttribute,true + ++++13 kGenericContainer states=kEditable,kRichlyEditable boolAttribute=kNonAtomicTextFieldRoot,true + ++++14 kGenericContainer name="name" + ++++15 kGenericContainer + ++++16 kGenericContainer state=kFocusable + ++++17 kForm name="name" + )HTML")); + ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID(); update.tree_data.tree_id = tree_id; update.has_tree_data = true; update.root_id = 1; - update.nodes.resize(17); - update.nodes[0].id = 1; - update.nodes[0].role = ax::mojom::Role::kRootWebArea; - update.nodes[0].child_ids = {2, 4, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17}; - update.nodes[1].id = 2; - update.nodes[1].role = ax::mojom::Role::kButton; - update.nodes[1].child_ids = {3}; - update.nodes[2].id = 3; - update.nodes[2].role = ax::mojom::Role::kStaticText; - update.nodes[2].SetName("some text"); - update.nodes[3].id = 4; - update.nodes[3].role = ax::mojom::Role::kGenericContainer; - update.nodes[3].child_ids = {5}; - update.nodes[4].id = 5; - update.nodes[4].role = ax::mojom::Role::kStaticText; - update.nodes[4].SetName("more text"); - update.nodes[5].id = 6; - update.nodes[5].role = ax::mojom::Role::kTable; - update.nodes[6].id = 7; - update.nodes[6].role = ax::mojom::Role::kList; - update.nodes[7].id = 8; - update.nodes[7].role = ax::mojom::Role::kForm; - update.nodes[8].id = 9; - update.nodes[8].role = ax::mojom::Role::kImage; - update.nodes[9].id = 10; - update.nodes[9].role = ax::mojom::Role::kImage; update.nodes[9].SetNameExplicitlyEmpty(); - update.nodes[10].id = 11; - update.nodes[10].role = ax::mojom::Role::kArticle; - update.nodes[11].id = 12; - update.nodes[11].role = ax::mojom::Role::kGenericContainer; - update.nodes[11].AddBoolAttribute(ax::mojom::BoolAttribute::kHasAriaAttribute, - true); - update.nodes[12].id = 13; - update.nodes[12].role = ax::mojom::Role::kGenericContainer; - update.nodes[12].AddState(ax::mojom::State::kEditable); - update.nodes[12].AddState(ax::mojom::State::kRichlyEditable); - update.nodes[12].AddBoolAttribute( - ax::mojom::BoolAttribute::kNonAtomicTextFieldRoot, true); - update.nodes[13].id = 14; - update.nodes[13].role = ax::mojom::Role::kGenericContainer; - update.nodes[13].SetName("name"); - update.nodes[14].id = 15; - update.nodes[14].role = ax::mojom::Role::kGenericContainer; update.nodes[14].SetDescription("description"); - update.nodes[15].id = 16; - update.nodes[15].role = ax::mojom::Role::kGenericContainer; - update.nodes[15].AddState(ax::mojom::State::kFocusable); - update.nodes[16].id = 17; - update.nodes[16].role = ax::mojom::Role::kForm; - update.nodes[16].SetName("name"); Init(update); + TestAXNodeWrapper::SetGlobalIsWebContent(true); EXPECT_UIA_BOOL_EQ(GetIRawElementProviderSimpleFromTree(tree_id, 2),
diff --git a/ui/accessibility/test_ax_tree_update.cc b/ui/accessibility/test_ax_tree_update.cc index db833fd..040c5ca8 100644 --- a/ui/accessibility/test_ax_tree_update.cc +++ b/ui/accessibility/test_ax_tree_update.cc
@@ -3,9 +3,191 @@ // found in the LICENSE file. #include "ui/accessibility/test_ax_tree_update.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" namespace ui { +int PlusSignCount(const std::string& s) { + int count = 0; + + for (auto& character : s) { + if (character == '+') { + count++; + } + } + + return count; +} + +bool IsSpaceOrTab(const char c) { + return c == ' ' || c == '\t'; +} + +void RemoveLeadingAndTrailingWhitespace(std::string& s) { + if (s.empty()) { + return; + } + auto front_it = s.begin(); + auto back_it = s.end() - 1; + + while (IsSpaceOrTab(*front_it) || IsSpaceOrTab(*back_it)) { + if (front_it > back_it) { + return; + } + if (front_it == back_it) { + if (IsSpaceOrTab(*front_it)) { + s.erase(front_it); + } + return; + } + if (IsSpaceOrTab(*front_it)) { + s.erase(front_it); + + // Iterators get invalidated when erasing. + front_it = s.begin(); + back_it = s.end() - 1; + } + if (IsSpaceOrTab(*back_it)) { + s.erase(back_it); + + // Iterators get invalidated when erasing. + back_it = s.end() - 1; + front_it = s.begin(); + } + } +} + +bool StringToBool(const std::string& s) { + if (s == "true" || s == "True" || s == "1") { + return true; + } + if (s == "false" || s == "False" || s == "0") { + return false; + } + + // TODO: Specify which node this error was found at. + NOTREACHED() << "Invalid value passed to StringToBool: " << s; + return false; +} + +void ParseAndAddNodeProperties( + AXNodeData& node_data, + const std::vector<std::string>& node_line) { + // At this point, the vector of strings we receive should be just a vector of + // properties of the format: + // [<property>=<value>] where value depends on the property. + + DCHECK(node_line.size() >= 1) + << "Error in formatting of the tree structure. Possibly extra whiespace."; + for (auto& prop : node_line) { + std::vector<std::string> property_vector = base::SplitStringUsingSubstr( + prop, "=", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + DCHECK(property_vector.size() == 2) + << "Properties should always be formed as " + "<SupportedProperty>=<PropertyValue/s>"; + std::string property = property_vector[0]; + + if (property == "name" || property == "Name") { + // Since the structure is passed in as an unformatted string, + // and the name has the format "<name>", + // the string adds escape characters before the quotes. + // Therefore when we set the name we must remove the `\"` character. + + std::string name = property_vector[1]; + DCHECK(name.front() == '\"' && name.back() == '\"'); + name.erase(name.begin()); + name.erase(--name.end()); + + node_data.SetName(name); + } else if (property == "states" || property == "state") { + std::vector<std::string> state_values = base::SplitStringUsingSubstr( + property_vector[1], ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + DCHECK(state_values.size() >= 1) + << "State values should be at least one, and they should be " + "separated by commas."; + for (auto& value : state_values) { + node_data.AddState(StringToState(value)); + } + + } else if (property == "intAttribute" || property == "IntAttribute" || + property == "intattribute") { + std::vector<std::string> int_attribute_vector = + base::SplitStringUsingSubstr(property_vector[1], ",", + base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + DCHECK(int_attribute_vector.size() == 2) + << "Int attribute in string must always be formed: " + "intAttribute=<intAttributeType>,<intAttributeValue>"; + int int_value = 0; + base::StringToInt(int_attribute_vector[1], &int_value); + DCHECK(int_value) << "Formatting error or non integer passed as node ID."; + node_data.AddIntAttribute(StringToIntAttribute(int_attribute_vector[0]), + int_value); + + } else if (property == "stringAttribute" || property == "StringAttribute" || + property == "stringattribute") { + std::vector<std::string> string_attribute_vector = + base::SplitStringUsingSubstr(property_vector[1], ",", + base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + DCHECK(string_attribute_vector.size() == 2) + << "String attribute in string must always be formed: " + "stringAttribute=<stringAttributeType>,<stringAttributeValue>"; + node_data.AddStringAttribute( + StringToStringAttribute(string_attribute_vector[0]), + string_attribute_vector[1]); + } else if (property == "boolAttribute" || property == "BoolAttribute" || + property == "boolattribute") { + std::vector<std::string> bool_attribute_vector = + base::SplitStringUsingSubstr(property_vector[1], ",", + base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + DCHECK(bool_attribute_vector.size() == 2) + << "Bool attribute in string must always be formed: " + "boolAttribute=<boolAttributeType>,<boolAttributeValue>"; + node_data.AddBoolAttribute( + StringToBoolAttribute(bool_attribute_vector[0]), + StringToBool(bool_attribute_vector[1])); + + } else { + // TODO: Will extend to more properties here. + NOTREACHED() + << "Either an invalid property was specified, or this function does " + "not currently support the specified property."; + } + } +} + +AXNodeData ParseNodeInfo(std::vector<std::string>& node_line, + std::set<int>& found_ids) { + AXNodeData data; + + // Must at the very least have id and role. + DCHECK(node_line.size() >= 2) << "Error, a node must have an id and role."; + int int_value = 0; + base::StringToInt(node_line[0], &int_value); + DCHECK(int_value) << "Formatting error or non integer passed as node ID."; + data.id = int_value; + + DCHECK(found_ids.find(data.id) == found_ids.end()) + << "Error, can't have duplicate IDs."; + found_ids.insert(data.id); + ax::mojom::Role role = StringToRole(node_line[1]); + + data.role = role; + + data.child_ids = {}; + + if (node_line.size() >= 3) { + node_line.erase(node_line.begin()); + node_line.erase(node_line.begin()); + ParseAndAddNodeProperties(data, node_line); + } + + return data; +} + TestAXTreeUpdateNode::TestAXTreeUpdateNode(const TestAXTreeUpdateNode&) = default; @@ -53,4 +235,114 @@ return nodes[node_index].id; } +TestAXTreeUpdate::TestAXTreeUpdate(const std::string& tree_structure) { + std::vector<AXNodeData> node_data_vector; + std::vector<std::string> tree_structure_vector = base::SplitStringUsingSubstr( + tree_structure, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + + // Test authors might accidentally include whitespace when declaring the non + // formatted string. + RemoveLeadingAndTrailingWhitespace(*tree_structure_vector.begin()); + RemoveLeadingAndTrailingWhitespace(*--tree_structure_vector.end()); + + // With how we pass in the non formatted string, the first and last elements + // of the vector should be empty. + DCHECK(tree_structure_vector.front().empty() && + tree_structure_vector.back().empty()) + << "Error in parsing the tree structure, double check the formatting."; + tree_structure_vector.erase(tree_structure_vector.begin()); + tree_structure_vector.erase(--tree_structure_vector.end()); + + node_data_vector.reserve(tree_structure_vector.size()); + + RemoveLeadingAndTrailingWhitespace(tree_structure_vector[0]); + + int root_pluses = PlusSignCount(tree_structure_vector[0]); + DCHECK_EQ(root_pluses, 2) + << "The first line of the test needs to start with 2 '+' sign, not " + << root_pluses; + + // We remove the plus signs from the string + tree_structure_vector[0].erase(0, root_pluses); + std::vector<std::string> root_line = + base::SplitStringUsingSubstr(tree_structure_vector[0], " ", + base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + + // Set to keep track of found IDs and make sure we don't have duplicates. + std::set<int> found_ids; + + node_data_vector.push_back(ParseNodeInfo(root_line, found_ids)); + + // This maps the number of plus signs to the last index that number of plus + // signs was found at in the `tree_structure_vector` This will be useful for + // determining descendants. + std::unordered_map<int, int> last_index_appearance_of_plus_count; + + // The first (zeroth) row always has two plus signs + last_index_appearance_of_plus_count[2] = 0; + int last_count = 2; + int greatest_count = 2; + for (size_t i = 1; i < tree_structure_vector.size(); i++) { + // Test authors might have added whitespace when passing in the tree + // structure + RemoveLeadingAndTrailingWhitespace(tree_structure_vector[i]); + + int plus_count = PlusSignCount(tree_structure_vector[i]); + DCHECK(plus_count % 2 == 0) + << "Error in plus sign count, can't have an odd number of plus signs"; + DCHECK(plus_count <= greatest_count + 2) + << "Error in plus signs count at tree structure line number " << i + << ", it can't have more than two more plus signs than the previous " + "element."; + + if (plus_count > greatest_count) { + greatest_count = plus_count; + } + + auto elem = last_index_appearance_of_plus_count.find(plus_count); + if (elem == last_index_appearance_of_plus_count.end() || + (int)i > elem->second) { + last_index_appearance_of_plus_count[plus_count] = i; + } + + // We remove the plus signs from the string. + tree_structure_vector[i].erase(0, plus_count); + std::vector<std::string> node_line = base::SplitStringUsingSubstr( + tree_structure_vector[i], " ", base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + + AXNodeData curr_node = ParseNodeInfo(node_line, found_ids); + node_data_vector.push_back(curr_node); + + // Two cases. Either This line's plus count is greater than the last line's, + // which would make `curr_node` the direct child of the last node. Or the + // current plus count is <= last one, which would mean the parent is higher + // up. + if (plus_count > last_count) { + node_data_vector[i - 1].child_ids.push_back(curr_node.id); + } else { + elem = last_index_appearance_of_plus_count.find(plus_count - 2); + DCHECK(elem != last_index_appearance_of_plus_count.end()) + << "Error in plus sign count."; + int parent_index = elem->second; + node_data_vector[parent_index].child_ids.push_back(curr_node.id); + } + + last_count = plus_count; + } + + DCHECK(node_data_vector.size() >= 1); + + tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID(); + tree_data.focused_tree_id = tree_data.tree_id; + tree_data.parent_tree_id = ui::AXTreeIDUnknown(); + tree_data = tree_data; + has_tree_data = true; + root_id = node_data_vector[0].id; + + for (auto& node : node_data_vector) { + nodes.push_back(node); + } +} + } // namespace ui
diff --git a/ui/accessibility/test_ax_tree_update.h b/ui/accessibility/test_ax_tree_update.h index d9b21082..eeaa5ee 100644 --- a/ui/accessibility/test_ax_tree_update.h +++ b/ui/accessibility/test_ax_tree_update.h
@@ -5,10 +5,19 @@ #ifndef UI_ACCESSIBILITY_TEST_AX_TREE_UPDATE_H_ #define UI_ACCESSIBILITY_TEST_AX_TREE_UPDATE_H_ +#include <set> +#include <unordered_map> + +#include "ui/accessibility/ax_enum_util.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_tree_update.h" namespace ui { +struct AXNodeData; +struct AXTreeData; +class AXTreeID; + // These utility classes, help construct an AXTreeUpdate together with all of // the updated nodes more easily. Only for use in tests for constructing / // updating simple accessibility trees. @@ -41,14 +50,41 @@ public: TestAXTreeUpdate(const TestAXTreeUpdateNode& root); + // Returns an `AXTreeUpdate` from a tree structure string of the format: + // ++<id> <role> <name?>="<name>" <state?>=<state_value>,<state_value> + // Where the properties denoted with a `?` are optional. + // For example: + // ++++4 kTextField name="placeholder" state=kEditable,kFocusable + // + // Other supported properties are: + // * intAttribute=<intAttributeType>,<intAttributeValue> + // * stringAttribute=<stringAttributeType>,<stringAttributeValue> + // * boolAttribute=<boolAttributeType>,<boolAttributeValue> + // + // Some of the expectations this function makes are: + // * Roles and states are always valid. + // * Roles and states are prefixed by a 'k'. + // * The `name` property value passed in is surrounded by double quotes. + // * Properties that may have multiple possible values passed in have those + // values separated ONLY by a comma. + // * There is always a newline separating each node of the tree. + // + // LIMITATIONS: + // - Because the parsing uses newline characters to distinguish between lines + // (where each line is one node), names for nodes can't be newline characters. + // - For similar reasons, spaces, '+', '=', commas, and double quotes can't be + // used as or within node names. + // Follow up CLs will be made so alleviate these limitations. + TestAXTreeUpdate(const std::string& tree_structure); + TestAXTreeUpdate(const TestAXTreeUpdate&) = delete; TestAXTreeUpdate& operator=(const TestAXTreeUpdate&) = delete; private: // Recursively creates the tree update structure. AXNodeID SetSubtree(const TestAXTreeUpdateNode& node); -}; +}; } // namespace ui #endif // UI_ACCESSIBILITY_TEST_AX_TREE_UPDATE_H_
diff --git a/ui/chromeos/events/keyboard_capability.cc b/ui/chromeos/events/keyboard_capability.cc index d9c05d7..69c3f539 100644 --- a/ui/chromeos/events/keyboard_capability.cc +++ b/ui/chromeos/events/keyboard_capability.cc
@@ -217,6 +217,16 @@ return modifier_keys; } +KeyboardCapability::DeviceType KeyboardCapability::GetDeviceType( + const InputDevice& keyboard) { + const auto* keyboard_info = GetKeyboardInfo(keyboard); + if (!keyboard_info) { + return DeviceType::kDeviceUnknown; + } + + return keyboard_info->device_type; +} + void KeyboardCapability::SetKeyboardInfoForTesting(const InputDevice& keyboard, KeyboardInfo keyboard_info) { keyboard_info_map_.insert_or_assign(keyboard.id, std::move(keyboard_info));
diff --git a/ui/chromeos/events/keyboard_capability.h b/ui/chromeos/events/keyboard_capability.h index d781f2a..a589a71 100644 --- a/ui/chromeos/events/keyboard_capability.h +++ b/ui/chromeos/events/keyboard_capability.h
@@ -206,6 +206,9 @@ // Returns the set of modifier keys present on the given keyboard. std::vector<mojom::ModifierKey> GetModifierKeys(const InputDevice& keyboard); + // Returns the device type of the given keyboard. + DeviceType GetDeviceType(const InputDevice& keyboard); + // Takes a `KeyboardInfo` to use for testing the passed in keyboard. void SetKeyboardInfoForTesting(const InputDevice& keyboard, KeyboardInfo keyboard_info);
diff --git a/ui/file_manager/file_manager/externs/ts/store.js b/ui/file_manager/file_manager/externs/ts/store.js index d121c13..54de133 100644 --- a/ui/file_manager/file_manager/externs/ts/store.js +++ b/ui/file_manager/file_manager/externs/ts/store.js
@@ -22,7 +22,7 @@ subscribe(observer) {} /** @param {!StoreObserver} observer */ - usubscribe(observer) {} + unsubscribe(observer) {} /** @return {!State} */ getState() {}
diff --git a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js index 12b835e..bbd3fd763 100644 --- a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js +++ b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js
@@ -4,6 +4,9 @@ import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js'; +import {Store} from '../../externs/ts/store.js'; +import {updateDirectoryContent, updateSelection} from '../../state/actions/current_directory.js'; + import {FileSelection, FileSelectionHandler} from './file_selection.js'; /** @@ -19,7 +22,12 @@ computeAdditionalCallback() {} - updateSelection(entries, mimeTypes) { + /** + * @param entries {!Array<Entry|FilesAppEntry>} + * @param mimeTypes {!Array<string>} + * @param store {Store=} + */ + updateSelection(entries, mimeTypes, store = null) { this.selection = /** @type {!FileSelection} */ ({ entries: entries, mimeTypes: mimeTypes, @@ -30,6 +38,16 @@ }); }, }); + + if (store) { + // Make sure that the entry is in the directory content. + store.dispatch(updateDirectoryContent({entries})); + // Mark the entry as selected. + store.dispatch(updateSelection({ + selectedKeys: entries.map(e => e.toURL()), + entries, + })); + } } addEventListener(...args) {
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.ts b/ui/file_manager/file_manager/foreground/js/task_controller.ts index 42c4a92..cb4d923 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller.ts +++ b/ui/file_manager/file_manager/foreground/js/task_controller.ts
@@ -41,6 +41,16 @@ params: chrome.fileManagerPrivate.IOTaskParams; } +/** + * Small helper function that makes easier to flip from Store to non-Store + * tasks. + */ +function shouldUseStore() { + // Enabling the Store by default, meaning when the experimental flag is ON we + // fallback to the legacy version. + return !util.isFilesAppExperimental(); +} + export class TaskController { private fileTransferController_: FileTransferController|null = null; private taskHistory_: TaskHistory; @@ -65,7 +75,7 @@ private lastSelectedEntries_: Entry[]; private store_: Store; private selectionFilesData_: FileData[] = []; - private selectionKeys_: FileKey[]|undefined = []; + private selectionKeys_: FileKey[] = []; private selectionTasks_: StoreFileTasks|undefined; constructor( @@ -84,7 +94,7 @@ this.lastSelectedEntries_ = []; this.store_ = getStore(); - if (util.isFilesAppExperimental()) { + if (shouldUseStore()) { this.store_.subscribe(this); } else { // These events are superseded by the store. @@ -108,16 +118,20 @@ } onStateChanged(newState: State) { - const keys = newState.currentDirectory?.selection.keys; + const keys = newState.currentDirectory?.selection.keys ?? []; const tasks = newState.currentDirectory?.selection.fileTasks; - if (keys !== this.selectionKeys_) { + if (keys !== this.selectionKeys_ && + (keys.length > 0 || this.selectionKeys_.length > 0)) { this.selectionKeys_ = keys; this.selectionFilesData_ = getFilesData(newState, keys ?? []); // Kickoff the async/ActionsProducer to fetch the tasks for the new // selection. - if (util.isFilesAppExperimental()) { + if (shouldUseStore()) { this.tasks_ = null; - this.store_.dispatch(fetchFileTasks(this.selectionFilesData_)); + // Only fetch if there is anything to fetch. + if (keys.length > 0) { + this.store_.dispatch(fetchFileTasks(this.selectionFilesData_)); + } // Hides the button while fetching the tasks. this.maybeHideButton(); } @@ -191,7 +205,8 @@ format = extensions[0]!; } - // Change default was clicked. We should open "change default" dialog. + // Change default was clicked. We should open "change default" + // dialog. tasks.showTaskPicker( this.ui_.defaultTaskPicker, str('CHANGE_DEFAULT_MENU_ITEM'), strf('CHANGE_DEFAULT_CAPTION', format), @@ -247,8 +262,8 @@ /** * Populate the #tasks-menu with the open-with tasks. The menu is managed by - * the top task menu Open combobutton, but it is also used as the right-click - * open-with context menu. + * the top task menu Open combobutton, but it is also used as the + * right-click open-with context menu. */ private updateTasksDropdown_(fileTasks: FileTasks) { const combobutton = this.ui_.taskMenuButton; @@ -290,7 +305,8 @@ // default is not set by policy, we show an item to change default task. if (defaultTask && !fileTasks.getPolicyDefaultHandlerStatus()) { combobutton.addSeparator(); - // TODO(greengrape): Ensure that the passed object is a `DropdownItem`. + // TODO(greengrape): Ensure that the passed object is a + // `DropdownItem`. const changeDefaultMenuItem = combobutton.addDropDownItem({ type: TaskMenuItemType.CHANGE_DEFAULT_TASK, label: str('CHANGE_DEFAULT_MENU_ITEM'), @@ -303,7 +319,8 @@ } /** - * Creates sorted array of available task descriptions such as title and icon. + * Creates sorted array of available task descriptions such as title and + * icon. * * @param fileTasks File Tasks to create items. * @return Created array can be used to feed combobox, menus and so on. @@ -318,7 +335,8 @@ const title = task.title + ' ' + str('DEFAULT_TASK_LABEL'); items.push(createDropdownItem( task, title, /*bold=*/ true, /*isDefault=*/ true, - /*isPolicyDefault=*/ !!fileTasks.getPolicyDefaultHandlerStatus())); + /*isPolicyDefault=*/ + !!fileTasks.getPolicyDefaultHandlerStatus())); } else { items.push(createDropdownItem(task)); } @@ -377,9 +395,9 @@ } /** - * Get MIME type for an entry. This method first tries to obtain the MIME type - * from metadata. If it fails, this falls back to obtain the MIME type from - * its content or name. + * Get MIME type for an entry. This method first tries to obtain the MIME + * type from metadata. If it fails, this falls back to obtain the MIME type + * from its content or name. * @param entry An entry to obtain its mime type. */ private async getMimeType_(entry: Entry): Promise<string> { @@ -416,12 +434,12 @@ } /** - * Explicitly removes the cached tasks first and and re-calculates the current - * tasks. + * Explicitly removes the cached tasks first and and re-calculates the + * current tasks. */ private clearCacheAndUpdateTasks_() { this.tasks_ = null; - if (util.isFilesAppExperimental()) { + if (shouldUseStore()) { // Dispatch an empty fetch to invalidate any ongoing fetch. this.store_.dispatch(fetchFileTasks([])); } @@ -431,7 +449,7 @@ private maybeHideButton(): boolean { const selection = this.selectionHandler_.selection; // For the Store version the other conditions are checked in the store. - const shouldDisableTasks = util.isFilesAppExperimental() ? + const shouldDisableTasks = shouldUseStore() ? (this.selectionTasks_?.tasks ?? []).length === 0 : ( // File Picker/Save As doesn't show the "Open" button. @@ -483,7 +501,7 @@ } async getFileTasks(): Promise<FileTasks> { - if (util.isFilesAppExperimental()) { + if (shouldUseStore()) { return this.getFileTasksStore_(); } const selection = this.selectionHandler_.selection;
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.ts b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.ts index 89c1986..7574d1f 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.ts +++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.ts
@@ -3,10 +3,12 @@ // found in the LICENSE file. import {assert} from 'chrome://resources/ash/common/assert.js'; -import {assertDeepEquals, assertNotReached, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js'; +import {assertDeepEquals, assertEquals, assertNotReached, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js'; import {createCrostiniForTest} from '../../background/js/mock_crostini.js'; +import {MockVolumeManager} from '../../background/js/mock_volume_manager.js'; import {DialogType} from '../../common/js/dialog_type.js'; +import {queryDecoratedElement} from '../../common/js/dom_utils.js'; import {metrics} from '../../common/js/metrics.js'; import {installMockChrome} from '../../common/js/mock_chrome.js'; import {MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.js'; @@ -14,28 +16,39 @@ import {decorate} from '../../common/js/ui.js'; import {util} from '../../common/js/util.js'; import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js'; +import {Crostini} from '../../externs/background/crostini.js'; import {ProgressCenter} from '../../externs/background/progress_center.js'; +import {PropStatus} from '../../externs/ts/state.js'; +import {VolumeInfo} from '../../externs/volume_info.js'; import {VolumeManager} from '../../externs/volume_manager.js'; +import {changeDirectory} from '../../state/actions/current_directory.js'; +import {getEmptyState, getStore} from '../../state/store.js'; import {DirectoryModel} from './directory_model.js'; import {FakeFileSelectionHandler} from './fake_file_selection_handler.js'; import {FileSelectionHandler} from './file_selection.js'; -import {FileTasks} from './file_tasks.js'; import {MetadataModel} from './metadata/metadata_model.js'; import {MockMetadataModel} from './metadata/mock_metadata.js'; import {MetadataUpdateController} from './metadata_update_controller.js'; +import {createFakeDirectoryModel} from './mock_directory_model.js'; import {TaskController} from './task_controller.js'; +import {ComboButton} from './ui/combobutton.js'; import {Command} from './ui/command.js'; import {FileManagerUI} from './ui/file_manager_ui.js'; +import {FilesMenuItem} from './ui/files_menu.js'; /** Mock metrics. */ metrics.recordEnum = function( _name: string, _value: any, _valid?: any[]|number) {}; +metrics.recordDirectoryListLoadWithTolerance = function() {}; /** Mock chrome APIs. */ let mockChrome: any; +/** VolumeInfo for Downloads volume */ +let downloads: VolumeInfo; + // Set up test components. export function setUp() { // Mock chrome APIs. @@ -58,10 +71,38 @@ document.body.innerHTML = [ '<command id="default-task">', '<command id="open-with">', + '<cr-menu id="tasks-menu">', + ' <cr-menu-item id="default-task-menu-item" command="#default-task">', + ' </cr-menu-item>', + '</cr-menu>', + '<cr-button id="tasks" menu="#tasks-menu"> Open </cr-button>', ].join(''); // Initialize Command with the <command>s. decorate('command', Command); + + const volumeManager = new MockVolumeManager(); + window.fileManager = { + dialogType: DialogType.FULL_PAGE, + volumeManager: volumeManager, + metadataModel: new MockMetadataModel({}) as unknown as MetadataModel, + crostini: {} as unknown as Crostini, + selectionHandler: new FakeFileSelectionHandler(), + taskController: {} as unknown as TaskController, + directoryModel: createFakeDirectoryModel(), + }; + + downloads = volumeManager.getCurrentProfileVolumeInfo( + VolumeManagerCommon.VolumeType.DOWNLOADS)!; + + const store = getStore(); + store.init(getEmptyState()); + + store.dispatch(changeDirectory({ + to: downloads.displayRoot, + toKey: downloads.displayRoot.toURL(), + status: PropStatus.SUCCESS, + })); } function createTaskController(fileSelectionHandler: FileSelectionHandler): @@ -81,11 +122,12 @@ }, } as unknown as VolumeManager, { - taskMenuButton: document.createElement('button'), - fileContextMenu: { - defaultActionMenuItem: document.createElement('div'), - }, + taskMenuButton: queryDecoratedElement('#tasks', ComboButton), + defaultTaskMenuItem: + queryDecoratedElement('#default-task-menu-item', FilesMenuItem), speakA11yMessage: (_text: string) => {}, + listContainer: document.createElement('div'), + tasksSeparator: document.createElement('hr'), } as unknown as FileManagerUI, new MockMetadataModel({}) as unknown as MetadataModel, { getCurrentRootType: () => null, @@ -102,10 +144,12 @@ function setupFileManagerPrivate() { mockChrome.fileManagerPrivate = { getFileTaskCalledCount_: 0, + getFileTaskCalledEntries_: [], getFileTasks: function( - _entries: Entry[], _sourceUrls: string[], + entries: Entry[], _sourceUrls: string[], callback: (tasks: any) => void) { mockChrome.fileManagerPrivate.getFileTaskCalledCount_++; + mockChrome.fileManagerPrivate.getFileTaskCalledEntries_.push(entries); const fileTasks = ([ /** @type {!chrome.fileManagerPrivate.FileTask} */ ({ descriptor: { @@ -133,10 +177,9 @@ * Tests that executeEntryTask() runs the expected task. */ export function testExecuteEntryTask(callback: () => void) { - const selectionHandler = - new FakeFileSelectionHandler() as unknown as FileSelectionHandler; + const selectionHandler = window.fileManager.selectionHandler; - const fileSystem = new MockFileSystem('volumeId'); + const fileSystem = downloads.fileSystem as MockFileSystem; fileSystem.entries['/test.png'] = MockFileEntry.create(fileSystem, '/test.png'); const taskController = createTaskController(selectionHandler); @@ -161,30 +204,33 @@ */ export async function testGetFileTasksShouldNotBeCalledMultipleTimes( done: () => void) { - const selectionHandler = new FakeFileSelectionHandler(); - - const fileSystem = new MockFileSystem('volumeId'); - selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/test.png')], ['image/png']); + const selectionHandler = window.fileManager.selectionHandler; + const store = getStore(); const taskController = createTaskController(selectionHandler as unknown as FileSelectionHandler); + const fileSystem = downloads.fileSystem; + selectionHandler.updateSelection( + [MockFileEntry.create(fileSystem, '/test.png')], ['image/png'], store); + assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 0); let tasks = await taskController.getFileTasks(); assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 1); assert(util.isSameEntries(tasks.entries, selectionHandler.selection.entries)); - // Make oldSelection.entries !== newSelection.entries + // NOTE: It updates to the same file. selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/test.png')], ['image/png']); + [MockFileEntry.create(fileSystem, '/test.png')], ['image/png'], store); tasks = await taskController.getFileTasks(); - assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 1); + assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 2); assert(util.isSameEntries(tasks.entries, selectionHandler.selection.entries)); - // Check concurrent calls, should only create one promise and one call to the - // private API. + // The update above generates a new selection, even though it's updating to + // the same file, this causes a new private API call. + // The Store ActionsProducer debounces multiple concurrent calls for the same + // file so in practice this shouldn't be a problem. const promise1 = taskController.getFileTasks(); - // Await 0ms to give time to pomise1 to initialize. + // Await 0ms to give time to promise1 to initialize. await new Promise(r => setTimeout(r)); const promise2 = taskController.getFileTasks(); const [tasks1, tasks2] = await Promise.all([promise1, promise2]); @@ -192,25 +238,24 @@ tasks1.entries, tasks2.entries, 'both tasks should have test.png as entry'); assertTrue(tasks1 === tasks2); - assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 1); + assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 2); assert( util.isSameEntries(tasks1.entries, selectionHandler.selection.entries)); // Check concurrent calls right after changing the selection. selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/hello.txt')], ['text/plain']); + [MockFileEntry.create(fileSystem, '/hello.txt')], ['text/plain'], store); const promise3 = taskController.getFileTasks(); - // Await 0ms to give time to pomise3 to initialize. + // Await 0ms to give time to promise3 to initialize. await new Promise(r => setTimeout(r)); const promise4 = taskController.getFileTasks(); const [tasks3, tasks4] = await Promise.all([promise3, promise4]); assertDeepEquals( tasks3.entries, tasks4.entries, 'both tasks should have hello.txt as entry'); - assertTrue(tasks3 === tasks4); assert( util.isSameEntries(tasks3.entries, selectionHandler.selection.entries)); - assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 2); + assert(mockChrome.fileManagerPrivate.getFileTaskCalledCount_ === 3); done(); } @@ -222,21 +267,21 @@ */ export function testGetFileTasksShouldNotReturnObsoletePromise( callback: () => void) { - const selectionHandler = new FakeFileSelectionHandler(); - - const fileSystem = new MockFileSystem('volumeId'); - selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/test.png')], ['image/png']); + const selectionHandler = window.fileManager.selectionHandler; + const store = getStore(); + const fileSystem = downloads.fileSystem; const taskController = createTaskController(selectionHandler as unknown as FileSelectionHandler); + selectionHandler.updateSelection( + [MockFileEntry.create(fileSystem, '/test.png')], ['image/png'], store); taskController.getFileTasks() .then(tasks => { assert(util.isSameEntries( tasks.entries, selectionHandler.selection.entries)); selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/testtest.jpg')], - ['image/jpeg']); + [MockFileEntry.create(fileSystem, '/testtest.jpg')], ['image/jpeg'], + store); return taskController.getFileTasks(); }) .then(tasks => { @@ -253,40 +298,54 @@ * Tests that changing the file selection during a getFileTasks() call causes * the getFileTasks() promise to reject. */ -export function testGetFileTasksShouldNotCacheRejectedPromise( - callback: () => void) { - const selectionHandler = new FakeFileSelectionHandler(); - - const fileSystem = new MockFileSystem('volumeId'); - selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/test.png')], ['image/png']); +export async function testGetFileTasksShouldNotCacheRejectedPromise( + done: () => void) { + const selectionHandler = window.fileManager.selectionHandler; + const store = getStore(); + const fileSystem = downloads.fileSystem; const taskController = createTaskController(selectionHandler as unknown as FileSelectionHandler); // Setup the selection handler computeAdditionalCallback to change the file // selection during the getFileTasks() call. + let selectionUpdated = false; selectionHandler.computeAdditionalCallback = () => { + // Update the selection. selectionHandler.updateSelection( - [MockFileEntry.create(fileSystem, '/test.png')], ['image/png']); + [MockFileEntry.create(fileSystem, '/other-file.png')], ['image/png'], + store); + selectionUpdated = true; }; - taskController.getFileTasks().then( - (_tasks: FileTasks) => { - assertNotReached('Fail: getFileTasks promise should be rejected'); - }, - () => { - // Clears the selection handler computeAdditionalCallback so that the - // promise won't be rejected during the getFileTasks() call. - selectionHandler.computeAdditionalCallback = () => {}; + // Set the initial selection. + selectionHandler.updateSelection( + [MockFileEntry.create(fileSystem, '/test.png')], ['image/png'], store); - taskController.getFileTasks().then( - tasks => { - assert(util.isSameEntries( - tasks.entries, selectionHandler.selection.entries)); - callback(); - }, - () => { - assertNotReached('Fail: getFileTasks promise was rejected'); - }); - }); + const tasks = await taskController.getFileTasks(); + assertTrue(selectionUpdated, 'selection should update'); + + // Clears the selection handler computeAdditionalCallback so that the + // promise won't be rejected during the getFileTasks() call. + selectionHandler.computeAdditionalCallback = () => {}; + const callsToApi = mockChrome.fileManagerPrivate.getFileTaskCalledCount_; + + // Calling getFileTasks() in the same selection should not call the + // private API. + const tasks2 = await taskController.getFileTasks(); + assert(util.isSameEntries(tasks.entries, tasks2.entries)); + assert( + util.isSameEntries(tasks2.entries, selectionHandler.selection.entries)); + + // No more calls to the private API. + assertEquals( + callsToApi, mockChrome.fileManagerPrivate.getFileTaskCalledCount_); + assertEquals( + 0, + mockChrome.fileManagerPrivate.getFileTaskCalledEntries_ + .filter( + (entries: Entry[]) => + entries.filter((e: Entry) => e.name === '/test.png').length) + .length, + 'Should have NO calls to private API for the initial selection'); + done(); }
diff --git a/ui/message_center/public/cpp/notification.h b/ui/message_center/public/cpp/notification.h index fad74a6d0..33ccebc7 100644 --- a/ui/message_center/public/cpp/notification.h +++ b/ui/message_center/public/cpp/notification.h
@@ -407,6 +407,12 @@ const gfx::Image& image() const { return optional_fields_.image; } void set_image(const gfx::Image& image) { optional_fields_.image = image; } +#if BUILDFLAG(IS_CHROMEOS) + void set_image_path(const base::FilePath& image_path) { + optional_fields_.image_path = image_path; + } +#endif + const gfx::Image& small_image() const { return optional_fields_.small_image; } void set_small_image(const gfx::Image& image) { optional_fields_.small_image = image;