diff --git a/.gn b/.gn index d8529c7..2836133 100644 --- a/.gn +++ b/.gn
@@ -49,6 +49,13 @@ # Changes some setup for the Crashpad build to set them to build against # Chromium's zlib, base, etc. crashpad_dependencies = "chromium" + + # Override ANGLE's Vulkan dependencies. + angle_vulkan_headers_dir = "//third_party/vulkan-deps/vulkan-headers/src" + angle_vulkan_loader_dir = "//third_party/vulkan-deps/vulkan-loader/src" + angle_vulkan_tools_dir = "//third_party/vulkan-deps/vulkan-tools/src" + angle_vulkan_validation_layers_dir = + "//third_party/vulkan-deps/vulkan-validation-layers/src" } # These are the targets to skip header checking by default. The files in targets
diff --git a/BUILD.gn b/BUILD.gn index f7a8c62f..89fff8cc 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -149,9 +149,9 @@ "//ppapi/examples/video_decode", "//ppapi/examples/video_encode", "//printing:printing_unittests", - "//third_party/SPIRV-Tools/src:SPIRV-Tools", - "//third_party/SPIRV-Tools/src/test/fuzzers", "//third_party/pdfium/samples:pdfium_test", + "//third_party/vulkan-deps/spirv-tools/src:SPIRV-Tools", + "//third_party/vulkan-deps/spirv-tools/src/test/fuzzers", "//tools/perf/clear_system_cache", "//tools/polymer:polymer_tools_python_unittests", "//tools/privacy_budget:privacy_budget_tools",
diff --git a/DEPS b/DEPS index 29786e29..2dbc76b 100644 --- a/DEPS +++ b/DEPS
@@ -199,11 +199,11 @@ # 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': '860d01ca8bae3a8a85a104fa755c4149fd1349c5', + 'skia_revision': '415642b766face3623257248e2c0f1d99d1406b2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'fc4ac7024d121a1fdc77cecab42defe4bd11a967', + 'v8_revision': '68e7e8e44e2565c394ee558210d6d9fa5a4d80ff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -215,7 +215,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '1ca6504eb7bb9971d317cf8c8033b38b914036b7', + 'swiftshader_revision': '1cc5b3357d2ff3c81ef7ec0b07a6660796bde5cd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -250,7 +250,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. - 'freetype_revision': '84b3616c94f48726c596ead4150218d4431b3412', + 'freetype_revision': '7bdf386e758cb7c01392e625f4d723e5abb3f9a6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -266,7 +266,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '5039608d33669976de3673888c138b0aba2f47ff', + 'catapult_revision': '8d43e589947e9279336118ca568525261849f886', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -274,7 +274,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '7df55c21d64b6df52a923c3e6e3b370db6e0a495', + 'devtools_frontend_revision': '50f3473f0f8aae9c656db4922a33607de0d7530e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -310,23 +310,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': '671914c28e8249f0a555726a0f3f38691fe5c1df', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling feed - # and whatever else without interference from each other. - 'spv_headers_revision': '05836bdba63e7debce9fa9feaed42f20cd43af9d', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling feed - # and whatever else without interference from each other. - 'spirv_cross_revision': '16d9fea77c376cb5d7d6e06d33bf054fe24734a7', - # Three lines of non-changing comments so that - # the commit queue can handle CLs rolling feed - # and whatever else without interference from each other. 'shaderc_revision': '4089217d30c1f035c44a08255b875b5fea4f4bc5', # 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': '155241b665f8305d54145ca460e0b8cebe888336', + 'dawn_revision': 'ee977a0df8e3f3a12a6f2983db98838bf65566da', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -354,7 +342,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '03db3f121129434cd1298c098b6d14444e488c01', + 'nearby_revision': '183aed7f6cc2bc86c4deac1037b9873b567b4a52', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -649,22 +637,6 @@ 'dep_type': 'cipd', }, - # SPIRV-Cross is in third_party/spirv-cross/spirv-cross instead of - # third_party/spirv-cross/src because its header files are at the root of - # the repository and dependencies include them like so: - # #include "spirv-cross/spirv_glsl.hpp" - 'src/third_party/spirv-cross/spirv-cross': - Var('chromium_git') + '/external/github.com/KhronosGroup/SPIRV-Cross.git@' + - Var('spirv_cross_revision'), - - 'src/third_party/spirv-headers/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/SPIRV-Headers.git@' + - Var('spv_headers_revision'), - - 'src/third_party/SPIRV-Tools/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/SPIRV-Tools.git@' + - Var('spv_tools_revision'), - 'src/third_party/shaderc/src': Var('chromium_git') + '/external/github.com/google/shaderc.git@' + Var('shaderc_revision'), @@ -916,7 +888,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'efa6d9547c85979240e5bf0c4c796e0a84b0fdf5', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'd6f3734b69e2f842a58bdc6c6a63cf17d82629df', 'condition': 'checkout_linux', }, @@ -987,9 +959,6 @@ 'src/third_party/libgav1/src': Var('chromium_git') + '/codecs/libgav1.git' + '@' + 'a9449e612bc251b4271bbe1e3a0d12e9809bf74c', - 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'd550bebee919179c9e332a0ab28a67f8fe3ca239', - 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), 'condition': 'checkout_ios or checkout_mac', @@ -1276,7 +1245,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3dd5b80bc4f172dd82925bb259cb7c82348409c5', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + '4a33b7b19905753224349bc09e1b4adef115cb3c', + Var('chromium_git') + '/openscreen' + '@' + '31a6a84b0393546e7076a90d0d5b5c5c606825a0', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '97cfe495bb7a3853266b646d1c79e169387f9c7a', @@ -1293,7 +1262,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '0d23e521cc40b7a795ad98247a5d5b20121a5cf4', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c65f224a7259d87bf1f980e7424d73fc0cfca795', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1371,7 +1340,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/aemu/linux-amd64', - 'version': 'xbub5pS-4jut2bXIXFZ4xABfPqAJC0wMGX7DZaoMJNcC' + 'version': 'qMq36BPvKEIxjpVFBefO08HoyM51jARe3EuX0vcgzWsC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1512,6 +1481,8 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '995c0b84414466d77d52011e5b572cbe213b770a', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@b08eace32e9cb8dd7dce9866f051558ac57acb15', + 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '6c656df63da5995a932aafd45b32af1974e497d9', @@ -1615,7 +1586,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fdd70108b562959fc71b0d0c0c7e76c4e7b25b9c', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@36bcb86f66a4d861de00d0b4dff06111fd1cab21', 'condition': 'checkout_src_internal', }, @@ -5043,6 +5014,7 @@ # ANGLE manages DEPS that it also owns the build files for, such as dEQP. 'src/third_party/angle', 'src/third_party/openscreen/src', + 'src/third_party/vulkan-deps', # src-internal has its own DEPS file to pull additional internal repos 'src-internal', ]
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index b32bceb..bed617c 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1005,6 +1005,8 @@ "system/holding_space/holding_space_tray_icon.h", "system/holding_space/holding_space_tray_icon_preview.cc", "system/holding_space/holding_space_tray_icon_preview.h", + "system/holding_space/holding_space_util.cc", + "system/holding_space/holding_space_util.h", "system/holding_space/pinned_files_bubble.cc", "system/holding_space/pinned_files_bubble.h", "system/holding_space/pinned_files_section.cc", @@ -1240,6 +1242,8 @@ "system/power/battery_notification.h", "system/power/dual_role_notification.cc", "system/power/dual_role_notification.h", + "system/power/peripheral_battery_listener.cc", + "system/power/peripheral_battery_listener.h", "system/power/peripheral_battery_notifier.cc", "system/power/peripheral_battery_notifier.h", "system/power/power_button_controller.cc", @@ -2223,6 +2227,8 @@ "system/phonehub/silence_phone_quick_action_controller_unittest.cc", "system/phonehub/task_continuation_view_unittest.cc", "system/power/backlights_forced_off_setter_unittest.cc", + "system/power/peripheral_battery_listener_unittest.cc", + "system/power/peripheral_battery_notifier_listener_integration_test.cc", "system/power/peripheral_battery_notifier_unittest.cc", "system/power/power_button_controller_unittest.cc", "system/power/power_button_screenshot_controller_unittest.cc",
diff --git a/ash/app_list/app_list_color_provider_impl.cc b/ash/app_list/app_list_color_provider_impl.cc index e940722..889cdad 100644 --- a/ash/app_list/app_list_color_provider_impl.cc +++ b/ash/app_list/app_list_color_provider_impl.cc
@@ -69,9 +69,9 @@ } SkColor AppListColorProviderImpl::GetSearchBoxCardBackgroundColor() const { - // Set solid color background to avoid broken text. See crbug.com/746563. - return DeprecatedGetBaseLayerColor(AshColorProvider::BaseLayerType::kOpaque, - /*default_color*/ SK_ColorWHITE); + return DeprecatedGetBaseLayerColor( + AshColorProvider::BaseLayerType::kTransparent80, + /*default_color*/ SK_ColorWHITE); } SkColor AppListColorProviderImpl::GetSearchBoxTextColor(
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc index cc7c683..61e6707 100644 --- a/ash/app_list/views/search_result_tile_item_view.cc +++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -155,10 +155,7 @@ title_->SetFontList(font); title_->SetEnabledColor(AppListConfig::instance().grid_title_color()); } else { - // Set solid color background to avoid broken text. See crbug.com/746563. if (rating_) { - rating_->SetBackground(views::CreateSolidBackground( - AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor())); if (!IsSuggestedAppTile()) { // App search results use different fonts than AppList apps. rating_->SetFontList( @@ -169,8 +166,6 @@ } } if (price_) { - price_->SetBackground(views::CreateSolidBackground( - AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor())); if (!IsSuggestedAppTile()) { // App search results use different fonts than AppList apps. price_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( @@ -179,8 +174,6 @@ price_->SetFontList(font); } } - title_->SetBackground(views::CreateSolidBackground( - AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor())); if (!IsSuggestedAppTile()) { // App search results use different fonts than AppList apps. title_->SetFontList(
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc index b7cf9926..d4bec00 100644 --- a/ash/app_list/views/search_result_view.cc +++ b/ash/app_list/views/search_result_view.cc
@@ -265,12 +265,6 @@ text_bounds.set_x( GetMirroredXWithWidthInView(text_bounds.x(), text_bounds.width())); - // Set solid color background to avoid broken text. See crbug.com/746563. - // This should be drawn before selected color which is semi-transparent. - canvas->FillRect( - text_bounds, - AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor()); - if (title_text_ && details_text_) { gfx::Size title_size(text_bounds.width(), kTitleLineHeight); gfx::Size details_size(text_bounds.width(), kDetailsLineHeight);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index b7524f1..d6a5fcab 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1005,11 +1005,14 @@ </message> <!-- Holding space tray--> + <message name="IDS_ASH_HOLDING_SPACE_A11Y_NAME" desc="A11y name of the holding space tray and bubble."> + Tote: recent screen captures, downloads, and pinned files + </message> <message name="IDS_ASH_HOLDING_SPACE_TITLE" desc="Title of the holding space tray and bubble."> - Recent screen captures and downloads + Tote </message> <message name="IDS_ASH_HOLDING_SPACE_PINNED_TITLE" desc="Title of the pinned files area in the holding space bubble."> - Pinned + Pinned files </message> <message name="IDS_ASH_HOLDING_SPACE_PINNED_EMPTY_PROMPT" desc="Prompt shown in the pinned files area of the holding space bubble if the user has no pinned files."> You can pin your important files here. Open Files app to get started. @@ -1155,13 +1158,13 @@ Connecting... </message> <message name="IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION" desc="The description of the generic connecting dialog that indicates the device is trying to connect to your phone."> - Make sure your phone is nearby with Bluetooth and Wi-Fi is turned on. + Make sure your phone is nearby and has Bluetooth turned on. </message> <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE" desc="The title of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> - Can’t find your phone + Can't find your phone </message> - <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION" desc="The description of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone."> - Looks like your phone is not online and we are not able to connect to it. + <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION" desc="The description of the dialog that pops up when the Phone Hub feature is not available because there is currently no active connection to the phone. This message reminds users that Bluetooth must be enabled on the phone in order to use the feature."> + Looks like Bluetooth is turned off on your phone. Please turn on Bluetooth on your phone to use Phone Hub. </message> <message name="IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_REFRESH_BUTTON" desc="Refresh button on the disconnected dialog to retry the connection attempt to the phone."> Refresh @@ -1173,7 +1176,7 @@ Check your connection </message> <message name="IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_DESCRIPTION" desc="The description of the dialog that pops up when the phone hub feature is not available because Bluetooth is disabled on this device."> - Looks like your Bluetooth or Wi-Fi is turned off on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Please check your connection to use Phone Hub. + Looks like Bluetooth is turned off on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Please turn on Bluetooth to use Phone Hub. </message> <message name="IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_OK_BUTTON" desc="Confirm button on the bluetooth disabled dialog to acknowledge."> Ok, got it
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_A11Y_NAME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_A11Y_NAME.png.sha1 new file mode 100644 index 0000000..fdde242a --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_A11Y_NAME.png.sha1
@@ -0,0 +1 @@ +92b881183adeee722264758040b985931d297c76 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_PINNED_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_PINNED_TITLE.png.sha1 index 9445e407..d686f597 100644 --- a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_PINNED_TITLE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_PINNED_TITLE.png.sha1
@@ -1 +1 @@ -85c7fe7a8351346a4e7a66ce9ce589976679acdc \ No newline at end of file +32dedae20977b0adaaf306ff0006386059843701 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_TITLE.png.sha1 index f5d5066..3d291b0 100644 --- a/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_TITLE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_HOLDING_SPACE_TITLE.png.sha1
@@ -1 +1 @@ -7a846ec66eddbcccbf37c03d96beea25663b9a97 \ No newline at end of file +b1e14f708e4414d20b01289a0f829310aa2724e2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_DESCRIPTION.png.sha1 index 6331713..ef4905ca 100644 --- a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_DESCRIPTION.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_DESCRIPTION.png.sha1
@@ -1 +1 @@ -b3ee721c9aed0855dfb4a5dedf460b0d6ed29fdb \ No newline at end of file +cf2623528270d5709d2f6e7342e52c83ebb95452 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1 index b8078aa..ada703df6 100644 --- a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_CONNECTING_DIALOG_DESCRIPTION.png.sha1
@@ -1 +1 @@ -11e0cec900673f197970ef1b4708dc6e79b51810 \ No newline at end of file +6c8c74f15a9aedd655ada2b0e7c29888b590ae33 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1 index 430195f..819bbae 100644 --- a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_DESCRIPTION.png.sha1
@@ -1 +1 @@ -4d218cdf721211bc4342dc2320c5ecd3720c64d8 \ No newline at end of file +5a0ea0877d50fb9bed2e05640f9170489c3b447a \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1 index 430195f..819bbae 100644 --- a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_PHONE_DISCONNECTED_DIALOG_TITLE.png.sha1
@@ -1 +1 @@ -4d218cdf721211bc4342dc2320c5ecd3720c64d8 \ No newline at end of file +5a0ea0877d50fb9bed2e05640f9170489c3b447a \ No newline at end of file
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc index 8829a6e..e96cce3 100644 --- a/ash/public/cpp/ash_features.cc +++ b/ash/public/cpp/ash_features.cc
@@ -154,7 +154,7 @@ const base::Feature kKeyboardBasedDisplayArrangementInSettings{ "KeyboardBasedDisplayArrangementInSettings", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; bool IsAllowAmbientEQEnabled() { return base::FeatureList::IsEnabled(kAllowAmbientEQ);
diff --git a/ash/public/cpp/external_arc/BUILD.gn b/ash/public/cpp/external_arc/BUILD.gn index 8f83d7f..05dd821 100644 --- a/ash/public/cpp/external_arc/BUILD.gn +++ b/ash/public/cpp/external_arc/BUILD.gn
@@ -43,6 +43,7 @@ "//base", "//chromeos/constants", "//components/account_id", + "//components/arc:arc_base_utils", "//components/arc:arc_metrics_constants", "//components/arc:connection_holder", "//components/arc/mojom:notifications",
diff --git a/ash/public/cpp/external_arc/overlay/DEPS b/ash/public/cpp/external_arc/overlay/DEPS new file mode 100644 index 0000000..1598002 --- /dev/null +++ b/ash/public/cpp/external_arc/overlay/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/arc/arc_util.h", +]
diff --git a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc index 003e5fa..60af55de 100644 --- a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc +++ b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc
@@ -6,6 +6,7 @@ #include "ash/public/cpp/external_arc/overlay/arc_overlay_controller_impl.h" #include "base/logging.h" +#include "components/arc/arc_util.h" #include "components/exo/shell_surface_base.h" #include "components/exo/shell_surface_util.h" #include "components/exo/surface.h" @@ -66,45 +67,29 @@ } void ArcOverlayManager::OnWindowInitialized(aura::Window* window) { - // Ignore windows that do not have a delegate set. - if (!window->delegate()) + // Ignore windows that are container (no delegate), or non arc window. + if (!window->delegate() || !arc::IsArcAppWindow(window)) return; - // We only ever observe the most recent window being created - unknown_window_observation_.Reset(); - unknown_window_observation_.Observe(window); + window_observations_.AddObservation(window); } void ArcOverlayManager::OnWindowDestroying(aura::Window* window) { - if (unknown_window_observation_.IsObservingSource(window)) - unknown_window_observation_.Reset(); - - if (overlay_window_observations_.IsObservingSource(window)) - overlay_window_observations_.RemoveObservation(window); + window_observations_.RemoveObservation(window); } -void ArcOverlayManager::OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) { - // We only care about property changes on the single unknown window. - // (We also are observing other windows via overlay_window_observations_) - if (!unknown_window_observation_.IsObservingSource(window)) +void ArcOverlayManager::OnWindowVisibilityChanged(aura::Window* window, + bool visible) { + // We only care about windows that are now visible. + if (!visible) return; - // exo::ShellSurfaceBase sets this key soon after creating the window - if (!exo::IsShellMainSurfaceKey(key)) - return; + // We do not need to keep observing the window. + DCHECK(window_observations_.IsObservingSource(window)); + window_observations_.RemoveObservation(window); - // It may still be of interest as an overlay, but we don't need to observe it - // as an unknown window. - unknown_window_observation_.Reset(); - - // If this isn't actually a variant of a exo::ShellSurfaceBase, it is not an - // overlay candidate. auto* shell_surface_base = exo::GetShellSurfaceBaseForWindow(window); - if (!shell_surface_base) - return; - + DCHECK(shell_surface_base); auto* shell_root_surface = shell_surface_base->root_surface(); DCHECK(shell_root_surface); @@ -114,30 +99,6 @@ if (!base::StartsWith(client_surface_id, kBillingIdPrefix)) return; - // This window seems to be an overlay candidate. Continue observing it as one - // until it is ready. exo::ShellSurfaceBase is still setting it up. - overlay_window_observations_.AddObservation(window); -} - -void ArcOverlayManager::OnWindowVisibilityChanged(aura::Window* window, - bool visible) { - // For this event, we only care about windows that are potential overlays. - if (!overlay_window_observations_.IsObservingSource(window)) - return; - - // We only care about windows that are now visible. - if (!visible) - return; - - // We do not need to keep observing the window. - overlay_window_observations_.RemoveObservation(window); - - auto* shell_surface_base = exo::GetShellSurfaceBaseForWindow(window); - DCHECK(shell_surface_base); - auto* shell_root_surface = shell_surface_base->root_surface(); - DCHECK(shell_root_surface); - - std::string client_surface_id = shell_root_surface->GetClientSurfaceId(); std::string overlay_token = client_surface_id.substr(strlen(kBillingIdPrefix));
diff --git a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.h b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.h index 3609e8bc..640dc03 100644 --- a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.h +++ b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.h
@@ -63,9 +63,6 @@ // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override; - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; private: @@ -78,16 +75,10 @@ base::ScopedObservation<aura::Env, aura::EnvObserver> env_observer_{this}; - // This tracks a single newly created window until we get a confirmation that - // it is an exo::ShellSurfaceBase with the right settings to be an overlay - // (which should happen immediately after creation), or until another new - // window is created. - base::ScopedObservation<aura::Window, aura::WindowObserver> - unknown_window_observation_{this}; - - // This tracks all the overlay candidates until they are actually ready + // This tracks newly created arc windows until they're being shown, or + // destoryed. base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver> - overlay_window_observations_{this}; + window_observations_{this}; }; } // namespace ash
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 4866c91..78a6eec3 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -54,6 +54,7 @@ "dictation_on.icon", "dictation_on_newui.icon", "dogfood.icon", + "files_app.icon", "folder.icon", "global_media_controls.icon", "holding_space.icon", @@ -133,12 +134,14 @@ "palette_action_capture_screen.icon", "palette_action_create_note.icon", "palette_mode_laser_pointer.icon", + "palette_mode_laser_pointer_light_mode.icon", "palette_mode_magnify.icon", "palette_mode_metalayer.icon", "palette_tray_icon_capture_region.icon", "palette_tray_icon_default.icon", "palette_tray_icon_default_newui.icon", "palette_tray_icon_laser_pointer.icon", + "palette_tray_icon_laser_pointer_light_mode.icon", "palette_tray_icon_magnify.icon", "palette_tray_icon_metalayer.icon", "phone_hub_battery_saver.icon",
diff --git a/ash/resources/vector_icons/files_app.icon b/ash/resources/vector_icons/files_app.icon new file mode 100644 index 0000000..0d86793 --- /dev/null +++ b/ash/resources/vector_icons/files_app.icon
@@ -0,0 +1,39 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 192, +PATH_COLOR_ARGB, 0xFF, 0x1A, 0x73, 0xE8, +CIRCLE, 96, 96, 96, +NEW_PATH, +PATH_COLOR_ARGB, 0xFF, 0x8A, 0xB4, 0xF8, +MOVE_TO, 149, 67, +CUBIC_TO, 149, 62.58f, 145.42f, 59, 141, 59, +LINE_TO, 50, 59, +CUBIC_TO, 45.58f, 59, 42, 62.58f, 42, 67, +LINE_TO, 42, 132, +CUBIC_TO, 42, 136.42f, 45.58f, 140, 50, 140, +LINE_TO, 141, 140, +CUBIC_TO, 145.42f, 140, 149, 136.42f, 149, 132, +LINE_TO, 149, 67, +NEW_PATH, +PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF, +MOVE_TO, 50, 52, +CUBIC_TO, 45.58f, 52, 42, 55.58f, 42, 60, +V_LINE_TO, 132, +CUBIC_TO, 42, 136.42f, 45.58f, 140, 50, 140, +H_LINE_TO, 141.13f, +CUBIC_TO, 145.55f, 140, 149.13f, 136.42f, 149.13f, 132, +V_LINE_TO, 125.13f, +LINE_TO, 76, 52, +H_LINE_TO, 50, +NEW_PATH, +PATH_COLOR_ARGB, 0xFF, 0x80, 0xF9, 0xF9, +R_MOVE_TO, 149, 77, +R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8, +R_H_LINE_TO, -99, +R_V_LINE_TO, 63, +R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8, +R_H_LINE_TO, 91, +R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8, +CLOSE
diff --git a/ash/resources/vector_icons/palette_mode_laser_pointer_light_mode.icon b/ash/resources/vector_icons/palette_mode_laser_pointer_light_mode.icon new file mode 100644 index 0000000..1c7955bb --- /dev/null +++ b/ash/resources/vector_icons/palette_mode_laser_pointer_light_mode.icon
@@ -0,0 +1,80 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 40, +PATH_COLOR_ARGB, 0x4D, 0x00, 0x00, 0x00, +MOVE_TO, 30.06f, 15, +R_H_LINE_TO, -9.59f, +R_LINE_TO, 9.6f, -9.27f, +R_CUBIC_TO, 0.6f, -0.48f, 1, -1.24f, 1, -2.11f, +CUBIC_TO, 31.07f, 2.17f, 29.96f, 1, 28.6f, 1, +R_CUBIC_TO, -0.51f, 0, -0.98f, 0.16f, -1.37f, 0.44f, +LINE_TO, 8.09f, 15.03f, +R_CUBIC_TO, -0.23f, 0.13f, -0.44f, 0.28f, -0.64f, 0.46f, +R_LINE_TO, -0.07f, 0.05f, +CUBIC_TO, 6.54f, 16.31f, 6, 17.43f, 6, 18.69f, +R_CUBIC_TO, 0, 2.31f, 1.76f, 4.18f, 3.93f, 4.31f, +R_H_LINE_TO, 6.22f, +R_LINE_TO, -7.54f, 4.83f, +R_CUBIC_TO, 0.84f, -0.54f, 1.81f, -0.86f, 2.86f, -0.86f, +R_CUBIC_TO, 3.07f, 0, 5.55f, 2.64f, 5.55f, 5.9f, +R_CUBIC_TO, 0, 1.61f, -0.61f, 3.07f, -1.6f, 4.13f, +R_LINE_TO, 16.68f, -14.75f, +R_CUBIC_TO, 0.32f, -0.21f, 0.61f, -0.46f, 0.86f, -0.76f, +R_CUBIC_TO, 0.65f, -0.81f, 1.03f, -1.75f, 1.03f, -2.79f, +R_CUBIC_TO, 0, -2.31f, -1.76f, -3.67f, -3.94f, -3.69f, +CLOSE, +NEW_PATH, +MOVE_TO, 18, 32.57f, +R_CUBIC_TO, 0, -3.31f, -2.69f, -6, -6, -6, +R_CUBIC_TO, -1.13f, 0, -2.18f, 0.33f, -3.09f, 0.88f, +R_LINE_TO, -0.36f, 0.23f, +R_CUBIC_TO, -0.03f, 0.02f, -0.05f, 0.05f, -0.08f, 0.07f, +CUBIC_TO, 6.98f, 28.83f, 6, 30.58f, 6, 32.56f, +R_CUBIC_TO, 0, 3.31f, 2.69f, 6, 6, 6, +R_CUBIC_TO, 1.24f, 0, 2.39f, -0.38f, 3.34f, -1.03f, +R_LINE_TO, 0, 0, +R_LINE_TO, 0.02f, -0.01f, +R_CUBIC_TO, 0.33f, -0.22f, 0.63f, -0.48f, 0.91f, -0.76f, +CUBIC_TO, 17.34f, 35.69f, 18, 34.21f, 18, 32.57f, +CLOSE + +CANVAS_DIMENSIONS, 20, +PATH_COLOR_ARGB, 0x4D, 0x00, 0x00, 0x00, +MOVE_TO, 14.96f, 8.04f, +R_H_LINE_TO, -4.56f, +R_LINE_TO, 4.56f, -4.8f, +R_CUBIC_TO, 0.3f, -0.23f, 0.5f, -0.59f, 0.5f, -0.99f, +R_CUBIC_TO, 0, -0.68f, -0.55f, -1.24f, -1.22f, -1.24f, +R_CUBIC_TO, -0.25f, 0, -0.48f, 0.08f, -0.68f, 0.21f, +R_CUBIC_TO, 0, 0, -9.48f, 6.42f, -9.48f, 6.42f, +R_LINE_TO, -0.36f, 0.24f, +R_CUBIC_TO, -0.41f, 0.37f, -0.7f, 0.16f, -0.7f, 1.41f, +R_CUBIC_TO, 0, 0.56f, 0.92f, 1.69f, 2, 1.69f, +H_LINE_TO, 9.03f, +R_LINE_TO, -1.18f, 0.69f, +R_CUBIC_TO, -1.17f, 0.68f, -3.52f, 2.04f, -3.52f, 2.04f, +R_CUBIC_TO, 0.42f, -0.25f, 0.9f, -0.41f, 1.42f, -0.41f, +R_CUBIC_TO, 1.52f, 0, 2.75f, 1.25f, 2.75f, 2.79f, +R_CUBIC_TO, 0, 0.76f, -0.3f, 1.45f, -0.79f, 1.96f, +R_LINE_TO, 8.26f, -6.98f, +R_CUBIC_TO, 0.16f, -0.1f, 0.3f, -0.22f, 0.43f, -0.36f, +R_CUBIC_TO, 0.25f, -0.29f, 0.47f, -0.54f, 0.56f, -0.86f, +R_CUBIC_TO, 0.03f, -0.1f, 0.04f, -0.2f, 0.04f, -0.32f, +R_CUBIC_TO, 0, -1.31f, -0.96f, -1.48f, -2.04f, -1.48f, +CLOSE, +NEW_PATH, +MOVE_TO, 9, 16, +R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3, +R_CUBIC_TO, -0.57f, 0, -1.09f, 0.17f, -1.54f, 0.44f, +R_LINE_TO, -0.18f, 0.11f, +R_CUBIC_TO, -0.01f, 0.01f, -0.03f, 0.02f, -0.04f, 0.03f, +CUBIC_TO, 3.49f, 14.13f, 3, 15.01f, 3, 16, +R_CUBIC_TO, 0, 1.66f, 1.34f, 3, 3, 3, +R_CUBIC_TO, 0.62f, 0, 1.19f, -0.19f, 1.67f, -0.51f, +R_H_LINE_TO, 0, +R_LINE_TO, 0.01f, -0.01f, +R_CUBIC_TO, 0.16f, -0.11f, 0.32f, -0.24f, 0.45f, -0.38f, +CUBIC_TO, 8.67f, 17.56f, 9, 16.82f, 9, 16, +CLOSE
diff --git a/ash/resources/vector_icons/palette_tray_icon_laser_pointer_light_mode.icon b/ash/resources/vector_icons/palette_tray_icon_laser_pointer_light_mode.icon new file mode 100644 index 0000000..98f9959 --- /dev/null +++ b/ash/resources/vector_icons/palette_tray_icon_laser_pointer_light_mode.icon
@@ -0,0 +1,79 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 32, +NEW_PATH, +PATH_COLOR_ARGB, 0x4D, 0x00, 0x00, 0x00, +MOVE_TO, 24.05f, 12, +H_LINE_TO, 16.38f, +R_LINE_TO, 7.68f, -7.42f, +R_CUBIC_TO, 0.48f, -0.38f, 0.8f, -0.99f, 0.8f, -1.68f, +CUBIC_TO, 24.86f, 1.74f, 23.97f, 0.8f, 22.88f, 0.8f, +R_CUBIC_TO, -0.4f, 0, -0.78f, 0.13f, -1.1f, 0.35f, +LINE_TO, 6.47f, 12.02f, +R_CUBIC_TO, -0.18f, 0.1f, -0.36f, 0.23f, -0.51f, 0.37f, +R_LINE_TO, -0.06f, 0.04f, +R_CUBIC_TO, -0.67f, 0.62f, -1.1f, 1.52f, -1.1f, 2.53f, +R_CUBIC_TO, 0, 1.85f, 1.41f, 3.34f, 3.15f, 3.44f, +R_H_LINE_TO, 4.98f, +R_LINE_TO, -6.03f, 3.87f, +R_CUBIC_TO, 0.67f, -0.43f, 1.45f, -0.69f, 2.29f, -0.69f, +R_CUBIC_TO, 2.46f, 0, 4.44f, 2.11f, 4.44f, 4.72f, +R_CUBIC_TO, 0, 1.29f, -0.49f, 2.45f, -1.28f, 3.31f, +R_LINE_TO, 13.35f, -11.8f, +R_CUBIC_TO, 0.26f, -0.17f, 0.49f, -0.37f, 0.69f, -0.61f, +R_CUBIC_TO, 0.52f, -0.64f, 0.82f, -1.4f, 0.82f, -2.23f, +R_CUBIC_TO, 0, -1.84f, -1.41f, -2.94f, -3.15f, -2.96f, +CLOSE, +NEW_PATH, +MOVE_TO, 14.4f, 26.05f, +R_CUBIC_TO, 0, -2.65f, -2.15f, -4.8f, -4.8f, -4.8f, +R_CUBIC_TO, -0.91f, 0, -1.75f, 0.27f, -2.47f, 0.71f, +R_LINE_TO, -0.29f, 0.18f, +R_CUBIC_TO, -0.02f, 0.02f, -0.04f, 0.04f, -0.07f, 0.05f, +R_CUBIC_TO, -1.19f, 0.88f, -1.97f, 2.27f, -1.97f, 3.86f, +R_CUBIC_TO, 0, 2.65f, 2.15f, 4.8f, 4.8f, 4.8f, +R_CUBIC_TO, 0.99f, 0, 1.91f, -0.3f, 2.67f, -0.82f, +R_LINE_TO, 0.02f, -0.01f, +R_CUBIC_TO, 0.26f, -0.18f, 0.51f, -0.38f, 0.73f, -0.61f, +R_CUBIC_TO, 0.85f, -0.87f, 1.38f, -2.05f, 1.38f, -3.36f, +CLOSE + +CANVAS_DIMENSIONS, 16, +NEW_PATH, +PATH_COLOR_ARGB, 0x4D, 0x00, 0x00, 0x00, +MOVE_TO, 12.03f, 6, +H_LINE_TO, 8.19f, +R_LINE_TO, 3.84f, -3.71f, +R_CUBIC_TO, 0.24f, -0.19f, 0.4f, -0.5f, 0.4f, -0.84f, +CUBIC_TO, 12.43f, 0.87f, 11.99f, 0.4f, 11.44f, 0.4f, +R_CUBIC_TO, -0.2f, 0, -0.39f, 0.07f, -0.55f, 0.18f, +LINE_TO, 3.24f, 6.01f, +R_CUBIC_TO, -0.09f, 0.05f, -0.18f, 0.11f, -0.26f, 0.18f, +R_LINE_TO, -0.03f, 0.02f, +R_CUBIC_TO, -0.33f, 0.31f, -0.55f, 0.76f, -0.55f, 1.26f, +R_CUBIC_TO, 0, 0.92f, 0.7f, 1.67f, 1.57f, 1.72f, +R_H_LINE_TO, 2.49f, +R_LINE_TO, -3.02f, 1.93f, +R_CUBIC_TO, 0.34f, -0.21f, 0.72f, -0.35f, 1.14f, -0.35f, +R_CUBIC_TO, 1.23f, 0, 2.22f, 1.06f, 2.22f, 2.36f, +R_CUBIC_TO, 0, 0.64f, -0.24f, 1.23f, -0.64f, 1.65f, +R_LINE_TO, 6.68f, -5.9f, +R_CUBIC_TO, 0.13f, -0.08f, 0.24f, -0.18f, 0.34f, -0.3f, +R_CUBIC_TO, 0.26f, -0.32f, 0.41f, -0.7f, 0.41f, -1.12f, +R_CUBIC_TO, 0, -0.92f, -0.71f, -1.47f, -1.57f, -1.48f, +CLOSE, +NEW_PATH, +MOVE_TO, 7.2f, 13.03f, +R_CUBIC_TO, 0, -1.33f, -1.07f, -2.4f, -2.4f, -2.4f, +R_CUBIC_TO, -0.45f, 0, -0.87f, 0.13f, -1.24f, 0.35f, +R_LINE_TO, -0.15f, 0.09f, +R_CUBIC_TO, -0.01f, 0.01f, -0.02f, 0.02f, -0.03f, 0.03f, +R_CUBIC_TO, -0.59f, 0.44f, -0.98f, 1.14f, -0.98f, 1.93f, +R_CUBIC_TO, 0, 1.33f, 1.08f, 2.4f, 2.4f, 2.4f, +R_CUBIC_TO, 0.5f, 0, 0.96f, -0.15f, 1.34f, -0.41f, +R_LINE_TO, 0.01f, 0, +R_CUBIC_TO, 0.13f, -0.09f, 0.25f, -0.19f, 0.36f, -0.3f, +R_CUBIC_TO, 0.43f, -0.43f, 0.69f, -1.02f, 0.69f, -1.68f, +CLOSE
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc index 5a1dce6..09d265b3 100644 --- a/ash/search_box/search_box_view_base.cc +++ b/ash/search_box/search_box_view_base.cc
@@ -338,8 +338,6 @@ is_search_box_active_ = active; UpdateSearchIcon(); - UpdateBackgroundColor( - ash::AppListColorProvider::Get()->GetSearchBoxBackgroundColor()); search_box_->set_placeholder_text_draw_flags( active ? (base::i18n::IsRTL() ? gfx::Canvas::TEXT_ALIGN_RIGHT : gfx::Canvas::TEXT_ALIGN_LEFT)
diff --git a/ash/shell.cc b/ash/shell.cc index 4e053eda1..b20100f 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -1193,7 +1193,10 @@ cursor_manager_->HideCursor(); // Hide the mouse cursor on startup. cursor_manager_->SetCursor(ui::mojom::CursorType::kPointer); - peripheral_battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>(); + peripheral_battery_listener_ = std::make_unique<PeripheralBatteryListener>(); + + peripheral_battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>( + peripheral_battery_listener_.get()); if (base::FeatureList::IsEnabled( chromeos::features::kShowBluetoothDeviceBattery)) { peripheral_battery_tracker_ = std::make_unique<PeripheralBatteryTracker>();
diff --git a/ash/shell.h b/ash/shell.h index 25d79cb..f2dd6eb 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -150,6 +150,7 @@ class OverviewController; class ParentAccessController; class PartialMagnificationController; +class PeripheralBatteryListener; class PeripheralBatteryNotifier; class PeripheralBatteryTracker; class PersistentWindowController; @@ -787,6 +788,7 @@ std::unique_ptr<ScreenPinningController> screen_pinning_controller_; + std::unique_ptr<PeripheralBatteryListener> peripheral_battery_listener_; std::unique_ptr<PeripheralBatteryNotifier> peripheral_battery_notifier_; std::unique_ptr<PeripheralBatteryTracker> peripheral_battery_tracker_; std::unique_ptr<PowerEventObserver> power_event_observer_;
diff --git a/ash/system/holding_space/downloads_section.cc b/ash/system/holding_space/downloads_section.cc index 68f7b6f4..20066f2 100644 --- a/ash/system/holding_space/downloads_section.cc +++ b/ash/system/holding_space/downloads_section.cc
@@ -13,8 +13,7 @@ #include "ash/style/ash_color_provider.h" #include "ash/system/holding_space/holding_space_item_chip_view.h" #include "ash/system/holding_space/holding_space_item_chips_container.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" +#include "ash/system/holding_space/holding_space_util.h" #include "base/bind.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" @@ -48,16 +47,12 @@ kHoldingSpaceDownloadsHeaderSpacing)); // Label. - auto* label = AddChildView(std::make_unique<views::Label>( + auto* label = AddChildView(holding_space_util::CreateLabel( + holding_space_util::LabelStyle::kHeader, l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_DOWNLOADS_TITLE))); - label->SetEnabledColor(ash_color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); layout->SetFlexForView(label, 1); - TrayPopupUtils::SetLabelFontList(label, - TrayPopupUtils::FontStyle::kSubHeader); - // Chevron. auto* chevron = AddChildView(std::make_unique<views::ImageView>()); chevron->SetFlipCanvasOnPaintForRTLUI(true);
diff --git a/ash/system/holding_space/holding_space_drag_util.cc b/ash/system/holding_space/holding_space_drag_util.cc index 2e134f1..84ffa636 100644 --- a/ash/system/holding_space/holding_space_drag_util.cc +++ b/ash/system/holding_space/holding_space_drag_util.cc
@@ -13,7 +13,7 @@ #include "ash/style/ash_color_provider.h" #include "ash/style/scoped_light_mode_as_default.h" #include "ash/system/holding_space/holding_space_item_view.h" -#include "ash/system/tray/tray_popup_utils.h" +#include "ash/system/holding_space/holding_space_util.h" #include "base/containers/adapters.h" #include "base/i18n/rtl.h" #include "ui/compositor/canvas_painter.h" @@ -207,16 +207,11 @@ icon->SetImage(item->image().image_skia(), icon->GetPreferredSize()); // Label. - auto* label = AddChildView(std::make_unique<views::Label>(item->text())); + ScopedLightModeAsDefault scoped_light_mode; + auto* label = AddChildView(CreateLabel(LabelStyle::kChip, item->text())); label->SetElideBehavior(gfx::ElideBehavior::ELIDE_MIDDLE); label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); layout->SetFlexForView(label, 1); - - TrayPopupUtils::SetLabelFontList( - label, TrayPopupUtils::FontStyle::kDetailedViewLabel); - ScopedLightModeAsDefault scoped_light_mode; - label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); } }; @@ -290,11 +285,9 @@ views::BoxLayout::MainAxisAlignment::kCenter); // Label. - auto* label = AddChildView(std::make_unique<views::Label>()); - label->SetText(base::UTF8ToUTF16(base::NumberToString(count))); + auto* label = AddChildView(CreateLabel(LabelStyle::kBadge)); label->SetEnabledColor(gfx::kGoogleGrey200); - TrayPopupUtils::SetLabelFontList(label, - TrayPopupUtils::FontStyle::kSmallTitle); + label->SetText(base::UTF8ToUTF16(base::NumberToString(count))); } };
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc index bcc03918..5b4608a 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.cc +++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -9,7 +9,7 @@ #include "ash/public/cpp/rounded_image_view.h" #include "ash/style/ash_color_provider.h" #include "ash/system/holding_space/holding_space_item_view.h" -#include "ash/system/tray/tray_popup_utils.h" +#include "ash/system/holding_space/holding_space_util.h" #include "ui/compositor/paint_recorder.h" #include "ui/gfx/skia_paint_util.h" #include "ui/views/controls/label.h" @@ -19,6 +19,8 @@ namespace ash { +// HoldingSpaceItemChipView::LabelMaskOwner ------------------------------------ + class HoldingSpaceItemChipView::LabelMaskLayerOwner : public ui::LayerDelegate { public: LabelMaskLayerOwner() : layer_(ui::LAYER_TEXTURED) { @@ -69,6 +71,8 @@ ui::Layer layer_; }; +// HoldingSpaceItemChipView ---------------------------------------------------- + HoldingSpaceItemChipView::HoldingSpaceItemChipView( HoldingSpaceItemViewDelegate* delegate, const HoldingSpaceItem* item) @@ -92,13 +96,10 @@ std::make_unique<views::FillLayout>()); label_ = label_and_pin_button_container_->AddChildView( - std::make_unique<views::Label>(item->text())); + holding_space_util::CreateLabel(holding_space_util::LabelStyle::kChip)); label_->SetElideBehavior(gfx::ELIDE_MIDDLE); label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); - label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); - TrayPopupUtils::SetLabelFontList( - label_, TrayPopupUtils::FontStyle::kDetailedViewLabel); + label_->SetText(item->text()); label_mask_layer_owner_ = std::make_unique<LabelMaskLayerOwner>();
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc index b76b4808..cb9c0af0 100644 --- a/ash/system/holding_space/holding_space_tray.cc +++ b/ash/system/holding_space/holding_space_tray.cc
@@ -107,7 +107,7 @@ } base::string16 HoldingSpaceTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_TITLE); + return l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_A11Y_NAME); } void HoldingSpaceTray::HandleLocaleChange() {
diff --git a/ash/system/holding_space/holding_space_util.cc b/ash/system/holding_space/holding_space_util.cc new file mode 100644 index 0000000..03d3353 --- /dev/null +++ b/ash/system/holding_space/holding_space_util.cc
@@ -0,0 +1,43 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/holding_space/holding_space_util.h" + +#include "ash/style/ash_color_provider.h" +#include "ui/views/controls/label.h" + +namespace ash { +namespace holding_space_util { + +std::unique_ptr<views::Label> CreateLabel(LabelStyle style, + const base::string16& text) { + auto label = std::make_unique<views::Label>(text); + label->SetAutoColorReadabilityEnabled(false); + label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorPrimary)); + + switch (style) { + case LabelStyle::kBadge: + label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 14, + gfx::Font::Weight::MEDIUM)); + break; + case LabelStyle::kBody: + label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 14, + gfx::Font::Weight::NORMAL)); + break; + case LabelStyle::kChip: + label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 13, + gfx::Font::Weight::NORMAL)); + break; + case LabelStyle::kHeader: + label->SetFontList(gfx::FontList({"Roboto"}, gfx::Font::NORMAL, 16, + gfx::Font::Weight::MEDIUM)); + break; + } + + return label; +} + +} // namespace holding_space_util +} // namespace ash
diff --git a/ash/system/holding_space/holding_space_util.h b/ash/system/holding_space/holding_space_util.h new file mode 100644 index 0000000..9cf6680 --- /dev/null +++ b/ash/system/holding_space/holding_space_util.h
@@ -0,0 +1,33 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_ +#define ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_ + +#include "base/strings/string16.h" + +namespace views { +class Label; +} // namespace views + +namespace ash { +namespace holding_space_util { + +// Enumeration of supported label styles. +enum class LabelStyle { + kBadge, + kBody, + kChip, + kHeader, +}; + +// Creates a label with optional `text` matching the specified `style`. +std::unique_ptr<views::Label> CreateLabel( + LabelStyle style, + const base::string16& text = base::string16()); + +} // namespace holding_space_util +} // namespace ash + +#endif // ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_UTIL_H_
diff --git a/ash/system/holding_space/pinned_files_section.cc b/ash/system/holding_space/pinned_files_section.cc index 927c9bbf..d576137e 100644 --- a/ash/system/holding_space/pinned_files_section.cc +++ b/ash/system/holding_space/pinned_files_section.cc
@@ -9,15 +9,16 @@ #include "ash/public/cpp/holding_space/holding_space_controller.h" #include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/public/cpp/holding_space/holding_space_prefs.h" +#include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" #include "ash/system/holding_space/holding_space_item_chip_view.h" #include "ash/system/holding_space/holding_space_item_chips_container.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" +#include "ash/system/holding_space/holding_space_util.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/controls/button/button.h" @@ -31,9 +32,9 @@ namespace { // Appearance. -constexpr int kFilesAppChipChildSpacing = 16; +constexpr int kFilesAppChipChildSpacing = 8; constexpr int kFilesAppChipHeight = 32; -constexpr int kFilesAppChipIconHeight = 16; +constexpr int kFilesAppChipIconSize = 20; constexpr gfx::Insets kFilesAppChipInsets(0, 8, 0, 16); constexpr int kPlaceholderChildSpacing = 16; @@ -106,24 +107,15 @@ // Icon. auto* icon = AddChildView(std::make_unique<views::ImageView>()); - icon->SetBackground(views::CreateRoundedRectBackground( - ash_color_provider->GetControlsLayerColor( - AshColorProvider::ControlsLayerType:: - kControlBackgroundColorInactive), - kFilesAppChipIconHeight / 2)); - icon->SetPreferredSize( - gfx::Size(kFilesAppChipIconHeight, kFilesAppChipIconHeight)); + icon->SetImage(gfx::CreateVectorIcon(kFilesAppIcon, kFilesAppChipIconSize, + gfx::kPlaceholderColor)); // Label. - auto* label = AddChildView(std::make_unique<views::Label>()); - label->SetEnabledColor(ash_color_provider->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); + auto* label = AddChildView( + holding_space_util::CreateLabel(holding_space_util::LabelStyle::kChip)); label->SetText(l10n_util::GetStringUTF16( IDS_ASH_HOLDING_SPACE_PINNED_FILES_APP_CHIP_TEXT)); layout->SetFlexForView(label, 1); - - TrayPopupUtils::SetLabelFontList( - label, TrayPopupUtils::FontStyle::kDetailedViewLabel); } void OnPressed(const ui::Event& event) { @@ -148,17 +140,12 @@ } std::unique_ptr<views::View> PinnedFilesSection::CreateHeader() { - auto header = std::make_unique<views::Label>( + auto header = holding_space_util::CreateLabel( + holding_space_util::LabelStyle::kHeader, l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_PINNED_TITLE)); - header->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); header->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); header->SetPaintToLayer(); header->layer()->SetFillsBoundsOpaquely(false); - - TrayPopupUtils::SetLabelFontList(header.get(), - TrayPopupUtils::FontStyle::kSubHeader); - return header; } @@ -191,16 +178,12 @@ views::BoxLayout::CrossAxisAlignment::kStart); // Prompt. - auto* prompt = placeholder->AddChildView(std::make_unique<views::Label>( + auto* prompt = placeholder->AddChildView(holding_space_util::CreateLabel( + holding_space_util::LabelStyle::kBody, l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_PINNED_EMPTY_PROMPT))); - prompt->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); prompt->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); prompt->SetMultiLine(true); - TrayPopupUtils::SetLabelFontList( - prompt, TrayPopupUtils::FontStyle::kDetailedViewLabel); - // Files app chip. placeholder->AddChildView(std::make_unique<FilesAppChip>());
diff --git a/ash/system/holding_space/screen_captures_section.cc b/ash/system/holding_space/screen_captures_section.cc index ea03451..6f9f06f7 100644 --- a/ash/system/holding_space/screen_captures_section.cc +++ b/ash/system/holding_space/screen_captures_section.cc
@@ -7,10 +7,8 @@ #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_item.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/style/ash_color_provider.h" #include "ash/system/holding_space/holding_space_item_screen_capture_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" +#include "ash/system/holding_space/holding_space_util.h" #include "ui/base/l10n/l10n_util.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/label.h" @@ -34,17 +32,12 @@ } std::unique_ptr<views::View> ScreenCapturesSection::CreateHeader() { - auto header = std::make_unique<views::Label>( + auto header = holding_space_util::CreateLabel( + holding_space_util::LabelStyle::kHeader, l10n_util::GetStringUTF16(IDS_ASH_HOLDING_SPACE_SCREEN_CAPTURES_TITLE)); - header->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); header->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); header->SetPaintToLayer(); header->layer()->SetFillsBoundsOpaquely(false); - - TrayPopupUtils::SetLabelFontList(header.get(), - TrayPopupUtils::FontStyle::kSubHeader); - return header; }
diff --git a/ash/system/palette/tools/laser_pointer_mode.cc b/ash/system/palette/tools/laser_pointer_mode.cc index 8a20d62..fb88bc8 100644 --- a/ash/system/palette/tools/laser_pointer_mode.cc +++ b/ash/system/palette/tools/laser_pointer_mode.cc
@@ -8,6 +8,7 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/style/ash_color_provider.h" #include "ash/system/palette/palette_ids.h" #include "ui/base/l10n/l10n_util.h" @@ -41,11 +42,17 @@ } const gfx::VectorIcon& LaserPointerMode::GetActiveTrayIcon() const { - return kPaletteTrayIconLaserPointerIcon; + if (AshColorProvider::Get()->IsDarkModeEnabled()) + return kPaletteTrayIconLaserPointerIcon; + + return kPaletteTrayIconLaserPointerLightModeIcon; } const gfx::VectorIcon& LaserPointerMode::GetPaletteIcon() const { - return kPaletteModeLaserPointerIcon; + if (AshColorProvider::Get()->IsDarkModeEnabled()) + return kPaletteModeLaserPointerIcon; + + return kPaletteModeLaserPointerLightModeIcon; } views::View* LaserPointerMode::CreateView() {
diff --git a/ash/system/phonehub/quick_action_item.cc b/ash/system/phonehub/quick_action_item.cc index bd3d82c..bdd79f0 100644 --- a/ash/system/phonehub/quick_action_item.cc +++ b/ash/system/phonehub/quick_action_item.cc
@@ -121,10 +121,10 @@ icon_button_->SetEnabled(enabled); if (!enabled) { - label_->SetEnabledColor( - AshColorProvider::GetDisabledColor(label_->GetEnabledColor())); - sub_label_->SetEnabledColor( - AshColorProvider::GetDisabledColor(sub_label_->GetEnabledColor())); + label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorSecondary)); + sub_label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorSecondary)); sub_label_->SetText(l10n_util::GetStringUTF16( IDS_ASH_PHONE_HUB_QUICK_ACTIONS_NOT_AVAILABLE_STATE));
diff --git a/ash/system/power/peripheral_battery_listener.cc b/ash/system/power/peripheral_battery_listener.cc new file mode 100644 index 0000000..f8fd1a84 --- /dev/null +++ b/ash/system/power/peripheral_battery_listener.cc
@@ -0,0 +1,256 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/power/peripheral_battery_listener.h" + +#include <vector> + +#include "ash/power/hid_battery_util.h" +#include "ash/public/cpp/notification_utils.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/default_tick_clock.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/bluetooth_device.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/events/devices/device_data_manager.h" +#include "ui/events/devices/touchscreen_device.h" +#include "ui/gfx/image/image.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/public/cpp/notification.h" + +namespace ash { + +namespace { + +constexpr char kBluetoothDeviceIdPrefix[] = "battery_bluetooth-"; + +// Checks if the device is an external stylus. +bool IsStylusDevice(const std::string& path, const std::string& model_name) { + std::string identifier = ExtractHIDBatteryIdentifier(path); + for (const ui::TouchscreenDevice& device : + ui::DeviceDataManager::GetInstance()->GetTouchscreenDevices()) { + if (device.has_stylus && + (device.name == model_name || + device.name.find(model_name) != std::string::npos) && + device.sys_path.value().find(identifier) != std::string::npos) { + return true; + } + } + + return false; +} + +std::string GetMapKeyForBluetoothAddress(const std::string& bluetooth_address) { + return kBluetoothDeviceIdPrefix + base::ToLowerASCII(bluetooth_address); +} + +// Returns the corresponding map key for a HID device. +std::string GetBatteryMapKey(const std::string& path) { + // Check if the HID path corresponds to a Bluetooth device. + const std::string bluetooth_address = + ExtractBluetoothAddressFromHIDBatteryPath(path); + return bluetooth_address.empty() + ? path + : GetMapKeyForBluetoothAddress(bluetooth_address); +} + +std::string GetBatteryMapKey(device::BluetoothDevice* device) { + return GetMapKeyForBluetoothAddress(device->GetAddress()); +} + +} // namespace + +PeripheralBatteryListener::BatteryInfo::BatteryInfo() = default; + +PeripheralBatteryListener::BatteryInfo::BatteryInfo( + const std::string& key, + const base::string16& name, + base::Optional<uint8_t> level, + base::TimeTicks last_update_timestamp, + bool is_stylus, + const std::string& bluetooth_address) + : key(key), + name(name), + level(level), + last_update_timestamp(last_update_timestamp), + is_stylus(is_stylus), + bluetooth_address(bluetooth_address) {} + +PeripheralBatteryListener::BatteryInfo::~BatteryInfo() = default; + +PeripheralBatteryListener::BatteryInfo::BatteryInfo(const BatteryInfo& info) { + key = info.key; + name = info.name; + level = info.level; + last_update_timestamp = info.last_update_timestamp; + is_stylus = info.is_stylus; + bluetooth_address = info.bluetooth_address; +} + +PeripheralBatteryListener::PeripheralBatteryListener() + : clock_(base::DefaultTickClock::GetInstance()) { + chromeos::PowerManagerClient::Get()->AddObserver(this); + device::BluetoothAdapterFactory::Get()->GetAdapter( + base::BindOnce(&PeripheralBatteryListener::InitializeOnBluetoothReady, + weak_factory_.GetWeakPtr())); +} + +PeripheralBatteryListener::~PeripheralBatteryListener() { + if (bluetooth_adapter_) + bluetooth_adapter_->RemoveObserver(this); + chromeos::PowerManagerClient::Get()->RemoveObserver(this); +} + +// Observing chromeos::PowerManagerClient +void PeripheralBatteryListener::PeripheralBatteryStatusReceived( + const std::string& path, + const std::string& name, + int level) { + // TODO(sammiequon): Powerd never sends negative levels. Investigate changing + // this check and the one below. + if (level < -1 || level > 100) { + LOG(ERROR) << "Invalid battery level " << level << " for device " << name + << " at path " << path; + return; + } + + if (!IsHIDBattery(path)) { + LOG(ERROR) << "Unsupported battery path " << path; + return; + } + + std::string map_key = GetBatteryMapKey(path); + base::Optional<uint8_t> opt_level; + if (level != -1) + opt_level = level; + else + opt_level = base::nullopt; + PeripheralBatteryListener::BatteryInfo battery{ + map_key, + base::ASCIIToUTF16(name), + opt_level, + base::TimeTicks(), // TODO(crbug/1153985): should be clock_->NowTicks() + IsStylusDevice(path, name), + ExtractBluetoothAddressFromHIDBatteryPath(path)}; + UpdateBattery(battery); +} + +// Observing device::BluetoothAdapter +void PeripheralBatteryListener::DeviceBatteryChanged( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device, + base::Optional<uint8_t> new_battery_percentage) { + if (new_battery_percentage) + DCHECK_LE(new_battery_percentage.value(), 100); + + BatteryInfo battery{ + GetBatteryMapKey(device), + device->GetNameForDisplay(), + new_battery_percentage, + base::TimeTicks(), // TODO(crbug/1153985): should be clock_->NowTicks() + false, + device->GetAddress()}; + UpdateBattery(battery); +} + +// Observing device::BluetoothAdapter +void PeripheralBatteryListener::DeviceConnectedStateChanged( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device, + bool is_now_connected) { + if (!is_now_connected) + RemoveBluetoothBattery(device->GetAddress()); +} + +// Observing device::BluetoothAdapter +void PeripheralBatteryListener::DeviceRemoved(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) { + RemoveBluetoothBattery(device->GetAddress()); +} + +void PeripheralBatteryListener::InitializeOnBluetoothReady( + scoped_refptr<device::BluetoothAdapter> adapter) { + bluetooth_adapter_ = adapter; + CHECK(bluetooth_adapter_); + bluetooth_adapter_->AddObserver(this); +} + +void PeripheralBatteryListener::RemoveBluetoothBattery( + const std::string& bluetooth_address) { + auto it = batteries_.find(kBluetoothDeviceIdPrefix + + base::ToLowerASCII(bluetooth_address)); + if (it != batteries_.end()) { + NotifyRemovingBattery(it->second); + batteries_.erase(it); + } +} + +void PeripheralBatteryListener::UpdateBattery(const BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; + auto it = batteries_.find(map_key); + + if (it == batteries_.end()) { + batteries_[map_key] = battery_info; + NotifyAddingBattery(batteries_[map_key]); + } else { + BatteryInfo& existing_battery_info = it->second; + // Only some fields should ever change. + DCHECK(existing_battery_info.bluetooth_address == battery_info.bluetooth_address); + DCHECK(existing_battery_info.is_stylus == battery_info.is_stylus); + existing_battery_info.name = battery_info.name; + existing_battery_info.level = battery_info.level; + existing_battery_info.last_update_timestamp = + battery_info.last_update_timestamp; + } + + const BatteryInfo& info = batteries_[map_key]; + NotifyUpdatedBatteryLevel(info); +} + +void PeripheralBatteryListener::NotifyAddingBattery( + const BatteryInfo& battery) { + for (auto& obs : observers_) + obs.OnAddingBattery(battery); +} + +void PeripheralBatteryListener::NotifyRemovingBattery( + const BatteryInfo& battery) { + for (auto& obs : observers_) + obs.OnRemovingBattery(battery); +} + +void PeripheralBatteryListener::NotifyUpdatedBatteryLevel( + const BatteryInfo& battery) { + for (auto& obs : observers_) + obs.OnUpdatedBatteryLevel(battery); +} + +void PeripheralBatteryListener::AddObserver(Observer* observer) { + observers_.AddObserver(observer); + // As possible latecomer, introduce observer to batteries that already exist. + for (auto it : batteries_) { + observer->OnAddingBattery(it.second); + observer->OnUpdatedBatteryLevel(it.second); + } +} + +void PeripheralBatteryListener::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +bool PeripheralBatteryListener::HasObserver(const Observer* observer) const { + return observers_.HasObserver(observer); +} + +} // namespace ash
diff --git a/ash/system/power/peripheral_battery_listener.h b/ash/system/power/peripheral_battery_listener.h new file mode 100644 index 0000000..d9baf70 --- /dev/null +++ b/ash/system/power/peripheral_battery_listener.h
@@ -0,0 +1,180 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_LISTENER_H_ +#define ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_LISTENER_H_ + +#include <cstdint> +#include <map> + +#include "ash/ash_export.h" +#include "base/compiler_specific.h" +#include "base/containers/flat_map.h" +#include "base/gtest_prod_util.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/optional.h" +#include "base/time/tick_clock.h" +#include "chromeos/dbus/power/power_manager_client.h" +#include "device/bluetooth/bluetooth_adapter.h" + +namespace ash { + +class BluetoothDevice; +class PeripheralBatteryListenerTest; + +// This class listens for peripheral device battery status across +// several sources, allowing simpler unified observation. +class ASH_EXPORT PeripheralBatteryListener + : public chromeos::PowerManagerClient::Observer, + public device::BluetoothAdapter::Observer { + public: + struct BatteryInfo { + BatteryInfo(); + BatteryInfo(const std::string& key, + const base::string16& name, + base::Optional<uint8_t> level, + base::TimeTicks last_update_timestamp, + bool is_stylus, + const std::string& bluetooth_address); + ~BatteryInfo(); + BatteryInfo(const BatteryInfo& info); + // ID key, unique to all current batteries, will not change + // during existence of this battery. If battery is removed, the + // same name may be re-used when a battery is added again. + std::string key; + + // Human readable name for the device. It is changeable. + base::string16 name; + // Battery level within range [0, 100], or unset. This is changeable. + // TODO(kenalba): explain when we might have an unset state. + base::Optional<uint8_t> level; + // Time of last known update of the battery state; this is changeable, + // and may be updated even if no other fields are; it gives the time of the + // last known confirmed reading. + base::TimeTicks last_update_timestamp; + + // True if battery is for stylus being used with internal touch-screen, + // false for any other device. + bool is_stylus = false; + // Peripheral's Bluetooth address. Empty for non-Bluetooth devices. + std::string bluetooth_address; + }; + + // Interface for observing changes from the peripheral battery listener. + class Observer : public base::CheckedObserver { + public: + ~Observer() override {} + + // All callback methods are given the current BatteryInfo state: do not take + // or keep the address of the battery info, you will only be able to get the + // current state when another callback is invoked, using the key for + // identity. + + // Invoked when a new battery is detected; OnUpdatedBatteryLevel will always + // be invoked (with same key) after an OnAddingBattery invocation. All + // battery fields will match in the following OnUpdatedBatteryLevel + // invocation. + virtual void OnAddingBattery(const BatteryInfo& battery) = 0; + + // Invoked just before deletion of a battery record; there will be no + // further updates to this battery key, unless and until OnAddingBattery is + // invoked for the same key. + virtual void OnRemovingBattery(const BatteryInfo& battery) = 0; + + // Invoked when the battery level changes for a battery. The level, as + // optional, may not be set indicating an unknown level. An update may be + // issued without any change to name or level, as updates are issued when we + // specifically know we have received up-to-date information from the + // stylus, even if there is no change of state from the last information. + // Such no-change updates are not expected to occur faster than 30 second + // intervals. + virtual void OnUpdatedBatteryLevel(const BatteryInfo& battery) = 0; + }; + + // This class registers/unregisters itself as an observer in ctor/dtor. + PeripheralBatteryListener(); + PeripheralBatteryListener(const PeripheralBatteryListener&) = delete; + PeripheralBatteryListener& operator=(const PeripheralBatteryListener&) = + delete; + ~PeripheralBatteryListener() override; + + // Adds and removes an observer. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + bool HasObserver(const Observer* observer) const; + + // chromeos::PowerManagerClient::Observer: + void PeripheralBatteryStatusReceived(const std::string& path, + const std::string& name, + int level) override; + + // device::BluetoothAdapter::Observer: + void DeviceBatteryChanged( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device, + base::Optional<uint8_t> new_battery_percentage) override; + void DeviceConnectedStateChanged(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device, + bool is_now_connected) override; + void DeviceRemoved(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + + private: + friend class PeripheralBatteryNotifierListenerTest; + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, Basic); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, + InvalidBatteryInfo); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, + ExtractBluetoothAddress); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, DeviceRemove); + + friend class PeripheralBatteryNotifierTest; + + friend class PeripheralBatteryListenerTest; + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, Basic); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, DeviceRemove); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, + ObserverationLifetimeObeyed); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, + PartialObserverationLifetimeObeyed); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, + PartialObserverationLifetimeCatchUp); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryListenerTest, + MultipleObserverationLifetimeObeyed); + + void NotifyAddingBattery(const BatteryInfo& battery); + void NotifyRemovingBattery(const BatteryInfo& battery); + void NotifyUpdatedBatteryLevel(const BatteryInfo& battery); + + void InitializeOnBluetoothReady( + scoped_refptr<device::BluetoothAdapter> adapter); + + // Removes the Bluetooth battery with address |bluetooth_address|, and posts + // the removal. Called when a bluetooth device has been changed or removed. + void RemoveBluetoothBattery(const std::string& bluetooth_address); + + // Updates the battery information of the peripheral, posting the update. + void UpdateBattery(const BatteryInfo& battery_info); + + // Record of existing battery information. For Bluetooth Devices, the key is + // kBluetoothDeviceIdPrefix + the device's address. For HID devices, the key + // is the device path. If a device uses HID over Bluetooth, it is indexed as a + // Bluetooth device. + base::flat_map<std::string, BatteryInfo> batteries_; + + // PeripheralBatteryListener is an observer of |bluetooth_adapter_| for + // bluetooth device change/remove events. + scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; + + base::ObserverList<Observer> observers_; + + const base::TickClock* clock_; + + base::WeakPtrFactory<PeripheralBatteryListener> weak_factory_{this}; +}; + +} // namespace ash + +#endif // ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_LISTENER_H_
diff --git a/ash/system/power/peripheral_battery_listener_unittest.cc b/ash/system/power/peripheral_battery_listener_unittest.cc new file mode 100644 index 0000000..d1407a88 --- /dev/null +++ b/ash/system/power/peripheral_battery_listener_unittest.cc
@@ -0,0 +1,971 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/power/peripheral_battery_listener.h" + +#include <memory> + +#include "ash/shell.h" +#include "ash/system/power/peripheral_battery_tests.h" +#include "ash/test/ash_test_base.h" +#include "base/scoped_observation.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/simple_test_tick_clock.h" +#include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/bluetooth/test/mock_bluetooth_device.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/events/devices/device_data_manager_test_api.h" +#include "ui/events/devices/touchscreen_device.h" +#include "ui/message_center/public/cpp/notification.h" + +using testing::_; +using testing::AllOf; +using testing::Eq; +using testing::Field; +using testing::InSequence; +using testing::NiceMock; +using testing::StrictMock; + +namespace { + +class MockPeripheralBatteryObserver + : public ash::PeripheralBatteryListener::Observer { + public: + MockPeripheralBatteryObserver() {} + + // ash::PeripheralBatteryListener::Observer: + MOCK_METHOD(void, + OnAddingBattery, + (const ash::PeripheralBatteryListener::BatteryInfo& battery)); + MOCK_METHOD(void, + OnRemovingBattery, + (const ash::PeripheralBatteryListener::BatteryInfo& battery)); + MOCK_METHOD(void, + OnUpdatedBatteryLevel, + (const ash::PeripheralBatteryListener::BatteryInfo& battery)); +}; + +} // namespace + +namespace ash { + +class PeripheralBatteryListenerTest : public AshTestBase { + public: + PeripheralBatteryListenerTest() = default; + PeripheralBatteryListenerTest(const PeripheralBatteryListenerTest&) = delete; + PeripheralBatteryListenerTest& operator=( + const PeripheralBatteryListenerTest&) = delete; + ~PeripheralBatteryListenerTest() override = default; + + void SetUp() override { + AshTestBase::SetUp(); + + mock_adapter_ = + base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); + mock_device_1_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( + mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName1, + kBluetoothDeviceAddress1, /*paired=*/true, /*connected=*/true); + mock_device_2_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( + mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName2, + kBluetoothDeviceAddress2, /*paired=*/true, /*connected=*/true); + + battery_listener_ = std::make_unique<PeripheralBatteryListener>(); + } + + void TearDown() override { + battery_listener_.reset(); + AshTestBase::TearDown(); + } + + void SetTestingClock(base::SimpleTestTickClock* clock) { + battery_listener_->clock_ = clock; + } + + base::TimeTicks GetTestingClock() { + // TODO(crbug/1153985): the next line should use clock_->NowTicks() + return base::TimeTicks(); + } + + protected: + scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; + std::unique_ptr<device::MockBluetoothDevice> mock_device_1_; + std::unique_ptr<device::MockBluetoothDevice> mock_device_2_; + std::unique_ptr<PeripheralBatteryListener> battery_listener_; +}; + +TEST_F(PeripheralBatteryListenerTest, Basic) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + + // Level 50 at time 100, listener should be notified. + clock.Advance(base::TimeDelta::FromSeconds(100)); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(50))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 50); + + // Level 5 at time 110, listener should be notified. + clock.Advance(base::TimeDelta::FromSeconds(10)); + + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(5))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + // Level -1 at time 115, listener should be notified. + clock.Advance(base::TimeDelta::FromSeconds(5)); + + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, + Eq(base::nullopt))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, -1); + + // Level 50 at time 120, listener should be notified. + clock.Advance(base::TimeDelta::FromSeconds(5)); + + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(50))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 50); +} + +TEST_F(PeripheralBatteryListenerTest, InvalidBatteryInfo) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + const std::string invalid_path1 = "invalid-path"; + const std::string invalid_path2 = "/sys/class/power_supply/hid-battery"; + + EXPECT_CALL(listener_observer_mock, OnAddingBattery(_)).Times(0); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)).Times(0); + + battery_listener_->PeripheralBatteryStatusReceived(invalid_path1, + kTestDeviceName, 10); + + battery_listener_->PeripheralBatteryStatusReceived(invalid_path2, + kTestDeviceName, 10); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, -2); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 101); + + // Note that -1 is a valid battery level for the Listener, so not checked. +} + +// Verify that for Bluetooth devices, the correct address gets stored in the +// BatteryInfo's bluetooth_address member, and for non-Bluetooth devices, that +// bluetooth_address member is empty. +TEST_F(PeripheralBatteryListenerTest, ExtractBluetoothAddress) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + const std::string bluetooth_path = + "/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f5-battery"; + const std::string expected_bluetooth_address = "a0:b1:c2:d3:e4:f5"; + const std::string expected_bluetooth_id = + "battery_bluetooth-a0:b1:c2:d3:e4:f5"; + const std::string non_bluetooth_path = + "/sys/class/power_supply/hid-notbluetooth-battery"; + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(expected_bluetooth_id)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(expected_bluetooth_id)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(10))))); + + battery_listener_->PeripheralBatteryStatusReceived(bluetooth_path, + kTestDeviceName, 10); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(non_bluetooth_path)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(non_bluetooth_path)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(""))))); + + battery_listener_->PeripheralBatteryStatusReceived(non_bluetooth_path, + kTestDeviceName, 10); +} + +TEST_F(PeripheralBatteryListenerTest, DeviceRemove) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); +} + +TEST_F(PeripheralBatteryListenerTest, StylusNotification) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + const std::string kTestStylusBatteryPath = + "/sys/class/power_supply/hid-AAAA:BBBB:CCCC.DDDD-battery"; + const std::string kTestStylusName = "test_stylus"; + + // Add an external stylus to our test device manager. + ui::TouchscreenDevice stylus(/*id=*/0, ui::INPUT_DEVICE_USB, kTestStylusName, + gfx::Size(), + /*touch_points=*/1, /*has_stylus=*/true); + stylus.sys_path = base::FilePath(kTestStylusBatteryPath); + + ui::DeviceDataManagerTestApi().SetTouchscreenDevices({stylus}); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestStylusBatteryPath)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestStylusBatteryPath)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(50)), + Field(&PeripheralBatteryListener::BatteryInfo::is_stylus, Eq(true)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(""))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, 50); + + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel( + AllOf(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestStylusBatteryPath)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(5))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, 5); + + EXPECT_CALL(listener_observer_mock, + OnUpdatedBatteryLevel( + AllOf(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestStylusBatteryPath)), + Field(&PeripheralBatteryListener::BatteryInfo::level, + Eq(base::nullopt))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, -1); +} + +TEST_F(PeripheralBatteryListenerTest, + Bluetooth_CreatesANotificationForEachDevice) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(5)), + Field(&PeripheralBatteryListener::BatteryInfo::is_stylus, Eq(false)), + Field(&PeripheralBatteryListener::BatteryInfo::name, + Eq(base::ASCIIToUTF16(kBluetoothDeviceName1))), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress1))))); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(0)), + Field(&PeripheralBatteryListener::BatteryInfo::is_stylus, Eq(false)), + Field(&PeripheralBatteryListener::BatteryInfo::name, + Eq(base::ASCIIToUTF16(kBluetoothDeviceName2))), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress2))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_2_.get(), + /*new_battery_percentage=*/0); +} + +TEST_F(PeripheralBatteryListenerTest, + Bluetooth_RemovesNotificationForDisconnectedDevices) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(5)), + Field(&PeripheralBatteryListener::BatteryInfo::is_stylus, Eq(false)), + Field(&PeripheralBatteryListener::BatteryInfo::name, + Eq(base::ASCIIToUTF16(kBluetoothDeviceName1))), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress1))))); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(0)), + Field(&PeripheralBatteryListener::BatteryInfo::is_stylus, Eq(false)), + Field(&PeripheralBatteryListener::BatteryInfo::name, + Eq(base::ASCIIToUTF16(kBluetoothDeviceName2))), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress2))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_2_.get(), + /*new_battery_percentage=*/0); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + + // Verify only the notification for device 1 gets removed. + battery_listener_->DeviceConnectedStateChanged(mock_adapter_.get(), + mock_device_1_.get(), false); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)))); + + // Remove the second notification. + battery_listener_->DeviceRemoved(mock_adapter_.get(), mock_device_2_.get()); +} + +TEST_F(PeripheralBatteryListenerTest, + Bluetooth_RemovesNotificationForDisconnectedDevicesInOtherOrder) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress1))))); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress2))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_2_.get(), + /*new_battery_percentage=*/0); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId2)))); + + // Remove the second notification. + battery_listener_->DeviceRemoved(mock_adapter_.get(), mock_device_2_.get()); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + + // Verify only the notification for device 1 gets removed. + battery_listener_->DeviceConnectedStateChanged(mock_adapter_.get(), + mock_device_1_.get(), false); +} + +TEST_F(PeripheralBatteryListenerTest, Bluetooth_RemoveAndReconnect) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress1))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + + battery_listener_->DeviceConnectedStateChanged(mock_adapter_.get(), + mock_device_1_.get(), false); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::bluetooth_address, + Eq(kBluetoothDeviceAddress1))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); +} + +TEST_F(PeripheralBatteryListenerTest, + Bluetooth_CancelNotificationForInvalidBatteryLevel) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel( + AllOf(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(1))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + + EXPECT_CALL(listener_observer_mock, + OnUpdatedBatteryLevel( + AllOf(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::level, + Eq(base::nullopt))))); + + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); +} + +// Do notify observer if the battery level drops again under the +// threshold before kNotificationInterval is completed. +TEST_F(PeripheralBatteryListenerTest, EnsureUpdatesWithinSmallTimeIntervals) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(1))))); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + clock.Advance(base::TimeDelta::FromSeconds(1)); + + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, + Eq(base::nullopt))))); + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); + + clock.Advance(base::TimeDelta::FromSeconds(1)); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(1))))); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); +} + +// Notify observer if the battery is under threshold, then unknown level and +// then is again under the threshold after kNotificationInterval is completed. +// (Listener should not pay attention to kNotificationInterval anyway.) +TEST_F(PeripheralBatteryListenerTest, + PostNotificationIfBatteryGoesFromUnknownLevelToBelowThreshold) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + testing::InSequence sequence; + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(1))))); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + + clock.Advance(base::TimeDelta::FromSeconds(1)); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, + Eq(base::nullopt))))); + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); + + clock.Advance(base::TimeDelta::FromSeconds(100)); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(1))))); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); +} + +// If there is an existing notification and the battery level remains low, +// update its content. +TEST_F(PeripheralBatteryListenerTest, UpdateNotificationIfVisible) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + scoped_listener_obs.Observe(battery_listener_.get()); + + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + + testing::InSequence sequence; + + clock.Advance(base::TimeDelta::FromSeconds(100)); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)))); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(5))))); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + + // The battery level remains low, should update the notification. + clock.Advance(base::TimeDelta::FromSeconds(100)); + EXPECT_CALL( + listener_observer_mock, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kBluetoothDeviceId1)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(3))))); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/3); +} + +TEST_F(PeripheralBatteryListenerTest, MultipleObserversCoexist) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock_1; + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock_2; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs_1{&listener_observer_mock_1}; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs_2{&listener_observer_mock_2}; + + scoped_listener_obs_1.Observe(battery_listener_.get()); + scoped_listener_obs_2.Observe(battery_listener_.get()); + + EXPECT_CALL( + listener_observer_mock_1, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL( + listener_observer_mock_2, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL( + listener_observer_mock_1, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(50))))); + EXPECT_CALL( + listener_observer_mock_2, + OnUpdatedBatteryLevel(AllOf( + Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)), + Field(&PeripheralBatteryListener::BatteryInfo::last_update_timestamp, + Eq(GetTestingClock())), + Field(&PeripheralBatteryListener::BatteryInfo::level, Eq(50))))); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 50); +} + +TEST_F(PeripheralBatteryListenerTest, ObserverationLifetimeObeyed) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + + testing::InSequence sequence; + + // Connect observer, add and remove battery + scoped_listener_obs.Observe(battery_listener_.get()); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); + + // Disconnect observer, add and remove battery + + scoped_listener_obs.Reset(); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); + + // Reconnect observer, add and remove battery + + scoped_listener_obs.Observe(battery_listener_.get()); + + EXPECT_CALL( + listener_observer_mock, + OnAddingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL( + listener_observer_mock, + OnRemovingBattery(Field(&PeripheralBatteryListener::BatteryInfo::key, + Eq(kTestBatteryId)))); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); +} + +// Check that observers only see events occuring while they are connected. +TEST_F(PeripheralBatteryListenerTest, PartialObserverationLifetimeObeyed) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + + testing::InSequence sequence; + + // Connect observer, add and remove battery. + scoped_listener_obs.Observe(battery_listener_.get()); + + EXPECT_CALL(listener_observer_mock, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + // Disconnect observer before we remove battery. + + scoped_listener_obs.Reset(); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); + + // Reconnect battery. + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + // Reconnect observer, add and remove battery. + + EXPECT_CALL(listener_observer_mock, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + scoped_listener_obs.Observe(battery_listener_.get()); + + EXPECT_CALL(listener_observer_mock, OnRemovingBattery(_)); + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); +} + +// Check that observers will get events to 'catch up' on batteries they missed. +TEST_F(PeripheralBatteryListenerTest, PartialObserverationLifetimeCatchUp) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs{&listener_observer_mock}; + + testing::InSequence sequence; + + // Connect battery. + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL(listener_observer_mock, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock, OnUpdatedBatteryLevel(_)); + scoped_listener_obs.Observe(battery_listener_.get()); + + EXPECT_CALL(listener_observer_mock, OnRemovingBattery(_)); + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); +} + +TEST_F(PeripheralBatteryListenerTest, MultipleObserverationLifetimeObeyed) { + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock_1; + testing::StrictMock<MockPeripheralBatteryObserver> listener_observer_mock_2; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs_1{&listener_observer_mock_1}; + base::ScopedObservation<PeripheralBatteryListener, + PeripheralBatteryListener::Observer> + scoped_listener_obs_2{&listener_observer_mock_2}; + + testing::InSequence sequence; + + scoped_listener_obs_1.Observe(battery_listener_.get()); + + EXPECT_CALL(listener_observer_mock_1, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock_1, OnUpdatedBatteryLevel(_)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL(listener_observer_mock_2, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock_2, OnUpdatedBatteryLevel(_)); + scoped_listener_obs_2.Observe(battery_listener_.get()); + + EXPECT_CALL(listener_observer_mock_1, OnRemovingBattery(_)); + EXPECT_CALL(listener_observer_mock_2, OnRemovingBattery(_)); + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); + + scoped_listener_obs_1.Reset(); + + EXPECT_CALL(listener_observer_mock_2, OnAddingBattery(_)); + EXPECT_CALL(listener_observer_mock_2, OnUpdatedBatteryLevel(_)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + + EXPECT_CALL(listener_observer_mock_2, OnRemovingBattery(_)); + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); +} + +} // namespace ash
diff --git a/ash/system/power/peripheral_battery_notifier.cc b/ash/system/power/peripheral_battery_notifier.cc index 188d2783..1f7cc3b7 100644 --- a/ash/system/power/peripheral_battery_notifier.cc +++ b/ash/system/power/peripheral_battery_notifier.cc
@@ -13,7 +13,6 @@ #include "ash/strings/grit/ash_strings.h" #include "base/bind.h" #include "base/logging.h" -#include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" @@ -40,32 +39,16 @@ constexpr base::TimeDelta kNotificationInterval = base::TimeDelta::FromSeconds(60); -const char kNotifierStylusBattery[] = "ash.stylus-battery"; +constexpr char kNotifierStylusBattery[] = "ash.stylus-battery"; // TODO(sammiequon): Add a notification url to chrome://settings/stylus once // battery related information is shown there. -const char kNotificationOriginUrl[] = "chrome://peripheral-battery"; -const char kNotifierNonStylusBattery[] = "power.peripheral-battery"; +constexpr char kNotificationOriginUrl[] = "chrome://peripheral-battery"; +constexpr char kNotifierNonStylusBattery[] = "power.peripheral-battery"; -// Prefix added to the address of a Bluetooth device to generate an unique ID -// when posting a notification to the Message Center. -const char kBluetoothDeviceIdPrefix[] = "battery_notification_bluetooth-"; - -// Checks if the device is an external stylus. -bool IsStylusDevice(const std::string& path, const std::string& model_name) { - std::string identifier = ExtractHIDBatteryIdentifier(path); - for (const ui::TouchscreenDevice& device : - ui::DeviceDataManager::GetInstance()->GetTouchscreenDevices()) { - if (device.has_stylus && - (device.name == model_name || - device.name.find(model_name) != std::string::npos) && - device.sys_path.value().find(identifier) != std::string::npos) { - return true; - } - } - - return false; -} +// Prefix added to the key of a device to generate a unique ID when posting +// a notification to the Message Center. +constexpr char kPeripheralDeviceIdPrefix[] = "battery_notification-"; // Struct containing parameters for the notification which vary between the // stylus notifications and the non stylus notifications. @@ -83,7 +66,7 @@ uint8_t battery_level, bool is_bluetooth) { return NotificationParams{ - map_key, + kPeripheralDeviceIdPrefix + map_key, name, l10n_util::GetStringFUTF16Int( IDS_ASH_LOW_PERIPHERAL_BATTERY_NOTIFICATION_TEXT, battery_level), @@ -103,202 +86,124 @@ &kNotificationStylusBatteryWarningIcon}; } -std::string GetMapKeyForBluetoothAddress(const std::string& bluetooth_address) { - return kBluetoothDeviceIdPrefix + base::ToLowerASCII(bluetooth_address); -} - -// Returns the corresponding map key for a HID device. -std::string GetBatteryMapKey(const std::string& path) { - // Check if the HID path corresponds to a Bluetooth device. - const std::string bluetooth_address = - ExtractBluetoothAddressFromHIDBatteryPath(path); - return bluetooth_address.empty() - ? path - : GetMapKeyForBluetoothAddress(bluetooth_address); -} - -std::string GetBatteryMapKey(device::BluetoothDevice* device) { - return GetMapKeyForBluetoothAddress(device->GetAddress()); -} - } // namespace const char PeripheralBatteryNotifier::kStylusNotificationId[] = "stylus-battery"; -PeripheralBatteryNotifier::BatteryInfo::BatteryInfo() = default; +PeripheralBatteryNotifier::NotificationInfo::NotificationInfo() = default; -PeripheralBatteryNotifier::BatteryInfo::BatteryInfo( - const base::string16& name, +PeripheralBatteryNotifier::NotificationInfo::NotificationInfo( base::Optional<uint8_t> level, - base::TimeTicks last_notification_timestamp, - bool is_stylus, - const std::string& bluetooth_address) - : name(name), - level(level), - last_notification_timestamp(last_notification_timestamp), - is_stylus(is_stylus), - bluetooth_address(bluetooth_address) {} + base::TimeTicks last_notification_timestamp) + : level(level), last_notification_timestamp(last_notification_timestamp) {} -PeripheralBatteryNotifier::BatteryInfo::~BatteryInfo() = default; +PeripheralBatteryNotifier::NotificationInfo::~NotificationInfo() = default; -PeripheralBatteryNotifier::BatteryInfo::BatteryInfo(const BatteryInfo& info) { - name = info.name; +PeripheralBatteryNotifier::NotificationInfo::NotificationInfo( + const NotificationInfo& info) { level = info.level; last_notification_timestamp = info.last_notification_timestamp; - is_stylus = info.is_stylus; - bluetooth_address = info.bluetooth_address; } -PeripheralBatteryNotifier::PeripheralBatteryNotifier() - : clock_(base::DefaultTickClock::GetInstance()), - weakptr_factory_( - new base::WeakPtrFactory<PeripheralBatteryNotifier>(this)) { - chromeos::PowerManagerClient::Get()->AddObserver(this); - device::BluetoothAdapterFactory::Get()->GetAdapter( - base::BindOnce(&PeripheralBatteryNotifier::InitializeOnBluetoothReady, - weakptr_factory_->GetWeakPtr())); +PeripheralBatteryNotifier::PeripheralBatteryNotifier( + PeripheralBatteryListener* listener) + : peripheral_battery_listener_(listener), + clock_(base::DefaultTickClock::GetInstance()) { + peripheral_battery_listener_->AddObserver(this); } PeripheralBatteryNotifier::~PeripheralBatteryNotifier() { - if (bluetooth_adapter_.get()) - bluetooth_adapter_->RemoveObserver(this); - chromeos::PowerManagerClient::Get()->RemoveObserver(this); + peripheral_battery_listener_->RemoveObserver(this); } -void PeripheralBatteryNotifier::PeripheralBatteryStatusReceived( - const std::string& path, - const std::string& name, - int level) { - // TODO(sammiequon): Powerd never sends negative levels. Investigate changing - // this check and the one below. - if (level < -1 || level > 100) { - LOG(ERROR) << "Invalid battery level " << level << " for device " << name - << " at path " << path; +void PeripheralBatteryNotifier::OnUpdatedBatteryLevel( + const PeripheralBatteryListener::BatteryInfo& battery) { + UpdateBattery(battery); +} + +void PeripheralBatteryNotifier::OnAddingBattery( + const PeripheralBatteryListener::BatteryInfo& battery) {} + +void PeripheralBatteryNotifier::OnRemovingBattery( + const PeripheralBatteryListener::BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; + CancelNotification(battery_info); + battery_notifications_.erase(map_key); +} + +void PeripheralBatteryNotifier::UpdateBattery( + const PeripheralBatteryListener::BatteryInfo& battery_info) { + if (!battery_info.level) { + CancelNotification(battery_info); return; } - if (!IsHIDBattery(path)) { - LOG(ERROR) << "Unsupported battery path " << path; - return; - } - - // If unknown battery level received, cancel any existing notification. - if (level == -1) { - CancelNotification(GetBatteryMapKey(path)); - return; - } - - BatteryInfo battery{base::ASCIIToUTF16(name), level, base::TimeTicks(), - IsStylusDevice(path, name), - ExtractBluetoothAddressFromHIDBatteryPath(path)}; - UpdateBattery(GetBatteryMapKey(path), battery); -} - -void PeripheralBatteryNotifier::DeviceBatteryChanged( - device::BluetoothAdapter* adapter, - device::BluetoothDevice* device, - base::Optional<uint8_t> new_battery_percentage) { - if (!new_battery_percentage) { - CancelNotification(kBluetoothDeviceIdPrefix + - base::ToLowerASCII(device->GetAddress())); - return; - } - - DCHECK_LE(new_battery_percentage.value(), 100); - BatteryInfo battery{device->GetNameForDisplay(), - new_battery_percentage.value(), base::TimeTicks(), - false /* is_stylus */, device->GetAddress()}; - UpdateBattery(GetBatteryMapKey(device), battery); -} - -void PeripheralBatteryNotifier::DeviceConnectedStateChanged( - device::BluetoothAdapter* adapter, - device::BluetoothDevice* device, - bool is_now_connected) { - if (!is_now_connected) - RemoveBluetoothBattery(device->GetAddress()); -} - -void PeripheralBatteryNotifier::DeviceRemoved(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device) { - RemoveBluetoothBattery(device->GetAddress()); -} - -void PeripheralBatteryNotifier::InitializeOnBluetoothReady( - scoped_refptr<device::BluetoothAdapter> adapter) { - bluetooth_adapter_ = adapter; - CHECK(bluetooth_adapter_.get()); - bluetooth_adapter_->AddObserver(this); -} - -void PeripheralBatteryNotifier::RemoveBluetoothBattery( - const std::string& bluetooth_address) { - std::string address_lowercase = base::ToLowerASCII(bluetooth_address); - auto it = batteries_.find(kBluetoothDeviceIdPrefix + address_lowercase); - if (it != batteries_.end()) { - CancelNotification(it->first); - batteries_.erase(it); - } -} - -void PeripheralBatteryNotifier::UpdateBattery(const std::string& map_key, - const BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; bool was_old_battery_level_low = false; - auto it = batteries_.find(map_key); + auto it = battery_notifications_.find(map_key); - if (it == batteries_.end()) { - batteries_[map_key] = battery_info; + if (it == battery_notifications_.end()) { + NotificationInfo new_notification_info; + new_notification_info.level = battery_info.level; + new_notification_info.last_notification_timestamp = + battery_info.last_update_timestamp; + battery_notifications_[map_key] = new_notification_info; } else { - BatteryInfo& existing_battery_info = it->second; - base::Optional<uint8_t> old_level = existing_battery_info.level; - was_old_battery_level_low = old_level && *old_level < kLowBatteryLevel; - existing_battery_info.name = battery_info.name; - existing_battery_info.level = battery_info.level; + NotificationInfo& existing_notification_info = it->second; + base::Optional<uint8_t> old_level = existing_notification_info.level; + was_old_battery_level_low = old_level && *old_level <= kLowBatteryLevel; + existing_notification_info.level = battery_info.level; } - const BatteryInfo& info = batteries_[map_key]; - if (!info.level || *info.level > kLowBatteryLevel) { - CancelNotification(map_key); + if (*battery_info.level > kLowBatteryLevel) { + CancelNotification(battery_info); return; } // If low battery was on record, check if there is a notification, otherwise // the user dismissed it and we shouldn't create another one. if (was_old_battery_level_low) - UpdateBatteryNotificationIfVisible(map_key, info); + UpdateBatteryNotificationIfVisible(battery_info); else - ShowNotification(map_key, info); + ShowNotification(battery_info); } void PeripheralBatteryNotifier::UpdateBatteryNotificationIfVisible( - const std::string& map_key, - const BatteryInfo& battery) { + const PeripheralBatteryListener::BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; + std::string notification_map_key = + battery_info.is_stylus ? kStylusNotificationId + : (kPeripheralDeviceIdPrefix + map_key); message_center::Notification* notification = message_center::MessageCenter::Get()->FindVisibleNotificationById( - map_key); + notification_map_key); if (notification) - ShowOrUpdateNotification(map_key, battery); + ShowOrUpdateNotification(battery_info); } -void PeripheralBatteryNotifier::ShowNotification(const std::string& map_key, - const BatteryInfo& battery) { +void PeripheralBatteryNotifier::ShowNotification( + const PeripheralBatteryListener::BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; + NotificationInfo& notification_info = battery_notifications_[map_key]; base::TimeTicks now = clock_->NowTicks(); - if (now - battery.last_notification_timestamp >= kNotificationInterval) { - ShowOrUpdateNotification(map_key, battery); - batteries_[map_key].last_notification_timestamp = clock_->NowTicks(); + if (now - notification_info.last_notification_timestamp >= + kNotificationInterval) { + ShowOrUpdateNotification(battery_info); + notification_info.last_notification_timestamp = clock_->NowTicks(); } } void PeripheralBatteryNotifier::ShowOrUpdateNotification( - const std::string& map_key, - const BatteryInfo& battery) { + const PeripheralBatteryListener::BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; // Stylus battery notifications differ slightly. - NotificationParams params = battery.is_stylus - ? GetStylusNotificationParams() - : GetNonStylusNotificationParams( - map_key, battery.name, *battery.level, - !battery.bluetooth_address.empty()); + NotificationParams params = + battery_info.is_stylus + ? GetStylusNotificationParams() + : GetNonStylusNotificationParams( + map_key, battery_info.name, *battery_info.level, + !battery_info.bluetooth_address.empty()); auto notification = CreateSystemNotification( message_center::NOTIFICATION_TYPE_SIMPLE, params.id, params.title, @@ -312,13 +217,17 @@ std::move(notification)); } -void PeripheralBatteryNotifier::CancelNotification(const std::string& map_key) { - const auto it = batteries_.find(map_key); - if (it != batteries_.end()) { +void PeripheralBatteryNotifier::CancelNotification( + const PeripheralBatteryListener::BatteryInfo& battery_info) { + const std::string& map_key = battery_info.key; + const auto it = battery_notifications_.find(map_key); + if (it != battery_notifications_.end()) { std::string notification_map_key = - it->second.is_stylus ? kStylusNotificationId : map_key; + battery_info.is_stylus ? kStylusNotificationId + : (kPeripheralDeviceIdPrefix + map_key); + message_center::MessageCenter::Get()->RemoveNotification( - notification_map_key, false /* by_user */); + notification_map_key, /*by_user=*/false); // Resetting this value allows a new low battery level to post a // notification if the old one was also under the threshold.
diff --git a/ash/system/power/peripheral_battery_notifier.h b/ash/system/power/peripheral_battery_notifier.h index 7a18fd0..530501a3 100644 --- a/ash/system/power/peripheral_battery_notifier.h +++ b/ash/system/power/peripheral_battery_notifier.h
@@ -9,9 +9,9 @@ #include <map> #include "ash/ash_export.h" +#include "ash/system/power/peripheral_battery_listener.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/time/tick_clock.h" @@ -26,106 +26,76 @@ // This class listens for peripheral device battery status and shows // notifications for low battery conditions. class ASH_EXPORT PeripheralBatteryNotifier - : public chromeos::PowerManagerClient::Observer, - public device::BluetoothAdapter::Observer { + : public PeripheralBatteryListener::Observer { public: static const char kStylusNotificationId[]; // This class registers/unregisters itself as an observer in ctor/dtor. - PeripheralBatteryNotifier(); + explicit PeripheralBatteryNotifier(PeripheralBatteryListener* listener); + PeripheralBatteryNotifier(const PeripheralBatteryNotifier&) = delete; + PeripheralBatteryNotifier& operator=(const PeripheralBatteryNotifier&) = + delete; ~PeripheralBatteryNotifier() override; - - // chromeos::PowerManagerClient::Observer: - void PeripheralBatteryStatusReceived(const std::string& path, - const std::string& name, - int level) override; - - // device::BluetoothAdapter::Observer: - void DeviceBatteryChanged( - device::BluetoothAdapter* adapter, - device::BluetoothDevice* device, - base::Optional<uint8_t> new_battery_percentage) override; - void DeviceConnectedStateChanged(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device, - bool is_now_connected) override; - void DeviceRemoved(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device) override; - private: + friend class PeripheralBatteryNotifierListenerTest; + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, Basic); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, + InvalidBatteryInfo); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, + ExtractBluetoothAddress); + FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierListenerTest, DeviceRemove); + friend class PeripheralBatteryNotifierTest; FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, Basic); - FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, InvalidBatteryInfo); - FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, - ExtractBluetoothAddress); - FRIEND_TEST_ALL_PREFIXES(PeripheralBatteryNotifierTest, DeviceRemove); - struct BatteryInfo { - BatteryInfo(); - BatteryInfo(const base::string16& name, - base::Optional<uint8_t> level, - base::TimeTicks last_notification_timestamp, - bool is_stylus, - const std::string& bluetooth_address); - ~BatteryInfo(); - BatteryInfo(const BatteryInfo& info); - - // Human readable name for the device. It is changeable. - base::string16 name; + struct NotificationInfo { + NotificationInfo(); + NotificationInfo(base::Optional<uint8_t> level, + base::TimeTicks last_notification_timestamp); + ~NotificationInfo(); + NotificationInfo(const NotificationInfo& info); // Battery level within range [0, 100]. base::Optional<uint8_t> level; base::TimeTicks last_notification_timestamp; - bool is_stylus = false; - // Peripheral's Bluetooth address. Empty for non-Bluetooth devices. - std::string bluetooth_address; }; - void InitializeOnBluetoothReady( - scoped_refptr<device::BluetoothAdapter> adapter); + // PeripheralBatteryListener::Observer: + void OnAddingBattery( + const PeripheralBatteryListener::BatteryInfo& battery) override; + void OnRemovingBattery( + const PeripheralBatteryListener::BatteryInfo& battery) override; + void OnUpdatedBatteryLevel( + const PeripheralBatteryListener::BatteryInfo& battery) override; - // Removes the Bluetooth battery with address |bluetooth_address|, as well as - // the associated notification. Called when a bluetooth device has been - // changed or removed. - void RemoveBluetoothBattery(const std::string& bluetooth_address); - - // Updates the battery information of the peripheral with the corresponding - // |map_key|, and calls to post a notification if the battery level is under - // the threshold. - void UpdateBattery(const std::string& map_key, - const BatteryInfo& battery_info); + // Updates the battery information of the peripheral, and calls to post a + // notification if the battery level is under the threshold. + void UpdateBattery(const PeripheralBatteryListener::BatteryInfo& battery); // Updates the battery percentage in the corresponding notification. - void UpdateBatteryNotificationIfVisible(const std::string& map_key, - const BatteryInfo& battery); + void UpdateBatteryNotificationIfVisible( + const PeripheralBatteryListener::BatteryInfo& battery); // Calls to display a notification only if kNotificationInterval seconds have // passed since the last notification showed, avoiding the case where the // battery level oscillates around the threshold level. - void ShowNotification(const std::string& map_key, const BatteryInfo& battery); + void ShowNotification(const PeripheralBatteryListener::BatteryInfo& battery); - // Posts a low battery notification with id as |map_key|. If a notification + // Posts a low battery notification. If a notification // with the same id exists, its content gets updated. - void ShowOrUpdateNotification(const std::string& map_key, - const BatteryInfo& battery); + void ShowOrUpdateNotification( + const PeripheralBatteryListener::BatteryInfo& battery); - void CancelNotification(const std::string& map_key); + void CancelNotification( + const PeripheralBatteryListener::BatteryInfo& battery_info); - // Record of existing battery information. For Bluetooth Devices, the key is - // kBluetoothDeviceIdPrefix + the device's address. For HID devices, the key - // is the device path. If a device uses HID over Bluetooth, it is indexed as a - // Bluetooth device. - std::map<std::string, BatteryInfo> batteries_; + // Record of existing battery notification information, keyed by keys + // provided by PeripheralBatteryListener. + std::map<std::string, NotificationInfo> battery_notifications_; - // PeripheralBatteryNotifier is an observer of |bluetooth_adapter_| for - // bluetooth device change/remove events. - scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; + PeripheralBatteryListener* peripheral_battery_listener_; const base::TickClock* clock_; - - std::unique_ptr<base::WeakPtrFactory<PeripheralBatteryNotifier>> - weakptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotifier); }; } // namespace ash
diff --git a/ash/system/power/peripheral_battery_notifier_listener_integration_test.cc b/ash/system/power/peripheral_battery_notifier_listener_integration_test.cc new file mode 100644 index 0000000..7ac9595b8 --- /dev/null +++ b/ash/system/power/peripheral_battery_notifier_listener_integration_test.cc
@@ -0,0 +1,490 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/power/peripheral_battery_listener.h" + +#include <memory> + +#include "ash/shell.h" +#include "ash/system/power/peripheral_battery_notifier.h" +#include "ash/system/power/peripheral_battery_tests.h" +#include "ash/test/ash_test_base.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/simple_test_tick_clock.h" +#include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/bluetooth/test/mock_bluetooth_device.h" +#include "ui/events/devices/device_data_manager_test_api.h" +#include "ui/events/devices/touchscreen_device.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/public/cpp/notification.h" + +using testing::NiceMock; + +namespace { + +const base::string16& NotificationMessagePrefix() { + static const base::string16 prefix(base::ASCIIToUTF16("Battery low (")); + return prefix; +} + +const base::string16& NotificationMessageSuffix() { + static const base::string16 suffix(base::ASCIIToUTF16("%)")); + return suffix; +} + +} // namespace + +namespace ash { + +class PeripheralBatteryNotifierListenerTest : public AshTestBase { + public: + PeripheralBatteryNotifierListenerTest() = default; + PeripheralBatteryNotifierListenerTest( + const PeripheralBatteryNotifierListenerTest&) = delete; + PeripheralBatteryNotifierListenerTest& operator=( + const PeripheralBatteryNotifierListenerTest&) = delete; + ~PeripheralBatteryNotifierListenerTest() override = default; + + void SetUp() override { + AshTestBase::SetUp(); + + mock_adapter_ = + base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); + mock_device_1_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( + mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName1, + kBluetoothDeviceAddress1, /*paired=*/true, /*connected=*/true); + mock_device_2_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( + mock_adapter_.get(), /*bluetooth_class=*/0, kBluetoothDeviceName2, + kBluetoothDeviceAddress2, /*paired=*/true, /*connected=*/true); + + message_center_ = message_center::MessageCenter::Get(); + + battery_listener_ = std::make_unique<PeripheralBatteryListener>(); + battery_notifier_ = + std::make_unique<PeripheralBatteryNotifier>(battery_listener_.get()); + // No notifications should have been posted yet. + ASSERT_EQ(0u, message_center_->NotificationCount()); + } + + void TearDown() override { + battery_notifier_.reset(); + battery_listener_.reset(); + AshTestBase::TearDown(); + } + + // Extracts the battery percentage from the message of a notification. + uint8_t ExtractBatteryPercentage(message_center::Notification* notification) { + const base::string16& message = notification->message(); + EXPECT_TRUE(base::StartsWith(message, NotificationMessagePrefix(), + base::CompareCase::SENSITIVE)); + EXPECT_TRUE(base::EndsWith(message, NotificationMessageSuffix(), + base::CompareCase::SENSITIVE)); + + int prefix_size = NotificationMessagePrefix().size(); + int suffix_size = NotificationMessageSuffix().size(); + int key_len = message.size() - prefix_size - suffix_size; + EXPECT_GT(key_len, 0); + + int battery_percentage; + EXPECT_TRUE(base::StringToInt(message.substr(prefix_size, key_len), + &battery_percentage)); + EXPECT_GE(battery_percentage, 0); + EXPECT_LE(battery_percentage, 100); + return battery_percentage; + } + + void SetTestingClock(base::SimpleTestTickClock* clock) { + battery_notifier_->clock_ = clock; + battery_listener_->clock_ = clock; + } + + base::TimeTicks GetTestingClock() { + // TODO(crbug/1153985): the next line should use clock_->NowTicks() + return base::TimeTicks(); + } + + protected: + scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; + std::unique_ptr<device::MockBluetoothDevice> mock_device_1_; + std::unique_ptr<device::MockBluetoothDevice> mock_device_2_; + message_center::MessageCenter* message_center_; + std::unique_ptr<PeripheralBatteryNotifier> battery_notifier_; + std::unique_ptr<PeripheralBatteryListener> battery_listener_; +}; + +TEST_F(PeripheralBatteryNotifierListenerTest, Basic) { + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + + // Level 50 at time 100, no low-battery notification. + clock.Advance(base::TimeDelta::FromSeconds(100)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 50); + EXPECT_EQ(1u, + battery_notifier_->battery_notifications_.count(kTestBatteryId)); + + const PeripheralBatteryNotifier::NotificationInfo& info = + battery_notifier_->battery_notifications_[kTestBatteryId]; + + EXPECT_EQ(base::nullopt, info.level); + EXPECT_EQ(GetTestingClock(), info.last_notification_timestamp); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); + + // Level 5 at time 110, low-battery notification. + clock.Advance(base::TimeDelta::FromSeconds(10)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + EXPECT_EQ(5, info.level); + + // TODO(crbug/1153985): the next line should use GetTestingClock() + EXPECT_EQ(clock.NowTicks(), info.last_notification_timestamp); + EXPECT_TRUE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); + + // Verify that the low-battery notification for stylus does not show up. + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); + + // Level -1 at time 115, cancel previous notification + clock.Advance(base::TimeDelta::FromSeconds(5)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, -1); + EXPECT_EQ(base::nullopt, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock() + EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(5), + info.last_notification_timestamp); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); + + // Level 50 at time 120, no low-battery notification. + clock.Advance(base::TimeDelta::FromSeconds(5)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 50); + EXPECT_EQ(base::nullopt, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock() + EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(10), + info.last_notification_timestamp); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); + + // Level 5 at time 130, no low-battery notification (throttling). + clock.Advance(base::TimeDelta::FromSeconds(10)); + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + EXPECT_EQ(5, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock() + EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(20), + info.last_notification_timestamp); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, InvalidBatteryInfo) { + const std::string invalid_path1 = "invalid-path"; + const std::string invalid_path2 = "/sys/class/power_supply/hid-battery"; + + battery_listener_->PeripheralBatteryStatusReceived(invalid_path1, + kTestDeviceName, 10); + EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); + + battery_listener_->PeripheralBatteryStatusReceived(invalid_path2, + kTestDeviceName, 10); + EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, -2); + EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 101); + EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); + + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, -1); + EXPECT_TRUE(battery_notifier_->battery_notifications_.empty()); +} + +// Verify that for Bluetooth devices, the correct address gets stored in the +// BatteryInfo's bluetooth_address member, and for non-Bluetooth devices, that +// bluetooth_address member is empty. +TEST_F(PeripheralBatteryNotifierListenerTest, ExtractBluetoothAddress) { + const std::string bluetooth_path = + "/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f5-battery"; + const std::string expected_bluetooth_address = "a0:b1:c2:d3:e4:f5"; + const std::string expected_bluetooth_id = + "battery_notification_bluetooth-a0:b1:c2:d3:e4:f5"; + const std::string non_bluetooth_path = + "/sys/class/power_supply/hid-notbluetooth-battery"; + + battery_listener_->PeripheralBatteryStatusReceived(bluetooth_path, + kTestDeviceName, 10); + battery_listener_->PeripheralBatteryStatusReceived(non_bluetooth_path, + kTestDeviceName, 10); + EXPECT_EQ(2u, battery_notifier_->battery_notifications_.size()); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, DeviceRemove) { + battery_listener_->PeripheralBatteryStatusReceived(kTestBatteryPath, + kTestDeviceName, 5); + EXPECT_EQ(1u, + battery_notifier_->battery_notifications_.count(kTestBatteryId)); + EXPECT_TRUE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); + + battery_listener_->RemoveBluetoothBattery(kTestBatteryAddress); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, StylusNotification) { + const std::string kTestStylusBatteryPath = + "/sys/class/power_supply/hid-AAAA:BBBB:CCCC.DDDD-battery"; + const std::string kTestStylusName = "test_stylus"; + + // Add an external stylus to our test device manager. + ui::TouchscreenDevice stylus(/*id=*/0, ui::INPUT_DEVICE_USB, kTestStylusName, + gfx::Size(), + /*touch_points=*/1, /*has_stylus=*/true); + stylus.sys_path = base::FilePath(kTestStylusBatteryPath); + + ui::DeviceDataManagerTestApi().SetTouchscreenDevices({stylus}); + + // Verify that when the battery level is 50, no stylus low battery + // notification is shown. + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, 50); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); + + // Verify that when the battery level is 5, a stylus low battery notification + // is shown. Also check that a non stylus device low battery notification will + // not show up. + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, 5); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryAddress)); + + // Verify that when the battery level is -1, the previous stylus low battery + // notification is cancelled. + battery_listener_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, + kTestStylusName, -1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, + Bluetooth_OnlyShowNotificationForLowBatteryLevels) { + // Should not create a notification for battery changes above the threshold. + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/80); + EXPECT_EQ(0u, message_center_->NotificationCount()); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/100); + EXPECT_EQ(0u, message_center_->NotificationCount()); + + // Should trigger notificaiton. + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/10); + EXPECT_EQ(1u, message_center_->NotificationCount()); + message_center::Notification* notification = + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1); + EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); + EXPECT_EQ(10, ExtractBatteryPercentage(notification)); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, + Bluetooth_CreatesANotificationForEachDevice) { + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_2_.get(), + /*new_battery_percentage=*/0); + + // Verify 2 notifications were posted with the correct values. + EXPECT_EQ(2u, message_center_->NotificationCount()); + message_center::Notification* notification_1 = + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1); + message_center::Notification* notification_2 = + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId2); + + EXPECT_TRUE(notification_1); + EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification_1->title()); + EXPECT_EQ(5, ExtractBatteryPercentage(notification_1)); + EXPECT_TRUE(notification_2); + EXPECT_EQ(mock_device_2_->GetNameForDisplay(), notification_2->title()); + EXPECT_EQ(0, ExtractBatteryPercentage(notification_2)); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, + Bluetooth_RemovesNotificationForDisconnectedDevices) { + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_2_.get(), + /*new_battery_percentage=*/0); + + // Verify 2 notifications were posted. + EXPECT_EQ(2u, message_center_->NotificationCount()); + + // Verify only the notification for device 1 gets removed. + battery_listener_->DeviceConnectedStateChanged(mock_adapter_.get(), + mock_device_1_.get(), false); + EXPECT_EQ(1u, message_center_->NotificationCount()); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId2)); + + // Remove the second notification. + battery_listener_->DeviceRemoved(mock_adapter_.get(), mock_device_2_.get()); + EXPECT_EQ(0u, message_center_->NotificationCount()); +} + +TEST_F(PeripheralBatteryNotifierListenerTest, + Bluetooth_CancelNotificationForInvalidBatteryLevel) { + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); + + // The notification should get canceled. + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); +} + +// Don't post a notification if the battery level drops again under the +// threshold before kNotificationInterval is completed. +TEST_F(PeripheralBatteryNotifierListenerTest, + DontShowSecondNotificationWithinASmallTimeInterval) { + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + // Post a notification. + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); + + // Cancel the notification. + clock.Advance(base::TimeDelta::FromSeconds(1)); + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); + + // The battery level falls below the threshold after a short time period. No + // notification should get posted. + clock.Advance(base::TimeDelta::FromSeconds(1)); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); +} + +// Post a notification if the battery is under threshold, then unknown level and +// then is again under the threshold after kNotificationInterval is completed. +TEST_F(PeripheralBatteryNotifierListenerTest, + PostNotificationIfBatteryGoesFromUnknownLevelToBelowThreshold) { + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + // Post a notification. + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); + + // Cancel the notification. + clock.Advance(base::TimeDelta::FromSeconds(1)); + battery_listener_->DeviceBatteryChanged( + mock_adapter_.get(), mock_device_1_.get(), + /*new_battery_percentage=*/base::nullopt); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); + + // Post notification if we are out of the kNotificationInterval. + clock.Advance(base::TimeDelta::FromSeconds(100)); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); +} + +// Don't Post another notification if the battery level keeps low and the user +// dismissed the previous notification. +TEST_F(PeripheralBatteryNotifierListenerTest, + DontRepostNotificationIfUserDismissedPreviousOne) { + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + EXPECT_EQ(1u, message_center_->NotificationCount()); + + // Simulate the user clears the notification. + message_center_->RemoveAllNotifications( + /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); + + // The battery level remains low, but shouldn't post a notificaiton. + clock.Advance(base::TimeDelta::FromSeconds(100)); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/3); + EXPECT_EQ(0u, message_center_->NotificationCount()); +} + +// If there is an existing notificaiton and the battery level remains low, +// update its content. +TEST_F(PeripheralBatteryNotifierListenerTest, UpdateNotificationIfVisible) { + base::SimpleTestTickClock clock; + SetTestingClock(&clock); + clock.Advance(base::TimeDelta::FromSeconds(100)); + + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/5); + EXPECT_EQ(1u, message_center_->NotificationCount()); + + // The battery level remains low, should update the notification. + clock.Advance(base::TimeDelta::FromSeconds(100)); + battery_listener_->DeviceBatteryChanged(mock_adapter_.get(), + mock_device_1_.get(), + /*new_battery_percentage=*/3); + + message_center::Notification* notification = + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1); + EXPECT_TRUE(notification); + EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); + EXPECT_EQ(3, ExtractBatteryPercentage(notification)); +} + +} // namespace ash
diff --git a/ash/system/power/peripheral_battery_notifier_unittest.cc b/ash/system/power/peripheral_battery_notifier_unittest.cc index 4ee1442..4488855 100644 --- a/ash/system/power/peripheral_battery_notifier_unittest.cc +++ b/ash/system/power/peripheral_battery_notifier_unittest.cc
@@ -7,42 +7,22 @@ #include <memory> #include "ash/shell.h" +#include "ash/system/power/peripheral_battery_listener.h" +#include "ash/system/power/peripheral_battery_tests.h" #include "ash/test/ash_test_base.h" -#include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/simple_test_tick_clock.h" -#include "device/bluetooth/bluetooth_device.h" -#include "device/bluetooth/test/mock_bluetooth_adapter.h" -#include "device/bluetooth/test/mock_bluetooth_device.h" #include "ui/events/devices/device_data_manager_test_api.h" #include "ui/events/devices/touchscreen_device.h" #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" -using testing::NiceMock; - namespace { -// HID device. -const char kTestBatteryPath[] = - "/sys/class/power_supply/hid-AA:BB:CC:DD:EE:FF-battery"; -const char kTestBatteryAddress[] = "aa:bb:cc:dd:ee:ff"; -const char kTestDeviceName[] = "test device"; -const char kTestBatteryId[] = - "battery_notification_bluetooth-aa:bb:cc:dd:ee:ff"; - -// Bluetooth devices. -const char kBluetoothDeviceAddress1[] = "aa:bb:cc:dd:ee:ff"; -const char kBluetoothDeviceAddress2[] = "11:22:33:44:55:66"; -const char kBluetoothDeviceId1[] = - "battery_notification_bluetooth-aa:bb:cc:dd:ee:ff"; -const char kBluetoothDeviceId2[] = - "battery_notification_bluetooth-11:22:33:44:55:66"; - const base::string16& NotificationMessagePrefix() { static const base::string16 prefix(base::ASCIIToUTF16("Battery low (")); return prefix; @@ -60,29 +40,26 @@ class PeripheralBatteryNotifierTest : public AshTestBase { public: PeripheralBatteryNotifierTest() = default; + PeripheralBatteryNotifierTest(const PeripheralBatteryNotifierTest&) = delete; + PeripheralBatteryNotifierTest& operator=( + const PeripheralBatteryNotifierTest&) = delete; ~PeripheralBatteryNotifierTest() override = default; void SetUp() override { AshTestBase::SetUp(); - mock_adapter_ = - base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); - mock_device_1_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( - mock_adapter_.get(), 0 /* bluetooth_class */, "device_name_1", - kBluetoothDeviceAddress1, true /* paired */, true /* connected */); - mock_device_2_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( - mock_adapter_.get(), 0 /* bluetooth_class */, "device_name_2", - kBluetoothDeviceAddress2, true /* paired */, true /* connected */); - message_center_ = message_center::MessageCenter::Get(); - battery_notifier_ = std::make_unique<PeripheralBatteryNotifier>(); + battery_listener_ = std::make_unique<PeripheralBatteryListener>(); + battery_notifier_ = + std::make_unique<PeripheralBatteryNotifier>(battery_listener_.get()); // No notifications should have been posted yet. - EXPECT_EQ(0u, message_center_->NotificationCount()); + ASSERT_EQ(0u, message_center_->NotificationCount()); } void TearDown() override { battery_notifier_.reset(); + battery_listener_.reset(); AshTestBase::TearDown(); } @@ -109,17 +86,43 @@ void SetTestingClock(base::SimpleTestTickClock* clock) { battery_notifier_->clock_ = clock; + battery_listener_->clock_ = clock; + } + + base::TimeTicks GetTestingClock() { + // TODO(crbug/1153985): the next line should use clock_->NowTicks(). + return base::TimeTicks(); + } + + void UpdateBatteryLevel(bool add_first, + const std::string key, + const std::string name, + base::Optional<uint8_t> level, + bool is_stylus, + const std::string btaddr) { + PeripheralBatteryListener::BatteryInfo info(key, base::ASCIIToUTF16(name), + level, GetTestingClock(), + is_stylus, btaddr); + if (add_first) + battery_notifier_->OnAddingBattery(info); + battery_notifier_->OnUpdatedBatteryLevel(info); + } + + void RemoveBattery(const std::string key, + const std::string name, + base::Optional<uint8_t> level, + bool is_stylus, + const std::string btaddr) { + PeripheralBatteryListener::BatteryInfo info(key, base::ASCIIToUTF16(name), + level, GetTestingClock(), + is_stylus, btaddr); + battery_notifier_->OnRemovingBattery(info); } protected: - scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; - std::unique_ptr<device::MockBluetoothDevice> mock_device_1_; - std::unique_ptr<device::MockBluetoothDevice> mock_device_2_; message_center::MessageCenter* message_center_; std::unique_ptr<PeripheralBatteryNotifier> battery_notifier_; - - private: - DISALLOW_COPY_AND_ASSIGN(PeripheralBatteryNotifierTest); + std::unique_ptr<PeripheralBatteryListener> battery_listener_; }; TEST_F(PeripheralBatteryNotifierTest, Basic) { @@ -128,250 +131,165 @@ // Level 50 at time 100, no low-battery notification. clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 50); - EXPECT_EQ(1u, battery_notifier_->batteries_.count(kTestBatteryId)); + UpdateBatteryLevel(true, kTestBatteryId, kTestDeviceName, 50, false, + kTestBatteryAddress); + EXPECT_EQ(1u, + battery_notifier_->battery_notifications_.count(kTestBatteryId)); - const PeripheralBatteryNotifier::BatteryInfo& info = - battery_notifier_->batteries_[kTestBatteryId]; + const PeripheralBatteryNotifier::NotificationInfo& info = + battery_notifier_->battery_notifications_[kTestBatteryId]; - EXPECT_EQ(base::ASCIIToUTF16(kTestDeviceName), info.name); EXPECT_EQ(base::nullopt, info.level); - EXPECT_EQ(base::TimeTicks(), info.last_notification_timestamp); - EXPECT_EQ(kTestBatteryAddress, info.bluetooth_address); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) == - nullptr); + EXPECT_EQ(GetTestingClock(), info.last_notification_timestamp); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); // Level 5 at time 110, low-battery notification. clock.Advance(base::TimeDelta::FromSeconds(10)); - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 5); + UpdateBatteryLevel(false, kTestBatteryId, kTestDeviceName, 5, false, + kTestBatteryAddress); EXPECT_EQ(5, info.level); + + // TODO(crbug/1153985): the next line should use GetTestingClock(). EXPECT_EQ(clock.NowTicks(), info.last_notification_timestamp); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) != - nullptr); + EXPECT_TRUE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); // Verify that the low-battery notification for stylus does not show up. EXPECT_FALSE(message_center_->FindVisibleNotificationById( - PeripheralBatteryNotifier::kStylusNotificationId) != - nullptr); + PeripheralBatteryNotifier::kStylusNotificationId)); - // Level -1 at time 115, cancel previous notification + // Level -1 at time 115, cancel previous notification. clock.Advance(base::TimeDelta::FromSeconds(5)); - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, -1); + UpdateBatteryLevel(false, kTestBatteryId, kTestDeviceName, base::nullopt, + false, kTestBatteryAddress); EXPECT_EQ(base::nullopt, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock() EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(5), info.last_notification_timestamp); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) == - nullptr); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); // Level 50 at time 120, no low-battery notification. clock.Advance(base::TimeDelta::FromSeconds(5)); - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 50); + UpdateBatteryLevel(false, kTestBatteryId, kTestDeviceName, 50, false, + kTestBatteryAddress); EXPECT_EQ(base::nullopt, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock() EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(10), info.last_notification_timestamp); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) == - nullptr); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); // Level 5 at time 130, no low-battery notification (throttling). clock.Advance(base::TimeDelta::FromSeconds(10)); - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 5); + UpdateBatteryLevel(false, kTestBatteryId, kTestDeviceName, 5, false, + kTestBatteryAddress); EXPECT_EQ(5, info.level); + // TODO(crbug/1153985): the next line should use GetTestingClock(). EXPECT_EQ(clock.NowTicks() - base::TimeDelta::FromSeconds(20), info.last_notification_timestamp); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) == - nullptr); -} - -TEST_F(PeripheralBatteryNotifierTest, InvalidBatteryInfo) { - const std::string invalid_path1 = "invalid-path"; - const std::string invalid_path2 = "/sys/class/power_supply/hid-battery"; - - battery_notifier_->PeripheralBatteryStatusReceived(invalid_path1, - kTestDeviceName, 10); - EXPECT_TRUE(battery_notifier_->batteries_.empty()); - - battery_notifier_->PeripheralBatteryStatusReceived(invalid_path2, - kTestDeviceName, 10); - EXPECT_TRUE(battery_notifier_->batteries_.empty()); - - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, -2); - EXPECT_TRUE(battery_notifier_->batteries_.empty()); - - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 101); - EXPECT_TRUE(battery_notifier_->batteries_.empty()); - - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, -1); - EXPECT_TRUE(battery_notifier_->batteries_.empty()); -} - -// Verify that for Bluetooth devices, the correct address gets stored in the -// BatteryInfo's bluetooth_address member, and for non-Bluetooth devices, that -// bluetooth_address member is empty. -TEST_F(PeripheralBatteryNotifierTest, ExtractBluetoothAddress) { - const std::string bluetooth_path = - "/sys/class/power_supply/hid-A0:b1:C2:d3:E4:f5-battery"; - const std::string expected_bluetooth_address = "a0:b1:c2:d3:e4:f5"; - const std::string expected_bluetooth_id = - "battery_notification_bluetooth-a0:b1:c2:d3:e4:f5"; - const std::string non_bluetooth_path = - "/sys/class/power_supply/hid-notbluetooth-battery"; - - battery_notifier_->PeripheralBatteryStatusReceived(bluetooth_path, - kTestDeviceName, 10); - battery_notifier_->PeripheralBatteryStatusReceived(non_bluetooth_path, - kTestDeviceName, 10); - EXPECT_EQ(2u, battery_notifier_->batteries_.size()); - - const PeripheralBatteryNotifier::BatteryInfo& bluetooth_device_info = - battery_notifier_->batteries_[expected_bluetooth_id]; - EXPECT_EQ(expected_bluetooth_address, - bluetooth_device_info.bluetooth_address); - const PeripheralBatteryNotifier::BatteryInfo& non_bluetooth_device_info = - battery_notifier_->batteries_[non_bluetooth_path]; - EXPECT_TRUE(non_bluetooth_device_info.bluetooth_address.empty()); -} - -TEST_F(PeripheralBatteryNotifierTest, DeviceRemove) { - battery_notifier_->PeripheralBatteryStatusReceived(kTestBatteryPath, - kTestDeviceName, 5); - EXPECT_EQ(1u, battery_notifier_->batteries_.count(kTestBatteryId)); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) != - nullptr); - - battery_notifier_->RemoveBluetoothBattery(kTestBatteryAddress); - EXPECT_TRUE(message_center_->FindVisibleNotificationById(kTestBatteryId) == - nullptr); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryNotificationId)); } TEST_F(PeripheralBatteryNotifierTest, StylusNotification) { const std::string kTestStylusBatteryPath = "/sys/class/power_supply/hid-AAAA:BBBB:CCCC.DDDD-battery"; + const std::string kTestStylusBatteryId = + "???hxxxxid-AAAA:BBBB:CCCC.DDDD-battery"; const std::string kTestStylusName = "test_stylus"; // Add an external stylus to our test device manager. - ui::TouchscreenDevice stylus(0 /* id */, ui::INPUT_DEVICE_USB, - kTestStylusName, gfx::Size(), - 1 /* touch_points */, true /* has_stylus */); + ui::TouchscreenDevice stylus(/*id=*/0, ui::INPUT_DEVICE_USB, kTestStylusName, + gfx::Size(), + /*touch_points=*/1, /*has_stylus=*/true); stylus.sys_path = base::FilePath(kTestStylusBatteryPath); ui::DeviceDataManagerTestApi().SetTouchscreenDevices({stylus}); // Verify that when the battery level is 50, no stylus low battery // notification is shown. - battery_notifier_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, - kTestStylusName, 50); - EXPECT_TRUE(message_center_->FindVisibleNotificationById( - PeripheralBatteryNotifier::kStylusNotificationId) == nullptr); + UpdateBatteryLevel(true, kTestStylusBatteryId, kTestStylusName, 50, true, ""); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); // Verify that when the battery level is 5, a stylus low battery notification // is shown. Also check that a non stylus device low battery notification will // not show up. - battery_notifier_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, - kTestStylusName, 5); + UpdateBatteryLevel(false, kTestStylusBatteryId, kTestStylusName, 5, true, ""); EXPECT_TRUE(message_center_->FindVisibleNotificationById( - PeripheralBatteryNotifier::kStylusNotificationId) != nullptr); - EXPECT_TRUE(message_center_->FindVisibleNotificationById( - kTestBatteryAddress) == nullptr); + PeripheralBatteryNotifier::kStylusNotificationId)); + EXPECT_FALSE( + message_center_->FindVisibleNotificationById(kTestBatteryAddress)); // Verify that when the battery level is -1, the previous stylus low battery // notification is cancelled. - battery_notifier_->PeripheralBatteryStatusReceived(kTestStylusBatteryPath, - kTestStylusName, -1); - EXPECT_TRUE(message_center_->FindVisibleNotificationById( - PeripheralBatteryNotifier::kStylusNotificationId) == nullptr); -} - -TEST_F(PeripheralBatteryNotifierTest, - Bluetooth_OnlyShowNotificationForLowBatteryLevels) { - // Should not create a notification for battery changes above the threshold. - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 80 /* new_battery_percentage */); - EXPECT_EQ(0u, message_center_->NotificationCount()); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 100 /* new_battery_percentage */); - EXPECT_EQ(0u, message_center_->NotificationCount()); - - // Should trigger notificaiton. - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 10 /* new_battery_percentage */); - EXPECT_EQ(1u, message_center_->NotificationCount()); - message_center::Notification* notification = - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1); - EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); - EXPECT_EQ(10, ExtractBatteryPercentage(notification)); + UpdateBatteryLevel(false, kTestStylusBatteryId, kTestStylusName, + base::nullopt, true, ""); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + PeripheralBatteryNotifier::kStylusNotificationId)); } TEST_F(PeripheralBatteryNotifierTest, Bluetooth_CreatesANotificationForEachDevice) { - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 5 /* new_battery_percentage */); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_2_.get(), - 0 /* new_battery_percentage */); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); + UpdateBatteryLevel(true, kBluetoothDeviceId2, kBluetoothDeviceName2, 0, false, + kBluetoothDeviceAddress2); // Verify 2 notifications were posted with the correct values. EXPECT_EQ(2u, message_center_->NotificationCount()); message_center::Notification* notification_1 = - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1); + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1); message_center::Notification* notification_2 = - message_center_->FindVisibleNotificationById(kBluetoothDeviceId2); + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId2); - EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification_1->title()); + EXPECT_TRUE(notification_1); + EXPECT_EQ(base::ASCIIToUTF16(kBluetoothDeviceName1), notification_1->title()); EXPECT_EQ(5, ExtractBatteryPercentage(notification_1)); - EXPECT_EQ(mock_device_2_->GetNameForDisplay(), notification_2->title()); + EXPECT_TRUE(notification_2); + EXPECT_EQ(base::ASCIIToUTF16(kBluetoothDeviceName2), notification_2->title()); EXPECT_EQ(0, ExtractBatteryPercentage(notification_2)); } TEST_F(PeripheralBatteryNotifierTest, Bluetooth_RemovesNotificationForDisconnectedDevices) { - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 5 /* new_battery_percentage */); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_2_.get(), - 0 /* new_battery_percentage */); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); + UpdateBatteryLevel(true, kBluetoothDeviceId2, kBluetoothDeviceName2, 0, false, + kBluetoothDeviceAddress2); // Verify 2 notifications were posted. EXPECT_EQ(2u, message_center_->NotificationCount()); // Verify only the notification for device 1 gets removed. - battery_notifier_->DeviceConnectedStateChanged(mock_adapter_.get(), - mock_device_1_.get(), false); + RemoveBattery(kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); EXPECT_EQ(1u, message_center_->NotificationCount()); - EXPECT_TRUE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId2)); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId2)); // Remove the second notification. - battery_notifier_->DeviceRemoved(mock_adapter_.get(), mock_device_2_.get()); + RemoveBattery(kBluetoothDeviceId2, kBluetoothDeviceName2, 0, false, + kBluetoothDeviceAddress2); EXPECT_EQ(0u, message_center_->NotificationCount()); } TEST_F(PeripheralBatteryNotifierTest, Bluetooth_CancelNotificationForInvalidBatteryLevel) { - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 1 /* new_battery_percentage */); - EXPECT_TRUE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 1, false, + kBluetoothDeviceAddress1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); // The notification should get canceled. - battery_notifier_->DeviceBatteryChanged( - mock_adapter_.get(), mock_device_1_.get(), - base::nullopt /* new_battery_percentage */); - EXPECT_FALSE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, + base::nullopt, false, kBluetoothDeviceAddress1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); } // Don't post a notification if the battery level drops again under the @@ -383,28 +301,25 @@ clock.Advance(base::TimeDelta::FromSeconds(100)); // Post a notification. - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 1 /* new_battery_percentage */); - EXPECT_TRUE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 1, false, + kBluetoothDeviceAddress1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); // Cancel the notification. clock.Advance(base::TimeDelta::FromSeconds(1)); - battery_notifier_->DeviceBatteryChanged( - mock_adapter_.get(), mock_device_1_.get(), - base::nullopt /* new_battery_percentage */); - EXPECT_FALSE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(false, kBluetoothDeviceId1, kBluetoothDeviceName1, + base::nullopt, false, kBluetoothDeviceAddress1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); // The battery level falls below the threshold after a short time period. No // notification should get posted. clock.Advance(base::TimeDelta::FromSeconds(1)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 1 /* new_battery_percentage */); - EXPECT_FALSE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 1, false, + kBluetoothDeviceAddress1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); } // Post a notification if the battery is under threshold, then unknown level and @@ -416,27 +331,24 @@ clock.Advance(base::TimeDelta::FromSeconds(100)); // Post a notification. - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 1) /* new_battery_percentage */; - EXPECT_TRUE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 1, false, + kBluetoothDeviceAddress1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); // Cancel the notification. clock.Advance(base::TimeDelta::FromSeconds(1)); - battery_notifier_->DeviceBatteryChanged( - mock_adapter_.get(), mock_device_1_.get(), - base::nullopt /* new_battery_percentage */); - EXPECT_FALSE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, + base::nullopt, false, kBluetoothDeviceAddress1); + EXPECT_FALSE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); // Post notification if we are out of the kNotificationInterval. clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 1 /* new_battery_percentage */); - EXPECT_TRUE( - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1)); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 1, false, + kBluetoothDeviceAddress1); + EXPECT_TRUE(message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1)); } // Don't Post another notification if the battery level keeps low and the user @@ -447,20 +359,18 @@ SetTestingClock(&clock); clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 5 /* new_battery_percentage */); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); EXPECT_EQ(1u, message_center_->NotificationCount()); // Simulate the user clears the notification. message_center_->RemoveAllNotifications( - true /* by_user */, message_center::MessageCenter::RemoveType::ALL); + /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL); // The battery level remains low, but shouldn't post a notificaiton. clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 3 /* new_battery_percentage */); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); EXPECT_EQ(0u, message_center_->NotificationCount()); } @@ -471,20 +381,19 @@ SetTestingClock(&clock); clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 5 /* new_battery_percentage */); + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 5, false, + kBluetoothDeviceAddress1); EXPECT_EQ(1u, message_center_->NotificationCount()); // The battery level remains low, should update the notification. clock.Advance(base::TimeDelta::FromSeconds(100)); - battery_notifier_->DeviceBatteryChanged(mock_adapter_.get(), - mock_device_1_.get(), - 3 /* new_battery_percentage */); - + UpdateBatteryLevel(true, kBluetoothDeviceId1, kBluetoothDeviceName1, 3, false, + kBluetoothDeviceAddress1); message_center::Notification* notification = - message_center_->FindVisibleNotificationById(kBluetoothDeviceId1); - EXPECT_EQ(mock_device_1_->GetNameForDisplay(), notification->title()); + message_center_->FindVisibleNotificationById( + kBluetoothDeviceNotificationId1); + EXPECT_TRUE(notification); + EXPECT_EQ(base::ASCIIToUTF16(kBluetoothDeviceName1), notification->title()); EXPECT_EQ(3, ExtractBatteryPercentage(notification)); }
diff --git a/ash/system/power/peripheral_battery_tests.h b/ash/system/power/peripheral_battery_tests.h new file mode 100644 index 0000000..8460289 --- /dev/null +++ b/ash/system/power/peripheral_battery_tests.h
@@ -0,0 +1,35 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_TESTS_H_ +#define ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_TESTS_H_ + +// Constants common to peripheral battery listener and notifier tests. + +namespace { + +// HID device. +constexpr char kTestBatteryPath[] = + "/sys/class/power_supply/hid-AA:BB:CC:DD:EE:FF-battery"; +constexpr char kTestBatteryAddress[] = "aa:bb:cc:dd:ee:ff"; +constexpr char kTestDeviceName[] = "test device"; +constexpr char kTestBatteryId[] = "battery_bluetooth-aa:bb:cc:dd:ee:ff"; +constexpr char kTestBatteryNotificationId[] = + "battery_notification-battery_bluetooth-aa:bb:cc:dd:ee:ff"; + +// Bluetooth devices. +constexpr char kBluetoothDeviceAddress1[] = "aa:bb:cc:dd:ee:ff"; +constexpr char kBluetoothDeviceAddress2[] = "11:22:33:44:55:66"; +constexpr char kBluetoothDeviceName1[] = "device_name_1"; +constexpr char kBluetoothDeviceName2[] = "device_name_2"; +constexpr char kBluetoothDeviceId1[] = "battery_bluetooth-aa:bb:cc:dd:ee:ff"; +constexpr char kBluetoothDeviceNotificationId1[] = + "battery_notification-battery_bluetooth-aa:bb:cc:dd:ee:ff"; +constexpr char kBluetoothDeviceId2[] = "battery_bluetooth-11:22:33:44:55:66"; +constexpr char kBluetoothDeviceNotificationId2[] = + "battery_notification-battery_bluetooth-11:22:33:44:55:66"; + +} // namespace + +#endif // ASH_SYSTEM_POWER_PERIPHERAL_BATTERY_TESTS_H_
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java index c86d9b1d..7744d69 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.concurrent.GuardedBy; @@ -102,6 +103,9 @@ @GuardedBy("sBindingStateLock") private static final int[] sAllBindingStateCounts = new int[NUM_BINDING_STATES]; + // The last zygote PID metrics were recorded for. + private static final AtomicInteger sLastRecordedZygotePid = new AtomicInteger(); + @VisibleForTesting static void resetBindingStateCountsForTesting() { synchronized (sBindingStateLock) { @@ -607,6 +611,20 @@ mLauncherHandler.post(createUnbindRunnable()); } + @Override + public void sendZygoteInfo(int zygotePid, long zygoteStartupTimeMillis) { + // Only record the zygote startup time for a process the first time it is sent. + // The zygote may get killed and recreated, so keep track of the last PID + // recorded to avoid double counting. The app may reuse a zygote process if the + // app is stopped and started again quickly, so the startup time of that zygote + // may be recorded multiple times. There's not much we can do about that, and it + // shouldn't be a major issue. + if (sLastRecordedZygotePid.getAndSet(zygotePid) != zygotePid) { + RecordHistogram.recordMediumTimesHistogram( + "Android.ChildProcessStartTimeV2.Zygote", zygoteStartupTimeMillis); + } + } + private Runnable createUnbindRunnable() { return new Runnable() { @Override
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java index 0289d09..544825a 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java
@@ -68,6 +68,9 @@ // Only for a check that create is only called once. private static boolean sCreateCalled; + private static int sZygotePid; + private static long sZygoteStartupTimeMillis; + private final ChildProcessServiceDelegate mDelegate; private final Service mService; private final Context mApplicationContext; @@ -149,6 +152,9 @@ } parentProcess.sendPid(Process.myPid()); + if (sZygotePid != 0) { + parentProcess.sendZygoteInfo(sZygotePid, sZygoteStartupTimeMillis); + } mParentProcess = parentProcess; processConnectionBundle(args, callbacks); } @@ -336,6 +342,12 @@ return mBinder; } + /** This will be called from the zygote on startup. */ + public static void setZygoteInfo(int zygotePid, long zygoteStartupTimeMillis) { + sZygotePid = zygotePid; + sZygoteStartupTimeMillis = zygoteStartupTimeMillis; + } + private void processConnectionBundle(Bundle bundle, List<IBinder> clientInterfaces) { // Required to unparcel FileDescriptorInfo. ClassLoader classLoader = getApplicationContext().getClassLoader();
diff --git a/base/android/java/src/org/chromium/base/process_launcher/IParentProcess.aidl b/base/android/java/src/org/chromium/base/process_launcher/IParentProcess.aidl index 6f2b8322..17612940 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/IParentProcess.aidl +++ b/base/android/java/src/org/chromium/base/process_launcher/IParentProcess.aidl
@@ -18,4 +18,7 @@ // Tells the parent proces the child exited cleanly. Not oneway to ensure // the browser receives the message before child exits. void reportCleanExit(); + + // Sends the PID and startup time of the app zygote if available. + oneway void sendZygoteInfo(int zygotePid, long startupTimeMillis); }
diff --git a/base/callback_helpers.h b/base/callback_helpers.h index 54aabe5..8ba5e62 100644 --- a/base/callback_helpers.h +++ b/base/callback_helpers.h
@@ -65,20 +65,23 @@ namespace internal { template <typename... Args> -class AdaptCallbackForRepeatingHelper final { +class OnceCallbackHolder final { public: - explicit AdaptCallbackForRepeatingHelper(OnceCallback<void(Args...)> callback) - : callback_(std::move(callback)) { + OnceCallbackHolder(OnceCallback<void(Args...)> callback, + bool ignore_extra_runs) + : callback_(std::move(callback)), ignore_extra_runs_(ignore_extra_runs) { DCHECK(callback_); } - AdaptCallbackForRepeatingHelper(const AdaptCallbackForRepeatingHelper&) = - delete; - AdaptCallbackForRepeatingHelper& operator=( - const AdaptCallbackForRepeatingHelper&) = delete; + OnceCallbackHolder(const OnceCallbackHolder&) = delete; + OnceCallbackHolder& operator=(const OnceCallbackHolder&) = delete; void Run(Args... args) { - if (subtle::NoBarrier_AtomicExchange(&has_run_, 1)) + if (subtle::NoBarrier_AtomicExchange(&has_run_, 1)) { + CHECK(ignore_extra_runs_) << "Both OnceCallbacks returned by " + "base::SplitOnceCallback() were run. " + "At most one of the pair should be run."; return; + } DCHECK(callback_); std::move(callback_).Run(std::forward<Args>(args)...); } @@ -86,6 +89,7 @@ private: volatile subtle::Atomic32 has_run_ = 0; base::OnceCallback<void(Args...)> callback_; + const bool ignore_extra_runs_; }; } // namespace internal @@ -100,9 +104,23 @@ template <typename... Args> RepeatingCallback<void(Args...)> AdaptCallbackForRepeating( OnceCallback<void(Args...)> callback) { - using Helper = internal::AdaptCallbackForRepeatingHelper<Args...>; - return base::BindRepeating(&Helper::Run, - std::make_unique<Helper>(std::move(callback))); + using Helper = internal::OnceCallbackHolder<Args...>; + return base::BindRepeating( + &Helper::Run, std::make_unique<Helper>(std::move(callback), + /*ignore_extra_runs=*/true)); +} + +// Wraps the given OnceCallback and returns two OnceCallbacks with an identical +// signature. On first invokation of either returned callbacks, the original +// callback is invoked. Invoking the remaining callback results in a crash. +template <typename... Args> +std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>> +SplitOnceCallback(OnceCallback<void(Args...)> callback) { + using Helper = internal::OnceCallbackHolder<Args...>; + auto wrapped_once = base::BindRepeating( + &Helper::Run, std::make_unique<Helper>(std::move(callback), + /*ignore_extra_runs=*/false)); + return std::make_pair(wrapped_once, wrapped_once); } // ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc index b88c1c23..bfc276c 100644 --- a/base/callback_helpers_unittest.cc +++ b/base/callback_helpers_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/test/gtest_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -193,4 +194,46 @@ EXPECT_EQ(1, count); } +TEST(CallbackHelpersTest, SplitOnceCallback_FirstCallback) { + int count = 0; + base::OnceCallback<void(int*)> cb = + base::BindOnce([](int* count) { ++*count; }); + + auto split = base::SplitOnceCallback(std::move(cb)); + + static_assert(std::is_same<decltype(split), + std::pair<base::OnceCallback<void(int*)>, + base::OnceCallback<void(int*)>>>::value, + ""); + + EXPECT_EQ(0, count); + std::move(split.first).Run(&count); + EXPECT_EQ(1, count); + +#if GTEST_HAS_DEATH_TEST + EXPECT_CHECK_DEATH(std::move(split.second).Run(&count)); +#endif // GTEST_HAS_DEATH_TEST +} + +TEST(CallbackHelpersTest, SplitOnceCallback_SecondCallback) { + int count = 0; + base::OnceCallback<void(int*)> cb = + base::BindOnce([](int* count) { ++*count; }); + + auto split = base::SplitOnceCallback(std::move(cb)); + + static_assert(std::is_same<decltype(split), + std::pair<base::OnceCallback<void(int*)>, + base::OnceCallback<void(int*)>>>::value, + ""); + + EXPECT_EQ(0, count); + std::move(split.second).Run(&count); + EXPECT_EQ(1, count); + +#if GTEST_HAS_DEATH_TEST + EXPECT_CHECK_DEATH(std::move(split.first).Run(&count)); +#endif // GTEST_HAS_DEATH_TEST +} + } // namespace
diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h index e804b0b4..91f4e494 100644 --- a/base/files/dir_reader_linux.h +++ b/base/files/dir_reader_linux.h
@@ -14,7 +14,6 @@ #include <unistd.h> #include "base/logging.h" -#include "base/macros.h" #include "base/posix/eintr_wrapper.h" // See the comments in dir_reader_posix.h about this. @@ -38,6 +37,9 @@ memset(buf_, 0, sizeof(buf_)); } + DirReaderLinux(const DirReaderLinux&) = delete; + DirReaderLinux& operator=(const DirReaderLinux&) = delete; + ~DirReaderLinux() { if (fd_ >= 0) { if (IGNORE_EINTR(close(fd_))) @@ -93,8 +95,6 @@ alignas(linux_dirent) unsigned char buf_[512]; size_t offset_; size_t size_; - - DISALLOW_COPY_AND_ASSIGN(DirReaderLinux); }; } // namespace base
diff --git a/base/files/file.h b/base/files/file.h index 2743d1f..c4d99b1 100644 --- a/base/files/file.h +++ b/base/files/file.h
@@ -14,7 +14,6 @@ #include "base/files/file_path.h" #include "base/files/file_tracing.h" #include "base/files/platform_file.h" -#include "base/macros.h" #include "base/time/time.h" #include "build/build_config.h" @@ -168,6 +167,9 @@ File(File&& other); + File(const File&) = delete; + File& operator=(const File&) = delete; + ~File(); File& operator=(File&& other); @@ -393,8 +395,6 @@ Error error_details_ = FILE_ERROR_FAILED; bool created_ = false; bool async_ = false; - - DISALLOW_COPY_AND_ASSIGN(File); }; } // namespace base
diff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc index 0eaef1e..0da1c78 100644 --- a/base/files/file_descriptor_watcher_posix.cc +++ b/base/files/file_descriptor_watcher_posix.cc
@@ -37,6 +37,8 @@ public CurrentThread::DestructionObserver { public: Watcher(WeakPtr<Controller> controller, MessagePumpForIO::Mode mode, int fd); + Watcher(const Watcher&) = delete; + Watcher& operator=(const Watcher&) = delete; ~Watcher() override; void StartWatching(); @@ -78,8 +80,6 @@ // Whether this Watcher was registered as a DestructionObserver on the // MessagePumpForIO thread. bool registered_as_destruction_observer_ = false; - - DISALLOW_COPY_AND_ASSIGN(Watcher); }; FileDescriptorWatcher::Controller::Watcher::Watcher(
diff --git a/base/files/file_descriptor_watcher_posix.h b/base/files/file_descriptor_watcher_posix.h index 51958d1..3900d19 100644 --- a/base/files/file_descriptor_watcher_posix.h +++ b/base/files/file_descriptor_watcher_posix.h
@@ -10,7 +10,6 @@ #include "base/base_export.h" #include "base/callback.h" #include "base/check_op.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump_for_io.h" @@ -39,6 +38,8 @@ // readable or writable without blocking and the destructor unregisters it. class Controller { public: + Controller(const Controller&) = delete; + Controller& operator=(const Controller&) = delete; // Unregisters the callback registered by the constructor. ~Controller(); @@ -80,8 +81,6 @@ SequenceChecker sequence_checker_; WeakPtrFactory<Controller> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(Controller); }; // Registers |io_thread_task_runner| to watch file descriptors for which @@ -92,6 +91,8 @@ // blocking I/O) since ~Controller waits for a task posted to it. explicit FileDescriptorWatcher( scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner); + FileDescriptorWatcher(const FileDescriptorWatcher&) = delete; + FileDescriptorWatcher& operator=(const FileDescriptorWatcher&) = delete; ~FileDescriptorWatcher(); // Registers |callback| to be posted on the current sequence when |fd| is @@ -129,8 +130,6 @@ } const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); }; } // namespace base
diff --git a/base/files/file_descriptor_watcher_posix_unittest.cc b/base/files/file_descriptor_watcher_posix_unittest.cc index 5411ec36..9b04cfb 100644 --- a/base/files/file_descriptor_watcher_posix_unittest.cc +++ b/base/files/file_descriptor_watcher_posix_unittest.cc
@@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/files/file_util.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_pump_type.h" #include "base/posix/eintr_wrapper.h" @@ -32,12 +31,11 @@ class Mock { public: Mock() = default; + Mock(const Mock&) = delete; + Mock& operator=(const Mock&) = delete; MOCK_METHOD0(ReadableCallback, void()); MOCK_METHOD0(WritableCallback, void()); - - private: - DISALLOW_COPY_AND_ASSIGN(Mock); }; enum class FileDescriptorWatcherTestType { @@ -55,6 +53,9 @@ ? test::TaskEnvironment::MainThreadType::IO : test::TaskEnvironment::MainThreadType::DEFAULT)), other_thread_("FileDescriptorWatcherTest_OtherThread") {} + FileDescriptorWatcherTest(const FileDescriptorWatcherTest&) = delete; + FileDescriptorWatcherTest& operator=(const FileDescriptorWatcherTest&) = + delete; ~FileDescriptorWatcherTest() override = default; void SetUp() override { @@ -159,8 +160,6 @@ // Used to verify that callbacks run on the thread on which they are // registered. ThreadCheckerImpl thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcherTest); }; } // namespace
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h index fde311c..7ba9773 100644 --- a/base/files/file_enumerator.h +++ b/base/files/file_enumerator.h
@@ -14,7 +14,6 @@ #include "base/containers/stack.h" #include "base/files/file.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/optional.h" #include "base/time/time.h" #include "build/build_config.h" @@ -24,8 +23,6 @@ #elif defined(OS_POSIX) || defined(OS_FUCHSIA) #include <unistd.h> #include <unordered_set> - -#include "base/files/file.h" #endif namespace base { @@ -148,6 +145,8 @@ const FilePath::StringType& pattern, FolderSearchPolicy folder_search_policy, ErrorPolicy error_policy); + FileEnumerator(const FileEnumerator&) = delete; + FileEnumerator& operator=(const FileEnumerator&) = delete; ~FileEnumerator(); // Returns the next file or an empty string if there are no more results. @@ -205,8 +204,6 @@ // A stack that keeps track of which subdirectories we still need to // enumerate in the breadth-first search. base::stack<FilePath> pending_paths_; - - DISALLOW_COPY_AND_ASSIGN(FileEnumerator); }; } // namespace base
diff --git a/base/files/file_locking_unittest.cc b/base/files/file_locking_unittest.cc index 638d74dd..c2f21f9 100644 --- a/base/files/file_locking_unittest.cc +++ b/base/files/file_locking_unittest.cc
@@ -6,7 +6,6 @@ #include "base/files/file.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" -#include "base/macros.h" #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" @@ -133,6 +132,8 @@ class FileLockingTest : public testing::Test { public: FileLockingTest() = default; + FileLockingTest(const FileLockingTest&) = delete; + FileLockingTest& operator=(const FileLockingTest&) = delete; protected: void SetUp() override { @@ -193,9 +194,6 @@ base::ScopedTempDir temp_dir_; base::File lock_file_; base::Process lock_child_; - - private: - DISALLOW_COPY_AND_ASSIGN(FileLockingTest); }; // Test that locks are released by Unlock().
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc index 9adc23a..b9cc91e 100644 --- a/base/files/file_path_watcher.cc +++ b/base/files/file_path_watcher.cc
@@ -28,8 +28,7 @@ #endif } -FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) { -} +FilePathWatcher::PlatformDelegate::PlatformDelegate() = default; FilePathWatcher::PlatformDelegate::~PlatformDelegate() { DCHECK(is_cancelled());
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h index b0d0591e..c435451 100644 --- a/base/files/file_path_watcher.h +++ b/base/files/file_path_watcher.h
@@ -8,11 +8,11 @@ #define BASE_FILES_FILE_PATH_WATCHER_H_ #include <memory> +#include <utility> #include "base/base_export.h" #include "base/callback.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" @@ -64,6 +64,8 @@ using Type = FilePathWatcher::Type; PlatformDelegate(); + PlatformDelegate(const PlatformDelegate&) = delete; + PlatformDelegate& operator=(const PlatformDelegate&) = delete; virtual ~PlatformDelegate(); // Start watching for the given |path| and notify |delegate| about changes. @@ -97,12 +99,12 @@ private: scoped_refptr<SequencedTaskRunner> task_runner_; - bool cancelled_; - - DISALLOW_COPY_AND_ASSIGN(PlatformDelegate); + bool cancelled_ = false; }; FilePathWatcher(); + FilePathWatcher(const FilePathWatcher&) = delete; + FilePathWatcher& operator=(const FilePathWatcher&) = delete; ~FilePathWatcher(); // Returns true if the platform and OS version support recursive watches. @@ -122,8 +124,6 @@ std::unique_ptr<PlatformDelegate> impl_; SequenceChecker sequence_checker_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcher); }; } // namespace base
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc index 2956ba0..492cb3c9 100644 --- a/base/files/file_path_watcher_fsevents.cc +++ b/base/files/file_path_watcher_fsevents.cc
@@ -6,6 +6,7 @@ #include <dispatch/dispatch.h> +#include <algorithm> #include <list> #include "base/bind.h" @@ -72,9 +73,7 @@ : queue_(dispatch_queue_create( base::StringPrintf("org.chromium.base.FilePathWatcher.%p", this) .c_str(), - DISPATCH_QUEUE_SERIAL)), - fsevent_stream_(nullptr), - weak_factory_(this) {} + DISPATCH_QUEUE_SERIAL)) {} FilePathWatcherFSEvents::~FilePathWatcherFSEvents() { DCHECK(!task_runner() || task_runner()->RunsTasksInCurrentSequence());
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h index 145db2e..d85fab7 100644 --- a/base/files/file_path_watcher_fsevents.h +++ b/base/files/file_path_watcher_fsevents.h
@@ -13,7 +13,6 @@ #include "base/files/file_path.h" #include "base/files/file_path_watcher.h" #include "base/mac/scoped_dispatch_object.h" -#include "base/macros.h" #include "base/memory/weak_ptr.h" namespace base { @@ -27,6 +26,8 @@ class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate { public: FilePathWatcherFSEvents(); + FilePathWatcherFSEvents(const FilePathWatcherFSEvents&) = delete; + FilePathWatcherFSEvents& operator=(const FilePathWatcherFSEvents&) = delete; ~FilePathWatcherFSEvents() override; // FilePathWatcher::PlatformDelegate overrides. @@ -87,11 +88,9 @@ // Backend stream we receive event callbacks from (strong reference). // (Only accessed from the libdispatch queue.) - FSEventStreamRef fsevent_stream_; + FSEventStreamRef fsevent_stream_ = nullptr; - WeakPtrFactory<FilePathWatcherFSEvents> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents); + WeakPtrFactory<FilePathWatcherFSEvents> weak_factory_{this}; }; } // namespace base
diff --git a/base/files/file_path_watcher_fuchsia.cc b/base/files/file_path_watcher_fuchsia.cc index 13dfb73..cbf0017 100644 --- a/base/files/file_path_watcher_fuchsia.cc +++ b/base/files/file_path_watcher_fuchsia.cc
@@ -4,7 +4,6 @@ #include "base/files/file_path_watcher.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -14,8 +13,10 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { public: - FilePathWatcherImpl() {} - ~FilePathWatcherImpl() override {} + FilePathWatcherImpl() = default; + FilePathWatcherImpl(const FilePathWatcherImpl&) = delete; + FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete; + ~FilePathWatcherImpl() override = default; bool Watch(const FilePath& path, Type type, @@ -26,8 +27,6 @@ private: FilePathWatcher::Callback callback_; FilePath target_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); }; bool FilePathWatcherImpl::Watch(const FilePath& path,
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h index 4ff415a..480fd26 100644 --- a/base/files/file_path_watcher_kqueue.h +++ b/base/files/file_path_watcher_kqueue.h
@@ -13,7 +13,6 @@ #include "base/files/file_descriptor_watcher_posix.h" #include "base/files/file_path.h" #include "base/files/file_path_watcher.h" -#include "base/macros.h" #include "base/memory/weak_ptr.h" namespace base { @@ -32,6 +31,8 @@ class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate { public: FilePathWatcherKQueue(); + FilePathWatcherKQueue(const FilePathWatcherKQueue&) = delete; + FilePathWatcherKQueue& operator=(const FilePathWatcherKQueue&) = delete; ~FilePathWatcherKQueue() override; // FilePathWatcher::PlatformDelegate overrides. @@ -123,8 +124,6 @@ std::unique_ptr<FileDescriptorWatcher::Controller> kqueue_watch_controller_; WeakPtrFactory<FilePathWatcherKQueue> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherKQueue); }; } // namespace base
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc index 0271c05..b125a02 100644 --- a/base/files/file_path_watcher_linux.cc +++ b/base/files/file_path_watcher_linux.cc
@@ -28,7 +28,6 @@ #include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" #include "base/posix/eintr_wrapper.h" @@ -63,7 +62,7 @@ // Get the maximum number of inotify watches can be used by a FilePathWatcher // instance. This is based on /proc/sys/fs/inotify/max_user_watches entry. int GetMaxNumberOfInotifyWatches() { - const static int max = []() { + static const int max = []() { int max_number_of_inotify_watches = 0; std::ifstream in(kInotifyMaxUserWatchesPath); @@ -81,14 +80,15 @@ public: explicit InotifyReaderThreadDelegate(int inotify_fd) : inotify_fd_(inotify_fd) {} + InotifyReaderThreadDelegate(const InotifyReaderThreadDelegate&) = delete; + InotifyReaderThreadDelegate& operator=(const InotifyReaderThreadDelegate&) = + delete; ~InotifyReaderThreadDelegate() override = default; private: void ThreadMain() override; const int inotify_fd_; - - DISALLOW_COPY_AND_ASSIGN(InotifyReaderThreadDelegate); }; // Singleton to manage all inotify watches. @@ -100,6 +100,9 @@ static constexpr Watch kInvalidWatch = -1; static constexpr Watch kWatchLimitExceeded = -2; + InotifyReader(const InotifyReader&) = delete; + InotifyReader& operator=(const InotifyReader&) = delete; + // Watch directory |path| for changes. |watcher| will be notified on each // change. Returns |kInvalidWatch| on failure. Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher); @@ -135,13 +138,13 @@ // Flag set to true when startup was successful. bool valid_ = false; - - DISALLOW_COPY_AND_ASSIGN(InotifyReader); }; class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { public: FilePathWatcherImpl(); + FilePathWatcherImpl(const FilePathWatcherImpl&) = delete; + FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete; ~FilePathWatcherImpl() override; // Called for each event coming from the watch. |fired_watch| identifies the @@ -253,8 +256,6 @@ WeakPtr<FilePathWatcherImpl> weak_ptr_; WeakPtrFactory<FilePathWatcherImpl> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); }; LazyInstance<InotifyReader>::Leaky g_inotify_reader = LAZY_INSTANCE_INITIALIZER;
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc index edc34e53..dcc4831 100644 --- a/base/files/file_path_watcher_mac.cc +++ b/base/files/file_path_watcher_mac.cc
@@ -6,7 +6,6 @@ #include "base/files/file_path_watcher.h" #include "base/files/file_path_watcher_kqueue.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "build/build_config.h" @@ -21,6 +20,8 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { public: FilePathWatcherImpl() = default; + FilePathWatcherImpl(const FilePathWatcherImpl&) = delete; + FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete; ~FilePathWatcherImpl() override = default; bool Watch(const FilePath& path, @@ -49,8 +50,6 @@ private: std::unique_ptr<PlatformDelegate> impl_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); }; } // namespace
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc index 13a7164e..d34d98b 100644 --- a/base/files/file_path_watcher_stub.cc +++ b/base/files/file_path_watcher_stub.cc
@@ -7,7 +7,6 @@ #include "base/files/file_path_watcher.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" namespace base { @@ -17,6 +16,8 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { public: FilePathWatcherImpl() = default; + FilePathWatcherImpl(const FilePathWatcherImpl&) = delete; + FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete; ~FilePathWatcherImpl() override = default; bool Watch(const FilePath& path, @@ -26,9 +27,6 @@ } void Cancel() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); }; } // namespace
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc index ae726f32..596140cd 100644 --- a/base/files/file_path_watcher_unittest.cc +++ b/base/files/file_path_watcher_unittest.cc
@@ -12,6 +12,8 @@ #endif #include <set> +#include <string> +#include <vector> #include "base/bind.h" #include "base/callback_helpers.h" @@ -21,7 +23,6 @@ #include "base/files/scoped_temp_dir.h" #include "base/location.h" #include "base/logging.h" -#include "base/macros.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" @@ -106,12 +107,11 @@ class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> { public: TestDelegateBase() = default; + TestDelegateBase(const TestDelegateBase&) = delete; + TestDelegateBase& operator=(const TestDelegateBase&) = delete; virtual ~TestDelegateBase() = default; virtual void OnFileChanged(const FilePath& path, bool error) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(TestDelegateBase); }; // A mock class for testing. Gmock is not appropriate because it is not @@ -125,6 +125,8 @@ : collector_(collector) { collector_->Register(this); } + TestDelegate(const TestDelegate&) = delete; + TestDelegate& operator=(const TestDelegate&) = delete; ~TestDelegate() override = default; void OnFileChanged(const FilePath& path, bool error) override { @@ -136,8 +138,6 @@ private: scoped_refptr<NotificationCollector> collector_; - - DISALLOW_COPY_AND_ASSIGN(TestDelegate); }; class FilePathWatcherTest : public testing::Test { @@ -149,6 +149,8 @@ { } + FilePathWatcherTest(const FilePathWatcherTest&) = delete; + FilePathWatcherTest& operator=(const FilePathWatcherTest&) = delete; ~FilePathWatcherTest() override = default; protected: @@ -203,9 +205,6 @@ ScopedTempDir temp_dir_; scoped_refptr<NotificationCollector> collector_; - - private: - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest); }; bool FilePathWatcherTest::SetupWatch(const FilePath& target, @@ -277,6 +276,8 @@ explicit Deleter(base::OnceClosure done_closure) : watcher_(std::make_unique<FilePathWatcher>()), done_closure_(std::move(done_closure)) {} + Deleter(const Deleter&) = delete; + Deleter& operator=(const Deleter&) = delete; ~Deleter() override = default; void OnFileChanged(const FilePath&, bool) override { @@ -289,8 +290,6 @@ private: std::unique_ptr<FilePathWatcher> watcher_; base::OnceClosure done_closure_; - - DISALLOW_COPY_AND_ASSIGN(Deleter); }; // Verify that deleting a watcher during the callback doesn't crash.
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc index 61e0c70..da12e07 100644 --- a/base/files/file_path_watcher_win.cc +++ b/base/files/file_path_watcher_win.cc
@@ -4,12 +4,13 @@ #include "base/files/file_path_watcher.h" +#include <windows.h> + #include "base/bind.h" #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/threading/scoped_blocking_call.h" @@ -17,8 +18,6 @@ #include "base/time/time.h" #include "base/win/object_watcher.h" -#include <windows.h> - namespace base { namespace { @@ -26,8 +25,9 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, public base::win::ObjectWatcher::Delegate { public: - FilePathWatcherImpl() - : handle_(INVALID_HANDLE_VALUE), type_(Type::kNonRecursive) {} + FilePathWatcherImpl() = default; + FilePathWatcherImpl(const FilePathWatcherImpl&) = delete; + FilePathWatcherImpl& operator=(const FilePathWatcherImpl&) = delete; ~FilePathWatcherImpl() override; // FilePathWatcher::PlatformDelegate: @@ -64,13 +64,13 @@ bool* was_deleted_ptr_ = nullptr; // Handle for FindFirstChangeNotification. - HANDLE handle_; + HANDLE handle_ = INVALID_HANDLE_VALUE; // ObjectWatcher to watch handle_ for events. base::win::ObjectWatcher watcher_; // The type of watch requested. - Type type_; + Type type_ = Type::kNonRecursive; // Keep track of the last modified time of the file. We use nulltime // to represent the file not existing. @@ -79,8 +79,6 @@ // The time at which we processed the first notification with the // |last_modified_| time stamp. Time first_notification_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); }; FilePathWatcherImpl::~FilePathWatcherImpl() {
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc index a1b9187..d33ce389 100644 --- a/base/files/file_proxy.cc +++ b/base/files/file_proxy.cc
@@ -4,6 +4,7 @@ #include "base/files/file_proxy.h" +#include <memory> #include <utility> #include "base/bind.h" @@ -11,7 +12,6 @@ #include "base/files/file.h" #include "base/files/file_util.h" #include "base/location.h" -#include "base/macros.h" #include "base/task_runner.h" #include "base/task_runner_util.h" @@ -28,9 +28,10 @@ public: FileHelper(FileProxy* proxy, File file) : file_(std::move(file)), - error_(File::FILE_ERROR_FAILED), task_runner_(proxy->task_runner()), proxy_(AsWeakPtr(proxy)) {} + FileHelper(const FileHelper&) = delete; + FileHelper& operator=(const FileHelper&) = delete; void PassFile() { if (proxy_) @@ -42,12 +43,11 @@ protected: File file_; - File::Error error_; + File::Error error_ = File::FILE_ERROR_FAILED; private: scoped_refptr<TaskRunner> task_runner_; WeakPtr<FileProxy> proxy_; - DISALLOW_COPY_AND_ASSIGN(FileHelper); }; namespace { @@ -57,6 +57,8 @@ GenericFileHelper(FileProxy* proxy, File file) : FileHelper(proxy, std::move(file)) { } + GenericFileHelper(const GenericFileHelper&) = delete; + GenericFileHelper& operator=(const GenericFileHelper&) = delete; void Close() { file_.Close(); @@ -83,9 +85,6 @@ if (!callback.is_null()) std::move(callback).Run(error_); } - - private: - DISALLOW_COPY_AND_ASSIGN(GenericFileHelper); }; class CreateOrOpenHelper : public FileHelper { @@ -93,6 +92,8 @@ CreateOrOpenHelper(FileProxy* proxy, File file) : FileHelper(proxy, std::move(file)) { } + CreateOrOpenHelper(const CreateOrOpenHelper&) = delete; + CreateOrOpenHelper& operator=(const CreateOrOpenHelper&) = delete; void RunWork(const FilePath& file_path, int file_flags) { file_.Initialize(file_path, file_flags); @@ -104,9 +105,6 @@ PassFile(); std::move(callback).Run(error_); } - - private: - DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); }; class CreateTemporaryHelper : public FileHelper { @@ -114,6 +112,8 @@ CreateTemporaryHelper(FileProxy* proxy, File file) : FileHelper(proxy, std::move(file)) { } + CreateTemporaryHelper(const CreateTemporaryHelper&) = delete; + CreateTemporaryHelper& operator=(const CreateTemporaryHelper&) = delete; void RunWork(uint32_t additional_file_flags) { // TODO(darin): file_util should have a variant of CreateTemporaryFile @@ -146,7 +146,6 @@ private: FilePath file_path_; - DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); }; class GetInfoHelper : public FileHelper { @@ -154,6 +153,8 @@ GetInfoHelper(FileProxy* proxy, File file) : FileHelper(proxy, std::move(file)) { } + GetInfoHelper(const GetInfoHelper&) = delete; + GetInfoHelper& operator=(const GetInfoHelper&) = delete; void RunWork() { if (file_.GetInfo(&file_info_)) @@ -168,7 +169,6 @@ private: File::Info file_info_; - DISALLOW_COPY_AND_ASSIGN(GetInfoHelper); }; class ReadHelper : public FileHelper { @@ -176,9 +176,9 @@ ReadHelper(FileProxy* proxy, File file, int bytes_to_read) : FileHelper(proxy, std::move(file)), buffer_(new char[bytes_to_read]), - bytes_to_read_(bytes_to_read), - bytes_read_(0) { - } + bytes_to_read_(bytes_to_read) {} + ReadHelper(const ReadHelper&) = delete; + ReadHelper& operator=(const ReadHelper&) = delete; void RunWork(int64_t offset) { bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_); @@ -194,21 +194,22 @@ private: std::unique_ptr<char[]> buffer_; int bytes_to_read_; - int bytes_read_; - DISALLOW_COPY_AND_ASSIGN(ReadHelper); + int bytes_read_ = 0; }; class WriteHelper : public FileHelper { public: WriteHelper(FileProxy* proxy, File file, - const char* buffer, int bytes_to_write) + const char* buffer, + int bytes_to_write) : FileHelper(proxy, std::move(file)), buffer_(new char[bytes_to_write]), - bytes_to_write_(bytes_to_write), - bytes_written_(0) { + bytes_to_write_(bytes_to_write) { memcpy(buffer_.get(), buffer, bytes_to_write); } + WriteHelper(const WriteHelper&) = delete; + WriteHelper& operator=(const WriteHelper&) = delete; void RunWork(int64_t offset) { bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_); @@ -224,8 +225,7 @@ private: std::unique_ptr<char[]> buffer_; int bytes_to_write_; - int bytes_written_; - DISALLOW_COPY_AND_ASSIGN(WriteHelper); + int bytes_written_ = 0; }; } // namespace
diff --git a/base/files/file_proxy.h b/base/files/file_proxy.h index d17e4d3b..fbe71d6 100644 --- a/base/files/file_proxy.h +++ b/base/files/file_proxy.h
@@ -11,7 +11,6 @@ #include "base/callback_forward.h" #include "base/files/file.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -51,6 +50,8 @@ FileProxy(); explicit FileProxy(TaskRunner* task_runner); + FileProxy(const FileProxy&) = delete; + FileProxy& operator=(const FileProxy&) = delete; ~FileProxy(); // Creates or opens a file with the given flags. It is invalid to pass a null @@ -134,7 +135,6 @@ scoped_refptr<TaskRunner> task_runner_; File file_; - DISALLOW_COPY_AND_ASSIGN(FileProxy); }; } // namespace base
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc index 48f5741..243b5492 100644 --- a/base/files/file_tracing.cc +++ b/base/files/file_tracing.cc
@@ -44,8 +44,6 @@ provider->FileTracingDisable(this); } -FileTracing::ScopedTrace::ScopedTrace() : id_(nullptr) {} - FileTracing::ScopedTrace::~ScopedTrace() { if (id_) { FileTracing::Provider* provider = GetProvider();
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h index 1fbfcd4..38b2879b 100644 --- a/base/files/file_tracing.h +++ b/base/files/file_tracing.h
@@ -8,7 +8,6 @@ #include <stdint.h> #include "base/base_export.h" -#include "base/macros.h" #define FILE_TRACING_PREFIX "File" @@ -66,7 +65,9 @@ class ScopedTrace { public: - ScopedTrace(); + ScopedTrace() = default; + ScopedTrace(const ScopedTrace&) = delete; + ScopedTrace& operator=(const ScopedTrace&) = delete; ~ScopedTrace(); // Called only if the tracing category is enabled. |name| is the name of the @@ -78,16 +79,15 @@ private: // The ID of this trace. Based on the |file| passed to |Initialize()|. Must // outlive this class. - const void* id_; + const void* id_ = nullptr; // The name of the event to trace (e.g. "Read", "Write"). Prefixed with // "File". const char* name_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTrace); }; - DISALLOW_COPY_AND_ASSIGN(FileTracing); + FileTracing(const FileTracing&) = delete; + FileTracing& operator=(const FileTracing&) = delete; }; } // namespace base
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h index 6a17cc0..d56d501 100644 --- a/base/files/important_file_writer.h +++ b/base/files/important_file_writer.h
@@ -11,7 +11,6 @@ #include "base/base_export.h" #include "base/callback.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/strings/string_piece.h" @@ -73,6 +72,9 @@ TimeDelta interval, StringPiece histogram_suffix = StringPiece()); + ImportantFileWriter(const ImportantFileWriter&) = delete; + ImportantFileWriter& operator=(const ImportantFileWriter&) = delete; + // You have to ensure that there are no pending writes at the moment // of destruction. ~ImportantFileWriter(); @@ -184,8 +186,6 @@ SEQUENCE_CHECKER(sequence_checker_); WeakPtrFactory<ImportantFileWriter> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter); }; } // namespace base
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc index e326584..de09de1e 100644 --- a/base/files/important_file_writer_unittest.cc +++ b/base/files/important_file_writer_unittest.cc
@@ -10,7 +10,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/location.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/notreached.h" #include "base/run_loop.h" @@ -63,6 +62,8 @@ class WriteCallbacksObserver { public: WriteCallbacksObserver() = default; + WriteCallbacksObserver(const WriteCallbacksObserver&) = delete; + WriteCallbacksObserver& operator=(const WriteCallbacksObserver&) = delete; // Register OnBeforeWrite() and OnAfterWrite() to be called on the next write // of |writer|. @@ -86,8 +87,6 @@ bool before_write_called_ = false; WriteCallbackObservationState after_write_observation_state_ = NOT_CALLED; - - DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver); }; void WriteCallbacksObserver::ObserveNextWriteCallbacks(
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h index 8a8c320..08ace8c 100644 --- a/base/files/memory_mapped_file.h +++ b/base/files/memory_mapped_file.h
@@ -8,9 +8,10 @@ #include <stddef.h> #include <stdint.h> +#include <utility> + #include "base/base_export.h" #include "base/files/file.h" -#include "base/macros.h" #include "build/build_config.h" #if defined(OS_WIN) @@ -56,6 +57,8 @@ // The default constructor sets all members to invalid/null values. MemoryMappedFile(); + MemoryMappedFile(const MemoryMappedFile&) = delete; + MemoryMappedFile& operator=(const MemoryMappedFile&) = delete; ~MemoryMappedFile(); // Used to hold information about a region [offset + size] of a file. @@ -143,8 +146,6 @@ #if defined(OS_WIN) win::ScopedHandle file_mapping_; #endif - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); }; } // namespace base
diff --git a/base/files/os_validation_win_unittest.cc b/base/files/os_validation_win_unittest.cc index 5bf62477..f24ca77 100644 --- a/base/files/os_validation_win_unittest.cc +++ b/base/files/os_validation_win_unittest.cc
@@ -15,7 +15,6 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/win/scoped_handle.h" @@ -68,6 +67,8 @@ std::tuple<DWORD, DWORD, DWORD>>> { protected: OpenFileTest() = default; + OpenFileTest(const OpenFileTest&) = delete; + OpenFileTest& operator=(const OpenFileTest&) = delete; // Returns a dwDesiredAccess bitmask for use with CreateFileW containing the // test's access right bits. @@ -248,8 +249,6 @@ FilePath temp_file_path_; FilePath temp_file_dest_path_; win::ScopedHandle file_handle_; - - DISALLOW_COPY_AND_ASSIGN(OpenFileTest); }; // Tests that an opened but not mapped file can be deleted as expected.
diff --git a/base/strings/char_traits.h b/base/strings/char_traits.h index b193e216..574d6a2 100644 --- a/base/strings/char_traits.h +++ b/base/strings/char_traits.h
@@ -50,42 +50,35 @@ return i; } -// char specialization of CharTraits that can use clang's constexpr instrinsics, -// where available. +// char and wchar_t specialization of CharTraits that can use clang's constexpr +// instrinsics, where available. +#if HAS_FEATURE(cxx_constexpr_string_builtins) template <> struct CharTraits<char> { static constexpr int compare(const char* s1, const char* s2, - size_t n) noexcept; - static constexpr size_t length(const char* s) noexcept; + size_t n) noexcept { + return __builtin_memcmp(s1, s2, n); + } + + static constexpr size_t length(const char* s) noexcept { + return __builtin_strlen(s); + } }; -constexpr int CharTraits<char>::compare(const char* s1, - const char* s2, - size_t n) noexcept { -#if HAS_FEATURE(cxx_constexpr_string_builtins) - return __builtin_memcmp(s1, s2, n); -#else - for (; n; --n, ++s1, ++s2) { - if (*s1 < *s2) - return -1; - if (*s1 > *s2) - return 1; +template <> +struct CharTraits<wchar_t> { + static constexpr int compare(const wchar_t* s1, + const wchar_t* s2, + size_t n) noexcept { + return __builtin_wmemcmp(s1, s2, n); } - return 0; -#endif -} -constexpr size_t CharTraits<char>::length(const char* s) noexcept { -#if defined(__clang__) - return __builtin_strlen(s); -#else - size_t i = 0; - for (; *s; ++s) - ++i; - return i; + static constexpr size_t length(const wchar_t* s) noexcept { + return __builtin_wcslen(s); + } +}; #endif -} } // namespace base
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index 956405a..58afef01 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -69,7 +69,8 @@ # Chrome's clang. crbug.com/1033839 use_thin_lto = is_cfi || (is_official_build && (target_os == "android" || - (target_os == "chromeos" && is_chromeos_device))) + ((is_chromeos_ash || is_chromeos_lacros) + && is_chromeos_device))) # If true, use Goma for ThinLTO code generation where applicable. use_goma_thin_lto = false
diff --git a/build/config/ios/find_signing_identity.py b/build/config/ios/find_signing_identity.py index 8116e68..d508e2b 100644 --- a/build/config/ios/find_signing_identity.py +++ b/build/config/ios/find_signing_identity.py
@@ -33,18 +33,18 @@ def ListIdentities(): return subprocess.check_output([ - 'xcrun', - 'security', - 'find-identity', - '-v', - '-p', - 'codesigning', - ]) + 'xcrun', + 'security', + 'find-identity', + '-v', + '-p', + 'codesigning', + ]).decode('utf8') def FindValidIdentity(pattern): """Find all identities matching the pattern.""" - lines = list(map(str.strip, ListIdentities().splitlines())) + lines = list(l.strip() for l in ListIdentities().splitlines()) # Look for something like "2) XYZ "iPhone Developer: Name (ABC)"" regex = re.compile('[0-9]+\) ([A-F0-9]+) "([^"(]*) \(([^)"]*)\)"')
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 4a986949..39d197c 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -61,7 +61,7 @@ is_cfi = is_official_build && (((target_os == "linux" || is_chromeos_lacros) && target_cpu == "x64") || - (target_os == "chromeos" && is_chromeos_device && !is_chromeos_lacros)) + ((is_chromeos_ash || is_chromeos_lacros) && is_chromeos_device)) # Enable checks for indirect function calls via a function pointer. # TODO(pcc): remove this when we're ready to add these checks by default. @@ -123,7 +123,7 @@ # Enable checks for bad casts: derived cast and unrelated cast. # TODO(krasin): remove this, when we're ready to add these checks by default. # https://crbug.com/626794 - use_cfi_cast = is_cfi && target_os == "chromeos" + use_cfi_cast = is_cfi && (is_chromeos_ash || is_chromeos_lacros) } # Disable sanitizers for non-target toolchains.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 77f3645c..d1b8ddc 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20201217.1.1 +0.20201217.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 77f3645c..d1b8ddc 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20201217.1.1 +0.20201217.2.1
diff --git a/build_overrides/angle.gni b/build_overrides/angle.gni index 8af05e4..2879e29 100644 --- a/build_overrides/angle.gni +++ b/build_overrides/angle.gni
@@ -9,12 +9,12 @@ angle_has_build = true # Overrides for ANGLE's dependencies -angle_glslang_dir = "//third_party/glslang/src" +angle_glslang_dir = "//third_party/vulkan-deps/glslang/src" angle_googletest_dir = "//third_party/googletest/src" angle_jsoncpp_dir = "//third_party/jsoncpp" angle_libjpeg_turbo_dir = "//third_party/libjpeg_turbo" angle_libpng_dir = "//third_party/libpng" -angle_spirv_cross_dir = "//third_party/spirv-cross/spirv-cross" -angle_spirv_headers_dir = "//third_party/spirv-headers/src" -angle_spirv_tools_dir = "//third_party/SPIRV-Tools/src" +angle_spirv_cross_dir = "//third_party/vulkan-deps/spirv-cross/src" +angle_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src" +angle_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" angle_vulkan_memory_allocator_dir = "//third_party/vulkan_memory_allocator"
diff --git a/build_overrides/dawn.gni b/build_overrides/dawn.gni index 84bcfbd..f8848c4 100644 --- a/build_overrides/dawn.gni +++ b/build_overrides/dawn.gni
@@ -8,9 +8,9 @@ dawn_jinja2_dir = "//third_party/jinja2" dawn_jsoncpp_dir = "//third_party/jsoncpp" dawn_shaderc_dir = "//third_party/shaderc/src" -dawn_spirv_cross_dir = "//third_party/spirv-cross/spirv-cross" -dawn_spirv_tools_dir = "//third_party/SPIRV-Tools/src" +dawn_spirv_cross_dir = "//third_party/vulkan-deps/spirv-cross/src" +dawn_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" dawn_swiftshader_dir = "//third_party/swiftshader" dawn_tint_dir = "//third_party/tint/src" dawn_vulkan_validation_layers_dir = - "//third_party/angle/third_party/vulkan-validation-layers/src" + "//third_party/vulkan-deps/vulkan-validation-layers/src"
diff --git a/build_overrides/glslang.gni b/build_overrides/glslang.gni index d9f9d64d..9090ce61 100644 --- a/build_overrides/glslang.gni +++ b/build_overrides/glslang.gni
@@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -glslang_spirv_tools_dir = "//third_party/SPIRV-Tools/src" +glslang_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" # Chromium uses glslang for two things: #
diff --git a/build_overrides/shaderc.gni b/build_overrides/shaderc.gni index a826794..3de56ec 100644 --- a/build_overrides/shaderc.gni +++ b/build_overrides/shaderc.gni
@@ -2,9 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -shaderc_glslang_dir = "//third_party/glslang/src" -shaderc_spirv_tools_dir = "//third_party/SPIRV-Tools/src" -shaderc_spirv_cross_dir = "//third_party/spirv-cross/spirv-cross" -shaderc_spirv_headers_dir = "//third_party/spirv-headers/src" +shaderc_glslang_dir = "//third_party/vulkan-deps/glslang/src" +shaderc_spirv_cross_dir = "//third_party/vulkan-deps/spirv-cross/src" +shaderc_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src" +shaderc_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" shaderc_enable_spvc_parser = false
diff --git a/build_overrides/spirv_tools.gni b/build_overrides/spirv_tools.gni index cc7e7d1..a25b1ea 100644 --- a/build_overrides/spirv_tools.gni +++ b/build_overrides/spirv_tools.gni
@@ -7,4 +7,4 @@ # Paths to SPIRV-Tools dependencies in Chromium spirv_tools_googletest_dir = "//third_party/googletest/src" -spirv_tools_spirv_headers_dir = "//third_party/spirv-headers/src" +spirv_tools_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src"
diff --git a/build_overrides/swiftshader.gni b/build_overrides/swiftshader.gni index 338b8f2..2864da9 100644 --- a/build_overrides/swiftshader.gni +++ b/build_overrides/swiftshader.gni
@@ -9,4 +9,4 @@ swiftshader_dir = "//third_party/swiftshader" # Paths to SwiftShader dependencies -swiftshader_spirv_tools_dir = "//third_party/SPIRV-Tools/src" +swiftshader_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src"
diff --git a/build_overrides/tint.gni b/build_overrides/tint.gni index 95bb287..8cd0d6f 100644 --- a/build_overrides/tint.gni +++ b/build_overrides/tint.gni
@@ -3,9 +3,9 @@ # found in the LICENSE file. tint_root_dir = "//third_party/tint/src" -tint_spirv_tools_dir = "//third_party/SPIRV-Tools/src" +tint_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" tint_googletest_dir = "//third_party/googletest/src" -tint_spirv_headers_dir = "//third_party/spirv-headers/src" +tint_spirv_headers_dir = "//third_party/vulkan-deps/spirv-headers/src" tint_build_spv_reader = true tint_build_spv_writer = true
diff --git a/build_overrides/vulkan_common.gni b/build_overrides/vulkan_common.gni index ad1fb8e..7aafea8 100644 --- a/build_overrides/vulkan_common.gni +++ b/build_overrides/vulkan_common.gni
@@ -4,7 +4,7 @@ import("//third_party/angle/gni/angle.gni") -vulkan_headers_dir = "//third_party/angle/third_party/vulkan-headers/src" +vulkan_headers_dir = "//third_party/vulkan-deps/vulkan-headers/src" vulkan_data_subdir = angle_data_dir vulkan_gen_subdir = "angle/vulkan"
diff --git a/build_overrides/vulkan_validation_layers.gni b/build_overrides/vulkan_validation_layers.gni index b893ce13..5d1a0f6f 100644 --- a/build_overrides/vulkan_validation_layers.gni +++ b/build_overrides/vulkan_validation_layers.gni
@@ -4,5 +4,5 @@ import("//build_overrides/vulkan_common.gni") -vvl_spirv_tools_dir = "//third_party/SPIRV-Tools/src" -vvl_glslang_dir = "//third_party/glslang/src" +vvl_spirv_tools_dir = "//third_party/vulkan-deps/spirv-tools/src" +vvl_glslang_dir = "//third_party/vulkan-deps/glslang/src"
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc index 9392f0a..bab06012 100644 --- a/cc/metrics/compositor_frame_reporter.cc +++ b/cc/metrics/compositor_frame_reporter.cc
@@ -767,7 +767,7 @@ void CompositorFrameReporter::ReportEventLatencyHistograms() const { for (const auto& event_metrics : events_metrics_) { - DCHECK_NE(event_metrics, nullptr); + DCHECK(event_metrics); const std::string histogram_base_name = GetEventLatencyHistogramBaseName(*event_metrics); const int event_type_index = static_cast<int>(event_metrics->type());
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc index 7f6e1d0c..0d2fb6d 100644 --- a/cc/metrics/dropped_frame_counter.cc +++ b/cc/metrics/dropped_frame_counter.cc
@@ -29,6 +29,8 @@ uint32_t SlidingWindowHistogram::GetPercentDroppedFramePercentile( double percentile) const { + if (total_count == 0) + return 0; DCHECK_GE(percentile, 0.0); DCHECK_GE(1.0, percentile); int current_index = 100; // Last bin in historgam @@ -116,6 +118,9 @@ "Graphics.Smoothness.95pctPercentDroppedFrames_1sWindow", sliding_window_95pct_percent_dropped); + DCHECK_LE(sliding_window_95pct_percent_dropped, + static_cast<uint32_t>(round(sliding_window_max_percent_dropped_))); + if (ukm_smoothness_data_ && total_frames > 0) { UkmSmoothnessData smoothness_data; smoothness_data.avg_smoothness =
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc index 17dc231..558d746 100644 --- a/cc/metrics/dropped_frame_counter_unittest.cc +++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -321,6 +321,14 @@ // 20th bucket, and as a result 95th percentile is also 20. } +TEST_F(DroppedFrameCounterTest, IncompleteWindow) { + // There are only 5 frames submitted and both Max and 95pct should report + // zero. + SimulateFrameSequence({false, false, false, false, true}, 1); + EXPECT_EQ(MaxPercentDroppedFrame(), 0.0); + EXPECT_EQ(PercentDroppedFrame95Percentile(), 0); +} + TEST_F(DroppedFrameCounterTest, MaxPercentDroppedChanges) { // First 60 frames have 20% dropped. SimulateFrameSequence({false, false, false, false, true}, 12);
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc index 4b603a22..43c49c2 100644 --- a/cc/metrics/frame_sequence_tracker.cc +++ b/cc/metrics/frame_sequence_tracker.cc
@@ -78,6 +78,11 @@ throughput_ukm_reporter)) { DCHECK_LT(type, FrameSequenceTrackerType::kMaxType); DCHECK(type != FrameSequenceTrackerType::kCustom); + // TODO(crbug.com/1158439): remove the trace event once the validation is + // completed. + TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1( + "cc,benchmark", "TrackerValidation", TRACE_ID_LOCAL(this), + base::TimeTicks::Now(), "name", GetFrameSequenceTrackerTypeName(type)); } FrameSequenceTracker::FrameSequenceTracker( @@ -92,6 +97,9 @@ } FrameSequenceTracker::~FrameSequenceTracker() { + TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( + "cc,benchmark", "TrackerValidation", TRACE_ID_LOCAL(this), + base::TimeTicks::Now()); CleanUp(); }
diff --git a/cc/metrics/frame_sequence_tracker.h b/cc/metrics/frame_sequence_tracker.h index 2c4fb649..387a50b 100644 --- a/cc/metrics/frame_sequence_tracker.h +++ b/cc/metrics/frame_sequence_tracker.h
@@ -250,7 +250,6 @@ // only when the last impl-frame is ended (ReportFrameEnd). bool is_inside_frame_ = false; - #if DCHECK_IS_ON() // This stringstream represents a sequence of frame reporting activities on // the current tracker. Each letter can be one of the following:
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index a61a3097..9aa6819 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -131,7 +131,8 @@ renderer_->DecideRenderPassAllocationsForFrame(*pass_list); float device_scale_factor = 1.f; renderer_->DrawFrame(pass_list, device_scale_factor, device_viewport_size_, - display_color_spaces_, &surface_damage_rect_list_); + display_color_spaces_, + std::move(surface_damage_rect_list_)); // Call SwapBuffersSkipped(), so the renderer can have a chance to release // resources. @@ -166,7 +167,8 @@ renderer_->DecideRenderPassAllocationsForFrame(*pass_list); float device_scale_factor = 1.f; renderer_->DrawFrame(pass_list, device_scale_factor, device_viewport_size_, - display_color_spaces_, &surface_damage_rect_list_); + display_color_spaces_, + std::move(surface_damage_rect_list_)); // Call SwapBuffersSkipped(), so the renderer can have a chance to release // resources.
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 3243ab7..8d6debe 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -37,6 +37,7 @@ #include "cc/base/histograms.h" #include "cc/base/math_util.h" #include "cc/debug/rendering_stats_instrumentation.h" +#include "cc/document_transition/document_transition_request.h" #include "cc/input/layer_selection_bound.h" #include "cc/input/overscroll_behavior.h" #include "cc/input/page_scale_animation.h" @@ -801,6 +802,12 @@ first_scroll_timestamp); } +void LayerTreeHost::AddDocumentTransitionRequest( + std::unique_ptr<DocumentTransitionRequest> request) { + // TODO(vmpstr): Propagate this to viz after activation. + request->TakeCommitCallback().Run(); +} + bool LayerTreeHost::DoUpdateLayers() { TRACE_EVENT1("cc,benchmark", "LayerTreeHost::DoUpdateLayers", "source_frame_number", SourceFrameNumber());
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index cc2b7ab..6cd634c3 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -65,25 +65,27 @@ namespace cc { -class RasterDarkModeFilter; +class DocumentTransitionRequest; class HeadsUpDisplayLayer; class Layer; class LayerTreeHostImpl; class LayerTreeHostImplClient; class LayerTreeHostSingleThreadClient; class LayerTreeMutator; -class PaintWorkletLayerPainter; class MutatorEvents; class MutatorHost; -struct PendingPageScaleAnimation; +class PaintWorkletLayerPainter; +class RasterDarkModeFilter; class RenderFrameMetadataObserver; class RenderingStatsInstrumentation; -struct OverscrollBehavior; class TaskGraphRunner; class UIResourceManager; class UkmRecorderFactory; -struct RenderingStats; + struct CompositorCommitData; +struct OverscrollBehavior; +struct PendingPageScaleAnimation; +struct RenderingStats; // Returned from LayerTreeHost::DeferMainFrameUpdate. Automatically un-defers on // destruction. @@ -734,6 +736,9 @@ void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay, base::TimeTicks first_scroll_timestamp); + void AddDocumentTransitionRequest( + std::unique_ptr<DocumentTransitionRequest> request); + protected: LayerTreeHost(InitParams params, CompositorMode mode);
diff --git a/chrome/VERSION b/chrome/VERSION index 89fe89bc..776c3c7 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=89 MINOR=0 -BUILD=4359 +BUILD=4360 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 2f8badb..e940751 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -961,6 +961,8 @@ "//url/mojom:url_mojom_gurl_java", ] + deps += feed_test_deps + data_deps = [ "//testing/buildbot/filters:chrome_junit_tests_filters" ] package_name = chrome_public_manifest_package
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index a473867..f515267 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1185,7 +1185,6 @@ "java/src/org/chromium/chrome/browser/previews/PreviewsUma.java", "java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java", "java/src/org/chromium/chrome/browser/printing/TabPrinter.java", - "java/src/org/chromium/chrome/browser/privacy/settings/BandwidthType.java", "java/src/org/chromium/chrome/browser/privacy/settings/DoNotTrackSettings.java", "java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java", "java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index d77e7b18..86d1a63 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -282,6 +282,7 @@ "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDetailsUiTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantDirectActionHandlerTest.java", + "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacadeTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHeaderUiTest.java",
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java index 6e6e959c..476b1b8 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAccessibilityIntegrationTest.java
@@ -28,8 +28,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.espresso.matcher.ViewMatchers.Visibility; import androidx.test.filters.MediumTest; @@ -58,7 +56,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.TextInputSectionProto; import org.chromium.chrome.browser.autofill_assistant.proto.UserFormSectionProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -96,9 +93,10 @@ @Before public void setUp() { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAutostartTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAutostartTest.java index 242c99d..69ea4c8 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAutostartTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantAutostartTest.java
@@ -10,8 +10,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.startAutofillAssistant; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.filters.MediumTest; import org.junit.Before; @@ -28,7 +26,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -55,8 +52,9 @@ @MediumTest @DisabledTest(message = "https://crbug.com/1134118") public void testAutostart() { - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), "http://www.example.com")); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + "http://www.example.com", /* startImmediately = */ true)); AutofillAssistantTestScript script = new AutofillAssistantTestScript( SupportedScriptProto.newBuilder()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java index de66fb0..3de3cca 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
@@ -37,7 +37,6 @@ import static org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.ViewportResizing.RESIZE_VISUAL_VIEWPORT; import android.graphics.Rect; -import android.support.test.InstrumentationRegistry; import androidx.test.espresso.Espresso; import androidx.test.espresso.ViewAction; @@ -80,7 +79,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.TextInputSectionProto; import org.chromium.chrome.browser.autofill_assistant.proto.UserFormSectionProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -103,9 +101,10 @@ @Before public void setUp() { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java index 162bb30..8909cafb 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataIntegrationTest.java
@@ -40,7 +40,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilKeyboardMatchesCondition; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; import android.widget.DatePicker; import androidx.test.espresso.matcher.ViewMatchers; @@ -94,7 +93,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.UserFormSectionProto; import org.chromium.chrome.browser.autofill_assistant.proto.ValueProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; @@ -128,9 +126,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mHelper = new AutofillAssistantCollectUserDataTestHelper(); }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacadeTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacadeTest.java new file mode 100644 index 0000000..12f8c0e --- /dev/null +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacadeTest.java
@@ -0,0 +1,66 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill_assistant; + +import android.content.Intent; + +import androidx.test.filters.MediumTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features; + +/** + * Tests autofill assistant facade. + */ +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@RunWith(ChromeJUnit4ClassRunner.class) +public class AutofillAssistantFacadeTest { + @Rule + public ChromeTabbedActivityTestRule mTestRule = new ChromeTabbedActivityTestRule(); + + @Before + public void setUp() { + mTestRule.startMainActivityWithURL("about:blank"); + } + + /** + * Tests that mandatory parameters are indeed mandatory. + */ + @Test + @MediumTest + @Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ASSISTANT, + ChromeFeatureList.AUTOFILL_ASSISTANT_PROACTIVE_HELP}) + public void + testMandatoryParameters() { + Intent intent = new Intent(); + Assert.assertFalse(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + + String extrasPrefix = "org.chromium.chrome.browser.autofill_assistant."; + intent.putExtra(extrasPrefix + "ENABLED", false); + Assert.assertFalse(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + + intent.putExtra(extrasPrefix + "ENABLED", true); + Assert.assertFalse(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + + intent.putExtra(extrasPrefix + "START_IMMEDIATELY", true); + Assert.assertTrue(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + + intent.putExtra(extrasPrefix + "START_IMMEDIATELY", false); + Assert.assertFalse(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + + intent.putExtra(extrasPrefix + "REQUEST_TRIGGER_SCRIPT", true); + Assert.assertTrue(AutofillAssistantFacade.isAutofillAssistantEnabled(intent)); + } +}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java index 31d377f..df7e289 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFormActionTest.java
@@ -44,7 +44,6 @@ import android.content.Intent; import android.graphics.Typeface; import android.net.Uri; -import android.support.test.InstrumentationRegistry; import android.widget.RadioButton; import androidx.test.espresso.intent.Intents; @@ -77,7 +76,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -100,9 +98,10 @@ @Before public void setUp() { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java index 3d6287d..774da51 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
@@ -145,7 +145,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.ViewLayoutParamsProto; import org.chromium.chrome.browser.autofill_assistant.proto.ViewProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -171,9 +170,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHeaderUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHeaderUiTest.java index 164bd89..cc7be30 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHeaderUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantHeaderUiTest.java
@@ -20,7 +20,6 @@ import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.verify; -import android.support.test.InstrumentationRegistry; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -48,7 +47,6 @@ import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.browser_ui.widget.MaterialProgressBar; @@ -89,8 +87,8 @@ @Before public void setUp() { mCustomTabActivityTestRule.startCustomTabActivityWithIntent( - CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), "about:blank")); + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + "about:blank", /* startImmediately = */ true)); } private CustomTabActivity getActivity() {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java index f57875f..e5fe1df 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java
@@ -19,8 +19,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.filters.MediumTest; import org.junit.Before; @@ -63,7 +61,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.WaitForDomProto; import org.chromium.chrome.browser.autofill_assistant.proto.WaitForElementToBecomeStableProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer; @@ -94,9 +91,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); } @Test
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java index d39f6ab0..3d6f4d17 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayIntegrationTest.java
@@ -22,7 +22,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; import android.view.View; import android.view.ViewGroup; @@ -53,7 +52,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; @@ -80,9 +78,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); } /**
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java index 07c8e1e..3f4ce32 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantOverlayUiTest.java
@@ -26,7 +26,6 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.RectF; -import android.support.test.InstrumentationRegistry; import android.view.View; import androidx.annotation.Nullable; @@ -44,7 +43,6 @@ import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayModel; import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayState; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; @@ -68,9 +66,10 @@ @Before public void setUp() { - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java index 7107f59..29575f4 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPasswordManagerIntegrationTest.java
@@ -14,8 +14,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.getElementValue; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.filters.MediumTest; import org.junit.After; @@ -36,7 +34,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.password_manager.PasswordChangeLauncher; import org.chromium.chrome.browser.password_manager.PasswordManagerClientBridgeForTesting; @@ -66,9 +63,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); TestThreadUtils.runOnUiThreadBlocking( () -> PasswordManagerClientBridgeForTesting.setLeakDialogWasShownForTesting(
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java index 11f130c..483ecdf 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPersonalDataManagerTest.java
@@ -42,7 +42,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.withTextId; -import android.support.test.InstrumentationRegistry; import android.widget.RadioButton; import androidx.test.espresso.Espresso; @@ -67,7 +66,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.UseAddressProto; import org.chromium.chrome.browser.autofill_assistant.proto.UseAddressProto.RequiredField; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.WebContents; @@ -97,9 +95,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mHelper = new AutofillAssistantCollectUserDataTestHelper(); }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantProgressBarIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantProgressBarIntegrationTest.java index 8ab42c6..91445a8 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantProgressBarIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantProgressBarIntegrationTest.java
@@ -25,8 +25,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.startAutofillAssistant; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.filters.MediumTest; import org.junit.Before; @@ -48,7 +46,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.ui.widget.ChromeImageView; @@ -78,9 +75,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); } private StepProgressBarConfiguration getDefaultStepProgressBarConfiguration() {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPromptNavigationIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPromptNavigationIntegrationTest.java index c0f529b..656138a 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPromptNavigationIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPromptNavigationIntegrationTest.java
@@ -12,8 +12,6 @@ import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.InstrumentationRegistry; - import androidx.test.filters.MediumTest; import org.junit.Before; @@ -29,7 +27,6 @@ import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -52,9 +49,10 @@ @Before public void setUp() throws Exception { AutofillAssistantPreferencesUtil.setInitialPreferences(true); - mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), - mTestRule.getTestServer().getURL(TEST_PAGE))); + mTestRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestRule.getTestServer().getURL(TEST_PAGE), + /* startImmediately = */ true)); mTestRule.getActivity() .getRootUiCoordinatorForTesting() .getScrimCoordinator()
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java index aeb87fd..14c320ba 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
@@ -115,6 +115,7 @@ for (Map.Entry<String, Object> param : scriptParameters.entrySet()) { argsBuilder.addParameter(param.getKey(), param.getValue()); } + argsBuilder.addParameter(AutofillAssistantArguments.PARAMETER_START_IMMEDIATELY, false); TestThreadUtils.runOnUiThreadBlocking( () -> AutofillAssistantFacade.start(mTestRule.getActivity(), argsBuilder.build())); }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java index d5f3796..0ebc2c2a 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -101,8 +101,8 @@ * @see CustomTabsTestUtils#createMinimalCustomTabIntent(Context, String). */ private Intent createMinimalCustomTabIntent() { - return CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), mTestPage); + return AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + mTestPage, /* startImmediately = */ true); } private CustomTabActivity getActivity() {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java index a7dc9dd..1848009b 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
@@ -11,6 +11,7 @@ import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; @@ -537,8 +538,9 @@ * Starts the CCT test rule on a blank page. */ public static void startOnBlankPage(CustomTabActivityTestRule testRule) { - testRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent( - InstrumentationRegistry.getTargetContext(), "about:blank")); + testRule.startCustomTabActivityWithIntent( + AutofillAssistantUiTestUtil.createMinimalCustomTabIntentForAutobot( + "about:blank", /* startImmediately = */ true)); } /** @@ -755,4 +757,12 @@ return builder.toString(); } + + public static Intent createMinimalCustomTabIntentForAutobot( + String url, boolean startImmediately) { + Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent( + InstrumentationRegistry.getTargetContext(), url); + intent.putExtra(AutofillAssistantArguments.PARAMETER_START_IMMEDIATELY, startImmediately); + return intent; + } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantArguments.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantArguments.java index dc3d8a3..c029cb0e4 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantArguments.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantArguments.java
@@ -87,6 +87,14 @@ /** Special parameter that enables the feature. */ private static final String PARAMETER_ENABLED = "ENABLED"; + /** + * Special bool parameter that MUST be present in all intents. It allows the caller to either + * request immediate start of autobot (if set to true), or a delayed start using trigger scripts + * (if set to false). If this is set to false, one of the trigger script parameters must be set + * as well (@code{PARAMETER_REQUEST_TRIGGER_SCRIPT} or @code{PARAMETER_TRIGGER_SCRIPTS_BASE64}). + */ + public static final String PARAMETER_START_IMMEDIATELY = "START_IMMEDIATELY"; + /** Special parameter for the calling account. */ private static final String PARAMETER_CALLER_ACCOUNT = "CALLER_ACCOUNT"; @@ -200,12 +208,17 @@ return map; } - /** - * Searches the parameters for the ENABLED flag. - * @return whether the feature is set as enabled. - */ - public boolean isEnabled() { - return getBooleanParameter(PARAMETER_ENABLED); + /** Returns whether all mandatory script parameters are set. */ + public boolean areMandatoryParametersSet() { + if (!getBooleanParameter(PARAMETER_ENABLED) + || mAutofillAssistantParameters.get(PARAMETER_START_IMMEDIATELY) == null) { + return false; + } + if (!getBooleanParameter(PARAMETER_START_IMMEDIATELY)) { + return requestsTriggerScript() || containsBase64TriggerScripts() + || containsTriggerScript(); + } + return true; } /**
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index 99fe10a..a807fc2 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -52,7 +52,7 @@ /** Returns true if conditions are satisfied to attempt to start Autofill Assistant. */ private static boolean isConfigured(AutofillAssistantArguments arguments) { - return arguments.isEnabled(); + return arguments.areMandatoryParametersSet(); } /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java index b7fa427..b2608dd 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -311,7 +311,7 @@ public void initWithNative() { Profile profile = mTabModelSelector.getCurrentModel().getProfile(); - mTabListFaviconProvider.initWithNative(Profile.getLastUsedRegularProfile()); + mTabListFaviconProvider.initWithNative(profile); } /**
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ConditionalTabStripTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ConditionalTabStripTest.java index cc5f32f..8c1e5f0 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ConditionalTabStripTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/ConditionalTabStripTest.java
@@ -45,12 +45,15 @@ import androidx.test.filters.MediumTest; import org.hamcrest.Matchers; +import org.junit.After; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; @@ -81,6 +84,7 @@ import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher; import org.chromium.chrome.test.util.browser.Features; @@ -94,15 +98,22 @@ /** End-to-end tests for conditional tab strip component. */ @RunWith(ChromeJUnit4ClassRunner.class) // clang-format off -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + ChromeSwitches.DISABLE_STARTUP_PROMOS}) @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) @Features.EnableFeatures({CONDITIONAL_TAB_STRIP_ANDROID}) @Features.DisableFeatures({TAB_GRID_LAYOUT_ANDROID, TAB_GROUPS_ANDROID, START_SURFACE_ANDROID}) +@Batch(Batch.PER_CLASS) public class ConditionalTabStripTest { // clang-format on private static final int TEST_SESSION_MS = 600000; private static final int SWIPE_TO_RIGHT_DIRECTION = 1; private static final int SWIPE_TO_LEFT_DIRECTION = -1; + + @ClassRule + public static final ChromeTabbedActivityTestRule sActivityTestRule = + new ChromeTabbedActivityTestRule(); + private SimulateTabSwipeOnMainThread mSwipeToNormal; private SimulateTabSwipeOnMainThread mSwipeToIncognito; private float mPxToDp = 1f; @@ -110,7 +121,8 @@ private float mTabsViewWidthDp; @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + public final BlankCTATabInitialStateRule mInitialStateRule = + new BlankCTATabInitialStateRule(sActivityTestRule, false); @Before public void setUp() { @@ -120,9 +132,9 @@ CONDITIONAL_TAB_STRIP_SESSION_TIME_MS.setForTesting(0); ConditionalTabStripUtils.setOptOutIndicator(false); ConditionalTabStripUtils.setContinuousDismissCount(0); + ConditionalTabStripUtils.setFeatureStatus(ConditionalTabStripUtils.FeatureStatus.DEFAULT); - mActivityTestRule.startMainActivityOnBlankPage(); - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); CriteriaHelper.pollUiThread(cta.getTabModelSelector()::isTabStateInitialized); float dpToPx = InstrumentationRegistry.getInstrumentation() @@ -131,7 +143,7 @@ .getDisplayMetrics() .density; mPxToDp = 1.0f / dpToPx; - View tabsView = mActivityTestRule.getActivity().getTabsView(); + View tabsView = cta.getTabsView(); mTabsViewHeightDp = tabsView.getHeight() * mPxToDp; mTabsViewWidthDp = tabsView.getWidth() * mPxToDp; mSwipeToIncognito = @@ -141,6 +153,14 @@ mTabsViewHeightDp / 2, SWIPE_TO_RIGHT_DIRECTION * mTabsViewWidthDp, 0); } + @After + public void tearDown() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + sActivityTestRule.getActivity().getTabModelSelector().getModel(true).closeAllTabs(); + ChromeAccessibilityUtil.get().setAccessibilityEnabledForTesting(null); + }); + } + private void enterTabSwitcher(ChromeTabbedActivity cta) { OverviewModeBehaviorWatcher showWatcher = TabUiTestHelper.createOverviewShowWatcher(cta); TestThreadUtils.runOnUiThreadBlocking( @@ -152,7 +172,7 @@ @MediumTest @DisableIf.Build(sdk_is_less_than = M, message = "crbug.com/1081832") public void testStrip_updateWithAddition() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); // Unintentional tab creation will not trigger tab strip. @@ -199,7 +219,7 @@ @Test @MediumTest public void testStrip_updateWithClosure() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); createTabs(cta, false, 3); @@ -222,7 +242,7 @@ @Test @MediumTest public void testStrip_updateWithSelection() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); for (int i = 0; i < 3; i++) { @@ -249,7 +269,7 @@ @Test @MediumTest public void testStrip_updateWithTabModelSwitch() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); createTabs(cta, false, 3); @@ -279,7 +299,7 @@ @Test @MediumTest public void testStrip_createTabWithStrip() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); // Test creating normal tabs by clicking the plus button in tab strip. @@ -311,7 +331,7 @@ @Test @MediumTest public void testStrip_switchTabWithStrip() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); createTabs(cta, false, 4); @@ -328,7 +348,7 @@ @Test @MediumTest public void testStrip_closeTabWithStrip() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); createTabs(cta, false, 2); @@ -369,7 +389,7 @@ @Test @MediumTest public void testStrip_dismiss() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); verifyHidingStrip(); triggerStripAndDismiss(cta); @@ -387,7 +407,7 @@ @Test @MediumTest public void testStrip_disabled_expired() throws Exception { - triggerStripAndDismiss(mActivityTestRule.getActivity()); + triggerStripAndDismiss(sActivityTestRule.getActivity()); ChromeTabbedActivity cta = restartChrome(); verifyHidingStrip(); @@ -399,7 +419,7 @@ @Test @MediumTest public void testStrip_disabled_notExpired() throws Exception { - triggerStripAndDismiss(mActivityTestRule.getActivity()); + triggerStripAndDismiss(sActivityTestRule.getActivity()); // Update the session time so that the disabled state is not expired for next restart. CONDITIONAL_TAB_STRIP_SESSION_TIME_MS.setForTesting(TEST_SESSION_MS); @@ -413,7 +433,7 @@ @Test @MediumTest public void testStrip_enabled_expired() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); for (int i = 0; i < 3; i++) { createBlankPageWithLaunchType(cta, false, TabLaunchType.FROM_CHROME_UI); } @@ -426,7 +446,7 @@ @Test @MediumTest public void testStrip_enabled_notExpired() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); for (int i = 0; i < 3; i++) { createBlankPageWithLaunchType(cta, false, TabLaunchType.FROM_CHROME_UI); } @@ -442,7 +462,7 @@ @MediumTest @DisabledTest(message = "crbug.com/1081697") public void testStrip_UndoDismiss() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); for (int i = 0; i < 3; i++) { createBlankPageWithLaunchType(cta, false, TabLaunchType.FROM_CHROME_UI); } @@ -464,7 +484,7 @@ @MediumTest @DisableIf.Build(supported_abis_includes = "x86", message = "https://crbug.com/1094998") public void testStrip_InfoBarOptOut() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); for (int i = 0; i < 3; i++) { createBlankPageWithLaunchType(cta, false, TabLaunchType.FROM_CHROME_UI); } @@ -476,7 +496,7 @@ assertTrue(ConditionalTabStripUtils.shouldShowSnackbarForDismissal()); clickDismissButtonInStrip(); CriteriaHelper.pollUiThread( - () -> mActivityTestRule.getActivity().getSnackbarManager().isShowing()); + () -> sActivityTestRule.getActivity().getSnackbarManager().isShowing()); // Update the dismiss counter so that the next dismissal should be the third continuous // dismissal, and we should show opt-out info bar. @@ -512,7 +532,7 @@ @MediumTest @DisableIf.Build(supported_abis_includes = "x86", message = "https://crbug.com/1094998") public void testStrip_InfoBarOptIn() throws Exception { - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); for (int i = 0; i < 3; i++) { createBlankPageWithLaunchType(cta, false, TabLaunchType.FROM_CHROME_UI); } @@ -524,7 +544,7 @@ assertTrue(ConditionalTabStripUtils.shouldShowSnackbarForDismissal()); clickDismissButtonInStrip(); CriteriaHelper.pollUiThread( - () -> mActivityTestRule.getActivity().getSnackbarManager().isShowing()); + () -> sActivityTestRule.getActivity().getSnackbarManager().isShowing()); // Update the dismiss counter so that the next dismissal should be the third continuous // dismissal, and we should show opt-out info bar. @@ -550,7 +570,7 @@ verifyShowingStrip(cta, false, 6); clickDismissButtonInStrip(); CriteriaHelper.pollUiThread( - () -> mActivityTestRule.getActivity().getSnackbarManager().isShowing()); + () -> sActivityTestRule.getActivity().getSnackbarManager().isShowing()); } @Test @@ -580,7 +600,7 @@ verifyShowingStrip(cta, false, 3); clickDismissButtonInStrip(); CriteriaHelper.pollUiThread( - () -> mActivityTestRule.getActivity().getSnackbarManager().isShowing()); + () -> sActivityTestRule.getActivity().getSnackbarManager().isShowing()); // Update the dismiss counter so that the next dismissal should be the sixth continuous // dismissal, and we should show opt-out info bar. @@ -596,7 +616,7 @@ onView(withId(R.id.infobar_close_button)).perform(click()); CriteriaHelper.pollUiThread(() -> { InfoBarContainer container = InfoBarContainer.get( - mActivityTestRule.getActivity().getTabModelSelector().getCurrentTab()); + sActivityTestRule.getActivity().getTabModelSelector().getCurrentTab()); return container.getInfoBarsForTesting().size() == 0; }); @@ -611,8 +631,8 @@ public void testUndoClosure_AccessibilityMode() throws Exception { TestThreadUtils.runOnUiThreadBlocking( () -> ChromeAccessibilityUtil.get().setAccessibilityEnabledForTesting(true)); - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - SnackbarManager snackbarManager = mActivityTestRule.getActivity().getSnackbarManager(); + ChromeTabbedActivity cta = sActivityTestRule.getActivity(); + SnackbarManager snackbarManager = sActivityTestRule.getActivity().getSnackbarManager(); createTabs(cta, false, 3); verifyShowingStrip(cta, false, 3); verifyStripSelectedPosition(cta, 2); @@ -660,15 +680,16 @@ } private ChromeTabbedActivity restartChrome() throws Exception { - TabUiTestHelper.finishActivity(mActivityTestRule.getActivity()); - mActivityTestRule.startMainActivityFromLauncher(); + TabUiTestHelper.finishActivity(sActivityTestRule.getActivity()); + sActivityTestRule.startMainActivityFromLauncher(); // Wait for bottom controls to stabilize. - CriteriaHelper.pollUiThread(() - -> mActivityTestRule.getActivity() - .getBrowserControlsManager() - .getBottomControlOffset() - == 0); - return mActivityTestRule.getActivity(); + CriteriaHelper.pollUiThread(() -> { + Criteria.checkThat(sActivityTestRule.getActivity() + .getBrowserControlsManager() + .getBottomControlOffset(), + Matchers.is(0)); + }); + return sActivityTestRule.getActivity(); } private void createBlankPageWithLaunchType(ChromeTabbedActivity cta, boolean isIncognito, @@ -839,16 +860,16 @@ } private LayoutManagerChrome updateTabsViewSize() { - View tabsView = mActivityTestRule.getActivity().getTabsView(); + View tabsView = sActivityTestRule.getActivity().getTabsView(); mTabsViewHeightDp = tabsView.getHeight() * mPxToDp; mTabsViewWidthDp = tabsView.getWidth() * mPxToDp; - return mActivityTestRule.getActivity().getLayoutManager(); + return sActivityTestRule.getActivity().getLayoutManager(); } // Utility methods from OverviewListLayoutTest.java. private ListView getAccessibilityOverviewList() { AccessibilityTabModelWrapper container = - ((OverviewListLayout) mActivityTestRule.getActivity().getOverviewListLayout()) + ((OverviewListLayout) sActivityTestRule.getActivity().getOverviewListLayout()) .getContainer(); return (ListView) container.findViewById(R.id.list_view); }
diff --git a/chrome/android/feed/DEPS b/chrome/android/feed/DEPS index e0c32790..8b85460 100644 --- a/chrome/android/feed/DEPS +++ b/chrome/android/feed/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+chrome/browser/android/lifecycle", "+chrome/browser/image_fetcher", + "+chrome/browser/privacy/settings", "+chrome/browser/profiles/android/java", "+chrome/browser/tab/java", "+chrome/browser/ui/messages/android/java",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProvider.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProvider.java index 8bf47c5..c767a3c2 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProvider.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProvider.java
@@ -6,6 +6,8 @@ import android.content.Context; +import androidx.annotation.VisibleForTesting; + import org.chromium.base.BundleUtils; import org.chromium.base.ContextUtils; import org.chromium.base.Log; @@ -13,6 +15,9 @@ import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; import org.chromium.chrome.browser.base.SplitCompatUtils; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager; +import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.signin.services.IdentityServicesProvider; import org.chromium.chrome.browser.xsurface.ImageFetchClient; @@ -31,6 +36,9 @@ private ImageFetchClient mImageFetchClient; private LibraryResolver mLibraryResolver; + @VisibleForTesting + static PrivacyPreferencesManager sPrivacyPreferencesManagerForTest; + FeedProcessScopeDependencyProvider() { mContext = createFeedContext(ContextUtils.getApplicationContext()); mImageFetchClient = new FeedImageFetchClient(); @@ -108,6 +116,16 @@ return mLibraryResolver; } + @Override + public boolean isXsurfaceUsageAndCrashReportingEnabled() { + PrivacyPreferencesManager manager = sPrivacyPreferencesManagerForTest; + if (manager == null) { + manager = PrivacyPreferencesManagerImpl.getInstance(); + } + return ChromeFeatureList.isEnabled(ChromeFeatureList.XSURFACE_METRICS_REPORTING) + && manager.isMetricsReportingEnabled(); + } + public static Context createFeedContext(Context context) { return SplitCompatUtils.createContextForInflation(context, FEED_SPLIT_NAME); }
diff --git a/chrome/android/feed/feed_java_sources.gni b/chrome/android/feed/feed_java_sources.gni index 3589442..fd330a0 100644 --- a/chrome/android/feed/feed_java_sources.gni +++ b/chrome/android/feed/feed_java_sources.gni
@@ -430,6 +430,7 @@ feed_junit_test_java_sources += [ "junit/src/org/chromium/chrome/browser/feed/v2/FakeLinearLayoutManager.java", "junit/src/org/chromium/chrome/browser/feed/v2/FeedListContentManagerTest.java", + "junit/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProviderTest.java", "junit/src/org/chromium/chrome/browser/feed/v2/FeedSliceViewTrackerTest.java", "junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurfaceTest.java", "junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamTest.java", @@ -745,5 +746,6 @@ "//chrome/browser/user_education:java", "//third_party/google-truth:google_truth_java", "//third_party/android_deps:guava_android_java", + "//chrome/browser/privacy:java", ] }
diff --git a/chrome/android/java/res/layout/fre_tosanduma.xml b/chrome/android/java/res/layout/fre_tosanduma.xml index ab9496d..a0bd391 100644 --- a/chrome/android/java/res/layout/fre_tosanduma.xml +++ b/chrome/android/java/res/layout/fre_tosanduma.xml
@@ -14,7 +14,7 @@ android:id="@+id/scroll_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginBottom="@dimen/fre_tos_button_bar_height" + android:layout_above="@id/fre_bottom_group" android:fillViewport="true"> <!-- The orientation of this view is changed dynamically to give a nicer layout when in @@ -108,29 +108,19 @@ </LinearLayout> </ScrollView> - <ImageView - android:id="@+id/shadow" - android:layout_width="match_parent" - android:layout_height="@dimen/action_bar_shadow_height" - android:layout_gravity="bottom" - android:layout_marginBottom="@dimen/fre_tos_button_bar_height" - android:background="@drawable/modern_toolbar_shadow" - android:scaleY="-1" - android:visibility="gone" - android:importantForAccessibility="no" /> - <FrameLayout android:id="@+id/fre_bottom_group" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_marginVertical="@dimen/fre_button_vertical_margin" android:layout_marginHorizontal="@dimen/fre_content_margin"> <org.chromium.ui.widget.ButtonCompat android:id="@+id/terms_accept" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginVertical="@dimen/fre_button_vertical_margin" - android:layout_gravity="bottom|center_horizontal" + android:layout_gravity="center" android:paddingStart="@dimen/fre_button_padding" android:paddingEnd="@dimen/fre_button_padding" android:text="@string/fre_accept_continue" @@ -141,12 +131,22 @@ <ProgressBar android:id="@+id/progress_spinner" style="@style/Widget.AppCompat.ProgressBar" - android:layout_marginBottom="@dimen/fre_bottom_loading_spinner_margin" - android:layout_gravity="bottom|center_horizontal" + android:layout_gravity="center" android:layout_width="@dimen/fre_bottom_loading_spinner_size" android:layout_height="@dimen/fre_bottom_loading_spinner_size"/> </FrameLayout> + <ImageView + android:id="@+id/shadow" + android:layout_width="match_parent" + android:layout_height="@dimen/action_bar_shadow_height" + android:layout_gravity="bottom" + android:layout_above="@id/fre_bottom_group" + android:background="@drawable/modern_toolbar_shadow" + android:scaleY="-1" + android:visibility="gone" + android:importantForAccessibility="no" /> + <!-- Empty TextView to preload fonts for following pages. See https://crbug.com/1119990#c20 --> <TextView android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 9af057f..ed8c7f29 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -155,10 +155,8 @@ <dimen name="fre_button_vertical_margin">24dp</dimen> <!-- fre_button_bar_height = 68dp = layout_height (48dp) + 2 * layout_marginBottom(10dp) --> <dimen name="fre_button_bar_height">68dp</dimen> - <!-- fre_button_bar_height = button_height(48dp) + fre_button_vertical_margin * 2--> - <dimen name="fre_tos_button_bar_height">96dp</dimen> - <!-- fre_bottom_loading_spinner_margin = (fre_tos_button_bar_height - fre_bottom_loading_spinner_size) / 2--> - <dimen name='fre_bottom_loading_spinner_margin'>36dp</dimen> + + <dimen name="fre_button_vertical_margin_small">16dp</dimen> <!-- Account Signin dimensions --> <!-- The Account Signin page appears in the First Run Experience (amongst other places), so uses
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 14662ea7..6403222 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -764,7 +764,6 @@ return; } - DefaultBrowserPromoUtils.maybeRemoveIntentData(intent); mIntentHandlingTimeMs = SystemClock.uptimeMillis(); super.onNewIntent(intent); } @@ -899,7 +898,6 @@ handleDebugIntent(intent); } - DefaultBrowserPromoUtils.onNewIntentReceived(intent); } finally { TraceEvent.end("ChromeTabbedActivity.onNewIntentWithNative"); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java index 92b7d31..985fa94 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java
@@ -12,7 +12,6 @@ import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; -import org.chromium.chrome.R; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.image_fetcher.ImageFetcher; @@ -43,7 +42,6 @@ * before the video player activity launches. */ private static final int CARD_HIDE_ANIMATION_DURATION_MS = 500; - private static final String VARIATION_SUMMARY_CARD_POSTER_URL = "summary_card_poster_url"; private final Handler mHandler = new Handler(); private Context mContext; @@ -70,13 +68,15 @@ private void onFetchTutorials(List<Tutorial> tutorials) { if (tutorials.isEmpty()) return; - // Make a copy of the list before adding summary card. + // Add the summary tutorial to the list. List<Tutorial> tutorialsCopy = new ArrayList<>(tutorials); - addSyntheticSummaryTutorial(tutorialsCopy); - mTracker.addOnInitializedCallback(success -> { - if (!success) return; + mVideoTutorialService.getTutorial(FeatureType.SUMMARY, tutorial -> { + if (tutorial != null) tutorialsCopy.add(tutorial); - showFirstEligibleIPH(tutorialsCopy); + mTracker.addOnInitializedCallback(success -> { + if (!success) return; + showFirstEligibleIPH(tutorialsCopy); + }); }); } @@ -113,15 +113,6 @@ mVideoTutorialService.getTutorials(this::onFetchTutorials); } - private void addSyntheticSummaryTutorial(List<Tutorial> tutorials) { - String summaryCardImageUrl = ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.VIDEO_TUTORIALS, VARIATION_SUMMARY_CARD_POSTER_URL); - Tutorial summary = new Tutorial(FeatureType.SUMMARY, - mContext.getString(R.string.video_tutorials_card_all_videos), null, null, - summaryCardImageUrl, summaryCardImageUrl, null, null, 0); - tutorials.add(summary); - } - @VisibleForTesting protected void launchVideoPlayer(Tutorial tutorial) { VideoPlayerActivity.playVideoTutorial(mContext, tutorial.featureType);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java index e1ecaf63..a08a9a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -23,6 +23,7 @@ import org.chromium.base.Log; import org.chromium.base.PackageUtils; import org.chromium.base.TraceEvent; +import org.chromium.base.compat.ApiHelperForO; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; @@ -198,8 +199,13 @@ } // Make sure all splits are compiled correclty, and if not force a compile. - for (String sourceDir : getApplicationInfo().splitSourceDirs) { - if (DexFile.isDexOptNeeded(sourceDir)) { + String[] splitNames = ApiHelperForO.getSplitNames(getApplicationInfo()); + for (int i = 0; i < splitNames.length; i++) { + // Ignore config splits like "config.en". + if (splitNames[i].contains(".")) { + continue; + } + if (DexFile.isDexOptNeeded(getApplicationInfo().splitSourceDirs[i])) { performDexCompile(); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java index d757757..82215ca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupport.java
@@ -65,6 +65,7 @@ }; private boolean mViewCreated; + private View mBottomGroup; private View mLoadingSpinnerContainer; private LoadingView mLoadingSpinner; private TextView mPrivacyDisclaimer; @@ -110,6 +111,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + mBottomGroup = view.findViewById(R.id.fre_bottom_group); mLoadingSpinnerContainer = view.findViewById(R.id.loading_view_container); mLoadingSpinner = view.findViewById(R.id.progress_spinner_large); mPrivacyDisclaimer = view.findViewById(R.id.privacy_disclaimer); @@ -119,9 +121,11 @@ if (mSkipTosDialogPolicyListener.get() == null) { mLoadingSpinner.addObserver(this); mLoadingSpinner.showLoadingUI(); + mBottomGroup.setVisibility(View.GONE); setTosAndUmaVisible(false); } else if (mSkipTosDialogPolicyListener.get()) { // Skip the FRE if we know dialog is disabled by policy. + mBottomGroup.setVisibility(View.GONE); setTosAndUmaVisible(false); exitCctFirstRun(/*shiftA11yFocus*/ false); } @@ -159,6 +163,7 @@ exitCctFirstRun(hasAccessibilityFocus); } else { // Else, show the UMA as the loading spinner is GONE. + mBottomGroup.setVisibility(View.VISIBLE); setTosAndUmaVisible(true); if (hasAccessibilityFocus) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFragmentView.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFragmentView.java index ba3ce0d..b71cd46c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFragmentView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/TosAndUmaFragmentView.java
@@ -5,11 +5,12 @@ package org.chromium.chrome.browser.firstrun; import android.content.Context; +import android.os.Build; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; -import android.widget.FrameLayout; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.ScrollView; import org.chromium.chrome.R; @@ -20,21 +21,21 @@ * * See https://crbug.com/1151537 for illustration. */ -public class TosAndUmaFragmentView extends FrameLayout { +public class TosAndUmaFragmentView extends RelativeLayout { private ScrollView mScrollView; private LinearLayout mMainLayout; // The "title and content" contains the mTitle, mContentWrapper, and mLoadingSpinner that is // visible when waiting for policy to be loaded. - private LinearLayout mTitleAndContent; + private View mTitleAndContent; // The "content wrapper" contains the ToS text and the UMA check box. - private LinearLayout mContentWrapper; + private View mContentWrapper; // The "bottom group" contains the accept & continue button, and a small spinner that displays // in its place when waiting for C++ to load before processing the FRE screen. - private FrameLayout mBottomGroup; + private View mBottomGroup; private View mTitle; private View mLogo; @@ -53,7 +54,15 @@ private int mLandscapeTopPadding; private int mHeadlineSize; private int mContentMargin; - private int mButtonBarHeight; + private int mAcceptButtonHeight; + private int mBottomGroupVerticalMarginRegular; + private int mBottomGroupVerticalMarginSmall; + + // Store the bottom margins for different screen orientations. We are using a smaller bottom + // margin when the content becomes scrollable. Storing margins per orientation because there are + // cases where content is scrollable in landscape mode while not in portrait mode. + private int mBottomMarginPortrait; + private int mBottomMarginLandscape; /** * Constructor for inflating via XML. @@ -95,7 +104,16 @@ getResources().getDimensionPixelSize(R.dimen.fre_landscape_top_padding); mHeadlineSize = getResources().getDimensionPixelSize(R.dimen.headline_size); mContentMargin = getResources().getDimensionPixelSize(R.dimen.fre_content_margin); - mButtonBarHeight = getResources().getDimensionPixelSize(R.dimen.fre_tos_button_bar_height); + mAcceptButtonHeight = getResources().getDimensionPixelSize(R.dimen.min_touch_target_size); + + mBottomGroupVerticalMarginRegular = + getResources().getDimensionPixelSize(R.dimen.fre_button_vertical_margin); + mBottomGroupVerticalMarginSmall = + getResources().getDimensionPixelSize(R.dimen.fre_button_vertical_margin_small); + + // Default bottom margin to "regular", consistent with what is defined in xml. + mBottomMarginPortrait = mBottomGroupVerticalMarginRegular; + mBottomMarginLandscape = mBottomGroupVerticalMarginRegular; } @Override @@ -136,20 +154,77 @@ super.onMeasure(widthMeasureSpec, heightMeasureSpec); - updateShadowVisibility(); + // Do another round of view adjustments that depends on sizes assigned to children views in + // super#onMeasure. If the state of any view is changed in this process, trigger another + // round of measure to make changes take effect. + boolean changed = doPostMeasureAdjustment(); + if (changed) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } } private boolean shouldUseWideScreen(int width, int height) { - return (height >= mImageSize + 2 * mButtonBarHeight) && (width > 1.5 * height); + int maxButtonBarHeight = mAcceptButtonHeight + 2 * mBottomGroupVerticalMarginRegular; + return (height >= mImageSize + 2 * maxButtonBarHeight) && (width > 1.5 * height); } - private void updateShadowVisibility() { - if (mScrollView.canScrollVertically(1)) { - mShadow.setVisibility(VISIBLE); - mShadow.bringToFront(); - } else { - mShadow.setVisibility(GONE); + /** + * Adjust views after measure, when every view components has an initial size assigned. + * @return Whether any change happened to children views. + */ + private boolean doPostMeasureAdjustment() { + boolean changed = updateShadowVisibility(); + changed |= assignSmallBottomMarginIfNecessary(); + return changed; + } + + private boolean updateShadowVisibility() { + int newVisibility = mScrollView.canScrollVertically(1) ? VISIBLE : GONE; + if (newVisibility == mShadow.getVisibility()) { + return false; } + mShadow.setVisibility(newVisibility); + return true; + } + + /** + * When content is scrollable, use a smaller margin to present more content on screen. + * Note that once we change to using a smaller margin we currently will never switch back to the + * default margin size (e.g. enter then exit multi-window). + * + * TODO(https://crbug.com/1159198): Adjust the margin according to the size of + * TosAndUmaFragmentView. + */ + private boolean assignSmallBottomMarginIfNecessary() { + // Check the width and height of TosAndUmaFragmentView. This function may be executed + // between transitioning from landscape to portrait. If the current measure spec (mLastWidth + // and mLastHeight) is different than the size actually measured (getHeight() && + // getWidth()), the results from mScrollView#canScrollVertically could be stale. In such + // cases, it is safe to early return here, as current measure is in transition and a + // follow-up measure will be triggered when the measured spec and actual size matches. + if (getHeight() != mLastHeight || getWidth() != mLastWidth) { + return false; + } + + // Do not assign margins if the content is not scrollable. + if (!mScrollView.canScrollVertically(1) && !mScrollView.canScrollVertically(-1)) { + return false; + } + + MarginLayoutParams params = (MarginLayoutParams) mBottomGroup.getLayoutParams(); + if (params.bottomMargin == mBottomGroupVerticalMarginSmall) { + return false; + } + + if (shouldUseLandscapeBottomMargin()) { + mBottomMarginLandscape = mBottomGroupVerticalMarginSmall; + } else { + mBottomMarginPortrait = mBottomGroupVerticalMarginSmall; + } + params.setMargins(params.leftMargin, mBottomGroupVerticalMarginSmall, params.rightMargin, + mBottomGroupVerticalMarginSmall); + mBottomGroup.setLayoutParams(params); + return true; } private void setSpinnerLayoutParams(boolean useWideScreen, int width, int height) { @@ -236,13 +311,35 @@ } private void setBottomGroupLayoutParams(boolean useWideScreen) { - FrameLayout.LayoutParams bottomGroupParams = - (FrameLayout.LayoutParams) mBottomGroup.getLayoutParams(); - bottomGroupParams.gravity = useWideScreen ? Gravity.END | Gravity.BOTTOM - : Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + RelativeLayout.LayoutParams bottomGroupParams = + (RelativeLayout.LayoutParams) mBottomGroup.getLayoutParams(); + int removedRule = + useWideScreen ? RelativeLayout.CENTER_HORIZONTAL : RelativeLayout.ALIGN_PARENT_END; + int addedRule = + useWideScreen ? RelativeLayout.ALIGN_PARENT_END : RelativeLayout.CENTER_HORIZONTAL; + + // Remove left & right align. On M, #removeRule on ALIGN_PARENT_END does not translate + // into removing ALIGN_PARENT_LEFT or RIGHT automatically. This is fixed on M+ in Android. + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { + bottomGroupParams.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT); + bottomGroupParams.removeRule(RelativeLayout.ALIGN_PARENT_LEFT); + } + + bottomGroupParams.removeRule(removedRule); + bottomGroupParams.addRule(addedRule); + + int bottomMargin = + shouldUseLandscapeBottomMargin() ? mBottomMarginLandscape : mBottomMarginPortrait; + bottomGroupParams.setMargins(bottomGroupParams.leftMargin, bottomMargin, + bottomGroupParams.rightMargin, bottomMargin); + mBottomGroup.setLayoutParams(bottomGroupParams); } private int getTitleAndContentLayoutTopPadding(boolean useWideScreen) { return useWideScreen ? mLandscapeTopPadding : 0; } + + private boolean shouldUseLandscapeBottomMargin() { + return mLastWidth > mLastHeight; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java index 942c394..6e24417 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java
@@ -37,6 +37,7 @@ .withInitialUrl(origin) .addParameter(PASSWORD_CHANGE_USERNAME_PARAMETER, username) .addParameter(INTENT_PARAMETER, INTENT) + .addParameter(AutofillAssistantArguments.PARAMETER_START_IMMEDIATELY, true) .build()); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/BandwidthType.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/BandwidthType.java deleted file mode 100644 index 8237c6c..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/BandwidthType.java +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.privacy.settings; - -import androidx.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Bandwidth options available based on network. - */ -public class BandwidthType { - @IntDef({Type.NEVER_PRERENDER, Type.PRERENDER_ON_WIFI, Type.ALWAYS_PRERENDER}) - @Retention(RetentionPolicy.SOURCE) - public @interface Type { - // Values are numbered from 0 and can't have gaps. - int NEVER_PRERENDER = 0; - int PRERENDER_ON_WIFI = 1; // Default option. - int ALWAYS_PRERENDER = 2; - int NUM_ENTRIES = 3; - } - - private static final String[] TITLES = { - "never_prefetch", "prefetch_on_wifi", "always_prefetch"}; - - /** - * Returns the title of the bandwidthType. - * @return title - */ - public static String title(@Type int type) { - return TITLES[type]; - } - - /** - * Get the BandwidthType from the title. - * @param title - * @return BandwidthType - */ - public static @BandwidthType.Type int getBandwidthFromTitle(String title) { - for (@BandwidthType.Type int i = Type.NEVER_PRERENDER; i < Type.NUM_ENTRIES; i++) { - if (TITLES[i].equals(title)) return i; - } - assert false; - return Type.PRERENDER_ON_WIFI; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java index 4e6aa66..b6ff3704 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacyPreferencesManagerImpl.java
@@ -147,15 +147,6 @@ return PrivacyPreferencesManagerImplJni.get().isMetricsReportingManaged(); } - /** - * @return Whether there is a user set value for kNetworkPredictionOptions. This should only be - * used for preference migration. See http://crbug.com/334602 - */ - private boolean obsoleteNetworkPredictionOptionsHasUserSetting() { - return PrivacyPreferencesManagerImplJni.get() - .obsoleteNetworkPredictionOptionsHasUserSetting(); - } - @Override public boolean getNetworkPredictionEnabled() { return PrivacyPreferencesManagerImplJni.get().getNetworkPredictionEnabled(); @@ -175,7 +166,6 @@ public interface Natives { boolean canPrefetchAndPrerender(); boolean getNetworkPredictionManaged(); - boolean obsoleteNetworkPredictionOptionsHasUserSetting(); boolean getNetworkPredictionEnabled(); void setNetworkPredictionEnabled(boolean enabled); boolean isMetricsReportingEnabled();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index ec9c3e1..c8489ebb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -11,6 +11,7 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.Callback; +import org.chromium.base.CommandLine; import org.chromium.base.TraceEvent; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; @@ -33,6 +34,7 @@ import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.gesturenav.HistoryNavigationCoordinator; import org.chromium.chrome.browser.gesturenav.NavigationSheet; @@ -490,6 +492,10 @@ */ private boolean triggerPromo(boolean intentWithEffect) { try (TraceEvent e = TraceEvent.scoped("TabbedRootUiCoordinator.triggerPromo")) { + if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_STARTUP_PROMOS)) { + return false; + } + SharedPreferencesManager preferenceManager = SharedPreferencesManager.getInstance(); // Promos can only be shown when we start with ACTION_MAIN intent and // after FRE is complete. Native initialization can finish before the FRE flow is @@ -532,7 +538,7 @@ return true; } if (DefaultBrowserPromoUtils.prepareLaunchPromoIfNeeded( - mActivity, mActivity.getLifecycleDispatcher(), mActivity.getWindowAndroid())) { + mActivity, mActivity.getWindowAndroid())) { return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java index 254614e..d978aa0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.tab.TabLaunchType; import org.chromium.chrome.browser.tab.TabSelectionType; import org.chromium.chrome.browser.tab.state.CriticalPersistedTabData; +import org.chromium.chrome.browser.tab.state.PersistedTabData; import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier; import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; import org.chromium.components.external_intents.InterceptNavigationDelegateImpl; @@ -662,7 +663,7 @@ private void finalizeTabClosure(Tab tab, boolean notifyTabClosureCommitted) { if (mTabContentManager != null) mTabContentManager.removeTabThumbnail(tab.getId()); mTabSaver.removeTabFromQueues(tab); - tab.setIsTabSaveEnabled(false); + PersistedTabData.onTabClose(tab); if (!isIncognito()) HistoricalTabSaver.createHistoricalTab(tab);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java index 923f07c6..d8e49ce 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
@@ -39,6 +39,7 @@ private static final String AUTOFILL_ASSISTANT_INTENT_URL = "intent://www.example.com#Intent;scheme=https;" + "B.org.chromium.chrome.browser.autofill_assistant.ENABLED=true;" + + "B.org.chromium.chrome.browser.autofill_assistant.START_IMMEDIATELY=true;" + "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "=" + Uri.encode("https://www.example.com") + ";end"; private static final String[] SUPERVISOR_START_ACTIONS = {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java index b88db06..971ddcb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -36,7 +36,6 @@ import org.chromium.base.task.PostTask; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.ScalableTimeout; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -69,6 +68,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @Features.EnableFeatures(ChromeFeatureList.SHARE_BY_DEFAULT_IN_CCT) public class FirstRunIntegrationTest { + private static final long DEFERRED_START_UP_POLL_TIME = 10000L; @Rule public MultiActivityTestRule mTestRule = new MultiActivityTestRule(); @@ -321,10 +321,10 @@ @Test @MediumTest - @DisabledTest(message = "Test flaky: crbug.com/1157611") public void testFirstRunSkippedSharedPreferenceRefresh() { - // Set first run was previous skipped by policy in shared preference, then refresh shared - // preference value, since there's no policy set in this test case. + // Set that the first run was previous skipped by policy in shared preference, then + // refreshing shared preference should cause its value to become false, since there's no + // policy set in this test case. FirstRunStatus.setFirstRunSkippedByPolicy(true); DeferredStartupHandler.setExpectingActivityStartupForTesting(); @@ -333,10 +333,15 @@ CustomTabActivity activity = waitForActivity(CustomTabActivity.class); CriteriaHelper.pollUiThread(() -> activity.didFinishNativeInitialization()); + // DeferredStartupHandler could not finish with CriteriaHelper#DEFAULT_MAX_TIME_TO_POLL. + // Use longer timeout here to avoid flakiness. See https://crbug.com/1157611. Assert.assertTrue("Deferred startup never completed", DeferredStartupHandler.waitForDeferredStartupCompleteForTesting( - ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))); - CriteriaHelper.pollUiThread(() -> FirstRunStatus.isFirstRunSkippedByPolicy()); + ScalableTimeout.scaleTimeout(DEFERRED_START_UP_POLL_TIME))); + + // FirstRun status should be refreshed by TosDialogBehaviorSharedPrefInvalidator in deferred + // start up task. + CriteriaHelper.pollUiThread(() -> !FirstRunStatus.isFirstRunSkippedByPolicy()); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java index f54387d..79a534ce 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
@@ -58,9 +58,6 @@ @Mock EndpointFetcher.Natives mEndpointFetcherJniMock; - // Tracks if the endpoint fetcher has been called once or not - private boolean mCalledOnce; - private static final long PRICE_MICROS = 123456789012345L; private static final long UPDATED_PRICE_MICROS = 287000000L; private static final long HIGH_PRICE_MICROS = 141000000L; @@ -86,6 +83,8 @@ + "\"currentPrice\":{\"currencyCode\":\"USD\",\"amountMicros\":\"287000000\"}," + "\"referenceType\":\"MAIN_PRODUCT\"}}]}"; + private static final String EMPTY_RESPONSE = "{}"; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -150,7 +149,7 @@ private long shoppingPriceChange(Tab tab) { final Semaphore initialSemaphore = new Semaphore(0); final Semaphore updateSemaphore = new Semaphore(0); - mockEndpointResponse(); + mockEndpointResponse(ENDPOINT_RESPONSE_INITIAL); TestThreadUtils.runOnUiThreadBlocking(() -> { ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> { verifyEndpointFetcherCalled(1); @@ -169,6 +168,7 @@ }); acquireSemaphore(initialSemaphore); long firstUpdateTime = getTimeLastUpdatedOnUiThread(tab); + mockEndpointResponse(ENDPOINT_RESPONSE_UPDATE); TestThreadUtils.runOnUiThreadBlocking(() -> { ShoppingPersistedTabData.from(tab, (updatedShoppingPersistedTabData) -> { verifyEndpointFetcherCalled(2); @@ -191,7 +191,7 @@ final Semaphore initialSemaphore = new Semaphore(0); final Semaphore updateSemaphore = new Semaphore(0); Tab tab = createTabOnUiThread(TAB_ID, IS_INCOGNITO); - mockEndpointResponse(); + mockEndpointResponse(ENDPOINT_RESPONSE_INITIAL); TestThreadUtils.runOnUiThreadBlocking(() -> { ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> { Assert.assertEquals(PRICE_MICROS, shoppingPersistedTabData.getPriceMicros()); @@ -206,6 +206,7 @@ }); acquireSemaphore(initialSemaphore); verifyEndpointFetcherCalled(1); + mockEndpointResponse(ENDPOINT_RESPONSE_UPDATE); TestThreadUtils.runOnUiThreadBlocking(() -> { ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> { Assert.assertEquals(PRICE_MICROS, shoppingPersistedTabData.getPriceMicros()); @@ -515,6 +516,50 @@ Assert.assertNull(shoppingPersistedTabData.getPriceDrop()); } + @UiThreadTest + @SmallTest + @Test + public void testNewUrl() { + Tab tab = createTabOnUiThread(TAB_ID, IS_INCOGNITO); + ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(tab); + Assert.assertFalse(shoppingPersistedTabData.mIsTabSaveEnabledSupplier.get()); + shoppingPersistedTabData.mIsTabSaveEnabledSupplier.set(true); + shoppingPersistedTabData.mUrlUpdatedObserver.onUrlUpdated(tab); + Assert.assertFalse(shoppingPersistedTabData.mIsTabSaveEnabledSupplier.get()); + } + + @UiThreadTest + @SmallTest + @Test + public void testSPTDSavingEnabledUponSuccessfulResponse() { + final Semaphore semaphore = new Semaphore(0); + Tab tab = createTabOnUiThread(TAB_ID, IS_INCOGNITO); + mockEndpointResponse(ENDPOINT_RESPONSE_INITIAL); + TestThreadUtils.runOnUiThreadBlocking(() -> { + ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> { + Assert.assertTrue(shoppingPersistedTabData.mIsTabSaveEnabledSupplier.get()); + semaphore.release(); + }); + }); + acquireSemaphore(semaphore); + } + + @UiThreadTest + @SmallTest + @Test + public void testSPTDNullUponUnsuccessfulResponse() { + final Semaphore semaphore = new Semaphore(0); + Tab tab = createTabOnUiThread(TAB_ID, IS_INCOGNITO); + mockEndpointResponse(EMPTY_RESPONSE); + TestThreadUtils.runOnUiThreadBlocking(() -> { + ShoppingPersistedTabData.from(tab, (shoppingPersistedTabData) -> { + Assert.assertNull(shoppingPersistedTabData); + semaphore.release(); + }); + }); + acquireSemaphore(semaphore); + } + private void verifyEndpointFetcherCalled(int numTimes) { verify(mEndpointFetcherJniMock, times(numTimes)) .nativeFetchChromeAPIKey(any(Profile.class), anyString(), anyString(), anyString(), @@ -537,14 +582,12 @@ return res.get(); } - private void mockEndpointResponse() { + private void mockEndpointResponse(String response) { doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { Callback callback = (Callback) invocation.getArguments()[7]; - String res = mCalledOnce ? ENDPOINT_RESPONSE_UPDATE : ENDPOINT_RESPONSE_INITIAL; - mCalledOnce = true; - callback.onResult(new EndpointResponse(res)); + callback.onResult(new EndpointResponse(response)); return null; } })
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS index cca330f..d362e54 100644 --- a/chrome/android/junit/DEPS +++ b/chrome/android/junit/DEPS
@@ -6,6 +6,7 @@ "+chrome/browser/ui/android/appmenu/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuDelegate.java", "+chrome/android/java/src/org/chromium/chrome/browser/ssl/ChromeSecurityStateModelDelegate.java", "+chrome/browser/performance_hints/android/java", + "+chrome/browser/privacy/settings", "+chrome/browser/profiles/android", "+chrome/browser/share", "+chrome/browser/signin/services/android/java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProviderTest.java new file mode 100644 index 0000000..f9ef200 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedProcessScopeDependencyProviderTest.java
@@ -0,0 +1,113 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.feed.v2; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager; +import org.chromium.chrome.test.util.browser.Features; + +/** + * Tests for FeedProcessScopeDependencyProvider. + */ +@RunWith(BaseRobolectricTestRunner.class) +public final class FeedProcessScopeDependencyProviderTest { + @Rule + public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); + + FeedProcessScopeDependencyProvider mProvider; + boolean mMetricsReportingEnabled; + + private PrivacyPreferencesManager mStubPrivacyPrefsManager = new PrivacyPreferencesManager() { + @Override + public boolean isMetricsReportingEnabled() { + return mMetricsReportingEnabled; + } + + // Boilerplate. + @Override + public boolean shouldPrerender() { + return false; + } + @Override + public void setUsageAndCrashReporting(boolean enabled) {} + @Override + public void syncUsageAndCrashReportingPrefs() {} + @Override + public void setClientInMetricsSample(boolean inSample) {} + @Override + public boolean isClientInMetricsSample() { + return true; + } + @Override + public boolean isNetworkAvailableForCrashUploads() { + return true; + } + @Override + public boolean isUsageAndCrashReportingPermittedByUser() { + return true; + } + @Override + public boolean isUploadEnabledForTests() { + return true; + } + @Override + public boolean isMetricsUploadPermitted() { + return false; + } + @Override + public void setMetricsReportingEnabled(boolean enabled) {} + @Override + public boolean isMetricsReportingManaged() { + return false; + } + @Override + public boolean getNetworkPredictionEnabled() { + return false; + } + @Override + public void setNetworkPredictionEnabled(boolean enabled) {} + @Override + public boolean isNetworkPredictionManaged() { + return false; + } + }; + + @Before + public void setUp() { + FeedProcessScopeDependencyProvider.sPrivacyPreferencesManagerForTest = + mStubPrivacyPrefsManager; + mProvider = new FeedProcessScopeDependencyProvider(); + } + + @Test + @Features.DisableFeatures({ChromeFeatureList.XSURFACE_METRICS_REPORTING}) + public void usageAndCrashReporting_featureDisabled() { + mMetricsReportingEnabled = false; + assertFalse(mProvider.isXsurfaceUsageAndCrashReportingEnabled()); + + mMetricsReportingEnabled = true; + assertFalse(mProvider.isXsurfaceUsageAndCrashReportingEnabled()); + } + + @Test + @Features.EnableFeatures({ChromeFeatureList.XSURFACE_METRICS_REPORTING}) + public void usageAndCrashReporting_featureEnabled() { + mMetricsReportingEnabled = false; + assertFalse(mProvider.isXsurfaceUsageAndCrashReportingEnabled()); + + mMetricsReportingEnabled = true; + assertTrue(mProvider.isXsurfaceUsageAndCrashReportingEnabled()); + } +}
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 2312af5..6b79faeb 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -5415,6 +5415,20 @@ <ph name="APP_NAME">$1<ex>Parallels Desktop</ex></ph> is using your camera and microphone </message> + <!-- Strings for camera privacy switch toast and notification --> + <message name="IDS_CAMERA_PRIVACY_SWITCH_ON_TOAST" desc="Toast message shown to the user when the camera privacy switch, which disables camera feed, gets turned on."> + Camera is turned off + </message> + <message name="IDS_CAMERA_PRIVACY_SWITCH_OFF_TOAST" desc="Toast message shown to the user when the camera privacy switch gets turned off. The privacy switch disables the camera feed while it's on."> + Camera is turned on + </message> + <message name="IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE" desc="Title for a notification shown to the users when an app tries to use a camera while the camera privacy switch, which disables camera feed, is turned on"> + Camera is off + </message> + <message name="IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE" desc="Message for a notification shown to the users when an app tries to use a camera while the camera privacy switch, which disables camera feed, is turned on"> + An app is trying to access camera. Turn off the Webcam privacy switch to allow access + </message> + <!-- Strings for Account Manager error screen --> <message name="IDS_ACCOUNT_MANAGER_SECONDARY_ACCOUNTS_DISABLED_TITLE" desc="Title for the Chrome OS Account Manager error screen when addition of secondary Google Accounts is disabled."> Addition of more Google Accounts is disabled
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_OFF_TOAST.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_OFF_TOAST.png.sha1 new file mode 100644 index 0000000..49caad5 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_OFF_TOAST.png.sha1
@@ -0,0 +1 @@ +e038d9b78f12123cbc0ebbe7c21c95856a0bb52d \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE.png.sha1 new file mode 100644 index 0000000..faab3bb --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE.png.sha1
@@ -0,0 +1 @@ +18e2e8b7bb0533e9ac230801c4db1c3513ea24ec \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE.png.sha1 new file mode 100644 index 0000000..faab3bb --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@ +18e2e8b7bb0533e9ac230801c4db1c3513ea24ec \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_TOAST.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_TOAST.png.sha1 new file mode 100644 index 0000000..92bb8c1 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_CAMERA_PRIVACY_SWITCH_ON_TOAST.png.sha1
@@ -0,0 +1 @@ +2ed33b92ae5e4c51ae0fe84c31626472a5c03a03 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 28323b12..a13a5fd 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -602,7 +602,7 @@ <!-- Ambient Mode Page --> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_PAGE_DESCRIPTION" desc="Description for the ambient mode settings page."> - When your screen is idle, show photos, time, weather, and media info. Enabling screen saver will keep your device on while charging. + When your screen is idle, show photos, time, weather, and media info. Enabling screen saver will keep your display on while charging. </message> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ON" desc="Label for the toggle row in ambient mode settings page when it is enabled."> On @@ -658,6 +658,12 @@ <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_ALBUM_UNSELECTED" desc="A11y label of an unselected album in ambient mode."> Select album <ph name="TITLE">$1<ex>Recent highlights</ex></ph> <ph name="DESC">$2<ex>Your best auto selected photos</ex></ph> </message> + <message name="IDS_OS_SETTINGS_AMBIENT_MODE_LAST_ART_ALBUM_MESSAGE" desc="A message shown when deselecting the last art album."> + A minimum of one Art gallery album needs to be selected + </message> + <message name="IDS_OS_SETTINGS_AMBIENT_MODE_ART_ALBUM_DIALOG_CLOSE_BUTTON_LABEL" desc="Label on the close button in the art album dialog."> + Got it + </message> <message name="IDS_OS_SETTINGS_AMBIENT_MODE_WEATHER_TITLE" desc="Label for the radio button group of weather."> Weather </message> @@ -2106,6 +2112,9 @@ <message name="IDS_SETTINGS_INTERNET_DEVICE_INITIALIZING" desc="Settings > Internet > Message when a device (e.g a Cellular modem) is initializing."> Initializing </message> + <message name="IDS_SETTINGS_INTERNET_DEVICE_BUSY" desc="Settings > Internet > Message when a device (e.g a Cellular modem) is busy."> + Busy + </message> <message name="IDS_SETTINGS_INTERNET_JOIN_TYPE" desc="Title for the network configuration dialog for a new network."> Join <ph name="TYPE">$1<ex>WiFi</ex></ph> network </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ART_ALBUM_DIALOG_CLOSE_BUTTON_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ART_ALBUM_DIALOG_CLOSE_BUTTON_LABEL.png.sha1 new file mode 100644 index 0000000..d739ec8 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_ART_ALBUM_DIALOG_CLOSE_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@ +660454741a3269eec8beb132f2c890c057e9fd35 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_LAST_ART_ALBUM_MESSAGE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_LAST_ART_ALBUM_MESSAGE.png.sha1 new file mode 100644 index 0000000..d739ec8 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_LAST_ART_ALBUM_MESSAGE.png.sha1
@@ -0,0 +1 @@ +660454741a3269eec8beb132f2c890c057e9fd35 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_PAGE_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_PAGE_DESCRIPTION.png.sha1 index 409f2c6..50c3617d 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_PAGE_DESCRIPTION.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_AMBIENT_MODE_PAGE_DESCRIPTION.png.sha1
@@ -1 +1 @@ -d417099a90e50b80dca2a1ffffc2c59164a8983c \ No newline at end of file +0522d2e46d497b395c1bfa22e721bdfbb10e8013 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_DEVICE_BUSY.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_DEVICE_BUSY.png.sha1 new file mode 100644 index 0000000..53e18ce --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_INTERNET_DEVICE_BUSY.png.sha1
@@ -0,0 +1 @@ +383cedb19d54eac3dcd168df1f80b3b04e566e44 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d43857a..5777322 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -498,8 +498,6 @@ "enterprise/browser_management/browser_management_service.h", "enterprise/browser_management/browser_management_status_provider.cc", "enterprise/browser_management/browser_management_status_provider.h", - "enterprise/util/affiliation.cc", - "enterprise/util/affiliation.h", "enterprise/util/managed_browser_utils.cc", "enterprise/util/managed_browser_utils.h", "expired_flags_list.h", @@ -649,10 +647,15 @@ "lite_video/lite_video_user_blocklist.h", "lite_video/lite_video_util.cc", "lite_video/lite_video_util.h", + "login_detection/login_detection_keyed_service.cc", + "login_detection/login_detection_keyed_service.h", + "login_detection/login_detection_keyed_service_factory.cc", + "login_detection/login_detection_keyed_service_factory.h", "login_detection/login_detection_prefs.cc", "login_detection/login_detection_prefs.h", "login_detection/login_detection_tab_helper.cc", "login_detection/login_detection_tab_helper.h", + "login_detection/login_detection_type.h", "login_detection/login_detection_util.cc", "login_detection/login_detection_util.h", "login_detection/oauth_login_detector.cc", @@ -2943,8 +2946,6 @@ "android/webapk/webapk_update_data_fetcher.cc", "android/webapk/webapk_update_data_fetcher.h", "android/webapk/webapk_update_manager.cc", - "android/webapk/webapk_web_manifest_checker.cc", - "android/webapk/webapk_web_manifest_checker.h", "android/webapps/add_to_homescreen_coordinator.cc", "android/webapps/add_to_homescreen_coordinator.h", "android/webapps/add_to_homescreen_data_fetcher.cc", @@ -5298,6 +5299,8 @@ "payments/chrome_payment_request_delegate.h", "payments/payment_credential_factory.cc", "payments/payment_credential_factory.h", + "payments/payment_handler_navigation_throttle.cc", + "payments/payment_handler_navigation_throttle.h", "payments/payment_request_display_manager_factory.cc", "payments/payment_request_display_manager_factory.h", "payments/payment_request_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 61f0b2d..25f250c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2944,6 +2944,9 @@ {"trim-on-memory-pressure", flag_descriptions::kTrimOnMemoryPressureName, flag_descriptions::kTrimOnMemoryPressureDescription, kOsCrOS, FEATURE_VALUE_TYPE(performance_manager::features::kTrimOnMemoryPressure)}, + {"stylus-battery-status", flag_descriptions::kStylusBatteryStatusName, + flag_descriptions::kStylusBatteryStatusDescription, kOsCrOS, + FEATURE_VALUE_TYPE(ash::features::kStylusBatteryStatus)}, {"system-tray-mic-gain", flag_descriptions::kSystemTrayMicGainName, flag_descriptions::kSystemTrayMicGainDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kSystemTrayMicGainSetting)}, @@ -3661,6 +3664,10 @@ {"web-feed", flag_descriptions::kWebFeedName, flag_descriptions::kWebFeedDescription, kOsAndroid, FEATURE_VALUE_TYPE(feed::kWebFeed)}, + {"xsurface-metrics-reporting", + flag_descriptions::kXsurfaceMetricsReportingName, + flag_descriptions::kXsurfaceMetricsReportingDescription, kOsAndroid, + FEATURE_VALUE_TYPE(feed::kWebFeed)}, {"report-feed-user-actions", flag_descriptions::kReportFeedUserActionsName, flag_descriptions::kReportFeedUserActionsDescription, kOsAndroid, FEATURE_VALUE_TYPE(feed::kReportFeedUserActions)},
diff --git a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc index 89e65cc7..3744f0d 100644 --- a/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc +++ b/chrome/browser/android/preferences/privacy_preferences_manager_impl.cc
@@ -67,10 +67,3 @@ enabled ? chrome_browser_net::NETWORK_PREDICTION_WIFI_ONLY : chrome_browser_net::NETWORK_PREDICTION_NEVER); } - -static jboolean -JNI_PrivacyPreferencesManagerImpl_ObsoleteNetworkPredictionOptionsHasUserSetting( - JNIEnv* env) { - return GetPrefService()->GetUserPrefValue(prefs::kNetworkPredictionOptions) != - nullptr; -}
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc index 8f56dad..ced563d 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -17,9 +17,9 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/android/chrome_jni_headers/WebApkUpdateDataFetcher_jni.h" -#include "chrome/browser/android/webapk/webapk_web_manifest_checker.h" #include "chrome/browser/profiles/profile.h" #include "components/webapps/android/webapps_icon_utils.h" +#include "components/webapps/android/webapps_utils.h" #include "components/webapps/installable/installable_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" @@ -145,7 +145,8 @@ // change, we will treat the new Web Manifest as the one of another WebAPK. if (!data.NoBlockingErrors() || data.manifest->IsEmpty() || web_manifest_url_ != data.manifest_url || - !AreWebManifestUrlsWebApkCompatible(*data.manifest)) { + !webapps::WebappsUtils::AreWebManifestUrlsWebApkCompatible( + *data.manifest)) { return; }
diff --git a/chrome/browser/android/webapk/webapk_web_manifest_checker.cc b/chrome/browser/android/webapk/webapk_web_manifest_checker.cc deleted file mode 100644 index 10f9b805..0000000 --- a/chrome/browser/android/webapk/webapk_web_manifest_checker.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/android/webapk/webapk_web_manifest_checker.h" - -#include "third_party/blink/public/common/manifest/manifest.h" -#include "url/gurl.h" - -namespace { - -// Returns whether a URL in the Web Manifest is WebAPK compatible. -bool IsUrlWebApkCompatible(const GURL& url) { - // WebAPK web manifests are stored on the Chrome WebAPK server. Do not - // generate WebAPKs for Web Manifests with URLs with a user name or password - // in order to avoid storing user names and passwords on the WebAPK server. - return !url.has_username() && !url.has_password(); -} - -} // anonymous namespace - -bool AreWebManifestUrlsWebApkCompatible(const blink::Manifest& manifest) { - for (const auto& icon : manifest.icons) { - if (!IsUrlWebApkCompatible(icon.src)) - return false; - } - - // Do not check "related_applications" URLs because they are not used by - // WebAPKs. - - return IsUrlWebApkCompatible(manifest.start_url) && - IsUrlWebApkCompatible(manifest.scope); -}
diff --git a/chrome/browser/android/webapk/webapk_web_manifest_checker.h b/chrome/browser/android/webapk/webapk_web_manifest_checker.h deleted file mode 100644 index 8feafe6..0000000 --- a/chrome/browser/android/webapk/webapk_web_manifest_checker.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_WEB_MANIFEST_CHECKER_H_ -#define CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_WEB_MANIFEST_CHECKER_H_ - -namespace blink { -struct Manifest; -} - -// Returns whether the format of the URLs in the Web Manifest is WebAPK -// compatible. -bool AreWebManifestUrlsWebApkCompatible(const blink::Manifest& manifest); - -#endif // CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_WEB_MANIFEST_CHECKER_H_
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index cca3f47..9c0e145 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -20,7 +20,6 @@ #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/android/shortcut_helper.h" -#include "chrome/browser/android/webapk/webapk_web_manifest_checker.h" #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_constants.h" @@ -28,6 +27,7 @@ #include "components/favicon/core/favicon_service.h" #include "components/favicon_base/favicon_types.h" #include "components/webapps/android/webapps_icon_utils.h" +#include "components/webapps/android/webapps_utils.h" #include "components/webapps/installable/installable_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" @@ -278,7 +278,8 @@ bool webapk_compatible = (data.NoBlockingErrors() && data.valid_manifest && data.has_worker && - AreWebManifestUrlsWebApkCompatible(*data.manifest)); + webapps::WebappsUtils::AreWebManifestUrlsWebApkCompatible( + *data.manifest)); observer_->OnUserTitleAvailable( webapk_compatible ? shortcut_info_.name : shortcut_info_.user_title, shortcut_info_.url, webapk_compatible);
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc index ccd9f46299..30bba40 100644 --- a/chrome/browser/banners/app_banner_manager_android.cc +++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/android/tab_web_contents_delegate_android.h" #include "chrome/browser/android/webapk/webapk_metrics.h" #include "chrome/browser/android/webapk/webapk_ukm_recorder.h" -#include "chrome/browser/android/webapk/webapk_web_manifest_checker.h" #include "chrome/browser/android/webapps/add_to_homescreen_coordinator.h" #include "chrome/browser/android/webapps/add_to_homescreen_params.h" #include "chrome/browser/android/webapps/pwa_bottom_sheet_controller.h" @@ -184,7 +183,7 @@ } void AppBannerManagerAndroid::PerformInstallableWebAppCheck() { - if (!AreWebManifestUrlsWebApkCompatible(manifest_)) { + if (!webapps::WebappsUtils::AreWebManifestUrlsWebApkCompatible(manifest_)) { Stop(URL_NOT_SUPPORTED_FOR_WEBAPK); return; }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index d9e747d3..afc41bb 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -89,6 +89,9 @@ #include "chrome/browser/notifications/platform_notification_service_impl.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/payments/payment_request_display_manager_factory.h" +#if !defined(OS_ANDROID) +#include "chrome/browser/payments/payment_handler_navigation_throttle.h" +#endif #include "chrome/browser/performance_manager/chrome_browser_main_extra_parts_performance_manager.h" #include "chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.h" #include "chrome/browser/permissions/attestation_permission_request.h" @@ -4126,6 +4129,13 @@ &throttles); } +#if !defined(OS_ANDROID) + MaybeAddThrottle( + payments::PaymentHandlerNavigationThrottle::MaybeCreateThrottleFor( + handle), + &throttles); +#endif + return throttles; }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc index c4bb8989..23a20df 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -417,6 +417,8 @@ IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_DISMISS); SET_STRING("HOLDING_SPACE_WELCOME_TEXT", IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT); + SET_STRING("HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE", + IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE); SET_STRING("HOLDING_SPACE_WELCOME_TITLE", IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TITLE); }
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service.cc b/chrome/browser/chromeos/full_restore/full_restore_service.cc index 076061c..a6b8ab7 100644 --- a/chrome/browser/chromeos/full_restore/full_restore_service.cc +++ b/chrome/browser/chromeos/full_restore/full_restore_service.cc
@@ -16,7 +16,8 @@ #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chromeos/constants/chromeos_features.h" -#include "components/full_restore/full_restore_utils.h" +#include "components/account_id/account_id.h" +#include "components/full_restore/full_restore_info.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" #include "ui/base/l10n/l10n_util.h" @@ -132,7 +133,12 @@ } void FullRestoreService::Restore() { - ::full_restore::SetRestoreFlag(true); + const user_manager::User* user = + chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); + if (user) { + ::full_restore::FullRestoreInfo::GetInstance()->SetRestoreFlag( + user->GetAccountId(), true); + } // TODO(crbug.com/909794): Implement the restoration. And move the heavy load // out of this KeyedService class.
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc index 7824da8..7d78a91f 100644 --- a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc +++ b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
@@ -16,6 +16,8 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/constants/chromeos_features.h" +#include "components/account_id/account_id.h" +#include "components/full_restore/full_restore_info.h" #include "components/full_restore/full_restore_utils.h" #include "components/sync/base/model_type.h" #include "components/sync/model/sync_change.h" @@ -71,9 +73,6 @@ void SetUp() override { scoped_feature_list_.InitAndEnableFeature(ash::features::kFullRestore); - // Reset the restore flag as the default value. - ::full_restore::SetRestoreFlag(false); - EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); TestingProfile::Builder profile_builder; profile_builder.SetProfileName("user@gmail.com"); @@ -81,6 +80,15 @@ profile_ = profile_builder.Build(); profile_->GetPrefs()->ClearPref(kRestoreAppsAndPagesPrefName); + account_id_ = AccountId::FromUserEmailGaiaId(profile_->GetProfileUserName(), + "1234567890"); + GetFakeUserManager()->AddUser(account_id_); + GetFakeUserManager()->LoginUser(account_id_); + + // Reset the restore flag as the default value. + ::full_restore::FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id_, + false); + display_service_ = std::make_unique<NotificationDisplayServiceTester>(profile_.get()); } @@ -136,6 +144,8 @@ TestingProfile* profile() const { return profile_.get(); } + const AccountId& account_id() const { return account_id_; } + NotificationDisplayServiceTester* display_service() const { return display_service_.get(); } @@ -148,6 +158,7 @@ std::unique_ptr<TestingProfile> profile_; base::ScopedTempDir temp_dir_; user_manager::ScopedUserManager user_manager_enabler_; + AccountId account_id_; std::unique_ptr<NotificationDisplayServiceTester> display_service_; }; @@ -164,7 +175,7 @@ SimulateClick(kRestoreForCrashNotificationId, RestoreNotificationButtonIndex::kRestore); - EXPECT_TRUE(::full_restore::ShouldRestore()); + EXPECT_TRUE(::full_restore::ShouldRestore(account_id())); } // If the system is crash, show the crash notification, and verify the restore @@ -179,7 +190,7 @@ SimulateClick(kRestoreForCrashNotificationId, RestoreNotificationButtonIndex::kCancel); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // For a brand new user, if sync off, set 'Ask Every Time' as the default value, @@ -191,7 +202,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // For a new Chrome OS user, if the Chrome restore setting is 'Continue where @@ -204,7 +215,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Set the Chrome restore setting to simulate sync for the first time. syncer::SyncDataList sync_data_list; @@ -217,7 +228,7 @@ EXPECT_EQ(RestoreOption::kAlways, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Update the global values to simulate sync from other device. syncer::SyncChangeList change_list; @@ -235,7 +246,7 @@ content::RunAllTasksUntilIdle(); EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption()); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // For a new Chrome OS user, if the Chrome restore setting is 'New tab', after @@ -248,7 +259,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Set the Chrome restore setting to simulate sync for the first time. syncer::SyncDataList sync_data_list; @@ -261,7 +272,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Update the global values to simulate sync from other device. syncer::SyncChangeList change_list; @@ -279,7 +290,7 @@ content::RunAllTasksUntilIdle(); EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption()); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // For a new Chrome OS user, keep the ChromeOS restore setting from sync, and @@ -291,7 +302,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Set the restore pref setting to simulate sync for the first time. syncer::SyncDataList sync_data_list; @@ -307,7 +318,7 @@ EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Update the global values to simulate sync from other device. syncer::SyncChangeList change_list; @@ -325,7 +336,7 @@ content::RunAllTasksUntilIdle(); EXPECT_EQ(RestoreOption::kAlways, GetRestoreOption()); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // For the current ChromeOS user, when first time upgrading to the full restore @@ -340,7 +351,7 @@ EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); // Simulate the Chrome restore setting is changed. profile()->GetPrefs()->SetInteger( @@ -349,7 +360,7 @@ // The OS restore setting should not change. EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption()); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // If the OS restore setting is 'Ask every time', after reboot, show the restore @@ -368,7 +379,7 @@ RestoreNotificationButtonIndex::kRestore); EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); - EXPECT_TRUE(::full_restore::ShouldRestore()); + EXPECT_TRUE(::full_restore::ShouldRestore(account_id())); } // If the OS restore setting is 'Ask every time', after reboot, show the restore @@ -387,7 +398,7 @@ RestoreNotificationButtonIndex::kCancel); EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption()); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } // If the OS restore setting is 'Always', after reboot, don't show any @@ -400,7 +411,7 @@ EXPECT_EQ(RestoreOption::kAlways, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_TRUE(::full_restore::ShouldRestore()); + EXPECT_TRUE(::full_restore::ShouldRestore(account_id())); } // If the OS restore setting is 'Do not restore', after reboot, don't show any @@ -414,7 +425,7 @@ EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption()); EXPECT_FALSE(HasNotificationFor(kRestoreForCrashNotificationId)); EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId)); - EXPECT_FALSE(::full_restore::ShouldRestore()); + EXPECT_FALSE(::full_restore::ShouldRestore(account_id())); } } // namespace full_restore
diff --git a/chrome/browser/chromeos/login/screens/pin_setup_screen.cc b/chrome/browser/chromeos/login/screens/pin_setup_screen.cc index b46e8ba..cb377a8f 100644 --- a/chrome/browser/chromeos/login/screens/pin_setup_screen.cc +++ b/chrome/browser/chromeos/login/screens/pin_setup_screen.cc
@@ -96,8 +96,10 @@ DCHECK(view_); view_->Bind(this); - quick_unlock::PinBackend::GetInstance()->HasLoginSupport(base::BindOnce( - &PinSetupScreen::OnHasLoginSupport, weak_ptr_factory_.GetWeakPtr())); + if (features::IsPinSetupForFamilyLinkEnabled()) { + quick_unlock::PinBackend::GetInstance()->HasLoginSupport(base::BindOnce( + &PinSetupScreen::OnHasLoginSupport, weak_ptr_factory_.GetWeakPtr())); + } } PinSetupScreen::~PinSetupScreen() {
diff --git a/chrome/browser/chromeos/net/network_health/network_health.cc b/chrome/browser/chromeos/net/network_health/network_health.cc index 8a9251a..6c57561 100644 --- a/chrome/browser/chromeos/net/network_health/network_health.cc +++ b/chrome/browser/chromeos/net/network_health/network_health.cc
@@ -30,6 +30,7 @@ // UI, but not for purposes of network health, we can treat as Disabled. return mojom::NetworkState::kDisabled; case network_config::mojom::DeviceStateType::kEnabled: + case network_config::mojom::DeviceStateType::kInhibited: return mojom::NetworkState::kNotConnected; case network_config::mojom::DeviceStateType::kProhibited: return mojom::NetworkState::kProhibited;
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.cc b/chrome/browser/component_updater/first_party_sets_component_installer.cc index 6d516f1..be725f7 100644 --- a/chrome/browser/component_updater/first_party_sets_component_installer.cc +++ b/chrome/browser/component_updater/first_party_sets_component_installer.cc
@@ -9,6 +9,7 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/no_destructor.h" #include "base/optional.h" #include "base/path_service.h" #include "base/stl_util.h" @@ -56,10 +57,38 @@ return result; } +base::FilePath& GetConfigPathInstance() { + static base::NoDestructor<base::FilePath> instance; + return *instance; +} + +void SetFirstPartySetsConfig( + const base::RepeatingCallback<void(const std::string&)>& on_sets_ready) { + if (GetConfigPathInstance().empty()) + return; + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&LoadSetsFromDisk, GetConfigPathInstance()), + base::BindOnce( + [](base::RepeatingCallback<void(const std::string&)> on_sets_ready, + base::Optional<std::string> raw_sets) { + if (raw_sets.has_value()) + on_sets_ready.Run(*raw_sets); + }, + on_sets_ready)); +} + } // namespace namespace component_updater { +// static +void FirstPartySetsComponentInstallerPolicy::ReconfigureAfterNetworkRestart( + const base::RepeatingCallback<void(const std::string&)>& on_sets_ready) { + SetFirstPartySetsConfig(on_sets_ready); +} + FirstPartySetsComponentInstallerPolicy::FirstPartySetsComponentInstallerPolicy( base::RepeatingCallback<void(const std::string&)> on_sets_ready) : on_sets_ready_(std::move(on_sets_ready)) {} @@ -97,19 +126,15 @@ const base::Version& version, const base::FilePath& install_dir, std::unique_ptr<base::DictionaryValue> manifest) { + if (install_dir.empty()) + return; + VLOG(1) << "First-Party Sets Component ready, version " << version.GetString() << " in " << install_dir.value(); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&LoadSetsFromDisk, GetInstalledPath(install_dir)), - base::BindOnce( - [](base::RepeatingCallback<void(const std::string&)> on_sets_ready, - base::Optional<std::string> raw_sets) { - if (raw_sets.has_value()) - on_sets_ready.Run(*raw_sets); - }, - on_sets_ready_)); + GetConfigPathInstance() = GetInstalledPath(install_dir); + + SetFirstPartySetsConfig(on_sets_ready_); } // Called during startup and installation before ComponentReady().
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.h b/chrome/browser/component_updater/first_party_sets_component_installer.h index 063334553..e5fb105a 100644 --- a/chrome/browser/component_updater/first_party_sets_component_installer.h +++ b/chrome/browser/component_updater/first_party_sets_component_installer.h
@@ -36,8 +36,16 @@ FirstPartySetsComponentInstallerPolicy operator=( const FirstPartySetsComponentInstallerPolicy&) = delete; + // Calls the callback with the current First-Party Sets data, if the data + // exists and can be read. + static void ReconfigureAfterNetworkRestart( + const base::RepeatingCallback<void(const std::string&)>&); + private: - FRIEND_TEST_ALL_PREFIXES(FirstPartySetsComponentInstallerTest, LoadsSets); + FRIEND_TEST_ALL_PREFIXES(FirstPartySetsComponentInstallerTest, + LoadsSets_OnComponentReady); + FRIEND_TEST_ALL_PREFIXES(FirstPartySetsComponentInstallerTest, + LoadsSets_OnNetworkRestart); // The following methods override ComponentInstallerPolicy. bool SupportsGroupPolicyEnabledComponentUpdates() const override;
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc index 5b6e50e..592f10b 100644 --- a/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc +++ b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc
@@ -30,17 +30,19 @@ public: FirstPartySetsComponentInstallerTest() { CHECK(component_install_dir_.CreateUniqueTempDir()); + scoped_feature_list_.InitAndEnableFeature(net::features::kFirstPartySets); } protected: base::test::TaskEnvironment env_; base::ScopedTempDir component_install_dir_; + base::test::ScopedFeatureList scoped_feature_list_; }; TEST_F(FirstPartySetsComponentInstallerTest, FeatureDisabled) { - base::test::ScopedFeatureList scoped_list; - scoped_list.InitAndDisableFeature(net::features::kFirstPartySets); + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndDisableFeature(net::features::kFirstPartySets); auto service = std::make_unique<component_updater::MockComponentUpdateService>(); EXPECT_CALL(*service, RegisterComponent(_)).Times(0); @@ -49,10 +51,7 @@ env_.RunUntilIdle(); } -TEST_F(FirstPartySetsComponentInstallerTest, LoadsSets) { - base::test::ScopedFeatureList scoped_list; - scoped_list.InitAndEnableFeature(net::features::kFirstPartySets); - +TEST_F(FirstPartySetsComponentInstallerTest, LoadsSets_OnComponentReady) { SEQUENCE_CHECKER(sequence_checker); const std::string expectation = "some first party sets"; base::RunLoop run_loop; @@ -74,4 +73,43 @@ run_loop.Run(); } +TEST_F(FirstPartySetsComponentInstallerTest, LoadsSets_OnNetworkRestart) { + SEQUENCE_CHECKER(sequence_checker); + const std::string expectation = "some first party sets"; + + // We do this in order for the static to memoize the install path. + { + base::RunLoop run_loop; + FirstPartySetsComponentInstallerPolicy policy( + base::BindLambdaForTesting([&](const std::string& got) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(got, expectation); + run_loop.Quit(); + })); + + ASSERT_TRUE(base::WriteFile( + FirstPartySetsComponentInstallerPolicy::GetInstalledPath( + component_install_dir_.GetPath()), + expectation)); + + policy.ComponentReady(base::Version(), component_install_dir_.GetPath(), + std::make_unique<base::DictionaryValue>()); + + run_loop.Run(); + } + + { + base::RunLoop run_loop; + + FirstPartySetsComponentInstallerPolicy::ReconfigureAfterNetworkRestart( + base::BindLambdaForTesting([&](const std::string& got) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); + EXPECT_EQ(got, expectation); + run_loop.Quit(); + })); + + run_loop.Run(); + } +} + } // namespace component_updater
diff --git a/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc new file mode 100644 index 0000000..a3a5640 --- /dev/null +++ b/chrome/browser/data_saver/subresource_redirect_login_robots_browsertest.cc
@@ -0,0 +1,751 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> +#include <string> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/notreached.h" +#include "base/path_service.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h" +#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/subresource_redirect/https_image_compression_infobar_decider.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/data_reduction_proxy/proto/robots_rules.pb.h" +#include "components/metrics/content/subprocess_metrics_provider.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "net/base/url_util.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "url/gurl.h" + +namespace subresource_redirect { + +const bool kRuleTypeAllow = true; +const bool kRuleTypeDisallow = false; + +// Holds one allow or disallow robots rule +struct RobotsRule { + RobotsRule(bool rule_type, const std::string& pattern) + : rule_type(rule_type), pattern(pattern) {} + + bool rule_type; + std::string pattern; +}; + +// Convert robots rules to its proto. +std::string GetRobotsRulesProtoString(const std::vector<RobotsRule>& patterns) { + proto::RobotsRules robots_rules; + for (const auto& pattern : patterns) { + auto* new_rule = robots_rules.add_image_ordered_rules(); + if (pattern.rule_type == kRuleTypeAllow) { + new_rule->set_allowed_pattern(pattern.pattern); + } else { + new_rule->set_disallowed_pattern(pattern.pattern); + } + } + return robots_rules.SerializeAsString(); +} + +// Retries fetching |histogram_name| until it contains at least |count| samples. +void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester, + const std::string& histogram_name, + size_t count) { + while (true) { + content::FetchHistogramsFromChildProcesses(); + metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + + const std::vector<base::Bucket> buckets = + histogram_tester->GetAllSamples(histogram_name); + size_t total_count = 0; + for (const auto& bucket : buckets) { + total_count += bucket.count; + } + if (total_count >= count) { + break; + } + } +} + +// Fetches histograms from renderer child processes. +void FetchHistogramsFromChildProcesses() { + content::FetchHistogramsFromChildProcesses(); + metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); +} + +// Embedded test server for the robots rules +class RobotsRulesTestServer { + public: + // Different failures modes the robots server should return + enum FailureMode { + kNone = 0, + kLoadshed503RetryAfterResponse, + kTimeout, + }; + + RobotsRulesTestServer() : server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + + bool Start() { + server_.ServeFilesFromSourceDirectory("chrome/test/data"); + server_.RegisterRequestHandler(base::BindRepeating( + &RobotsRulesTestServer::OnServerRequest, base::Unretained(this))); + server_.RegisterRequestMonitor(base::BindRepeating( + &RobotsRulesTestServer::OnRequestMonitor, base::Unretained(this))); + return server_.Start(); + } + + std::string GetURL() const { + return server_.GetURL("robotsrules.com", "/").spec(); + } + + void AddRobotsRules(const GURL& origin, + const std::vector<RobotsRule>& robots_rules) { + robots_rules_proto_[origin.spec()] = + GetRobotsRulesProtoString(robots_rules); + } + + void VerifyRequestedOrigins(const std::set<std::string>& requests) { + EXPECT_EQ(received_requests_, requests); + } + + void set_failure_mode(FailureMode failure_mode) { + failure_mode_ = failure_mode; + } + + private: + std::unique_ptr<net::test_server::HttpResponse> OnServerRequest( + const net::test_server::HttpRequest& request) { + std::unique_ptr<net::test_server::BasicHttpResponse> response = + std::make_unique<net::test_server::BasicHttpResponse>(); + std::string robots_url_str; + EXPECT_EQ("/robots", request.GetURL().path()); + EXPECT_TRUE( + net::GetValueForKeyInQuery(request.GetURL(), "u", &robots_url_str)); + GURL robots_url(robots_url_str); + EXPECT_EQ("/robots.txt", GURL(robots_url).path()); + + switch (failure_mode_) { + case FailureMode::kLoadshed503RetryAfterResponse: + response->set_code(net::HTTP_SERVICE_UNAVAILABLE); + response->AddCustomHeader("Retry-After", "5"); + return response; + case FailureMode::kTimeout: + response = std::make_unique<net::test_server::DelayedHttpResponse>( + base::TimeDelta::FromSeconds(2)); + break; + case FailureMode::kNone: + break; + } + + auto it = robots_rules_proto_.find(robots_url.GetOrigin().spec()); + if (it != robots_rules_proto_.end()) + response->set_content(it->second); + return std::move(response); + } + + // Called on every robots request + void OnRequestMonitor(const net::test_server::HttpRequest& request) { + std::string robots_url_str; + EXPECT_EQ("/robots", request.GetURL().path()); + EXPECT_TRUE( + net::GetValueForKeyInQuery(request.GetURL(), "u", &robots_url_str)); + std::string robots_origin = GURL(robots_url_str).GetOrigin().spec(); + EXPECT_TRUE(received_requests_.find(robots_origin) == + received_requests_.end()); + received_requests_.insert(robots_origin); + } + + // Robots rules proto keyed by origin. + std::map<std::string, std::string> robots_rules_proto_; + + // Whether the robots server should return failure. + FailureMode failure_mode_ = FailureMode::kNone; + + // All the origins the robots rules are requested for. + std::set<std::string> received_requests_; + + net::EmbeddedTestServer server_; +}; + +class ImageCompressionTestServer { + public: + // Different failures modes the image server should return + enum FailureMode { + kNone = 0, + kLoadshed503RetryAfterResponse, + }; + ImageCompressionTestServer() : server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + + bool Start() { + server_.ServeFilesFromSourceDirectory("chrome/test/data"); + server_.RegisterRequestHandler(base::BindRepeating( + &ImageCompressionTestServer::OnServerRequest, base::Unretained(this))); + server_.RegisterRequestMonitor(base::BindRepeating( + &ImageCompressionTestServer::OnRequestMonitor, base::Unretained(this))); + return server_.Start(); + } + + std::string GetURL() const { + return server_.GetURL("imagecompression.com", "/").spec(); + } + + void VerifyRequestedImagePaths(const std::set<std::string>& paths) { + EXPECT_EQ(received_request_paths_, paths); + } + + void set_failure_mode(FailureMode failure_mode) { + failure_mode_ = failure_mode; + } + + private: + std::unique_ptr<net::test_server::HttpResponse> OnServerRequest( + const net::test_server::HttpRequest& request) { + std::unique_ptr<net::test_server::BasicHttpResponse> response = + std::make_unique<net::test_server::BasicHttpResponse>(); + + switch (failure_mode_) { + case FailureMode::kLoadshed503RetryAfterResponse: + response->set_code(net::HTTP_SERVICE_UNAVAILABLE); + response->AddCustomHeader("Retry-After", "5"); + return response; + case FailureMode::kNone: + break; + } + + // Serve the correct image file. + std::string img_url; + std::string file_contents; + base::FilePath test_data_directory; + EXPECT_EQ("/i", request.GetURL().path()); + EXPECT_TRUE(net::GetValueForKeyInQuery(request.GetURL(), "u", &img_url)); + base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); + if (base::ReadFileToString( + test_data_directory.AppendASCII(GURL(img_url).path().substr(1)), + &file_contents)) { + response->set_content(file_contents); + response->set_code(net::HTTP_OK); + } + return std::move(response); + } + + // Called on every subresource request + void OnRequestMonitor(const net::test_server::HttpRequest& request) { + std::string img_url; + EXPECT_EQ("/i", request.GetURL().path()); + EXPECT_TRUE(net::GetValueForKeyInQuery(request.GetURL(), "u", &img_url)); + img_url = GURL(img_url).PathForRequest(); + EXPECT_TRUE(received_request_paths_.find(img_url) == + received_request_paths_.end()); + received_request_paths_.insert(img_url); + } + + // All the URL paths of the requested images. + std::set<std::string> received_request_paths_; + + // Whether the subresource server should return failure. + FailureMode failure_mode_ = FailureMode::kNone; + + net::EmbeddedTestServer server_; +}; + +class SubresourceRedirectLoginRobotsBrowserTest : public InProcessBrowserTest { + public: + explicit SubresourceRedirectLoginRobotsBrowserTest( + bool enable_lite_mode = true, + bool enable_login_robots_compression_feature = true) + : enable_lite_mode_(enable_lite_mode), + enable_login_robots_compression_feature_( + enable_login_robots_compression_feature), + https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + + ~SubresourceRedirectLoginRobotsBrowserTest() override = default; + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII("host-rules", "MAP * 127.0.0.1"); + if (enable_lite_mode_) + command_line->AppendSwitch("enable-spdy-proxy-auth"); + + // Disable infobar shown check to actually compress the pages. + command_line->AppendSwitch("override-https-image-compression-infobar"); + } + + void SetUp() override { + ASSERT_TRUE(robots_rules_server_.Start()); + ASSERT_TRUE(image_compression_server_.Start()); + https_test_server_.ServeFilesFromSourceDirectory("chrome/test/data"); + ASSERT_TRUE(https_test_server_.Start()); + + std::vector<base::test::ScopedFeatureList::FeatureAndParams> + enabled_features; + if (enable_login_robots_compression_feature_) { + base::FieldTrialParams params; + params["enable_public_image_hints_based_compression"] = "false"; + params["enable_login_robots_based_compression"] = "true"; + params["lite_page_robots_origin"] = robots_rules_server_.GetURL(); + params["lite_page_subresource_origin"] = + image_compression_server_.GetURL(); + // This rules fetch timeout is chosen such that the tests would have + // enough time to fetch the rules without causing a timeout. + params["robots_rules_receive_timeout"] = "1000"; + enabled_features.emplace_back(blink::features::kSubresourceRedirect, + params); + } + scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features, {}); + InProcessBrowserTest::SetUp(); + } + + GURL GetHttpsTestURL(const std::string& path) const { + return https_test_server_.GetURL("test_https_server.com", path); + } + + void NavigateAndWaitForLoad(Browser* browser, const GURL& url) { + ui_test_utils::NavigateToURL(browser, url); + EXPECT_EQ(true, EvalJs(browser->tab_strip_model()->GetActiveWebContents(), + "checkImage()")); + FetchHistogramsFromChildProcesses(); + } + + bool RunScriptExtractBool(const std::string& script, + content::WebContents* web_contents = nullptr) { + if (!web_contents) + web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + return EvalJs(web_contents, script).ExtractBool(); + } + + protected: + bool enable_lite_mode_; + bool enable_login_robots_compression_feature_; + + base::test::ScopedFeatureList scoped_feature_list_; + + // Simulates the LitePages servers that return the robots rules and compress + // images. + RobotsRulesTestServer robots_rules_server_; + ImageCompressionTestServer image_compression_server_; + net::EmbeddedTestServer https_test_server_; + + base::HistogramTester histogram_tester_; +}; + +// Enable tests for linux since LiteMode is enabled only for Android. +#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_CHROMEOS) +#define DISABLE_ON_WIN_MAC_CHROMEOS(x) DISABLED_##x +#else +#define DISABLE_ON_WIN_MAC_CHROMEOS(x) x +#endif + +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageAllowedByRobots)) { + robots_rules_server_.AddRobotsRules( + GetHttpsTestURL("/"), + {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 1); + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); +} + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageDisallowedByRobots)) { + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + // The image will start redirect and pause when robots rules are getting + // fetched. But when the fetch timesout, it will reset and fetch the original + // URL. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths({}); +} + +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(NoTriggerWhenDataSaverOff)) { + data_reduction_proxy::DataReductionProxySettings:: + SetDataSaverEnabledForTesting(browser()->profile()->GetPrefs(), false); + base::RunLoop().RunUntilIdle(); + + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeAllow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({}); + image_compression_server_.VerifyRequestedImagePaths({}); +} + +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(NoTriggerInIncognito)) { + auto* incognito_browser = CreateIncognitoBrowser(); + + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeAllow, ""}}); + NavigateAndWaitForLoad(incognito_browser, + GetHttpsTestURL("/load_image/image.html")); + + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({}); + image_compression_server_.VerifyRequestedImagePaths({}); +} + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestRobotsRulesFetchTimeout)) { + robots_rules_server_.set_failure_mode( + RobotsRulesTestServer::FailureMode::kTimeout); + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeAllow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + // The image will start redirect and pause when robots rules are getting + // fetched. But when the fetch timesout, it will reset and fetch the original + // URL. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + + // Wait until the robots rules fetch times-out. + RetryForHistogramUntilCountReached( + &histogram_tester_, "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", + 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths({}); +} + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestOneImageAllowedOneDisallowed)) { + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeDisallow, "*foo"}}); + NavigateAndWaitForLoad(browser(), + GetHttpsTestURL("/load_image/two_images.html")); + + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 2); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); +} + +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestTwoImagesAllowed)) { + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeAllow, ""}}); + NavigateAndWaitForLoad(browser(), + GetHttpsTestURL("/load_image/two_images.html")); + + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 2); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 2); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 2); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.ImageCompressionNotificationInfoBar", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png", "/load_image/image.png?foo"}); +} + +// Verify an new image loads fine after robots rules fetch is complete. +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageLoadAfterRobotsFetch)) { + robots_rules_server_.AddRobotsRules( + GetHttpsTestURL("/"), + {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 1); + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); + + // Load another image and that will be immediately redirected as well. + EXPECT_TRUE(RunScriptExtractBool(R"(loadNewImage("image.png?foo"))")); + FetchHistogramsFromChildProcesses(); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 2); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 2); + EXPECT_TRUE(RunScriptExtractBool("checkImage()")); + + // No more new robots rules fetches. + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 1); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png", "/load_image/image.png?foo"}); +} + +IN_PROC_BROWSER_TEST_F( + SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestDifferentOriginImageLoad)) { + robots_rules_server_.AddRobotsRules( + GetHttpsTestURL("/"), + {{kRuleTypeAllow, "/load_image/image.png"}, {kRuleTypeDisallow, ""}}); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 1); + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.CompressionAttempt.ServerResponded", true, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); + + // Load a compressible image from different origin and that will trigger + // robots rules fetch. + robots_rules_server_.AddRobotsRules( + https_test_server_.GetURL("differentorigin.com", "/"), + {{kRuleTypeDisallow, "*disallowed*"}}); + EXPECT_TRUE(RunScriptExtractBool(content::JsReplace( + "loadNewImage($1)", + https_test_server_.GetURL("differentorigin.com", + "/load_image/image.png?allowed")))); + FetchHistogramsFromChildProcesses(); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", net::HTTP_OK, 2); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 2); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 2); + + // Another robots rules fetch happened. + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 2); + robots_rules_server_.VerifyRequestedOrigins( + {GetHttpsTestURL("/").spec(), + https_test_server_.GetURL("differentorigin.com", "/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png", "/load_image/image.png?allowed"}); + + // Load a disallowed image from the different origin. + EXPECT_TRUE(RunScriptExtractBool(content::JsReplace( + "loadNewImage($1)", + https_test_server_.GetURL("differentorigin.com", + "/load_image/image.png?disallowed")))); + FetchHistogramsFromChildProcesses(); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", 4); + + // No more new robots rules fetches. + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 2); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png", "/load_image/image.png?allowed"}); +} + +// Verifies that LitePages gets blocked due to robots fetch failure, and +// subsequent robots rules fetch does not happen. +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestRobotsFetchLoadshed)) { + robots_rules_server_.set_failure_mode( + RobotsRulesTestServer::FailureMode::kLoadshed503RetryAfterResponse); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + // One robots rules fetch failure should result in LitePages block. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", + net::HTTP_SERVICE_UNAVAILABLE, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + // Bypass check happens twice - once for pageload, and once for robots + // fetch. + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.LitePagesService.BypassResult", false, 2); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 0); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths({}); + + // Load an image from different origin and that should not trigger robots + // rules fetch, since LitePages is blocked. + EXPECT_TRUE(RunScriptExtractBool(content::JsReplace( + "loadNewImage($1)", + https_test_server_.GetURL("differentorigin.com", + "/load_image/image.png?allowed")))); + FetchHistogramsFromChildProcesses(); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.LitePagesService.BypassResult", true, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 1); + EXPECT_TRUE(RunScriptExtractBool("checkImage()")); + + // No more additional fetches. + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths({}); +} + +// Verifies that when an image load fails, LitePages gets blocked, and +// subsequent robots rules fetch, LitePages image loads does not happen. +IN_PROC_BROWSER_TEST_F(SubresourceRedirectLoginRobotsBrowserTest, + DISABLE_ON_WIN_MAC_CHROMEOS(TestImageFetchLoadshed)) { + robots_rules_server_.AddRobotsRules(GetHttpsTestURL("/"), + {{kRuleTypeAllow, ""}}); + image_compression_server_.set_failure_mode( + ImageCompressionTestServer::FailureMode::kLoadshed503RetryAfterResponse); + NavigateAndWaitForLoad(browser(), GetHttpsTestURL("/load_image/image.html")); + + // Robots rules fetch was success. + histogram_tester_.ExpectUniqueSample( + "SubresourceRedirect.RobotsRulesFetcher.ResponseCode", net::HTTP_OK, 1); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", false, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); + + // One compressed image fetch failed and then loaded directly. + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_TEMPORARY_REDIRECT, 2); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.CompressionAttempt.ResponseCode", + net::HTTP_SERVICE_UNAVAILABLE, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + + // Bypass check happens twice - once for pageload, and once for robots + // fetch. + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.LitePagesService.BypassResult", false, 2); + + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); + + // Load an image from different origin and that should not trigger robots + // rules fetch, since LitePages is blocked. + EXPECT_TRUE(RunScriptExtractBool(content::JsReplace( + "loadNewImage($1)", + https_test_server_.GetURL("differentorigin.com", + "/load_image/image.png?allowed")))); + FetchHistogramsFromChildProcesses(); + histogram_tester_.ExpectBucketCount( + "SubresourceRedirect.LitePagesService.BypassResult", true, 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.CompressionAttempt.ServerResponded", 0); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotRulesDecider.ApplyDuration", 1); + histogram_tester_.ExpectTotalCount( + "SubresourceRedirect.RobotsRules.Browser.InMemoryCacheHit", 1); + EXPECT_TRUE(RunScriptExtractBool("checkImage()")); + + // No more additional fetches. + robots_rules_server_.VerifyRequestedOrigins({GetHttpsTestURL("/").spec()}); + image_compression_server_.VerifyRequestedImagePaths( + {"/load_image/image.png"}); +} + +} // namespace subresource_redirect
diff --git a/chrome/browser/devtools/device/adb/adb_device_provider.cc b/chrome/browser/devtools/device/adb/adb_device_provider.cc index e6d0330f..fc21b61 100644 --- a/chrome/browser/devtools/device/adb/adb_device_provider.cc +++ b/chrome/browser/devtools/device/adb/adb_device_provider.cc
@@ -19,10 +19,10 @@ static void RunCommand(const std::string& serial, const std::string& command, - const AdbDeviceProvider::CommandCallback& callback) { + AdbDeviceProvider::CommandCallback callback) { std::string query = base::StringPrintf( kHostTransportCommand, serial.c_str(), command.c_str()); - AdbClientSocket::AdbQuery(kAdbPort, query, callback); + AdbClientSocket::AdbQuery(kAdbPort, query, std::move(callback)); } static void ReceivedAdbDevices(AdbDeviceProvider::SerialsCallback callback, @@ -54,7 +54,7 @@ void AdbDeviceProvider::QueryDeviceInfo(const std::string& serial, const DeviceInfoCallback& callback) { - AndroidDeviceManager::QueryDeviceInfo(base::Bind(&RunCommand, serial), + AndroidDeviceManager::QueryDeviceInfo(base::BindOnce(&RunCommand, serial), callback); }
diff --git a/chrome/browser/devtools/device/android_device_info_query.cc b/chrome/browser/devtools/device/android_device_info_query.cc index 29d9bec..3454e192 100644 --- a/chrome/browser/devtools/device/android_device_info_query.cc +++ b/chrome/browser/devtools/device/android_device_info_query.cc
@@ -356,10 +356,8 @@ } // static -void AndroidDeviceManager::QueryDeviceInfo( - const RunCommandCallback& command_callback, - const DeviceInfoCallback& callback) { - command_callback.Run( - kAllCommands, - base::Bind(&ReceivedResponse, callback)); +void AndroidDeviceManager::QueryDeviceInfo(RunCommandCallback command_callback, + const DeviceInfoCallback& callback) { + std::move(command_callback) + .Run(kAllCommands, base::BindOnce(&ReceivedResponse, callback)); }
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc index 923a2cf8..4bb9755 100644 --- a/chrome/browser/devtools/device/android_device_manager.cc +++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -74,11 +74,11 @@ static void PostCommandCallback( scoped_refptr<base::SingleThreadTaskRunner> response_task_runner, - const AndroidDeviceManager::CommandCallback& callback, + AndroidDeviceManager::CommandCallback callback, int result, const std::string& response) { - response_task_runner->PostTask(FROM_HERE, - base::BindOnce(callback, result, response)); + response_task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), result, response)); } static void PostHttpUpgradeCallback( @@ -99,14 +99,14 @@ typedef AndroidDeviceManager::HttpUpgradeCallback HttpUpgradeCallback; static void CommandRequest(const std::string& path, - const CommandCallback& callback, + CommandCallback callback, int result, std::unique_ptr<net::StreamSocket> socket) { if (result != net::OK) { - callback.Run(result, std::string()); + std::move(callback).Run(result, std::string()); return; } - new HttpRequest(std::move(socket), path, {}, callback); + new HttpRequest(std::move(socket), path, {}, std::move(callback)); } static void HttpUpgradeRequest(const std::string& path, @@ -133,9 +133,9 @@ HttpRequest(std::unique_ptr<net::StreamSocket> socket, const std::string& path, const std::map<std::string, std::string>& headers, - const CommandCallback& callback) + CommandCallback callback) : socket_(std::move(socket)), - command_callback_(callback), + command_callback_(std::move(callback)), expected_total_size_(0), header_size_(std::string::npos) { SendRequest(path, headers); @@ -260,7 +260,7 @@ const std::string& body = response_.substr(header_size_); if (!command_callback_.is_null()) { - command_callback_.Run(net::OK, body); + std::move(command_callback_).Run(net::OK, body); } else { http_upgrade_callback_.Run(net::OK, ExtractHeader("Sec-WebSocket-Extensions:"), @@ -296,7 +296,7 @@ if (result >= 0) return true; if (!command_callback_.is_null()) { - command_callback_.Run(result, std::string()); + std::move(command_callback_).Run(result, std::string()); } else { http_upgrade_callback_.Run(result, std::string(), std::string(), base::WrapUnique<net::StreamSocket>(nullptr)); @@ -416,9 +416,10 @@ const std::string& serial, const std::string& socket_name, const std::string& request, - const CommandCallback& callback) { + CommandCallback callback) { OpenSocket(serial, socket_name, - base::Bind(&HttpRequest::CommandRequest, request, callback)); + base::BindOnce(&HttpRequest::CommandRequest, request, + std::move(callback))); } void AndroidDeviceManager::DeviceProvider::HttpUpgrade( @@ -462,13 +463,14 @@ void AndroidDeviceManager::Device::SendJsonRequest( const std::string& socket_name, const std::string& request, - const CommandCallback& callback) { + CommandCallback callback) { task_runner_->PostTask( - FROM_HERE, base::BindOnce(&DeviceProvider::SendJsonRequest, provider_, - serial_, socket_name, request, - base::Bind(&PostCommandCallback, - base::ThreadTaskRunnerHandle::Get(), - callback))); + FROM_HERE, + base::BindOnce(&DeviceProvider::SendJsonRequest, provider_, serial_, + socket_name, request, + base::BindOnce(&PostCommandCallback, + base::ThreadTaskRunnerHandle::Get(), + std::move(callback)))); } void AndroidDeviceManager::Device::HttpUpgrade(
diff --git a/chrome/browser/devtools/device/android_device_manager.h b/chrome/browser/devtools/device/android_device_manager.h index 4ee6dbb..aa15898 100644 --- a/chrome/browser/devtools/device/android_device_manager.h +++ b/chrome/browser/devtools/device/android_device_manager.h
@@ -28,8 +28,7 @@ class AndroidDeviceManager { public: - using CommandCallback = - base::Callback<void(int, const std::string&)>; + using CommandCallback = base::OnceCallback<void(int, const std::string&)>; using SocketCallback = base::OnceCallback<void(int result, std::unique_ptr<net::StreamSocket>)>; // |body_head| should contain the body (WebSocket frame data) part that has @@ -120,7 +119,7 @@ void SendJsonRequest(const std::string& socket_name, const std::string& request, - const CommandCallback& callback); + CommandCallback callback); void HttpUpgrade(const std::string& socket_name, const std::string& path, @@ -172,10 +171,10 @@ const std::string& socket_name, SocketCallback callback) = 0; - virtual void SendJsonRequest(const std::string& serial, - const std::string& socket_name, - const std::string& request, - const CommandCallback& callback); + void SendJsonRequest(const std::string& serial, + const std::string& socket_name, + const std::string& request, + CommandCallback callback); virtual void HttpUpgrade(const std::string& serial, const std::string& socket_name, @@ -208,9 +207,9 @@ static std::string GetBrowserName(const std::string& socket, const std::string& package); using RunCommandCallback = - base::Callback<void(const std::string&, const CommandCallback&)>; + base::OnceCallback<void(const std::string&, CommandCallback)>; - static void QueryDeviceInfo(const RunCommandCallback& command_callback, + static void QueryDeviceInfo(RunCommandCallback command_callback, const DeviceInfoCallback& callback); struct DeviceDescriptor {
diff --git a/chrome/browser/devtools/device/usb/usb_device_provider.cc b/chrome/browser/devtools/device/usb/usb_device_provider.cc index 6e9e4e2..723eb18 100644 --- a/chrome/browser/devtools/device/usb/usb_device_provider.cc +++ b/chrome/browser/devtools/device/usb/usb_device_provider.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/devtools/device/usb/android_rsa.h" #include "chrome/browser/devtools/device/usb/android_usb_device.h" #include "crypto/rsa_private_key.h" +#include "net/base/completion_repeating_callback.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/socket/stream_socket.h" @@ -37,50 +38,52 @@ void OnRead(net::StreamSocket* socket, scoped_refptr<net::IOBuffer> buffer, const std::string& data, - const UsbDeviceProvider::CommandCallback& callback, + UsbDeviceProvider::CommandCallback callback, int result) { if (result <= 0) { - callback.Run(result, result == 0 ? data : std::string()); + std::move(callback).Run(result, result == 0 ? data : std::string()); delete socket; return; } std::string new_data = data + std::string(buffer->data(), result); - result = - socket->Read(buffer.get(), kBufferSize, - base::BindOnce(&OnRead, socket, buffer, new_data, callback)); + net::CompletionRepeatingCallback on_read = base::AdaptCallbackForRepeating( + base::BindOnce(&OnRead, socket, buffer, new_data, std::move(callback))); + result = socket->Read(buffer.get(), kBufferSize, on_read); if (result != net::ERR_IO_PENDING) - OnRead(socket, buffer, new_data, callback, result); + on_read.Run(result); } -void OpenedForCommand(const UsbDeviceProvider::CommandCallback& callback, +void OpenedForCommand(UsbDeviceProvider::CommandCallback callback, net::StreamSocket* socket, int result) { if (result != net::OK) { - callback.Run(result, std::string()); + std::move(callback).Run(result, std::string()); return; } scoped_refptr<net::IOBuffer> buffer = base::MakeRefCounted<net::IOBuffer>(kBufferSize); - result = socket->Read( - buffer.get(), kBufferSize, - base::BindOnce(&OnRead, socket, buffer, std::string(), callback)); + net::CompletionRepeatingCallback on_read = + base::AdaptCallbackForRepeating(base::BindOnce( + &OnRead, socket, buffer, std::string(), std::move(callback))); + result = socket->Read(buffer.get(), kBufferSize, on_read); if (result != net::ERR_IO_PENDING) - OnRead(socket, buffer, std::string(), callback, result); + on_read.Run(result); } void RunCommand(scoped_refptr<AndroidUsbDevice> device, const std::string& command, - const UsbDeviceProvider::CommandCallback& callback) { + UsbDeviceProvider::CommandCallback callback) { net::StreamSocket* socket = device->CreateSocket(command); if (!socket) { - callback.Run(net::ERR_CONNECTION_FAILED, std::string()); + std::move(callback).Run(net::ERR_CONNECTION_FAILED, std::string()); return; } + auto completion = base::AdaptCallbackForRepeating(std::move(callback)); int result = - socket->Connect(base::BindOnce(&OpenedForCommand, callback, socket)); + socket->Connect(base::BindOnce(&OpenedForCommand, completion, socket)); if (result != net::ERR_IO_PENDING) - callback.Run(result, std::string()); + completion.Run(result, std::string()); } } // namespace @@ -103,7 +106,7 @@ callback.Run(offline_info); return; } - AndroidDeviceManager::QueryDeviceInfo(base::Bind(&RunCommand, it->second), + AndroidDeviceManager::QueryDeviceInfo(base::BindOnce(&RunCommand, it->second), callback); }
diff --git a/chrome/browser/enterprise/connectors/common.cc b/chrome/browser/enterprise/connectors/common.cc index 5e78914a..c2f43fd 100644 --- a/chrome/browser/enterprise/connectors/common.cc +++ b/chrome/browser/enterprise/connectors/common.cc
@@ -15,10 +15,8 @@ AnalysisSettings::~AnalysisSettings() = default; ReportingSettings::ReportingSettings() = default; -ReportingSettings::ReportingSettings(GURL url, - const std::string& dm_token, - bool per_profile) - : reporting_url(url), dm_token(dm_token), per_profile(per_profile) {} +ReportingSettings::ReportingSettings(GURL url, const std::string& dm_token) + : reporting_url(url), dm_token(dm_token) {} ReportingSettings::ReportingSettings(ReportingSettings&&) = default; ReportingSettings& ReportingSettings::operator=(ReportingSettings&&) = default; ReportingSettings::~ReportingSettings() = default;
diff --git a/chrome/browser/enterprise/connectors/common.h b/chrome/browser/enterprise/connectors/common.h index 488b919a..e0450bf 100644 --- a/chrome/browser/enterprise/connectors/common.h +++ b/chrome/browser/enterprise/connectors/common.h
@@ -66,19 +66,13 @@ struct ReportingSettings { ReportingSettings(); - explicit ReportingSettings(GURL url, - const std::string& dm_token, - bool per_profile); + explicit ReportingSettings(GURL url, const std::string& dm_token); ReportingSettings(ReportingSettings&&); ReportingSettings& operator=(ReportingSettings&&); ~ReportingSettings(); GURL reporting_url; std::string dm_token; - - // Indicates if the report should be made for the profile, or the browser if - // false. - bool per_profile = false; }; // Returns the pref path corresponding to a connector.
diff --git a/chrome/browser/enterprise/connectors/connectors_service.cc b/chrome/browser/enterprise/connectors/connectors_service.cc index cfdf737..b4b379d 100644 --- a/chrome/browser/enterprise/connectors/connectors_service.cc +++ b/chrome/browser/enterprise/connectors/connectors_service.cc
@@ -7,20 +7,13 @@ #include "base/memory/singleton.h" #include "base/no_destructor.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/enterprise/connectors/connectors_manager.h" #include "chrome/browser/enterprise/connectors/service_provider_config.h" -#include "chrome/browser/enterprise/util/affiliation.h" -#include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "chrome/browser/policy/dm_token_utils.h" #include "chrome/browser/profiles/profile.h" -#include "components/enterprise/browser/controller/browser_dm_token_storage.h" #include "components/enterprise/common/proto/connectors.pb.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/policy/core/common/cloud/dm_token.h" -#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" -#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" #include "components/policy/core/common/policy_types.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/browser_context.h" @@ -30,9 +23,6 @@ const base::Feature kEnterpriseConnectorsEnabled{ "EnterpriseConnectorsEnabled", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kPerProfileConnectorsEnabled{ - "PerProfileConnectorsEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; - const char kServiceProviderConfig[] = R"({ "version": "1", "service_providers" : [ @@ -127,7 +117,7 @@ if (!ConnectorsEnabled()) return base::nullopt; - base::Optional<DmToken> dm_token = GetDmToken(ConnectorScopePref(connector)); + base::Optional<DmToken> dm_token = GetDmToken(ConnectorPref(connector)); if (!dm_token.has_value()) return base::nullopt; @@ -135,8 +125,6 @@ connectors_manager_->GetReportingSettings(connector); if (settings.has_value()) { settings.value().dm_token = dm_token.value().value; - settings.value().per_profile = - dm_token.value().scope == policy::POLICY_SCOPE_USER; } return settings; @@ -148,7 +136,7 @@ if (!ConnectorsEnabled()) return base::nullopt; - base::Optional<DmToken> dm_token = GetDmToken(ConnectorScopePref(connector)); + base::Optional<DmToken> dm_token = GetDmToken(ConnectorPref(connector)); if (!dm_token.has_value()) return base::nullopt; @@ -195,20 +183,10 @@ ConnectorsService::DmToken::~DmToken() = default; base::Optional<ConnectorsService::DmToken> ConnectorsService::GetDmToken( - const char* scope_pref) const { -#if defined(OS_CHROMEOS) - // On CrOS, the device must be affiliated to use the DM token for - // scanning/reporting so we always use the browser DM token. - return GetBrowserDmToken(); -#else - return GetPolicyScope(scope_pref) == policy::POLICY_SCOPE_USER - ? GetProfileDmToken() - : GetBrowserDmToken(); -#endif -} + const char* pref) { + // TODO(crbug.com/1148789): Add code to check the scope of |pref| and handle + // the "user" case. -base::Optional<ConnectorsService::DmToken> -ConnectorsService::GetBrowserDmToken() const { policy::DMToken dm_token = policy::GetDMToken(Profile::FromBrowserContext(context_)); @@ -218,60 +196,6 @@ return DmToken(dm_token.value(), policy::POLICY_SCOPE_MACHINE); } -#if !defined(OS_CHROMEOS) -base::Optional<ConnectorsService::DmToken> -ConnectorsService::GetProfileDmToken() const { - if (!base::FeatureList::IsEnabled(kPerProfileConnectorsEnabled)) - return base::nullopt; - - if (!CanUseProfileDmToken()) - return base::nullopt; - - policy::UserCloudPolicyManager* policy_manager = - Profile::FromBrowserContext(context_)->GetUserCloudPolicyManager(); - if (!policy_manager || !policy_manager->IsClientRegistered()) - return base::nullopt; - - return DmToken(policy_manager->core()->client()->dm_token(), - policy::POLICY_SCOPE_USER); -} - -bool ConnectorsService::CanUseProfileDmToken() const { - // If the browser isn't managed by CBCM, then the profile DM token can be - // used. - if (!policy::BrowserDMTokenStorage::Get()->RetrieveDMToken().is_valid()) - return true; - - policy::UserCloudPolicyManager* profile_policy_manager = - Profile::FromBrowserContext(context_)->GetUserCloudPolicyManager(); - policy::MachineLevelUserCloudPolicyManager* browser_policy_manager = - g_browser_process->browser_policy_connector() - ->machine_level_user_cloud_policy_manager(); - - if (!profile_policy_manager || !browser_policy_manager || - !profile_policy_manager->IsClientRegistered() || - !browser_policy_manager->IsClientRegistered()) { - return false; - } - - auto* profile_policy = profile_policy_manager->core()->store()->policy(); - auto* browser_policy = browser_policy_manager->core()->store()->policy(); - - if (!profile_policy || !browser_policy) - return false; - - return chrome::enterprise_util::IsProfileAffiliated(*profile_policy, - *browser_policy); -} -#endif // !defined(OS_CHROMEOS) - -policy::PolicyScope ConnectorsService::GetPolicyScope( - const char* scope_pref) const { - return static_cast<policy::PolicyScope>( - Profile::FromBrowserContext(context_)->GetPrefs()->GetInteger( - scope_pref)); -} - bool ConnectorsService::ConnectorsEnabled() const { if (!base::FeatureList::IsEnabled(kEnterpriseConnectorsEnabled)) return false;
diff --git a/chrome/browser/enterprise/connectors/connectors_service.h b/chrome/browser/enterprise/connectors/connectors_service.h index 47f4ccd..905d86c 100644 --- a/chrome/browser/enterprise/connectors/connectors_service.h +++ b/chrome/browser/enterprise/connectors/connectors_service.h
@@ -25,9 +25,6 @@ // ConnectorsManager. extern const base::Feature kEnterpriseConnectorsEnabled; -// Controls whether per-profile Enterprise Connector policies are applied. -extern const base::Feature kPerProfileConnectorsEnabled; - // For the moment, service provider configurations are static and only support // google endpoints. Therefore the configuration is placed here directly. // Once the configuration becomes more dynamic this static string will be @@ -74,26 +71,8 @@ // policy used to get a DM token. policy::PolicyScope scope; }; + base::Optional<DmToken> GetDmToken(const char* pref); - // Returns the DM token to use with the given |scope_pref|. That pref should - // contain either POLICY_SCOPE_MACHINE or POLICY_SCOPE_USER. - base::Optional<DmToken> GetDmToken(const char* scope_pref) const; - base::Optional<DmToken> GetBrowserDmToken() const; -#if !defined(OS_CHROMEOS) - base::Optional<DmToken> GetProfileDmToken() const; - - // Returns true if the browser isn't managed by CBCM, otherwise this checks if - // the affiliations IDs from the profile and browser policy fetching responses - // indicate that the same customer manages both. - bool CanUseProfileDmToken() const; -#endif - - // Returns the policy::PolicyScope stored in the given |scope_pref|. - policy::PolicyScope GetPolicyScope(const char* scope_pref) const; - - // Returns whether Connectors are enabled at all. This can be false if: - // - The kEnterpriseConnectorsEnabled feature is disabled - // - The profile is incognito bool ConnectorsEnabled() const; content::BrowserContext* context_;
diff --git a/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc b/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc deleted file mode 100644 index f372ad990..0000000 --- a/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc +++ /dev/null
@@ -1,326 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/enterprise/connectors/connectors_service.h" - -#include <memory> - -#include "base/json/json_reader.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/enterprise/connectors/common.h" -#include "chrome/browser/enterprise/connectors/connectors_prefs.h" -#include "chrome/browser/policy/chrome_browser_policy_connector.h" -#include "chrome/browser/policy/dm_token_utils.h" -#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h" -#include "chrome/browser/ui/browser.h" -#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" -#include "components/enterprise/browser/enterprise_switches.h" -#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" -#include "components/policy/core/common/cloud/mock_cloud_policy_client.h" -#include "components/policy/core/common/cloud/mock_cloud_policy_store.h" -#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" -#include "components/policy/core/common/policy_switches.h" -#include "content/public/test/browser_test.h" - -namespace enterprise_connectors { - -namespace { - -constexpr char kNormalAnalysisSettingsPref[] = R"([ - { - "service_provider": "google", - "enable": [ - {"url_list": ["*"], "tags": ["dlp", "malware"]} - ] - } -])"; - -constexpr char kNormalReportingSettingsPref[] = R"([ - { - "service_provider": "google" - } -])"; - -#if !defined(OS_CHROMEOS) -constexpr char kFakeProfileDMToken[] = "fake-profile-dm-token"; -constexpr char kFakeEnrollmentToken[] = "fake-enrollment-token"; -constexpr char kFakeBrowserClientId[] = "fake-browser-client-id"; -constexpr char kAffiliationId1[] = "affiliation-id-1"; -constexpr char kAffiliationId2[] = "affiliation-id-2"; -#endif - -constexpr char kFakeBrowserDMToken[] = "fake-browser-dm-token"; -constexpr char kTestUrl[] = "https://foo.com"; - -} // namespace - -// Profile DM token tests -// These tests validate that ConnectorsService obtains the correct DM token on -// each GetAnalysisSettings/GetReportingSettings call. There are 3 mains cases -// to validate here: -// -// - Affiliated: The profile and browser are managed by the same customer. In -// this case, it is OK to get the profile DM token and apply Connector policies. -// - Unaffiliated: The profile and browser are managed by different customers. -// In this case, no profile settings should be returned. -// - Unmanaged: The profile is managed by a customer while the browser is -// unmanaged. In this case, it is OK to get the profile DM token and apply -// Connector policies. -// -// The exception to the above rules is CrOS. Even when the policies are applied -// at a user scope, only the browser DM token should be returned. - -enum class ManagementStatus { AFFILIATED, UNAFFILIATED, UNMANAGED }; - -class ConnectorsServiceProfileBrowserTest - : public safe_browsing::DeepScanningBrowserTestBase { - public: - explicit ConnectorsServiceProfileBrowserTest( - ManagementStatus management_status) - : management_status_(management_status) { - if (management_status_ != ManagementStatus::UNMANAGED) { -#if defined(OS_CHROMEOS) - policy::SetDMTokenForTesting( - policy::DMToken::CreateValidTokenForTesting(kFakeBrowserDMToken)); -#else - browser_dm_token_storage_ = - std::make_unique<policy::FakeBrowserDMTokenStorage>(); - browser_dm_token_storage_->SetEnrollmentToken(kFakeEnrollmentToken); - browser_dm_token_storage_->SetClientId(kFakeBrowserClientId); - browser_dm_token_storage_->EnableStorage(true); - browser_dm_token_storage_->SetDMToken(kFakeBrowserDMToken); - policy::BrowserDMTokenStorage::SetForTesting( - browser_dm_token_storage_.get()); -#endif - } - - // Set the required features for the per-profile feature to work. - scoped_feature_list_.Reset(); - scoped_feature_list_.InitWithFeatures( - {kEnterpriseConnectorsEnabled, kPerProfileConnectorsEnabled}, {}); - } - -#if !defined(OS_CHROMEOS) - void SetUpOnMainThread() override { - safe_browsing::DeepScanningBrowserTestBase::SetUpOnMainThread(); - - auto client = std::make_unique<policy::MockCloudPolicyClient>(); - client->SetDMToken(kFakeProfileDMToken); - browser()->profile()->GetUserCloudPolicyManager()->Connect( - g_browser_process->local_state(), std::move(client)); - - // Set profile/browser affiliation IDs. - auto* profile_policy_manager = - browser()->profile()->GetUserCloudPolicyManager(); - auto* mock_profile_store = static_cast<policy::MockCloudPolicyStore*>( - profile_policy_manager->core()->store()); - mock_profile_store->policy_ = - std::make_unique<enterprise_management::PolicyData>(); - mock_profile_store->policy_->add_user_affiliation_ids(kAffiliationId1); - - if (management_status_ != ManagementStatus::UNMANAGED) { - auto* browser_policy_manager = - g_browser_process->browser_policy_connector() - ->machine_level_user_cloud_policy_manager(); - auto* mock_browser_store = static_cast<policy::MockCloudPolicyStore*>( - browser_policy_manager->core()->store()); - mock_browser_store->policy_ = - std::make_unique<enterprise_management::PolicyData>(); - mock_browser_store->policy_->add_device_affiliation_ids( - management_status() == ManagementStatus::AFFILIATED - ? kAffiliationId1 - : kAffiliationId2); - } - } - -#if !BUILDFLAG(GOOGLE_CHROME_BRANDING) - void SetUpDefaultCommandLine(base::CommandLine* command_line) override { - InProcessBrowserTest::SetUpDefaultCommandLine(command_line); - command_line->AppendSwitch(::switches::kEnableChromeBrowserCloudManagement); - } -#endif - -#endif // !defined(OS_CHROMEOS) - - void SetPrefs(const char* pref, - const char* scope_pref, - const char* pref_value) { - browser()->profile()->GetPrefs()->Set(pref, - *base::JSONReader::Read(pref_value)); - browser()->profile()->GetPrefs()->SetInteger(scope_pref, - policy::POLICY_SCOPE_USER); - } - - ManagementStatus management_status() { return management_status_; } - - protected: - std::unique_ptr<policy::FakeBrowserDMTokenStorage> browser_dm_token_storage_; - ManagementStatus management_status_; -}; - -class ConnectorsServiceReportingProfileBrowserTest - : public ConnectorsServiceProfileBrowserTest, - public testing::WithParamInterface< - std::tuple<ReportingConnector, ManagementStatus>> { - public: - ConnectorsServiceReportingProfileBrowserTest() - : ConnectorsServiceProfileBrowserTest(std::get<1>(GetParam())) {} - ReportingConnector connector() { return std::get<0>(GetParam()); } -}; - -INSTANTIATE_TEST_SUITE_P( - , - ConnectorsServiceReportingProfileBrowserTest, - testing::Combine(testing::Values(ReportingConnector::SECURITY_EVENT), - testing::Values(ManagementStatus::AFFILIATED, - ManagementStatus::UNAFFILIATED, - ManagementStatus::UNMANAGED))); - -IN_PROC_BROWSER_TEST_P(ConnectorsServiceReportingProfileBrowserTest, Test) { - SetPrefs(ConnectorPref(connector()), ConnectorScopePref(connector()), - kNormalReportingSettingsPref); - - auto settings = - ConnectorsServiceFactory::GetForBrowserContext(browser()->profile()) - ->GetReportingSettings(connector()); -#if defined(OS_CHROMEOS) - if (management_status() == ManagementStatus::UNMANAGED) { - ASSERT_FALSE(settings.has_value()); - } else { - ASSERT_TRUE(settings.has_value()); - ASSERT_FALSE(settings.value().per_profile); - ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token); - } -#else - switch (management_status()) { - case ManagementStatus::AFFILIATED: - EXPECT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token); - ASSERT_TRUE(settings.value().per_profile); - break; - case ManagementStatus::UNAFFILIATED: - EXPECT_FALSE(settings.has_value()); - break; - case ManagementStatus::UNMANAGED: - EXPECT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token); - ASSERT_TRUE(settings.value().per_profile); - break; - } -#endif -} - -class ConnectorsServiceAnalysisProfileBrowserTest - : public ConnectorsServiceProfileBrowserTest, - public testing::WithParamInterface< - std::tuple<AnalysisConnector, ManagementStatus>> { - public: - ConnectorsServiceAnalysisProfileBrowserTest() - : ConnectorsServiceProfileBrowserTest(std::get<1>(GetParam())) {} - AnalysisConnector connector() { return std::get<0>(GetParam()); } -}; - -INSTANTIATE_TEST_SUITE_P( - , - ConnectorsServiceAnalysisProfileBrowserTest, - testing::Combine( - testing::Values(FILE_ATTACHED, FILE_DOWNLOADED, BULK_DATA_ENTRY), - testing::Values(ManagementStatus::AFFILIATED, - ManagementStatus::UNAFFILIATED, - ManagementStatus::UNMANAGED))); - -IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest, Test) { - SetPrefs(ConnectorPref(connector()), ConnectorScopePref(connector()), - kNormalAnalysisSettingsPref); - auto settings = - ConnectorsServiceFactory::GetForBrowserContext(browser()->profile()) - ->GetAnalysisSettings(GURL(kTestUrl), connector()); - -#if defined(OS_CHROMEOS) - if (management_status() == ManagementStatus::UNMANAGED) { - ASSERT_FALSE(settings.has_value()); - } else { - ASSERT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token); - } -#else - switch (management_status()) { - case ManagementStatus::AFFILIATED: - EXPECT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token); - break; - case ManagementStatus::UNAFFILIATED: - EXPECT_FALSE(settings.has_value()); - break; - case ManagementStatus::UNMANAGED: - EXPECT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token); - break; - } -#endif -} - -// This test validates that no settings are obtained when -// kPerProfileConnectorsEnabled is disabled. CrOS is unaffected as it only gets -// the browser token if it is present. -class ConnectorsServiceNoProfileFeatureBrowserTest - : public ConnectorsServiceProfileBrowserTest, - public testing::WithParamInterface<ManagementStatus> { - public: - ConnectorsServiceNoProfileFeatureBrowserTest() - : ConnectorsServiceProfileBrowserTest(GetParam()) { - scoped_feature_list_.Reset(); - scoped_feature_list_.InitWithFeatures({kEnterpriseConnectorsEnabled}, - {kPerProfileConnectorsEnabled}); - } -}; - -INSTANTIATE_TEST_SUITE_P(, - ConnectorsServiceNoProfileFeatureBrowserTest, - testing::Values(ManagementStatus::AFFILIATED, - ManagementStatus::UNAFFILIATED, - ManagementStatus::UNMANAGED)); - -IN_PROC_BROWSER_TEST_P(ConnectorsServiceNoProfileFeatureBrowserTest, Test) { - for (auto connector : {FILE_ATTACHED, FILE_DOWNLOADED, BULK_DATA_ENTRY}) { - SetPrefs(ConnectorPref(connector), ConnectorScopePref(connector), - kNormalAnalysisSettingsPref); - } - SetPrefs(ConnectorPref(ReportingConnector::SECURITY_EVENT), - ConnectorScopePref(ReportingConnector::SECURITY_EVENT), - kNormalReportingSettingsPref); - - for (auto connector : {FILE_ATTACHED, FILE_DOWNLOADED, BULK_DATA_ENTRY}) { - auto settings = - ConnectorsServiceFactory::GetForBrowserContext(browser()->profile()) - ->GetAnalysisSettings(GURL(kTestUrl), connector); -#if defined(OS_CHROMEOS) - if (management_status() == ManagementStatus::UNMANAGED) { - ASSERT_FALSE(settings.has_value()); - } else { - ASSERT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token); - } -#else - EXPECT_FALSE(settings.has_value()); -#endif - } - - auto settings = - ConnectorsServiceFactory::GetForBrowserContext(browser()->profile()) - ->GetReportingSettings(ReportingConnector::SECURITY_EVENT); -#if defined(OS_CHROMEOS) - if (management_status() == ManagementStatus::UNMANAGED) { - ASSERT_FALSE(settings.has_value()); - } else { - ASSERT_TRUE(settings.has_value()); - ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token); - ASSERT_FALSE(settings.value().per_profile); - } -#else - EXPECT_FALSE(settings.has_value()); -#endif -} - -} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/connectors_service_unittest.cc b/chrome/browser/enterprise/connectors/connectors_service_unittest.cc index ce205407..95599dc 100644 --- a/chrome/browser/enterprise/connectors/connectors_service_unittest.cc +++ b/chrome/browser/enterprise/connectors/connectors_service_unittest.cc
@@ -11,7 +11,6 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/enterprise/common/proto/connectors.pb.h" -#include "components/policy/core/common/policy_types.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -131,8 +130,6 @@ const char* pref() const { return ConnectorPref(connector()); } - const char* scope_pref() const { return ConnectorScopePref(connector()); } - const char* pref_value() const { switch (policy_value()) { case 1: @@ -158,11 +155,8 @@ }; TEST_P(ConnectorsServiceReportingFeatureTest, Test) { - if (policy_value() != 0) { + if (policy_value() != 0) profile_->GetPrefs()->Set(pref(), *base::JSONReader::Read(pref_value())); - profile_->GetPrefs()->SetInteger(scope_pref(), - policy::POLICY_SCOPE_MACHINE); - } auto settings = ConnectorsServiceFactory::GetForBrowserContext(profile_) ->GetReportingSettings(connector());
diff --git a/chrome/browser/enterprise/connectors/content_analysis_delegate_browsertest.cc b/chrome/browser/enterprise/connectors/content_analysis_delegate_browsertest.cc index 9e98020..17715d1 100644 --- a/chrome/browser/enterprise/connectors/content_analysis_delegate_browsertest.cc +++ b/chrome/browser/enterprise/connectors/content_analysis_delegate_browsertest.cc
@@ -443,6 +443,8 @@ }), safe_browsing::DeepScanAccessPoint::PASTE); + // 2 responses are needed: 1 for pasting and 1 for reporting. + FakeBinaryUploadServiceStorage()->ReturnAuthorizedResponse(); FakeBinaryUploadServiceStorage()->ReturnAuthorizedResponse(); run_loop.Run();
diff --git a/chrome/browser/enterprise/util/affiliation.cc b/chrome/browser/enterprise/util/affiliation.cc deleted file mode 100644 index 506d164a..0000000 --- a/chrome/browser/enterprise/util/affiliation.cc +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/enterprise/util/affiliation.h" -#include <set> - -namespace chrome { -namespace enterprise_util { - -bool IsProfileAffiliated( - const enterprise_management::PolicyData& profile_policy, - const enterprise_management::PolicyData& browser_policy) { - std::set<std::string> profile_affiliation_ids; - profile_affiliation_ids.insert(profile_policy.user_affiliation_ids().begin(), - profile_policy.user_affiliation_ids().end()); - for (const std::string& browser_affiliation_id : - browser_policy.device_affiliation_ids()) { - if (profile_affiliation_ids.count(browser_affiliation_id)) - return true; - } - return false; -} - -} // namespace enterprise_util -} // namespace chrome
diff --git a/chrome/browser/enterprise/util/affiliation.h b/chrome/browser/enterprise/util/affiliation.h deleted file mode 100644 index 55de0787..0000000 --- a/chrome/browser/enterprise/util/affiliation.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_ENTERPRISE_UTIL_AFFILIATION_H_ -#define CHROME_BROWSER_ENTERPRISE_UTIL_AFFILIATION_H_ - -#include "device_management_backend.pb.h" - -namespace chrome { -namespace enterprise_util { - -// Returns true if the profile and browser are managed by the same customer -// (affiliated). This is determined by comparing affiliation IDs obtained in the -// policy fetching response. If either policies has no affiliation IDs, this -// function returns false. -bool IsProfileAffiliated( - const enterprise_management::PolicyData& profile_policy, - const enterprise_management::PolicyData& browser_policy); - -} // namespace enterprise_util -} // namespace chrome - -#endif // CHROME_BROWSER_ENTERPRISE_UTIL_AFFILIATION_H_
diff --git a/chrome/browser/enterprise/util/affiliation_unittest.cc b/chrome/browser/enterprise/util/affiliation_unittest.cc deleted file mode 100644 index 5ff9096..0000000 --- a/chrome/browser/enterprise/util/affiliation_unittest.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/enterprise/util/affiliation.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace chrome { -namespace enterprise_util { - -namespace { -const char kAffiliationID1[] = "id1"; -const char kAffiliationID2[] = "id2"; -} // namespace - -TEST(BrowserAffiliationTest, Affiliated) { - enterprise_management::PolicyData profile_policy; - profile_policy.add_user_affiliation_ids(kAffiliationID1); - enterprise_management::PolicyData browser_policy; - browser_policy.add_device_affiliation_ids(kAffiliationID1); - - EXPECT_TRUE(IsProfileAffiliated(profile_policy, browser_policy)); -} - -TEST(BrowserAffiliationTest, Unaffiliated) { - enterprise_management::PolicyData profile_policy; - profile_policy.add_user_affiliation_ids(kAffiliationID1); - enterprise_management::PolicyData browser_policy; - browser_policy.add_device_affiliation_ids(kAffiliationID2); - - EXPECT_FALSE(IsProfileAffiliated(profile_policy, browser_policy)); -} - -TEST(BrowserAffiliationTest, BrowserPolicyEmpty) { - enterprise_management::PolicyData profile_policy; - profile_policy.add_user_affiliation_ids(kAffiliationID1); - enterprise_management::PolicyData browser_policy; - - EXPECT_FALSE(IsProfileAffiliated(profile_policy, browser_policy)); -} - -TEST(BrowserAffiliationTest, ProfilePolicyEmpty) { - enterprise_management::PolicyData profile_policy; - enterprise_management::PolicyData browser_policy; - browser_policy.add_device_affiliation_ids(kAffiliationID2); - - EXPECT_FALSE(IsProfileAffiliated(profile_policy, browser_policy)); -} - -} // namespace enterprise_util -} // namespace chrome
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc index 8996cdb..beffad4a 100644 --- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc +++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -52,6 +52,7 @@ : processor_(base::MakeRefCounted<MockChromeJsErrorReportProcessor>()), previous_(JsErrorReportProcessor::Get()) { processor_->SetCrashEndpoint(endpoint.GetCrashEndpointURL()); + processor_->SetCrashEndpointStaging(endpoint.GetCrashEndpointURL()); processor_->SetAsDefault(); }
diff --git a/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc b/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc new file mode 100644 index 0000000..089da33 --- /dev/null +++ b/chrome/browser/error_reporting/webui_js_error_reporting_browsertest.cc
@@ -0,0 +1,109 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/page_transition_types.h" +#include "ui/events/keycodes/dom/dom_code.h" +#include "ui/events/keycodes/dom/dom_key.h" +#include "ui/events/keycodes/keyboard_codes.h" + +using ::testing::HasSubstr; + +class WebUIJSErrorReportingTest : public InProcessBrowserTest { + public: + void SetUpInProcessBrowserTestFixture() override { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kSendWebUIJavaScriptErrorReports, + {{features::kSendWebUIJavaScriptErrorReportsSendToProductionVariation, + "true"}}); + InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(WebUIJSErrorReportingTest, ReportsErrors) { + // mock_processor must be after BrowserProcessImpl::PreMainMessageLoopRun, so + // it can't be created in SetUp or SetUpInProcessBrowserTestFixture. + // Similarly, MockCrashEndpoint must be in the test function so that its + // MockCrashEndpoint::Client is not replaced by other crash clients. + MockCrashEndpoint endpoint(embedded_test_server()); + ScopedMockChromeJsErrorReportProcessor mock_processor(endpoint); + + GURL url(chrome::kChromeUIWebUIJsErrorURL); + ASSERT_TRUE(url.is_valid()); + NavigateParams navigate(browser(), url, ui::PAGE_TRANSITION_TYPED); + ui_test_utils::NavigateToURL(&navigate); + + // Look for page load error report. + MockCrashEndpoint::Report report = endpoint.WaitForReport(); + EXPECT_EQ(endpoint.report_count(), 1); + // Must match message in + // chrome/browser/resources/webui_js_error/webui_js_error.js, but with URL + // escapes. + constexpr char kPageLoadMessage[] = + "WebUI%20JS%20Error%3A%20printing%20error%20on%20page%20load"; + EXPECT_THAT(report.query, HasSubstr(kPageLoadMessage)); + // Expect that we get a good stack trace as well + EXPECT_THAT(report.content, AllOf(HasSubstr("logsErrorDuringPageLoadOuter"), + HasSubstr("logsErrorDuringPageLoadInner"))); + + endpoint.clear_last_report(); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + // Trigger uncaught exception. Simulating mouse clicks on a button requires + // there to not be CSP on the JavaScript, so use accesskeys instead. + content::SimulateKeyPress(web_contents, ui::DomKey::NONE, ui::DomCode::US_T, + ui::VKEY_T, /*control=*/false, /*shift=*/false, + /*alt=*/true, /*command=*/false); + report = endpoint.WaitForReport(); + EXPECT_EQ(endpoint.report_count(), 2); + constexpr char kExceptionButtonMessage[] = + "WebUI%20JS%20Error%3A%20exception%20button%20clicked"; + EXPECT_THAT(report.query, HasSubstr(kExceptionButtonMessage)); + EXPECT_THAT(report.content, AllOf(HasSubstr("throwExceptionHandler"), + HasSubstr("throwExceptionInner"))); + + endpoint.clear_last_report(); + // Trigger console.error call. + content::SimulateKeyPress(web_contents, ui::DomKey::NONE, ui::DomCode::US_L, + ui::VKEY_L, /*control=*/false, /*shift=*/false, + /*alt=*/true, /*command=*/false); + report = endpoint.WaitForReport(); + EXPECT_EQ(endpoint.report_count(), 3); + constexpr char kTriggeredErrorMessage[] = + "WebUI%20JS%20Error%3A%20printing%20error%20on%20button%20click"; + EXPECT_THAT(report.query, HasSubstr(kTriggeredErrorMessage)); + EXPECT_THAT(report.content, + AllOf(HasSubstr("logsErrorFromButtonClickHandler"), + HasSubstr("logsErrorFromButtonClickInner"))); + + endpoint.clear_last_report(); + // Trigger unhandled promise rejection. + content::SimulateKeyPress(web_contents, ui::DomKey::NONE, ui::DomCode::US_P, + ui::VKEY_P, /*control=*/false, /*shift=*/false, + /*alt=*/true, /*command=*/false); + report = endpoint.WaitForReport(); + EXPECT_EQ(endpoint.report_count(), 4); + constexpr char kUnhandledPromiseRejectionMessage[] = + "WebUI%20JS%20Error%3A%20The%20rejector%20always%20rejects!"; + EXPECT_THAT(report.query, HasSubstr(kUnhandledPromiseRejectionMessage)); + // V8 doesn't produce stacks for unhandle promise rejections. +}
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc index 6bf0e285..198de57 100644 --- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc +++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -84,11 +84,11 @@ namespace { void StoreDigest(std::vector<uint8_t>* digest, - const base::Closure& callback, + base::OnceClosure callback, base::Value value) { ASSERT_TRUE(value.is_blob()) << "Unexpected value in StoreDigest"; digest->assign(value.GetBlob().begin(), value.GetBlob().end()); - callback.Run(); + std::move(callback).Run(); } bool RsaSignRawData(uint16_t openssl_signature_algorithm,
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc index dac0359..daaf9b5 100644 --- a/chrome/browser/extensions/api/permissions/permissions_api.cc +++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -319,8 +319,8 @@ install_ui_.reset(new ExtensionInstallPrompt( Profile::FromBrowserContext(browser_context()), native_window)); install_ui_->ShowDialog( - base::Bind(&PermissionsRequestFunction::OnInstallPromptDone, - base::RetainedRef(this)), + base::BindOnce(&PermissionsRequestFunction::OnInstallPromptDone, + base::RetainedRef(this)), extension(), nullptr, std::make_unique<ExtensionInstallPrompt::Prompt>( ExtensionInstallPrompt::PERMISSIONS_PROMPT),
diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc index 1e36e2cd..837b4c7 100644 --- a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc +++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
@@ -253,8 +253,9 @@ extensions::ExtensionUpdater::CheckParams params; params.ids = {extension_id}; - params.callback = base::Bind(&ChromeRuntimeAPIDelegate::UpdateCheckComplete, - base::Unretained(this), extension_id); + params.callback = + base::BindOnce(&ChromeRuntimeAPIDelegate::UpdateCheckComplete, + base::Unretained(this), extension_id); updater->CheckNow(std::move(params)); } return true;
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc index 4a27346..3c78fc6 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -912,10 +912,16 @@ Profile::FromBrowserContext(context_)); } + auto settings = + enterprise_connectors::ConnectorsServiceFactory::GetForBrowserContext( + context_) + ->GetReportingSettings( + enterprise_connectors::ReportingConnector::SECURITY_EVENT); + // TODO(crbug/1069049): Use reporting URL. - if (binary_upload_service_) + if (binary_upload_service_ && settings.has_value()) binary_upload_service_->IsAuthorized( - GURL(), std::move(cont), + GURL(), std::move(cont), settings.value().dm_token, enterprise_connectors::AnalysisConnector:: ANALYSIS_CONNECTOR_UNSPECIFIED); }
diff --git a/chrome/browser/extensions/api/socket/udp_socket_unittest.cc b/chrome/browser/extensions/api/socket/udp_socket_unittest.cc index e25c6ddb..48b848c 100644 --- a/chrome/browser/extensions/api/socket/udp_socket_unittest.cc +++ b/chrome/browser/extensions/api/socket/udp_socket_unittest.cc
@@ -140,7 +140,7 @@ // Send a test multicast packet every second. // Once the target socket received the packet, the message loop will exit. -static void SendMulticastPacket(const base::Closure& quit_run_loop, +static void SendMulticastPacket(base::OnceClosure quit_run_loop, UDPSocket* src, int result) { if (result == 0) { @@ -149,15 +149,16 @@ src->Write(data, kTestMessageLength, base::BindOnce(&OnSendCompleted)); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, - base::BindOnce(&SendMulticastPacket, quit_run_loop, src, result), + base::BindOnce(&SendMulticastPacket, std::move(quit_run_loop), src, + result), base::TimeDelta::FromSeconds(1)); } else { - quit_run_loop.Run(); + std::move(quit_run_loop).Run(); FAIL() << "Failed to connect to multicast address. Error code: " << result; } } -static void OnMulticastReadCompleted(const base::Closure& quit_run_loop, +static void OnMulticastReadCompleted(base::OnceClosure quit_run_loop, bool* packet_received, int count, scoped_refptr<net::IOBuffer> io_buffer, @@ -167,7 +168,7 @@ EXPECT_EQ(kTestMessageLength, count); EXPECT_EQ(0, strncmp(io_buffer->data(), kTestMessage, kTestMessageLength)); *packet_received = true; - quit_run_loop.Run(); + std::move(quit_run_loop).Run(); } TEST_F(UDPSocketUnitTest, TestUDPMulticastRecv) {
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc index 6e45e43..b5a52ba 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -194,7 +194,7 @@ public: WebNavigationApiTest() { embedded_test_server()->RegisterRequestHandler( - base::Bind(&HandleTestRequest)); + base::BindRepeating(&HandleTestRequest)); } ~WebNavigationApiTest() override {}
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc index d5ddb85..3e5a4ac6 100644 --- a/chrome/browser/extensions/content_script_apitest.cc +++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -1081,7 +1081,7 @@ [](const content::WebContentsConsoleObserver::Message& message) { return message.message == base::ASCIIToUTF16("TestMessage"); }; - observer.SetFilter(base::Bind(filter)); + observer.SetFilter(base::BindRepeating(filter)); ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL(host, "/simple.html")); ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
diff --git a/chrome/browser/extensions/extension_install_prompt_unittest.cc b/chrome/browser/extensions/extension_install_prompt_unittest.cc index cf723e8..5c9e256 100644 --- a/chrome/browser/extensions/extension_install_prompt_unittest.cc +++ b/chrome/browser/extensions/extension_install_prompt_unittest.cc
@@ -63,7 +63,7 @@ } void VerifyPromptWithholdingUICallback( - base::Closure quit_closure, + base::OnceClosure quit_closure, const bool should_display, ExtensionInstallPromptShowParams* params, ExtensionInstallPrompt::DoneCallback done_callback, @@ -73,10 +73,10 @@ } void SetImage(gfx::Image* image_out, - const base::Closure& quit_closure, + base::OnceClosure quit_closure, const gfx::Image& image_in) { *image_out = image_in; - quit_closure.Run(); + std::move(quit_closure).Run(); } class ExtensionInstallPromptUnitTest : public testing::Test {
diff --git a/chrome/browser/extensions/extension_with_management_policy_apitest.cc b/chrome/browser/extensions/extension_with_management_policy_apitest.cc index 4d6186d..6c50dd9d 100644 --- a/chrome/browser/extensions/extension_with_management_policy_apitest.cc +++ b/chrome/browser/extensions/extension_with_management_policy_apitest.cc
@@ -13,9 +13,9 @@ void ExtensionApiTestWithManagementPolicy::SetUpInProcessBrowserTestFixture() { extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture(); - embedded_test_server()->RegisterRequestMonitor( - base::Bind(&ExtensionApiTestWithManagementPolicy::MonitorRequestHandler, - base::Unretained(this))); + embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( + &ExtensionApiTestWithManagementPolicy::MonitorRequestHandler, + base::Unretained(this))); ON_CALL(policy_provider_, IsInitializationComplete(testing::_)) .WillByDefault(testing::Return(true)); ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_))
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index de35bbc7..c38a765 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -3358,12 +3358,12 @@ { "name": "mixed-forms-disable-autofill", "owners": [ "carlosil" ], - "expiry_milestone": 88 + "expiry_milestone": 92 }, { "name": "mixed-forms-interstitial", "owners": [ "carlosil" ], - "expiry_milestone": 88 + "expiry_milestone": 92 }, { "name": "mobile-google-srp", @@ -4597,6 +4597,11 @@ "expiry_milestone": 90 }, { + "name": "stylus-battery-status", + "owners": ["amehfooz"], + "expiry_milestone": 91 + }, + { "name": "suggested-content-toggle", "owners": [ "jiameng", "wrong" ], "expiry_milestone": 88 @@ -5064,6 +5069,11 @@ "expiry_milestone": 89 }, { + "name": "xsurface-metrics-reporting", + "owners": [ "//chrom/android/feed/OWNERS", "feed@chromium.org" ], + "expiry_milestone": 99 + }, + { "name": "zero-copy-video-capture", "owners": [ // For CrOS
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 3cdbede..149f46d 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2283,6 +2283,12 @@ "keyboard shortcuts and have the events routed directly to the website " "when in fullscreen mode."; +const char kStylusBatteryStatusName[] = + "Show stylus battery stylus in the stylus tools menu"; +const char kStylusBatteryStatusDescription[] = + "Enables viewing the current stylus battery level in the stylus tools " + "menu."; + const char kSystemTrayMicGainName[] = "Modify mic gain in the system tray"; const char kSystemTrayMicGainDescription[] = "Enables mic gain settings in the system tray audio " @@ -3334,6 +3340,10 @@ const char kWebFeedDescription[] = "Allows users to keep up with and consume web content."; +const char kXsurfaceMetricsReportingName[] = "Xsurface Metrics Reporting"; +const char kXsurfaceMetricsReportingDescription[] = + "Allows metrics reporting state to be passed to Xsurface"; + // Non-Android ----------------------------------------------------------------- #else // !defined(OS_ANDROID)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index fc408ce6..42b32613 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1307,6 +1307,9 @@ extern const char kStrictOriginIsolationName[]; extern const char kStrictOriginIsolationDescription[]; +extern const char kStylusBatteryStatusName[]; +extern const char kStylusBatteryStatusDescription[]; + extern const char kSystemKeyboardLockName[]; extern const char kSystemKeyboardLockDescription[]; @@ -1921,6 +1924,9 @@ extern const char kWebFeedName[]; extern const char kWebFeedDescription[]; +extern const char kXsurfaceMetricsReportingName[]; +extern const char kXsurfaceMetricsReportingDescription[]; + // Non-Android ---------------------------------------------------------------- #else // !defined(OS_ANDROID)
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 741de7bc..1d2d51f3 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -117,6 +117,7 @@ &feed::kInterestFeedV2, &feed::kReportFeedUserActions, &feed::kWebFeed, + &feed::kXsurfaceMetricsReporting, &history::kHideFromApi3Transitions, &kAdjustWebApkInstallationSpace, &kAllowNewIncognitoTabIntents,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java index 3cc5de06..96eebafc 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -218,6 +218,10 @@ @VisibleForTesting public static void setOverrideTestValue(String preferenceKey, String overrideValue) { + if (sOverridesTestFeatures == null) { + sOverridesTestFeatures = new HashMap<>(); + } + sOverridesTestFeatures.put(preferenceKey, overrideValue); }
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index b83459d..84bf92a 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -476,6 +476,7 @@ public static final String WEB_AUTH = "WebAuthentication"; public static final String WEB_AUTH_PHONE_SUPPORT = "WebAuthenticationPhoneSupport"; public static final String WEB_FEED = "WebFeed"; + public static final String XSURFACE_METRICS_REPORTING = "XsurfaceMetricsReporting"; @NativeMethods interface Natives {
diff --git a/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl b/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl index 3af943a..dab93a6 100644 --- a/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl +++ b/chrome/browser/flags/android/java_templates/ChromeSwitches.java.tmpl
@@ -33,6 +33,9 @@ /** Disable the First Run Experience. */ public static final String DISABLE_FIRST_RUN_EXPERIENCE = "disable-fre"; + /** Disable promos shown on startup. */ + public static final String DISABLE_STARTUP_PROMOS = "disable-startup-promos-for-testing"; + /** * Forces the First Run Experience (FRE) flow complete check to always return true. */
diff --git a/chrome/browser/history/android/sqlite_cursor.cc b/chrome/browser/history/android/sqlite_cursor.cc index efb8a7b..348c48f 100644 --- a/chrome/browser/history/android/sqlite_cursor.cc +++ b/chrome/browser/history/android/sqlite_cursor.cc
@@ -79,8 +79,9 @@ const JavaParamRef<jobject>& obj, jint column) { base::string16 value = statement_->statement()->ColumnString16(column); - return ScopedJavaLocalRef<jstring>(env, - env->NewString(value.data(), value.size())); + return ScopedJavaLocalRef<jstring>( + env, env->NewString(reinterpret_cast<const jchar*>(value.data()), + value.size())); } jlong SQLiteCursor::GetLong(JNIEnv* env,
diff --git a/chrome/browser/login_detection/login_detection_browsertest.cc b/chrome/browser/login_detection/login_detection_browsertest.cc new file mode 100644 index 0000000..50764072 --- /dev/null +++ b/chrome/browser/login_detection/login_detection_browsertest.cc
@@ -0,0 +1,85 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/feature_list.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/login_detection/login_detection_tab_helper.h" +#include "chrome/browser/login_detection/login_detection_type.h" +#include "chrome/browser/login_detection/login_detection_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/site_isolation/features.h" +#include "components/ukm/test_ukm_recorder.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace login_detection { + +class LoginDetectionBrowserTest : public InProcessBrowserTest { + public: + LoginDetectionBrowserTest() { + scoped_feature_list_.InitWithFeaturesAndParameters( + {{kLoginDetection, {}}, + {site_isolation::features::kSiteIsolationForPasswordSites, {}}}, + {}); + } + + void SetUpOnMainThread() override { + embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); + ASSERT_TRUE(embedded_test_server()->Start()); + histogram_tester_ = std::make_unique<base::HistogramTester>(); + } + + void ResetHistogramTester() { + histogram_tester_ = std::make_unique<base::HistogramTester>(); + } + + // Verifies the histograms for the given login detection type to be recorded. + void ExpectLoginDetectionTypeMetric(LoginDetectionType type) { + histogram_tester_->ExpectUniqueSample("Login.PageLoad.DetectionType", type, + 1); + } + + protected: + std::unique_ptr<base::HistogramTester> histogram_tester_; + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Verifies that sites saved manual passworded list are detected correctly. +IN_PROC_BROWSER_TEST_F(LoginDetectionBrowserTest, + NavigateToManualPasswordedSite) { + GURL test_url( + embedded_test_server()->GetURL("www.saved.com", "/title1.html")); + + // Initial navigation will not be treated as no login. + ui_test_utils::NavigateToURL(browser(), test_url); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kNoLogin); + + // Use site-isolaiton to save the site to manual passworded list. + content::SiteInstance::StartIsolatingSite(browser()->profile(), test_url); + + // Subsequent navigation be detected as login. + ResetHistogramTester(); + ui_test_utils::NavigateToURL(browser(), test_url); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kPasswordEnteredLogin); + + // Navigations to other subdomains of saved.com are treated as login too. + ResetHistogramTester(); + ui_test_utils::NavigateToURL( + browser(), + embedded_test_server()->GetURL("mobile.saved.com", "/title1.html")); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kPasswordEnteredLogin); + + ResetHistogramTester(); + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("saved.com", "/title1.html")); + ExpectLoginDetectionTypeMetric(LoginDetectionType::kPasswordEnteredLogin); +} + +} // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_keyed_service.cc b/chrome/browser/login_detection/login_detection_keyed_service.cc new file mode 100644 index 0000000..97a917d --- /dev/null +++ b/chrome/browser/login_detection/login_detection_keyed_service.cc
@@ -0,0 +1,72 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/login_detection/login_detection_keyed_service.h" + +#include "chrome/browser/login_detection/login_detection_prefs.h" +#include "chrome/browser/login_detection/login_detection_util.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/child_process_security_policy.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace login_detection { + +namespace { + +// Gets the set of sites to be treated as logged-in from field trial. +std::set<std::string, OriginComparator> GetLoggedInSites() { + auto sites = GetLoggedInSitesFromFieldTrial(); + return std::set<std::string, OriginComparator>(sites.begin(), sites.end()); +} + +} // namespace + +bool OriginComparator::operator()(const std::string& a, + const std::string& b) const { + return url::Origin::Create(GURL(a)) < url::Origin::Create(GURL(b)); +} + +LoginDetectionKeyedService::LoginDetectionKeyedService(Profile* profile) + : profile_(profile), field_trial_logged_in_sites_(GetLoggedInSites()) {} + +LoginDetectionKeyedService::~LoginDetectionKeyedService() = default; + +LoginDetectionType LoginDetectionKeyedService::GetPersistentLoginDetection( + const GURL& url) const { + // Check if OAuth login for this site was detected earlier, and remembered + // in prefs. + if (prefs::IsSiteInOAuthSignedInList(profile_->GetPrefs(), url)) + return LoginDetectionType::kOauthLogin; + + // Check if this is common log-in site retrieved from field trial. + if (field_trial_logged_in_sites_.find(GetSiteNameForURL(url)) != + field_trial_logged_in_sites_.end()) { + return LoginDetectionType::kFieldTrialLoggedInSite; + } + + auto* child_process_security_policy = + content::ChildProcessSecurityPolicy::GetInstance(); + url::Origin url_origin = url::Origin::Create(url); + + // Check for password entered logins. These are saved as user triggered source + // in site-isolation. + if (child_process_security_policy->IsIsolatedSiteFromSource( + url_origin, content::ChildProcessSecurityPolicy:: + IsolatedOriginSource::USER_TRIGGERED)) { + return LoginDetectionType::kPasswordEnteredLogin; + } + + // Check for sites from preloaded list. These are saved as built-in source in + // site-isolation. + if (child_process_security_policy->IsIsolatedSiteFromSource( + url_origin, content::ChildProcessSecurityPolicy:: + IsolatedOriginSource::BUILT_IN)) { + return LoginDetectionType::kPreloadedPasswordSiteLogin; + } + + return LoginDetectionType::kNoLogin; +} + +} // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_keyed_service.h b/chrome/browser/login_detection/login_detection_keyed_service.h new file mode 100644 index 0000000..93e849c --- /dev/null +++ b/chrome/browser/login_detection/login_detection_keyed_service.h
@@ -0,0 +1,50 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_H_ +#define CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_H_ + +#include <set> +#include <string> + +#include "chrome/browser/login_detection/login_detection_type.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; +class GURL; + +namespace login_detection { + +// Comparator that converts string to url::Origin and performs the comparison. +// Comparing origins avoid inconsistencies with string comparison. For +// example, https://foo.com https://foo.com/ https://foo.com:443 are all the +// same. +struct OriginComparator { + bool operator()(const std::string& a, const std::string& b) const; +}; + +// Keyed service than can be used to get the type of login detected on a +// navigation. +class LoginDetectionKeyedService : public KeyedService { + public: + explicit LoginDetectionKeyedService(Profile* profile); + ~LoginDetectionKeyedService() override; + + // Returns the login type detected for |url|. This does not perform any + // detection. Only returns types based on previously detected logins saved in + // persistent memory. + LoginDetectionType GetPersistentLoginDetection(const GURL& url) const; + + private: + // Guaranteed to outlive |this|. + Profile* profile_; + + // Set of sites that should be treated as logged-in, retrieved from field + // trial. + const std::set<std::string, OriginComparator> field_trial_logged_in_sites_; +}; + +} // namespace login_detection + +#endif // CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_H_
diff --git a/chrome/browser/login_detection/login_detection_keyed_service_factory.cc b/chrome/browser/login_detection/login_detection_keyed_service_factory.cc new file mode 100644 index 0000000..29645d4 --- /dev/null +++ b/chrome/browser/login_detection/login_detection_keyed_service_factory.cc
@@ -0,0 +1,48 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/login_detection/login_detection_keyed_service_factory.h" + +#include "chrome/browser/login_detection/login_detection_keyed_service.h" +#include "chrome/browser/login_detection/login_detection_util.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "content/public/browser/browser_context.h" + +namespace login_detection { + +// static +LoginDetectionKeyedService* LoginDetectionKeyedServiceFactory::GetForProfile( + Profile* profile) { + if (profile->IsOffTheRecord()) + return nullptr; + + if (!IsLoginDetectionFeatureEnabled()) + return nullptr; + + return static_cast<LoginDetectionKeyedService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +LoginDetectionKeyedServiceFactory* +LoginDetectionKeyedServiceFactory::GetInstance() { + static base::NoDestructor<LoginDetectionKeyedServiceFactory> factory; + return factory.get(); +} + +LoginDetectionKeyedServiceFactory::LoginDetectionKeyedServiceFactory() + : BrowserContextKeyedServiceFactory( + "LoginDetectionKeyedService", + BrowserContextDependencyManager::GetInstance()) {} + +LoginDetectionKeyedServiceFactory::~LoginDetectionKeyedServiceFactory() = + default; + +KeyedService* LoginDetectionKeyedServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new LoginDetectionKeyedService(Profile::FromBrowserContext(context)); +} + +} // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_keyed_service_factory.h b/chrome/browser/login_detection/login_detection_keyed_service_factory.h new file mode 100644 index 0000000..c6b1a78 --- /dev/null +++ b/chrome/browser/login_detection/login_detection_keyed_service_factory.h
@@ -0,0 +1,48 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_FACTORY_H_ + +#include "base/macros.h" +#include "base/no_destructor.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace content { +class BrowserContext; +} // namespace content + +class Profile; + +namespace login_detection { + +class LoginDetectionKeyedService; + +// LazyInstance that owns all LoginDetectionKeyedServices and associates them +// with Profiles. +class LoginDetectionKeyedServiceFactory + : public BrowserContextKeyedServiceFactory { + public: + // Gets the LoginDetectionService for the profile. + // + // Returns null if the LoginDetection feature flag is disabled. + static LoginDetectionKeyedService* GetForProfile(Profile* profile); + + // Gets the LazyInstance that owns all LoginDetectionKeyedService(s). + static LoginDetectionKeyedServiceFactory* GetInstance(); + + private: + friend base::NoDestructor<LoginDetectionKeyedServiceFactory>; + + LoginDetectionKeyedServiceFactory(); + ~LoginDetectionKeyedServiceFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; +}; + +} // namespace login_detection + +#endif // CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_KEYED_SERVICE_FACTORY_H_
diff --git a/chrome/browser/login_detection/login_detection_tab_helper.cc b/chrome/browser/login_detection/login_detection_tab_helper.cc index 15a2465..a20aacd 100644 --- a/chrome/browser/login_detection/login_detection_tab_helper.cc +++ b/chrome/browser/login_detection/login_detection_tab_helper.cc
@@ -5,7 +5,10 @@ #include "chrome/browser/login_detection/login_detection_tab_helper.h" #include "base/metrics/histogram_functions.h" +#include "chrome/browser/login_detection/login_detection_keyed_service.h" +#include "chrome/browser/login_detection/login_detection_keyed_service_factory.h" #include "chrome/browser/login_detection/login_detection_prefs.h" +#include "chrome/browser/login_detection/login_detection_type.h" #include "chrome/browser/login_detection/login_detection_util.h" #include "chrome/browser/profiles/profile.h" #include "components/prefs/pref_service.h" @@ -27,9 +30,8 @@ ->GetPrefs(); } -void RecordLoginDetectionMetrics( - LoginDetectionTabHelper::LoginDetectionType type, - ukm::SourceId ukm_source_id) { +void RecordLoginDetectionMetrics(LoginDetectionType type, + ukm::SourceId ukm_source_id) { base::UmaHistogramEnumeration("Login.PageLoad.DetectionType", type); ukm::builders::LoginDetection builder(ukm_source_id); builder.SetPage_LoginType(static_cast<int64_t>(type)) @@ -85,16 +87,15 @@ } } - // Check if OAuth login for this site was detected earlier, and remembered - // in prefs. - if (prefs::IsSiteInOAuthSignedInList(GetPrefs(web_contents()), url)) { - RecordLoginDetectionMetrics(LoginDetectionType::kOauthLogin, - navigation_handle->GetNextPageUkmSourceId()); + LoginDetectionKeyedService* login_detection_keyed_service = + LoginDetectionKeyedServiceFactory::GetForProfile( + Profile::FromBrowserContext(web_contents()->GetBrowserContext())); + if (!login_detection_keyed_service) return; - } - RecordLoginDetectionMetrics(LoginDetectionType::kNoLogin, - navigation_handle->GetNextPageUkmSourceId()); + RecordLoginDetectionMetrics( + login_detection_keyed_service->GetPersistentLoginDetection(url), + navigation_handle->GetNextPageUkmSourceId()); } WEB_CONTENTS_USER_DATA_KEY_IMPL(LoginDetectionTabHelper)
diff --git a/chrome/browser/login_detection/login_detection_tab_helper.h b/chrome/browser/login_detection/login_detection_tab_helper.h index c9901b4..ed8b4f1 100644 --- a/chrome/browser/login_detection/login_detection_tab_helper.h +++ b/chrome/browser/login_detection/login_detection_tab_helper.h
@@ -22,24 +22,6 @@ : public content::WebContentsObserver, public content::WebContentsUserData<LoginDetectionTabHelper> { public: - // Enumerates the different types of user log-in that can be detected on a - // page based on the site (effective TLD+1). This is recorded in metrics and - // should not be reordered or removed. Should be in sync with the same name in - // enums.xml - enum LoginDetectionType { - // No login was detected. - kNoLogin, - - // OAuth login was detected for this site, and was remembered in persistent - // memory. - kOauthLogin, - - // Successful OAuth login flow was detected. - kOauthFirstTimeLoginFlow, - - kMaxValue = kOauthFirstTimeLoginFlow - }; - static void MaybeCreateForWebContents(content::WebContents* web_contents); ~LoginDetectionTabHelper() override;
diff --git a/chrome/browser/login_detection/login_detection_tab_helper_unittest.cc b/chrome/browser/login_detection/login_detection_tab_helper_unittest.cc index 5d235a59..0c59194 100644 --- a/chrome/browser/login_detection/login_detection_tab_helper_unittest.cc +++ b/chrome/browser/login_detection/login_detection_tab_helper_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/login_detection/login_detection_tab_helper.h" #include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/login_detection/login_detection_type.h" #include "chrome/browser/login_detection/login_detection_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" @@ -18,8 +19,13 @@ class LoginDetectionTabHelperTest : public ChromeRenderViewHostTestHarness { public: + explicit LoginDetectionTabHelperTest( + const std::string& field_trial_logged_in_sites = "") + : field_trial_logged_in_sites_(field_trial_logged_in_sites) {} + void SetUp() override { - scoped_feature_list_.InitAndEnableFeature(kLoginDetection); + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kLoginDetection, {{"logged_in_sites", field_trial_logged_in_sites_}}); ChromeRenderViewHostTestHarness::SetUp(); ResetMetricsTesters(); LoginDetectionTabHelper::MaybeCreateForWebContents(web_contents()); @@ -32,8 +38,7 @@ // Verifies the UMA and UKM metrics for the given login detection type to be // recorded. - void VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType type) { + void VerifyLoginDetectionTypeMetrics(LoginDetectionType type) { histogram_tester_->ExpectUniqueSample("Login.PageLoad.DetectionType", type, 1); @@ -49,31 +54,30 @@ base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<base::HistogramTester> histogram_tester_; std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_; + + // List of sites that are treated as logged-in from field trial. + const std::string field_trial_logged_in_sites_; }; TEST_F(LoginDetectionTabHelperTest, NoLogin) { NavigateAndCommit(GURL("https://foo.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); } TEST_F(LoginDetectionTabHelperTest, SimpleOAuthLogin) { // OAuth login start NavigateAndCommit(GURL("https://oauth.com/authenticate?client_id=123")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); // OAuth login complete ResetMetricsTesters(); NavigateAndCommit(GURL("https://foo.com/redirect?code=secret")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kOauthFirstTimeLoginFlow); // Subsequent navigations to OAuth signed-in site. ResetMetricsTesters(); NavigateAndCommit(GURL("https://images.foo.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kOauthLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kOauthLogin); } TEST_F(LoginDetectionTabHelperTest, NavigationToOAuthLoggedInSite) { @@ -84,14 +88,12 @@ // Subsequent navigations to OAuth signed-in site. ResetMetricsTesters(); NavigateAndCommit(GURL("https://images.foo.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kOauthLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kOauthLogin); // Navigation to a non logged-in site. ResetMetricsTesters(); NavigateAndCommit(GURL("https://bar.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); } TEST_F(LoginDetectionTabHelperTest, OAuthLoginViaRedirect) { @@ -106,14 +108,12 @@ simulator->Redirect(GURL("https://foo.com/redirect?code=secret")); simulator->Commit(); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kOauthFirstTimeLoginFlow); // Subsequent navigations to OAuth signed-in site. ResetMetricsTesters(); NavigateAndCommit(GURL("https://images.foo.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kOauthLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kOauthLogin); } // Test that OAuth login is not detected when there are intermediate navigations @@ -121,26 +121,22 @@ TEST_F(LoginDetectionTabHelperTest, InvalidOAuthLogins) { // OAuth login start NavigateAndCommit(GURL("https://oauth.com/authenticate?client_id=123")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); // Invalid intermediate navigation ResetMetricsTesters(); NavigateAndCommit(GURL("https://bar.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); // OAuth login complete will not be detected ResetMetricsTesters(); NavigateAndCommit(GURL("https://foo.com/redirect?code=secret")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); // Subsequent navigations is also no login. ResetMetricsTesters(); NavigateAndCommit(GURL("https://images.foo.com/page.html")); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); } // Test that OAuth login is not detected when there are intermediate redirect @@ -158,8 +154,39 @@ simulator->Redirect(GURL("https://foo.com/redirect?code=secret")); simulator->Commit(); - VerifyLoginDetectionTypeMetrics( - LoginDetectionTabHelper::LoginDetectionType::kNoLogin); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); +} + +class LoginDetectionTabHelperTestWithFieldTrialLoggedInList + : public LoginDetectionTabHelperTest { + public: + // Set up foo.com and bar.com as logged-in. + LoginDetectionTabHelperTestWithFieldTrialLoggedInList() + : LoginDetectionTabHelperTest("https://foo.com,https://bar.com/") {} +}; + +TEST_F(LoginDetectionTabHelperTestWithFieldTrialLoggedInList, FooLogin) { + NavigateAndCommit(GURL("https://foo.com/page.html")); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kFieldTrialLoggedInSite); + + // Other subdomains of foo.com should be treated as logged-in too. + ResetMetricsTesters(); + NavigateAndCommit(GURL("https://www.foo.com/page.html")); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kFieldTrialLoggedInSite); + + ResetMetricsTesters(); + NavigateAndCommit(GURL("https://m.foo.com/page.html")); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kFieldTrialLoggedInSite); +} + +TEST_F(LoginDetectionTabHelperTestWithFieldTrialLoggedInList, BarLogin) { + NavigateAndCommit(GURL("https://bar.com/page.html")); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kFieldTrialLoggedInSite); +} + +TEST_F(LoginDetectionTabHelperTestWithFieldTrialLoggedInList, NoLogin) { + NavigateAndCommit(GURL("https://qux.com/page.html")); + VerifyLoginDetectionTypeMetrics(LoginDetectionType::kNoLogin); } } // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_type.h b/chrome/browser/login_detection/login_detection_type.h new file mode 100644 index 0000000..0c451d73 --- /dev/null +++ b/chrome/browser/login_detection/login_detection_type.h
@@ -0,0 +1,40 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_TYPE_H_ +#define CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_TYPE_H_ + +namespace login_detection { + +// Enumerates the different types of user log-in that can be detected on a +// page based on the site (effective TLD+1). This is recorded in metrics and +// should not be reordered or removed. Should be in sync with the same name in +// enums.xml +enum class LoginDetectionType { + // No login was detected. + kNoLogin, + + // OAuth login was detected for this site, and was remembered in persistent + // memory. + kOauthLogin, + + // Successful OAuth login flow was detected. + kOauthFirstTimeLoginFlow, + + // The user had typed password to log-in. This includes sites where user + // typed password manually or used Chrome password manager to fill-in. + kPasswordEnteredLogin, + + // The site is in one of preloaded top sites where users commonly log-in. + kPreloadedPasswordSiteLogin, + + // Treated as logged-in since as the site was retrieved from field trial as + // commonly logged-in. + kFieldTrialLoggedInSite, + + kMaxValue = kFieldTrialLoggedInSite +}; +} // namespace login_detection + +#endif // CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_TYPE_H_
diff --git a/chrome/browser/login_detection/login_detection_util.cc b/chrome/browser/login_detection/login_detection_util.cc index b0a7fc17..c9a9f1d 100644 --- a/chrome/browser/login_detection/login_detection_util.cc +++ b/chrome/browser/login_detection/login_detection_util.cc
@@ -7,6 +7,8 @@ #include "base/metrics/field_trial_params.h" #include "base/strings/string_split.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "url/scheme_host_port.h" +#include "url/url_canon.h" namespace login_detection { @@ -18,8 +20,17 @@ } std::string GetSiteNameForURL(const GURL& url) { - return net::registry_controlled_domains::GetDomainAndRegistry( + DCHECK(url.SchemeIsHTTPOrHTTPS()); + std::string domain = net::registry_controlled_domains::GetDomainAndRegistry( url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + std::string scheme = url.scheme(); + // Use the default port for the scheme to ignore any non-standard ports for + // the scheme from the final string being returned. So, + // https://www.foo.com:1000/page.html would return just https://foo.com + return url::SchemeHostPort( + scheme, domain.empty() ? url.host() : domain, + url::DefaultPortForScheme(scheme.c_str(), scheme.length())) + .Serialize(); } std::set<std::string> GetOAuthLoginStartQueryParams() { @@ -55,4 +66,14 @@ "oauth_loggedin_sites_max_size", 100); } +std::vector<std::string> GetLoggedInSitesFromFieldTrial() { + // Get the field trial parameter which is a list of comma separated sites. + std::string param = + GetFieldTrialParamValueByFeature(kLoginDetection, "logged_in_sites"); + if (param.empty()) + return std::vector<std::string>(); + return base::SplitString(param, ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); +} + } // namespace login_detection
diff --git a/chrome/browser/login_detection/login_detection_util.h b/chrome/browser/login_detection/login_detection_util.h index 8597c0b..5dbf46a2 100644 --- a/chrome/browser/login_detection/login_detection_util.h +++ b/chrome/browser/login_detection/login_detection_util.h
@@ -7,6 +7,7 @@ #include <set> #include <string> +#include <vector> #include "base/feature_list.h" #include "url/gurl.h" @@ -19,7 +20,8 @@ // Returns whether login detection should be enabled. bool IsLoginDetectionFeatureEnabled(); -// Returns the site which is the effective TLD+1 of the URL. +// Returns the site which is the scheme and effective TLD+1 of the URL. The +// other components of the URL such as the port and path are ignored. std::string GetSiteNameForURL(const GURL& url); // Returns the query parameters that should be found in the navigation URL to @@ -38,6 +40,10 @@ // the size of the pref that stores the list. size_t GetOauthLoggedInSitesMaxSize(); +// Returns the sites retrieved from field trial, that should be treated as +// logged-in. +std::vector<std::string> GetLoggedInSitesFromFieldTrial(); + } // namespace login_detection #endif // CHROME_BROWSER_LOGIN_DETECTION_LOGIN_DETECTION_UTIL_H_
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc index 85868ec..0fdd8c3f 100644 --- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc +++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
@@ -23,42 +23,48 @@ using media_router::CastInternalMessage; template <> -const EnumTable<CastInternalMessage::Type> - EnumTable<CastInternalMessage::Type>::instance( - { - {CastInternalMessage::Type::kClientConnect, "client_connect"}, - {CastInternalMessage::Type::kAppMessage, "app_message"}, - {CastInternalMessage::Type::kV2Message, "v2_message"}, - {CastInternalMessage::Type::kLeaveSession, "leave_session"}, - {CastInternalMessage::Type::kReceiverAction, "receiver_action"}, - {CastInternalMessage::Type::kNewSession, "new_session"}, - {CastInternalMessage::Type::kUpdateSession, "update_session"}, - {CastInternalMessage::Type::kError, "error"}, - {CastInternalMessage::Type::kOther}, - }, - CastInternalMessage::Type::kMaxValue); +const EnumTable<CastInternalMessage::Type>& +EnumTable<CastInternalMessage::Type>::GetInstance() { + static const EnumTable<CastInternalMessage::Type> kInstance( + { + {CastInternalMessage::Type::kClientConnect, "client_connect"}, + {CastInternalMessage::Type::kAppMessage, "app_message"}, + {CastInternalMessage::Type::kV2Message, "v2_message"}, + {CastInternalMessage::Type::kLeaveSession, "leave_session"}, + {CastInternalMessage::Type::kReceiverAction, "receiver_action"}, + {CastInternalMessage::Type::kNewSession, "new_session"}, + {CastInternalMessage::Type::kUpdateSession, "update_session"}, + {CastInternalMessage::Type::kError, "error"}, + {CastInternalMessage::Type::kOther}, + }, + CastInternalMessage::Type::kMaxValue); + return kInstance; +} template <> -const EnumTable<CastInternalMessage::ErrorCode> - EnumTable<CastInternalMessage::ErrorCode>::instance( - { - {CastInternalMessage::ErrorCode::kInternalError, "internal_error"}, - {CastInternalMessage::ErrorCode::kCancel, "cancel"}, - {CastInternalMessage::ErrorCode::kTimeout, "timeout"}, - {CastInternalMessage::ErrorCode::kApiNotInitialized, - "api_not_initialized"}, - {CastInternalMessage::ErrorCode::kInvalidParameter, - "invalid_parameter"}, - {CastInternalMessage::ErrorCode::kExtensionNotCompatible, - "extension_not_compatible"}, - {CastInternalMessage::ErrorCode::kReceiverUnavailable, - "receiver_unavailable"}, - {CastInternalMessage::ErrorCode::kSessionError, "session_error"}, - {CastInternalMessage::ErrorCode::kChannelError, "channel_error"}, - {CastInternalMessage::ErrorCode::kLoadMediaFailed, - "load_media_failed"}, - }, - CastInternalMessage::ErrorCode::kMaxValue); +const EnumTable<CastInternalMessage::ErrorCode>& +EnumTable<CastInternalMessage::ErrorCode>::GetInstance() { + static const EnumTable<CastInternalMessage::ErrorCode> kInstance( + { + {CastInternalMessage::ErrorCode::kInternalError, "internal_error"}, + {CastInternalMessage::ErrorCode::kCancel, "cancel"}, + {CastInternalMessage::ErrorCode::kTimeout, "timeout"}, + {CastInternalMessage::ErrorCode::kApiNotInitialized, + "api_not_initialized"}, + {CastInternalMessage::ErrorCode::kInvalidParameter, + "invalid_parameter"}, + {CastInternalMessage::ErrorCode::kExtensionNotCompatible, + "extension_not_compatible"}, + {CastInternalMessage::ErrorCode::kReceiverUnavailable, + "receiver_unavailable"}, + {CastInternalMessage::ErrorCode::kSessionError, "session_error"}, + {CastInternalMessage::ErrorCode::kChannelError, "channel_error"}, + {CastInternalMessage::ErrorCode::kLoadMediaFailed, + "load_media_failed"}, + }, + CastInternalMessage::ErrorCode::kMaxValue); + return kInstance; +} } // namespace cast_util
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc index 40fb208..47bdc7399 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc +++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -240,16 +240,15 @@ // |storage_name| specifies the name of the storage device. // |read_only| specifies the mode of the storage device. // |request| is a struct containing details about the byte read request. -void ReadBytesOnUIThread( - const std::string& storage_name, - const bool read_only, - const MTPDeviceAsyncDelegate::ReadBytesRequest& request) { +void ReadBytesOnUIThread(const std::string& storage_name, + const bool read_only, + MTPDeviceAsyncDelegate::ReadBytesRequest request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); MTPDeviceTaskHelper* task_helper = GetDeviceTaskHelperForStorage(storage_name, read_only); if (!task_helper) return; - task_helper->ReadBytes(request); + task_helper->ReadBytes(std::move(request)); } // Renames |object_id| to |new_name|. @@ -644,14 +643,14 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(!device_file_path.empty()); base::OnceClosure closure = base::BindOnce( &MTPDeviceDelegateImplLinux::ReadBytesInternal, weak_ptr_factory_.GetWeakPtr(), device_file_path, base::RetainedRef(buf), - offset, buf_len, success_callback, error_callback); + offset, buf_len, std::move(success_callback), error_callback); EnsureInitAndRunTask(PendingTaskInfo(device_file_path, content::BrowserThread::IO, FROM_HERE, std::move(closure))); @@ -1009,7 +1008,7 @@ net::IOBuffer* buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -1017,14 +1016,15 @@ if (file_id) { ReadBytesRequest request( *file_id, buf, offset, buf_len, - base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes, - weak_ptr_factory_.GetWeakPtr(), success_callback), + base::BindOnce(&MTPDeviceDelegateImplLinux::OnDidReadBytes, + weak_ptr_factory_.GetWeakPtr(), + std::move(success_callback)), base::BindRepeating(&MTPDeviceDelegateImplLinux::HandleDeviceFileError, weak_ptr_factory_.GetWeakPtr(), error_callback, *file_id)); base::OnceClosure closure = base::BindOnce( - &ReadBytesOnUIThread, storage_name_, read_only_, request); + &ReadBytesOnUIThread, storage_name_, read_only_, std::move(request)); EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(), content::BrowserThread::UI, FROM_HERE, std::move(closure))); @@ -1635,10 +1635,11 @@ } void MTPDeviceDelegateImplLinux::OnDidReadBytes( - const ReadBytesSuccessCallback& success_callback, - const base::File::Info& file_info, int bytes_read) { + ReadBytesSuccessCallback success_callback, + const base::File::Info& file_info, + int bytes_read) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - success_callback.Run(file_info, bytes_read); + std::move(success_callback).Run(file_info, bytes_read); PendingRequestDone(); }
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h index 0de069f..498cdd8 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h +++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h
@@ -104,7 +104,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) override; bool IsReadOnly() const override; void CopyFileLocal( @@ -166,7 +166,7 @@ net::IOBuffer* buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback); void MoveFileLocalInternal( const base::FilePath& source_file_path, @@ -377,8 +377,9 @@ // // |success_callback| is invoked to notify the caller about the read bytes. // |bytes_read| is the number of bytes read. - void OnDidReadBytes(const ReadBytesSuccessCallback& success_callback, - const base::File::Info& file_info, int bytes_read); + void OnDidReadBytes(ReadBytesSuccessCallback success_callback, + const base::File::Info& file_info, + int bytes_read); // Called when FillFileCache() succeeds. void OnDidFillFileCache(const base::FilePath& path,
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc index da844455..c7c88d1 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc +++ b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc
@@ -181,7 +181,7 @@ } void MTPDeviceTaskHelper::ReadBytes( - const MTPDeviceAsyncDelegate::ReadBytesRequest& request) { + MTPDeviceAsyncDelegate::ReadBytesRequest request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (device_handle_.empty()) { return HandleDeviceError(request.error_callback, @@ -192,7 +192,7 @@ GetMediaTransferProtocolManager()->GetFileInfo( device_handle_, file_ids, base::BindOnce(&MTPDeviceTaskHelper::OnGetFileInfoToReadBytes, - weak_ptr_factory_.GetWeakPtr(), request)); + weak_ptr_factory_.GetWeakPtr(), std::move(request))); } void MTPDeviceTaskHelper::RenameObject( @@ -393,7 +393,7 @@ } void MTPDeviceTaskHelper::OnGetFileInfoToReadBytes( - const MTPDeviceAsyncDelegate::ReadBytesRequest& request, + MTPDeviceAsyncDelegate::ReadBytesRequest request, std::vector<device::mojom::MtpFileEntryPtr> entries, bool error) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -418,7 +418,8 @@ } if (request.offset == file_info.size) { content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(request.success_callback, file_info, 0u)); + FROM_HERE, + base::BindOnce(std::move(request.success_callback), file_info, 0u)); return; } @@ -430,11 +431,12 @@ device_handle_, request.file_id, base::checked_cast<uint32_t>(request.offset), bytes_to_read, base::BindOnce(&MTPDeviceTaskHelper::OnDidReadBytes, - weak_ptr_factory_.GetWeakPtr(), request, file_info)); + weak_ptr_factory_.GetWeakPtr(), std::move(request), + file_info)); } void MTPDeviceTaskHelper::OnDidReadBytes( - const MTPDeviceAsyncDelegate::ReadBytesRequest& request, + MTPDeviceAsyncDelegate::ReadBytesRequest request, const base::File::Info& file_info, const std::string& data, bool error) const { @@ -448,8 +450,8 @@ std::copy(data.begin(), data.end(), request.buf->data()); content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(request.success_callback, file_info, data.length())); + FROM_HERE, base::BindOnce(std::move(request.success_callback), file_info, + data.length())); } void MTPDeviceTaskHelper::OnRenameObject(
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h index eb362a8..db09dc3 100644 --- a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h +++ b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h
@@ -138,7 +138,7 @@ // |request| contains details about the byte request including the file path, // byte range, and the callbacks. The callbacks specified within |request| are // called on the IO thread to notify the caller about success or failure. - void ReadBytes(const MTPDeviceAsyncDelegate::ReadBytesRequest& request); + void ReadBytes(MTPDeviceAsyncDelegate::ReadBytesRequest request); // Forwards RenameObject request to the MediaTransferProtocolManager. void RenameObject(const uint32_t object_id, @@ -242,7 +242,7 @@ // Intermediate step to finish a ReadBytes request. void OnGetFileInfoToReadBytes( - const MTPDeviceAsyncDelegate::ReadBytesRequest& request, + MTPDeviceAsyncDelegate::ReadBytesRequest request, std::vector<device::mojom::MtpFileEntryPtr> entries, bool error); @@ -255,11 +255,10 @@ // If there is an error, |error| is set to true, the buffer within |request| // is untouched, and the error callback within |request| is invoked on the // IO thread to notify the caller. - void OnDidReadBytes( - const MTPDeviceAsyncDelegate::ReadBytesRequest& request, - const base::File::Info& file_info, - const std::string& data, - bool error) const; + void OnDidReadBytes(MTPDeviceAsyncDelegate::ReadBytesRequest request, + const base::File::Info& file_info, + const std::string& data, + bool error) const; // Called when RenameObject completes. void OnRenameObject(const RenameObjectSuccessCallback& success_callback,
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.cc b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.cc index 6a6d964..e455f0b5 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.cc +++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.cc
@@ -11,16 +11,22 @@ net::IOBuffer* buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) : file_id(file_id), buf(buf), offset(offset), buf_len(buf_len), - success_callback(success_callback), + success_callback(std::move(success_callback)), error_callback(error_callback) {} MTPDeviceAsyncDelegate::ReadBytesRequest::ReadBytesRequest( - const ReadBytesRequest& other) = default; + ReadBytesRequest&& other) + : file_id(other.file_id), + buf(other.buf), + offset(other.offset), + buf_len(other.buf_len), + success_callback(std::move(other.success_callback)), + error_callback(other.error_callback) {} MTPDeviceAsyncDelegate::ReadBytesRequest::~ReadBytesRequest() {}
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h index bd783ec..6c58670bf 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h +++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -54,18 +54,18 @@ CreateSnapshotFileSuccessCallback; // A callback to be called when ReadBytes method call succeeds. - typedef base::Callback< - void(const base::File::Info& file_info, - int bytes_read)> ReadBytesSuccessCallback; + typedef base::OnceCallback<void(const base::File::Info& file_info, + int bytes_read)> + ReadBytesSuccessCallback; struct ReadBytesRequest { ReadBytesRequest(uint32_t file_id, net::IOBuffer* buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback); - ReadBytesRequest(const ReadBytesRequest& other); + ReadBytesRequest(ReadBytesRequest&& other); ~ReadBytesRequest(); uint32_t file_id; @@ -142,7 +142,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) = 0; // Returns true if storage is opened for read only.
diff --git a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc index 7604e4f1..e47c86a 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc +++ b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc
@@ -64,17 +64,17 @@ header_buf_len = net::kMaxBytesToSniff; } - ReadBytes( - url_, header_buf.get(), 0, header_buf_len, - base::Bind(&MTPFileStreamReader::FinishValidateMediaHeader, - weak_factory_.GetWeakPtr(), base::RetainedRef(header_buf), - base::RetainedRef(buf), buf_len)); + ReadBytes(url_, header_buf.get(), 0, header_buf_len, + base::BindOnce(&MTPFileStreamReader::FinishValidateMediaHeader, + weak_factory_.GetWeakPtr(), + base::RetainedRef(header_buf), + base::RetainedRef(buf), buf_len)); return net::ERR_IO_PENDING; } - ReadBytes( - url_, buf, current_offset_, buf_len, - base::Bind(&MTPFileStreamReader::FinishRead, weak_factory_.GetWeakPtr())); + ReadBytes(url_, buf, current_offset_, buf_len, + base::BindOnce(&MTPFileStreamReader::FinishRead, + weak_factory_.GetWeakPtr())); return net::ERR_IO_PENDING; } @@ -123,9 +123,9 @@ // Header buffer isn't the same as the original read buffer. Make a separate // request for that. - ReadBytes( - url_, buf, current_offset_, buf_len, - base::Bind(&MTPFileStreamReader::FinishRead, weak_factory_.GetWeakPtr())); + ReadBytes(url_, buf, current_offset_, buf_len, + base::BindOnce(&MTPFileStreamReader::FinishRead, + weak_factory_.GetWeakPtr())); } void MTPFileStreamReader::FinishRead(const base::File::Info& file_info, @@ -169,7 +169,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const MTPDeviceAsyncDelegate::ReadBytesSuccessCallback& success_callback) { + MTPDeviceAsyncDelegate::ReadBytesSuccessCallback success_callback) { MTPDeviceAsyncDelegate* delegate = MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url); if (!delegate) { @@ -178,7 +178,7 @@ } delegate->ReadBytes( - url.path(), buf, offset, buf_len, success_callback, + url.path(), buf, offset, buf_len, std::move(success_callback), base::BindRepeating( &MTPFileStreamReader::CallReadCallbackwithPlatformFileError, weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h index 333078e1..d7d137c 100644 --- a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h +++ b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h
@@ -57,7 +57,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const MTPDeviceAsyncDelegate::ReadBytesSuccessCallback& success_callback); + MTPDeviceAsyncDelegate::ReadBytesSuccessCallback success_callback); scoped_refptr<storage::FileSystemContext> file_system_context_; storage::FileSystemURL url_;
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h index 061d088..75a98a01 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -61,7 +61,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) override; bool IsReadOnly() const override; void CopyFileLocal(
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm index b133424..49f90f31 100644 --- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm +++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -215,7 +215,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) { NOTREACHED(); }
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc index de574ae..5d3238f 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -446,7 +446,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) { NOTREACHED(); }
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h index dc934d1..706c1f10 100644 --- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h +++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -117,7 +117,7 @@ const scoped_refptr<net::IOBuffer>& buf, int64_t offset, int buf_len, - const ReadBytesSuccessCallback& success_callback, + ReadBytesSuccessCallback success_callback, const ErrorCallback& error_callback) override; bool IsReadOnly() const override; void CopyFileLocal(
diff --git a/chrome/browser/nearby_sharing/nearby_share_metrics_logger.cc b/chrome/browser/nearby_sharing/nearby_share_metrics_logger.cc index 96186e2..c5b99098 100644 --- a/chrome/browser/nearby_sharing/nearby_share_metrics_logger.cc +++ b/chrome/browser/nearby_sharing/nearby_share_metrics_logger.cc
@@ -30,16 +30,17 @@ // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. If entries are added, kMaxValue should // be updated. -enum class TransferNotCompletedReason { - kUnknown = 0, - kAwaitingRemoteAcceptanceFailed = 1, - kFailed = 2, - kRejected = 3, - kCancelled = 4, - kTimedOut = 5, - kMediaUnavailable = 6, - kNotEnoughSpace = 7, - kUnsupportedAttachmentType = 8, +enum class TransferFinalStatus { + kComplete = 0, + kUnknown = 1, + kAwaitingRemoteAcceptanceFailed = 2, + kFailed = 3, + kRejected = 4, + kCancelled = 5, + kTimedOut = 6, + kMediaUnavailable = 7, + kNotEnoughSpace = 8, + kUnsupportedAttachmentType = 9, kMaxValue = kUnsupportedAttachmentType }; @@ -68,35 +69,36 @@ kMaxValue = kCanceled }; -TransferNotCompletedReason TransferMetadataStatusToTransferNotCompletedReason( +TransferFinalStatus TransferMetadataStatusToTransferFinalStatus( TransferMetadata::Status status) { switch (status) { + case TransferMetadata::Status::kComplete: + return TransferFinalStatus::kComplete; case TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed: - return TransferNotCompletedReason::kAwaitingRemoteAcceptanceFailed; + return TransferFinalStatus::kAwaitingRemoteAcceptanceFailed; case TransferMetadata::Status::kFailed: - return TransferNotCompletedReason::kFailed; + return TransferFinalStatus::kFailed; case TransferMetadata::Status::kRejected: - return TransferNotCompletedReason::kRejected; + return TransferFinalStatus::kRejected; case TransferMetadata::Status::kCancelled: - return TransferNotCompletedReason::kCancelled; + return TransferFinalStatus::kCancelled; case TransferMetadata::Status::kTimedOut: - return TransferNotCompletedReason::kTimedOut; + return TransferFinalStatus::kTimedOut; case TransferMetadata::Status::kMediaUnavailable: - return TransferNotCompletedReason::kMediaUnavailable; + return TransferFinalStatus::kMediaUnavailable; case TransferMetadata::Status::kNotEnoughSpace: - return TransferNotCompletedReason::kNotEnoughSpace; + return TransferFinalStatus::kNotEnoughSpace; case TransferMetadata::Status::kUnsupportedAttachmentType: - return TransferNotCompletedReason::kUnsupportedAttachmentType; + return TransferFinalStatus::kUnsupportedAttachmentType; case TransferMetadata::Status::kUnknown: case TransferMetadata::Status::kConnecting: case TransferMetadata::Status::kAwaitingLocalConfirmation: case TransferMetadata::Status::kAwaitingRemoteAcceptance: case TransferMetadata::Status::kInProgress: - case TransferMetadata::Status::kComplete: case TransferMetadata::Status::kMediaDownloading: case TransferMetadata::Status::kExternalProviderLaunched: NOTREACHED(); - return TransferNotCompletedReason::kUnknown; + return TransferFinalStatus::kUnknown; } } @@ -153,6 +155,10 @@ return is_incoming ? ".Receive" : ".Send"; } +std::string GetIsKnownSubcategoryName(bool is_known) { + return is_known ? ".Contact" : ".NonContact"; +} + std::string GetShareTargetTypeSubcategoryName( nearby_share::mojom::ShareTargetType type) { switch (type) { @@ -345,32 +351,23 @@ } } -void RecordNearbyShareTransferCompletionStatusMetric( +void RecordNearbyShareTransferFinalStatusMetric( bool is_incoming, nearby_share::mojom::ShareTargetType type, - TransferMetadata::Status status) { + TransferMetadata::Status status, + bool is_known) { DCHECK(TransferMetadata::IsFinalStatus(status)); - bool is_complete = status == TransferMetadata::Status::kComplete; std::string send_or_receive = GetDirectionSubcategoryName(is_incoming); std::string share_target_type = GetShareTargetTypeSubcategoryName(type); + std::string contact_or_not = GetIsKnownSubcategoryName(is_known); - const std::string status_prefix = "Nearby.Share.Transfer.CompletionStatus"; - base::UmaHistogramBoolean(status_prefix, is_complete); - base::UmaHistogramBoolean(status_prefix + send_or_receive, is_complete); - base::UmaHistogramBoolean(status_prefix + share_target_type, is_complete); - base::UmaHistogramBoolean(status_prefix + send_or_receive + share_target_type, - is_complete); - if (!is_complete) { - TransferNotCompletedReason reason = - TransferMetadataStatusToTransferNotCompletedReason(status); + TransferFinalStatus final_status = + TransferMetadataStatusToTransferFinalStatus(status); - const std::string reason_prefix = - "Nearby.Share.Transfer.CompletionStatus.NotCompletedReason"; - base::UmaHistogramEnumeration(reason_prefix, reason); - base::UmaHistogramEnumeration(reason_prefix + send_or_receive, reason); - base::UmaHistogramEnumeration(reason_prefix + share_target_type, reason); - base::UmaHistogramEnumeration( - reason_prefix + send_or_receive + share_target_type, reason); - } + const std::string prefix = "Nearby.Share.Transfer.FinalStatus"; + base::UmaHistogramEnumeration(prefix, final_status); + base::UmaHistogramEnumeration( + prefix + send_or_receive + share_target_type + contact_or_not, + final_status); }
diff --git a/chrome/browser/nearby_sharing/nearby_share_metrics_logger.h b/chrome/browser/nearby_sharing/nearby_share_metrics_logger.h index e180996..dad0331 100644 --- a/chrome/browser/nearby_sharing/nearby_share_metrics_logger.h +++ b/chrome/browser/nearby_sharing/nearby_share_metrics_logger.h
@@ -48,9 +48,10 @@ bool is_high_visibility, location::nearby::connections::mojom::Status status); -void RecordNearbyShareTransferCompletionStatusMetric( +void RecordNearbyShareTransferFinalStatusMetric( bool is_incoming, nearby_share::mojom::ShareTargetType type, - TransferMetadata::Status status); + TransferMetadata::Status status, + bool is_known); #endif // CHROME_BROWSER_NEARBY_SHARING_NEARBY_SHARE_METRICS_LOGGER_H_
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc index 556e4b5..3a8e8cc 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -2464,8 +2464,9 @@ } if (metadata.is_final_status()) { - RecordNearbyShareTransferCompletionStatusMetric( - /*is_incoming=*/true, share_target.type, metadata.status()); + RecordNearbyShareTransferFinalStatusMetric( + /*is_incoming=*/true, share_target.type, metadata.status(), + share_target.is_known); OnTransferComplete(); if (metadata.status() != TransferMetadata::Status::kComplete) { // For any type of failure, lets make sure any pending files get cleaned @@ -2500,8 +2501,9 @@ if (metadata.is_final_status()) { is_connecting_ = false; - RecordNearbyShareTransferCompletionStatusMetric( - /*is_incoming=*/false, share_target.type, metadata.status()); + RecordNearbyShareTransferFinalStatusMetric( + /*is_incoming=*/false, share_target.type, metadata.status(), + share_target.is_known); OnTransferComplete(); } else if (metadata.status() == TransferMetadata::Status::kMediaDownloading || metadata.status() ==
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index e98ee784..1075f22 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/component_updater/crl_set_component_installer.h" +#include "chrome/browser/component_updater/first_party_sets_component_installer.h" #include "chrome/browser/component_updater/tls_deprecation_config_component_installer.h" #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" @@ -58,6 +59,7 @@ #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/features.h" +#include "net/cookies/cookie_util.h" #include "net/net_buildflags.h" #include "net/third_party/uri_template/uri_template.h" #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h" @@ -543,6 +545,20 @@ // Configure SCT Auditing in the NetworkService. SCTReportingService::ReconfigureAfterNetworkRestart(); + + if (net::cookie_util::IsFirstPartySetsEnabled()) { + component_updater::FirstPartySetsComponentInstallerPolicy:: + ReconfigureAfterNetworkRestart( + base::BindRepeating([](const std::string& raw_sets) { + // We use a fresh pointer here (instead of using `network_service` + // from the enclosing scope) to avoid use-after-free bugs, since + // `network_service` is not guaranteed to live until the + // invocation of this callback. + network::mojom::NetworkService* network_service = + content::GetNetworkService(); + network_service->SetPreloadedFirstPartySets(raw_sets); + })); + } } void SystemNetworkContextManager::DisableQuic() {
diff --git a/chrome/browser/payments/payment_handler_navigation_throttle.cc b/chrome/browser/payments/payment_handler_navigation_throttle.cc new file mode 100644 index 0000000..002bfba --- /dev/null +++ b/chrome/browser/payments/payment_handler_navigation_throttle.cc
@@ -0,0 +1,57 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/payments/payment_handler_navigation_throttle.h" + +#include <cstddef> +#include <string> + +#include "chrome/common/pdf_util.h" +#include "components/payments/content/payments_userdata_key.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/navigation_throttle.h" +#include "content/public/browser/web_contents.h" + +namespace payments { +constexpr char kPdfMimeType[] = "application/pdf"; + +PaymentHandlerNavigationThrottle::PaymentHandlerNavigationThrottle( + content::NavigationHandle* navigation_handle) + : content::NavigationThrottle(navigation_handle) {} + +PaymentHandlerNavigationThrottle::~PaymentHandlerNavigationThrottle() = default; + +const char* PaymentHandlerNavigationThrottle::GetNameForLogging() { + return "PaymentHandlerNavigationThrottle"; +} + +// static +std::unique_ptr<PaymentHandlerNavigationThrottle> +PaymentHandlerNavigationThrottle::MaybeCreateThrottleFor( + content::NavigationHandle* handle) { + if (!handle->IsInMainFrame()) + return nullptr; + + if (!handle->GetWebContents()->GetUserData( + kPaymentHandlerWebContentsUserDataKey)) { + return nullptr; + } + return std::make_unique<PaymentHandlerNavigationThrottle>(handle); +} + +content::NavigationThrottle::ThrottleCheckResult +PaymentHandlerNavigationThrottle::WillProcessResponse() { + const net::HttpResponseHeaders* response_headers = + navigation_handle()->GetResponseHeaders(); + if (!response_headers) + return PROCEED; + + std::string mime_type; + response_headers->GetMimeType(&mime_type); + if (mime_type != kPdfMimeType) + return PROCEED; + + return BLOCK_RESPONSE; +} +} // namespace payments
diff --git a/chrome/browser/payments/payment_handler_navigation_throttle.h b/chrome/browser/payments/payment_handler_navigation_throttle.h new file mode 100644 index 0000000..a3e7723 --- /dev/null +++ b/chrome/browser/payments/payment_handler_navigation_throttle.h
@@ -0,0 +1,38 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PAYMENTS_PAYMENT_HANDLER_NAVIGATION_THROTTLE_H_ +#define CHROME_BROWSER_PAYMENTS_PAYMENT_HANDLER_NAVIGATION_THROTTLE_H_ + +#include "base/macros.h" +#include "content/public/browser/navigation_throttle.h" + +namespace content { +class NavigationHandle; +} // namespace content + +namespace payments { +// The navigation throttle for the payment handler WebContents, used to +// prevent the WebContents from openning pages of certain categories, e.g. pdf. +class PaymentHandlerNavigationThrottle : public content::NavigationThrottle { + public: + explicit PaymentHandlerNavigationThrottle( + content::NavigationHandle* navigation_handle); + ~PaymentHandlerNavigationThrottle() override; + + PaymentHandlerNavigationThrottle(const PaymentHandlerNavigationThrottle&) = + delete; + PaymentHandlerNavigationThrottle& operator=( + const PaymentHandlerNavigationThrottle&) = delete; + + static std::unique_ptr<PaymentHandlerNavigationThrottle> + MaybeCreateThrottleFor(content::NavigationHandle* handle); + + // content::NavigationThrottle implementation: + ThrottleCheckResult WillProcessResponse() override; + const char* GetNameForLogging() override; +}; +} // namespace payments + +#endif // CHROME_BROWSER_PAYMENTS_PAYMENT_HANDLER_NAVIGATION_THROTTLE_H_
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index 613b397..06a9627e 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -560,9 +560,6 @@ public static final String PRIVACY_METRICS_REPORTING = "metrics_reporting"; public static final String PRIVACY_METRICS_IN_SAMPLE = "in_metrics_sample"; - public static final String PRIVACY_BANDWIDTH_OLD = "prefetch_bandwidth"; - public static final String PRIVACY_BANDWIDTH_NO_CELLULAR_OLD = "prefetch_bandwidth_no_cellular"; - public static final String PRIVACY_ALLOW_PRERENDER_OLD = "allow_prefetch"; public static final String PROFILES_BOOT_TIMESTAMP = "com.google.android.apps.chrome.ChromeMobileApplication.BOOT_TIMESTAMP";
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java index 8960d63..02790a90 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -39,6 +39,7 @@ "PrefMigrationVersion", "ServiceManagerFeatures", "allow_low_end_device_ui", + "allow_prefetch", "allow_starting_service_manager_only", "bookmark_search_history", "bottom_toolbar_enabled", @@ -65,6 +66,8 @@ "ntp_button_variant", "physical_web", "physical_web_sharing", + "prefetch_bandwidth", + "prefetch_bandwidth_no_cellular", "sole_integration_enabled", "start_surface_single_pane_enabled", "tab_persistent_store_task_runner_enabled",
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java index 24526dd3..dd508831 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
@@ -128,9 +128,6 @@ ChromePreferenceKeys.PREFETCH_NOTIFICATION_ENABLED, ChromePreferenceKeys.PREFETCH_NOTIFICATION_TIME, ChromePreferenceKeys.PREFETCH_OFFLINE_COUNTER, - ChromePreferenceKeys.PRIVACY_ALLOW_PRERENDER_OLD, - ChromePreferenceKeys.PRIVACY_BANDWIDTH_NO_CELLULAR_OLD, - ChromePreferenceKeys.PRIVACY_BANDWIDTH_OLD, ChromePreferenceKeys.PRIVACY_METRICS_IN_SAMPLE, ChromePreferenceKeys.PRIVACY_METRICS_REPORTING, ChromePreferenceKeys.PROFILES_BOOT_TIMESTAMP,
diff --git a/chrome/browser/privacy/BUILD.gn b/chrome/browser/privacy/BUILD.gn index 8b22035..9a9f0f3 100644 --- a/chrome/browser/privacy/BUILD.gn +++ b/chrome/browser/privacy/BUILD.gn
@@ -9,6 +9,8 @@ ":*", "//chrome/android:chrome_all_java", "//chrome/android:chrome_java", + "//chrome/android:chrome_junit_tests__java_binary", + "//chrome/android:chrome_test_java", ] sources = [ "java/src/org/chromium/chrome/browser/privacy/secure_dns/SecureDnsBridge.java",
diff --git a/chrome/browser/resources/bluetooth_internals/BUILD.gn b/chrome/browser/resources/bluetooth_internals/BUILD.gn index 1dd89b2..f289ac5 100644 --- a/chrome/browser/resources/bluetooth_internals/BUILD.gn +++ b/chrome/browser/resources/bluetooth_internals/BUILD.gn
@@ -4,6 +4,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/grit/grit_rule.gni") +import("//ui/webui/resources/tools/generate_grd.gni") js_type_check("closure_compile") { deps = [ ":bluetooth_internals" ] @@ -66,8 +67,83 @@ ] } +bluetooth_grd_prefix = "bluetooth_internals" +public_mojo_grdp_file = "$target_gen_dir/public_mojo_resources.grdp" +internals_mojo_grdp_file = "$target_gen_dir/internals_mojo_resources.grdp" +resources_grd_file = "$target_gen_dir/resources.grd" + +generate_grd("build_public_mojo_grdp") { + grd_prefix = bluetooth_grd_prefix + out_grd = public_mojo_grdp_file + input_files = [ + "adapter.mojom-lite.js", + "uuid.mojom-lite.js", + "device.mojom-lite.js", + ] + input_files_base_dir = + rebase_path("$root_gen_dir/device/bluetooth/public/mojom/", + root_build_dir) +} + +generate_grd("build_internal_mojo_grdp") { + grd_prefix = bluetooth_grd_prefix + out_grd = internals_mojo_grdp_file + input_files = [ "bluetooth_internals.mojom-lite.js" ] + input_files_base_dir = + rebase_path("$root_gen_dir/chrome/browser/ui/webui/bluetooth_internals/", + root_build_dir) +} + +generate_grd("build_grd") { + grd_prefix = bluetooth_grd_prefix + out_grd = resources_grd_file + deps = [ + ":build_internal_mojo_grdp", + ":build_public_mojo_grdp", + ] + input_files = [ + "adapter_broker.js", + "adapter_page.js", + "debug_log_page.js", + "characteristic_list.js", + "bluetooth_internals.css", + "descriptor_list.js", + "device_broker.js", + "device_collection.js", + "device_details_page.js", + "device_table.js", + "devices_page.js", + "expandable_list.js", + "bluetooth_internals.html", + "bluetooth_internals.js", + "menu.svg", + "node_utils.js", + "object_fieldset.js", + "page_manager.js", + "page.js", + "service_list.js", + "sidebar.js", + "snackbar.js", + "value_control.js", + ] + input_files_base_dir = rebase_path("./", "//") + + grdp_files = [ + public_mojo_grdp_file, + internals_mojo_grdp_file, + ] +} + grit("resources") { - source = "resources.grd" + enable_input_discovery_for_gn_analyze = false + source = resources_grd_file + + deps = [ + ":build_grd", + "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings_js", + "//device/bluetooth/public/mojom:deprecated_experimental_interfaces_js", + "//device/bluetooth/public/mojom:mojom_js", + ] outputs = [ "grit/bluetooth_internals_resources.h", @@ -76,5 +152,4 @@ "bluetooth_internals_resources.pak", ] output_dir = "$root_gen_dir/chrome" - deps = [ "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings_js" ] }
diff --git a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css index 5cb1cd22..4a130e7 100644 --- a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css +++ b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css
@@ -31,7 +31,7 @@ } .toggle-status { - background-image: url(../../../../ui/webui/resources/images/cancel_red.svg); + background-image: url(chrome://resources/images/cancel_red.svg); background-repeat: no-repeat; min-height: 24px; min-width: 24px; @@ -39,7 +39,7 @@ .toggle-status.checked { background-image: - url(../../../../ui/webui/resources/images/check_circle_green.svg); + url(chrome://resources/images/check_circle_green.svg); } /* Expandable List */ @@ -93,7 +93,7 @@ } .empty-message { - padding-left: calc(2 * var(--section-padding)); + padding-inline-start: calc(2 * var(--section-padding)); } /* Page container */ @@ -147,7 +147,7 @@ #menu-btn { background-color: transparent; - background-image: url(../../../../ui/webui/resources/images/menu.svg); + background-image: url(./menu.svg); background-position: center; background-repeat: no-repeat; border: 0; @@ -184,8 +184,8 @@ @media screen and (max-width: 600px) { #sidebar { - width: auto; visibility: hidden; + width: auto; } #sidebar.open {
diff --git a/ui/webui/resources/images/menu.svg b/chrome/browser/resources/bluetooth_internals/menu.svg similarity index 98% rename from ui/webui/resources/images/menu.svg rename to chrome/browser/resources/bluetooth_internals/menu.svg index fc0da0e..b765548 100644 --- a/ui/webui/resources/images/menu.svg +++ b/chrome/browser/resources/bluetooth_internals/menu.svg
@@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5F6368"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5F6368"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
diff --git a/chrome/browser/resources/bluetooth_internals/resources.grd b/chrome/browser/resources/bluetooth_internals/resources.grd deleted file mode 100644 index c9721ddc..0000000 --- a/chrome/browser/resources/bluetooth_internals/resources.grd +++ /dev/null
@@ -1,106 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="0" - current_release="1" - output_all_resource_defines="false"> - <outputs> - <output filename="grit/bluetooth_internals_resources.h" - type="rc_header"> - <emit emit_type='prepend'></emit> - </output> - <output filename="grit/bluetooth_internals_resources_map.cc" - type="resource_file_map_source" /> - <output filename="grit/bluetooth_internals_resources_map.h" - type="resource_map_header" /> - <output filename="bluetooth_internals_resources.pak" - type="data_package" /> - </outputs> - <release seq="1"> - <includes> - <include name="IDR_BLUETOOTH_INTERNALS_ADAPTER_BROKER_JS" - file="adapter_broker.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_ADAPTER_MOJO_JS" - file="${root_gen_dir}\device\bluetooth\public\mojom\adapter.mojom-lite.js" - use_base_dir="false" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_ADAPTER_PAGE_JS" - file="adapter_page.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEBUG_LOG_PAGE_JS" - file="debug_log_page.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_CHARACTERISTIC_LIST_JS" - file="characteristic_list.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_CSS" - file="bluetooth_internals.css" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DESCRIPTOR_LIST_JS" - file="descriptor_list.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_BROKER_JS" - file="device_broker.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_COLLECTION_JS" - file="device_collection.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_DETAILS_PAGE_JS" - file="device_details_page.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_MOJO_JS" - file="${root_gen_dir}\device\bluetooth\public\mojom\device.mojom-lite.js" - use_base_dir="false" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_TABLE_JS" - file="device_table.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_DEVICES_PAGE_JS" - file="devices_page.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_EXPANDABLE_LIST_JS" - file="expandable_list.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_HTML" - file="bluetooth_internals.html" - flattenhtml="true" - allowexternalscript="true" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_JS" - file="bluetooth_internals.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_MOJO_JS" - file="${root_gen_dir}\chrome\browser\ui\webui\bluetooth_internals\bluetooth_internals.mojom-lite.js" - use_base_dir="false" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_NODE_UTILS_JS" - file="node_utils.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_OBJECT_FIELDSET_JS" - file="object_fieldset.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_PAGE_MANAGER_JS" - file="page_manager.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_PAGE_JS" - file="page.js" - type="BINDATA" /> - - <include name="IDR_BLUETOOTH_INTERNALS_SERVICE_LIST_JS" - file="service_list.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_SIDEBAR_JS" - file="sidebar.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_SNACKBAR_JS" - file="snackbar.js" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_UUID_MOJO_JS" - file="${root_gen_dir}\device\bluetooth\public\mojom\uuid.mojom-lite.js" - use_base_dir="false" - type="BINDATA" /> - <include name="IDR_BLUETOOTH_INTERNALS_VALUE_CONTROL_JS" - file="value_control.js" - type="BINDATA" /> - </includes> - </release> -</grit>
diff --git a/chrome/browser/resources/chromeos/accessibility/OWNERS b/chrome/browser/resources/chromeos/accessibility/OWNERS index 03bd397..b1468c0b 100644 --- a/chrome/browser/resources/chromeos/accessibility/OWNERS +++ b/chrome/browser/resources/chromeos/accessibility/OWNERS
@@ -1,2 +1,3 @@ file://ui/accessibility/OWNERS anastasi@google.com +akihiroota@chromium.org
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 4c1b56c1..39009ad 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -48,7 +48,9 @@ "background/desktop_automation_handler.js", "background/download_handler.js", "background/earcon_engine.js", - "background/editing.js", + "background/editing/editable_line.js", + "background/editing/editing.js", + "background/editing/intent_handler.js", "background/event_source.js", "background/find_handler.js", "background/focus_automation_handler.js", @@ -450,7 +452,7 @@ "background/color_test.js", "background/cursors_test.js", "background/download_handler_test.js", - "background/editing_test.js", + "background/editing/editing_test.js", "background/keyboard_handler_test.js", "background/live_regions_test.js", "background/locale_output_helper_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/OWNERS b/chrome/browser/resources/chromeos/accessibility/chromevox/OWNERS deleted file mode 100644 index b9e3700..0000000 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -dtseng@chromium.org -akihiroota@chromium.org
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_line.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_line.js new file mode 100644 index 0000000..ca8bf55 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_line.js
@@ -0,0 +1,550 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview An EditableLine encapsulates all data concerning a line in the + * automation tree necessary to provide output. Editable: an editable selection + * (e.g. start/end offsets) get saved. Line: nodes/offsets at the beginning/end + * of a line get saved. + */ + +goog.provide('editing.EditableLine'); + +goog.scope(function() { +const AutomationEvent = chrome.automation.AutomationEvent; +const AutomationNode = chrome.automation.AutomationNode; +const Cursor = cursors.Cursor; +const Dir = constants.Dir; +const EventType = chrome.automation.EventType; +const FormType = LibLouis.FormType; +const Range = cursors.Range; +const RoleType = chrome.automation.RoleType; +const StateType = chrome.automation.StateType; +const Movement = cursors.Movement; +const Unit = cursors.Unit; + +editing.EditableLine = class { + /** + * @param {!AutomationNode} startNode + * @param {number} startIndex + * @param {!AutomationNode} endNode + * @param {number} endIndex + * @param {boolean=} opt_baseLineOnStart Controls whether to use + * |startNode| or |endNode| for Line computations. Selections are + * automatically truncated up to either the line start or end. + */ + constructor(startNode, startIndex, endNode, endIndex, opt_baseLineOnStart) { + /** @private {!Cursor} */ + this.start_ = new Cursor(startNode, startIndex); + this.start_ = this.start_.deepEquivalent || this.start_; + /** @private {!Cursor} */ + this.end_ = new Cursor(endNode, endIndex); + this.end_ = this.end_.deepEquivalent || this.end_; + + /** @private {AutomationNode|undefined} */ + this.endContainer_; + + // Update |startIndex| and |endIndex| if the calls above to + // cursors.Cursor.deepEquivalent results in cursors to different container + // nodes. The cursors can point directly to inline text boxes, in which case + // we should not adjust the container start or end index. + if (!AutomationPredicate.text(startNode) || + (this.start_.node !== startNode && + this.start_.node.parent !== startNode)) { + startIndex = + (this.start_.index === cursors.NODE_INDEX && this.start_.node.name) ? + this.start_.node.name.length : + this.start_.index; + } + + if (!AutomationPredicate.text(endNode) || + (this.end_.node !== endNode && this.end_.node.parent !== endNode)) { + endIndex = + (this.end_.index === cursors.NODE_INDEX && this.end_.node.name) ? + this.end_.node.name.length : + this.end_.index; + } + + /** @private {number} */ + this.localContainerStartOffset_ = startIndex; + /** @private {number} */ + this.localContainerEndOffset_ = endIndex; + + // Computed members. + /** @private {Spannable} */ + this.value_; + /** @private {AutomationNode|undefined} */ + this.lineStart_; + /** @private {AutomationNode|undefined} */ + this.lineEnd_; + /** @private {AutomationNode|undefined} */ + this.startContainer_; + /** @private {string} */ + this.startContainerValue_ = ''; + /** @private {AutomationNode|undefined} */ + this.lineStartContainer_; + /** @private {number} */ + this.localLineStartContainerOffset_ = 0; + /** @private {AutomationNode|undefined} */ + this.lineEndContainer_; + /** @private {number} */ + this.localLineEndContainerOffset_ = 0; + /** @type {RecoveryStrategy} */ + this.lineStartContainerRecovery_; + + this.computeLineData_(opt_baseLineOnStart); + } + + /** +* @param {boolean=} opt_baseLineOnStart Computes the line based on the start +node if true. + @private + */ + computeLineData_(opt_baseLineOnStart) { + // Note that we calculate the line based only upon |start_| or + // |end_| even if they do not fall on the same line. It is up to + // the caller to specify which end to base this line upon since it requires + // reasoning about two lines. + let nameLen = 0; + const lineBase = opt_baseLineOnStart ? this.start_ : this.end_; + const lineExtend = opt_baseLineOnStart ? this.end_ : this.start_; + + if (lineBase.node.name) { + nameLen = lineBase.node.name.length; + } + + this.value_ = new Spannable(lineBase.node.name || '', lineBase); + if (lineBase.node === lineExtend.node) { + this.value_.setSpan(lineExtend, 0, nameLen); + } + + this.startContainer_ = this.start_.node; + if (this.startContainer_.role === RoleType.INLINE_TEXT_BOX) { + this.startContainer_ = this.startContainer_.parent; + } + this.startContainerValue_ = + this.startContainer_.role === RoleType.TEXT_FIELD ? + this.startContainer_.value || '' : + this.startContainer_.name || ''; + this.endContainer_ = this.end_.node; + if (this.endContainer_.role === RoleType.INLINE_TEXT_BOX) { + this.endContainer_ = this.endContainer_.parent; + } + + // Initialize defaults. + this.lineStart_ = lineBase.node; + this.lineEnd_ = this.lineStart_; + this.lineStartContainer_ = this.lineStart_.parent; + this.lineEndContainer_ = this.lineStart_.parent; + + // Annotate each chunk with its associated inline text box node. + this.value_.setSpan(this.lineStart_, 0, nameLen); + + // Also, track the nodes necessary for selection (either their parents, in + // the case of inline text boxes, or the node itself). + const parents = [this.startContainer_]; + + // Compute the start of line. + let lineStart = this.lineStart_; + + // Hack: note underlying bugs require these hacks. + while ((lineStart.previousOnLine && lineStart.previousOnLine.role) || + (lineStart.previousSibling && lineStart.previousSibling.lastChild && + lineStart.previousSibling.lastChild.nextOnLine === lineStart)) { + if (lineStart.previousOnLine) { + lineStart = lineStart.previousOnLine; + } else { + lineStart = lineStart.previousSibling.lastChild; + } + + this.lineStart_ = lineStart; + + if (lineStart.role !== RoleType.INLINE_TEXT_BOX) { + parents.unshift(lineStart); + } else if (parents[0] !== lineStart.parent) { + parents.unshift(lineStart.parent); + } + + const prepend = new Spannable(lineStart.name, lineStart); + prepend.append(this.value_); + this.value_ = prepend; + } + this.lineStartContainer_ = this.lineStart_.parent; + + let lineEnd = this.lineEnd_; + + // Hack: note underlying bugs require these hacks. + while ((lineEnd.nextOnLine && lineEnd.nextOnLine.role) || + (lineEnd.nextSibling && + lineEnd.nextSibling.previousOnLine === lineEnd)) { + if (lineEnd.nextOnLine) { + lineEnd = lineEnd.nextOnLine; + } else { + lineEnd = lineEnd.nextSibling.firstChild; + } + + this.lineEnd_ = lineEnd; + + if (lineEnd.role !== RoleType.INLINE_TEXT_BOX) { + parents.push(this.lineEnd_); + } else if (parents[parents.length - 1] !== lineEnd.parent) { + parents.push(this.lineEnd_.parent); + } + + let annotation = lineEnd; + if (lineEnd === this.end_.node) { + annotation = this.end_; + } + + this.value_.append(new Spannable(lineEnd.name, annotation)); + } + this.lineEndContainer_ = this.lineEnd_.parent; + + // Finally, annotate with all parent static texts as NodeSpan's so that + // braille routing can key properly into the node with an offset. + // Note that both line start and end needs to account for + // potential offsets into the static texts as follows. + let textCountBeforeLineStart = 0, textCountAfterLineEnd = 0; + let finder = this.lineStart_; + while (finder.previousSibling) { + finder = finder.previousSibling; + textCountBeforeLineStart += finder.name ? finder.name.length : 0; + } + this.localLineStartContainerOffset_ = textCountBeforeLineStart; + + if (this.lineStartContainer_) { + this.lineStartContainerRecovery_ = + new TreePathRecoveryStrategy(this.lineStartContainer_); + } + + finder = this.lineEnd_; + while (finder.nextSibling) { + finder = finder.nextSibling; + textCountAfterLineEnd += finder.name ? finder.name.length : 0; + } + + if (this.lineEndContainer_.name) { + this.localLineEndContainerOffset_ = + this.lineEndContainer_.name.length - textCountAfterLineEnd; + } + + let len = 0; + for (let i = 0; i < parents.length; i++) { + const parent = parents[i]; + + if (!parent.name) { + continue; + } + + const prevLen = len; + + let currentLen = parent.name.length; + let offset = 0; + + // Subtract off the text count before when at the start of line. + if (i === 0) { + currentLen -= textCountBeforeLineStart; + offset = textCountBeforeLineStart; + } + + // Subtract text count after when at the end of the line. + if (i === parents.length - 1) { + currentLen -= textCountAfterLineEnd; + } + + len += currentLen; + + try { + this.value_.setSpan(new Output.NodeSpan(parent, offset), prevLen, len); + + // Also, annotate this span if it is associated with line containre. + if (parent === this.startContainer_) { + this.value_.setSpan(parent, prevLen, len); + } + } catch (e) { + } + } + } + + /** + * Gets the selection offset based on the text content of this line. + * @return {number} + */ + get startOffset() { + // It is possible that the start cursor points to content before this line + // (e.g. in a multi-line selection). + try { + return this.value_.getSpanStart(this.start_) + + (this.start_.index === cursors.NODE_INDEX ? 0 : this.start_.index); + } catch (e) { + // When that happens, fall back to the start of this line. + return 0; + } + } + + /** + * Gets the selection offset based on the text content of this line. + * @return {number} + */ + get endOffset() { + try { + return this.value_.getSpanStart(this.end_) + + (this.end_.index === cursors.NODE_INDEX ? 0 : this.end_.index); + } catch (e) { + return this.value_.length; + } + } + + /** + * Gets the selection offset based on the parent's text. + * The parent is expected to be static text. + * @return {number} + */ + get localStartOffset() { + return this.localContainerStartOffset_; + } + + /** + * Gets the selection offset based on the parent's text. + * The parent is expected to be static text. + * @return {number} + */ + get localEndOffset() { + return this.localContainerEndOffset_; + } + + /** + * Gets the start offset of the container, relative to the line text + * content. The container refers to the static text parenting the inline + * text box. + * @return {number} + */ + get containerStartOffset() { + return this.value_.getSpanStart(this.startContainer_); + } + + /** + * Gets the end offset of the container, relative to the line text content. + * The container refers to the static text parenting the inline text box. + * @return {number} + */ + get containerEndOffset() { + return this.value_.getSpanEnd(this.startContainer_) - 1; + } + + /** + * The text content of this line. + * @return {string} The text of this line. + */ + get text() { + return this.value_.toString(); + } + + /** @return {string} */ + get selectedText() { + return this.value_.toString().substring(this.startOffset, this.endOffset); + } + + /** @return {AutomationNode|undefined} */ + get startContainer() { + return this.startContainer_; + } + + /** @return {AutomationNode|undefined} */ + get endContainer() { + return this.endContainer_; + } + + /** @return {Spannable} */ + get value() { + return this.value_; + } + + /** @return {!cursors.Cursor} */ + get start() { + return this.start_; + } + + /** @return {!cursors.Cursor} */ + get end() { + return this.end_; + } + + /** @return {number} */ + get localContainerStartOffset() { + return this.localContainerStartOffset_; + } + + /** @return {number} */ + get localContainerEndOffset() { + return this.localContainerEndOffset_; + } + + /** @return {string} */ + get startContainerValue() { + return this.startContainerValue_; + } + + /** @return {boolean} */ + hasCollapsedSelection() { + return this.start_.equals(this.end_); + } + + /** + * Returns whether this line has selection over text nodes. + * @return {boolean} + */ + hasTextSelection() { + if (this.start_.node && this.end_.node) { + return AutomationPredicate.text(this.start_.node) && + AutomationPredicate.text(this.end_.node); + } + + return false; + } + + /** + * Returns true if |otherLine| surrounds the same line as |this|. Note that + * the contents of the line might be different. + * @param {editing.EditableLine} otherLine + * @return {boolean} + */ + isSameLine(otherLine) { + // Equality is intentionally loose here as any of the state nodes can be + // invalidated at any time. We rely upon the start/anchor of the line + // staying the same. + return (otherLine.lineStartContainer_ === this.lineStartContainer_ && + otherLine.localLineStartContainerOffset_ === + this.localLineStartContainerOffset_) || + (otherLine.lineEndContainer_ === this.lineEndContainer_ && + otherLine.localLineEndContainerOffset_ === + this.localLineEndContainerOffset_) || + (otherLine.lineStartContainerRecovery_.node === + this.lineStartContainerRecovery_.node && + otherLine.localLineStartContainerOffset_ === + this.localLineStartContainerOffset_); + } + + /** + * Returns true if |otherLine| surrounds the same line as |this| and has the + * same selection. + * @param {editing.EditableLine} otherLine + * @return {boolean} + */ + isSameLineAndSelection(otherLine) { + return this.isSameLine(otherLine) && + this.startOffset === otherLine.startOffset && + this.endOffset === otherLine.endOffset; + } + + /** + * Returns whether this line comes before |otherLine| in document order. + * @param {!editing.EditableLine} otherLine + * @return {boolean} + */ + isBeforeLine(otherLine) { + if (this.isSameLine(otherLine) || !this.lineStartContainer_ || + !otherLine.lineStartContainer_) { + return false; + } + return AutomationUtil.getDirection( + this.lineStartContainer_, otherLine.lineStartContainer_) === + Dir.FORWARD; + } + + /** + * Performs a validation that this line still refers to a line given its + * internally tracked state. + * @return {boolean} + */ + isValidLine() { + if (!this.lineStartContainer_ || !this.lineEndContainer_) { + return false; + } + + const start = new cursors.Cursor( + this.lineStartContainer_, this.localLineStartContainerOffset_); + const end = new cursors.Cursor( + this.lineEndContainer_, this.localLineEndContainerOffset_ - 1); + const localStart = start.deepEquivalent || start; + const localEnd = end.deepEquivalent || end; + const localStartNode = localStart.node; + const localEndNode = localEnd.node; + + // Unfortunately, there are asymmetric errors in lines, so we need to + // check in both directions. + let testStartNode = localStartNode; + do { + if (testStartNode === localEndNode) { + return true; + } + + // Hack/workaround for broken *OnLine links. + if (testStartNode.nextOnLine && testStartNode.nextOnLine.role) { + testStartNode = testStartNode.nextOnLine; + } else if ( + testStartNode.nextSibling && + testStartNode.nextSibling.previousOnLine === testStartNode) { + testStartNode = testStartNode.nextSibling; + } else { + break; + } + } while (testStartNode); + + let testEndNode = localEndNode; + do { + if (testEndNode === localStartNode) { + return true; + } + + // Hack/workaround for broken *OnLine links. + if (testEndNode.previousOnLine && testEndNode.previousOnLine.role) { + testEndNode = testEndNode.previousOnLine; + } else if ( + testEndNode.previousSibling && + testEndNode.previousSibling.nextOnLine === testEndNode) { + testEndNode = testEndNode.previousSibling; + } else { + break; + } + } while (testEndNode); + + return false; + } + + /** + * Speaks the line using text to speech. + * @param {editing.EditableLine} prevLine + */ + speakLine(prevLine) { + let prev = (prevLine && prevLine.startContainer_.role) ? + prevLine.startContainer_ : + null; + const lineNodes = + /** @type {Array<!AutomationNode>} */ (this.value_.getSpansInstanceOf( + /** @type {function()} */ (this.startContainer_.constructor))); + let queueMode = QueueMode.CATEGORY_FLUSH; + for (let i = 0, cur; cur = lineNodes[i]; i++) { + if (cur.children.length) { + continue; + } + + const o = new Output() + .withRichSpeech( + Range.fromNode(cur), + prev ? Range.fromNode(prev) : Range.fromNode(cur), + Output.EventType.NAVIGATE) + .withQueueMode(queueMode); + + // Ignore whitespace only output except if it is leading content on the + // line. + if (!o.isOnlyWhitespace || i === 0) { + o.go(); + } + prev = cur; + queueMode = QueueMode.QUEUE; + } + } +}; +}); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js similarity index 61% rename from chrome/browser/resources/chromeos/accessibility/chromevox/background/editing.js rename to chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js index d54fef2..a4cd4601 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing.js
@@ -11,11 +11,13 @@ goog.require('AutomationTreeWalker'); goog.require('AutomationUtil'); +goog.require('IntentHandler'); goog.require('Output'); goog.require('Output.EventType'); goog.require('TreePathRecoveryStrategy'); goog.require('cursors.Cursor'); goog.require('cursors.Range'); +goog.require('editing.EditableLine'); goog.require('BrailleBackground'); goog.require('ChromeVoxEditableTextBase'); goog.require('LibLouis.FormType'); @@ -349,7 +351,7 @@ /** @override */ isSelectionOnFirstLine() { - let deep = this.line_.end_.node; + let deep = this.line_.end.node; while (deep.previousOnLine) { deep = deep.previousOnLine; } @@ -366,7 +368,7 @@ /** @override */ isSelectionOnLastLine() { - let deep = this.line_.end_.node; + let deep = this.line_.end.node; while (deep.nextOnLine) { deep = deep.nextOnLine; } @@ -487,8 +489,8 @@ // Handle description of non-textual lines. new Output() .withRichSpeech( - new Range(cur.start_, cur.end_), - new Range(prev.start_, prev.end_), Output.EventType.NAVIGATE) + new Range(cur.start, cur.end), new Range(prev.start, prev.end), + Output.EventType.NAVIGATE) .go(); } @@ -502,16 +504,16 @@ const curBase = baseLineOnStart ? endLine : startLine; if (cur.text === '\u00a0' && cur.hasCollapsedSelection() && - !cur.end_.node.nextOnLine) { + !cur.end.node.nextOnLine) { // This is a specific pattern seen in Google Docs. A single node (static // text/in line text box), containing a non-breaking-space signifies a new // line. ChromeVox.tts.speak('\n', QueueMode.CATEGORY_FLUSH); } else if ( - (cur.startContainer_.role === RoleType.TEXT_FIELD || - (cur.startContainer_ === prev.startContainer_ && - cur.endContainer_ === prev.endContainer_)) && - cur.startContainerValue_ !== prev.startContainerValue_) { + (cur.startContainer.role === RoleType.TEXT_FIELD || + (cur.startContainer === prev.startContainer && + cur.endContainer === prev.endContainer)) && + cur.startContainerValue !== prev.startContainerValue) { // This block catches text changes between |prev| and | cur|. Note that we // can end up here if |prevStartLine| or |prevEndLine| were invalid // above for intra-line changes. This block therefore catches all text @@ -524,17 +526,17 @@ // of the container) and speak that. this.describeTextChanged( new TextChangeEvent( - prev.startContainerValue_, prev.localContainerStartOffset_, - prev.localContainerEndOffset_, true), + prev.startContainerValue, prev.localContainerStartOffset, + prev.localContainerEndOffset, true), new TextChangeEvent( - cur.startContainerValue_, cur.localContainerStartOffset_, - cur.localContainerEndOffset_, true)); + cur.startContainerValue, cur.localContainerStartOffset, + cur.localContainerEndOffset, true)); } else if (cur.text === '') { // This line has no text content. Describe the DOM selection. new Output() .withRichSpeech( - new Range(cur.start_, cur.end_), - new Range(prev.start_, prev.end_), Output.EventType.NAVIGATE) + new Range(cur.start, cur.end), new Range(prev.start, prev.end), + Output.EventType.NAVIGATE) .go(); } else if ( !prev.hasCollapsedSelection() && !cur.hasCollapsedSelection() && @@ -552,21 +554,21 @@ // Wrapped across the baseline. Read out the new selection. suffixMsg = 'selected'; text = this.getTextSelection_( - curBase.startContainer_, curBase.localStartOffset, - curExtent.endContainer_, curExtent.localEndOffset); + curBase.startContainer, curBase.localStartOffset, + curExtent.endContainer, curExtent.localEndOffset); } else { if (prev.isBeforeLine(curExtent)) { // Grew. suffixMsg = 'selected'; text = this.getTextSelection_( - prev.endContainer_, prev.localEndOffset, - curExtent.endContainer_, curExtent.localEndOffset); + prev.endContainer, prev.localEndOffset, curExtent.endContainer, + curExtent.localEndOffset); } else { // Shrank. suffixMsg = 'unselected'; text = this.getTextSelection_( - curExtent.endContainer_, curExtent.localEndOffset, - prev.endContainer_, prev.localEndOffset); + curExtent.endContainer, curExtent.localEndOffset, + prev.endContainer, prev.localEndOffset); } } } else { @@ -575,21 +577,21 @@ // Wrapped across the baseline. Read out the new selection. suffixMsg = 'selected'; text = this.getTextSelection_( - curExtent.startContainer_, curExtent.localStartOffset, - curBase.endContainer_, curBase.localEndOffset); + curExtent.startContainer, curExtent.localStartOffset, + curBase.endContainer, curBase.localEndOffset); } else { if (curExtent.isBeforeLine(prev)) { // Grew. suffixMsg = 'selected'; text = this.getTextSelection_( - curExtent.startContainer_, curExtent.localStartOffset, - prev.startContainer_, prev.localStartOffset); + curExtent.startContainer, curExtent.localStartOffset, + prev.startContainer, prev.localStartOffset); } else { // Shrank. suffixMsg = 'unselected'; text = this.getTextSelection_( - prev.startContainer_, prev.localStartOffset, - curExtent.startContainer_, curExtent.localStartOffset); + prev.startContainer, prev.localStartOffset, + curExtent.startContainer, curExtent.localStartOffset); } } } @@ -600,7 +602,7 @@ // Without any other information, try describing the selection. This state // catches things like select all. const text = this.getTextSelection_( - cur.startContainer_, cur.localStartOffset, cur.endContainer_, + cur.startContainer, cur.localStartOffset, cur.endContainer, cur.localEndOffset); ChromeVox.tts.speak(text, QueueMode.CATEGORY_FLUSH); ChromeVox.tts.speak(Msgs.getMsg('selected'), QueueMode.QUEUE); @@ -611,7 +613,7 @@ // selections and picking the line edge boundary that changed (as computed // above). This is also the code path for describing paste. It also covers // jump commands which are non-overlapping selections from prev to cur. - this.speakCurrentRichLine_(prev); + this.line_.speakLine(prev); } this.updateIntraLineState_(cur); } @@ -620,11 +622,11 @@ handleBraille_() { const isFirstLine = this.isSelectionOnFirstLine(); const cur = this.line_; - if (cur.value_ === null) { + if (cur.value === null) { return; } - let value = new MultiSpannable(cur.value_); + let value = new MultiSpannable(cur.value); if (!this.node_.constructor) { return; } @@ -656,7 +658,7 @@ }); // Provide context for the current selection. - const context = cur.startContainer_; + const context = cur.startContainer; if (context && context.role !== RoleType.TEXT_FIELD) { const output = new Output().suppress('name').withBraille( Range.fromNode(context), Range.fromNode(this.node_), @@ -683,7 +685,7 @@ } value.append(Msgs.getMsg('tag_textarea_brl')); } - value.setSpan(new ValueSpan(0), 0, cur.value_.length); + value.setSpan(new ValueSpan(0), 0, cur.value.length); value.setSpan(new ValueSelectionSpan(), cur.startOffset, cur.endOffset); ChromeVox.braille.write(new NavBraille( {text: value, startIndex: cur.startOffset, endIndex: cur.endOffset})); @@ -838,41 +840,6 @@ } } - /** - * @param {editing.EditableLine} prevLine - * @private - */ - speakCurrentRichLine_(prevLine) { - let prev = (prevLine && prevLine.startContainer_.role) ? - prevLine.startContainer_ : - null; - const lineNodes = - /** @type {Array<!AutomationNode>} */ ( - this.line_.value_.getSpansInstanceOf( - /** @type {function()} */ (this.node_.constructor))); - let queueMode = QueueMode.CATEGORY_FLUSH; - for (let i = 0, cur; cur = lineNodes[i]; i++) { - if (cur.children.length) { - continue; - } - - const o = new Output() - .withRichSpeech( - Range.fromNode(cur), - prev ? Range.fromNode(prev) : Range.fromNode(cur), - Output.EventType.NAVIGATE) - .withQueueMode(queueMode); - - // Ignore whitespace only output except if it is leading content on the - // line. - if (!o.isOnlyWhitespace || i === 0) { - o.go(); - } - prev = cur; - queueMode = QueueMode.QUEUE; - } - } - /** @override */ describeSelectionChanged(evt) { // Note that since Chrome allows for selection to be placed immediately at @@ -927,42 +894,16 @@ * @param {!Array<AutomationIntent>} intents * @param {!editing.EditableLine} cur * @param {!editing.EditableLine} prev + * @return {boolean} * @private */ maybeSpeakUsingIntents_(intents, cur, prev) { - if (intents.length === 0) { - return false; - } - - // Only consider selection moves. - const intent = intents.find( - i => i.command === chrome.automation.IntentCommandType.MOVE_SELECTION); - if (!intent) { - return false; - } - - if (intent.textBoundary === - chrome.automation.IntentTextBoundaryType.CHARACTER) { + if (IntentHandler.onIntents(intents, cur, prev)) { this.updateIntraLineState_(cur); - - // Read character to the right of the cursor. It is assumed to be a new - // line if empty. - const text = - cur.text.substring(cur.startOffset, cur.startOffset + 1) || '\n'; - ChromeVox.tts.speak(text, QueueMode.CATEGORY_FLUSH); this.speakAllMarkers_(cur); return true; } - if (intent.textBoundary === - chrome.automation.IntentTextBoundaryType.LINE_START || - intent.textBoundary === - chrome.automation.IntentTextBoundaryType.LINE_END) { - this.updateIntraLineState_(cur); - this.speakCurrentRichLine_(prev); - return true; - } - return false; } @@ -971,7 +912,7 @@ * @private */ speakAllMarkers_(cur) { - const container = cur.startContainer_; + const container = cur.startContainer; if (!container) { return; } @@ -1013,451 +954,4 @@ * @private {ChromeVoxStateObserver} */ editing.observer_ = new editing.EditingChromeVoxStateObserver(); - -/** - * An EditableLine encapsulates all data concerning a line in the automation - * tree necessary to provide output. - * Editable: an editable selection (e.g. start/end offsets) get saved. - * Line: nodes/offsets at the beginning/end of a line get saved. - */ -editing.EditableLine = class { - /** - * @param {!AutomationNode} startNode - * @param {number} startIndex - * @param {!AutomationNode} endNode - * @param {number} endIndex - * @param {boolean=} opt_baseLineOnStart Controls whether to use - * |startNode| or |endNode| for Line computations. Selections are - * automatically truncated up to either the line start or end. - */ - constructor(startNode, startIndex, endNode, endIndex, opt_baseLineOnStart) { - /** @private {!Cursor} */ - this.start_ = new Cursor(startNode, startIndex); - this.start_ = this.start_.deepEquivalent || this.start_; - /** @private {!Cursor} */ - this.end_ = new Cursor(endNode, endIndex); - this.end_ = this.end_.deepEquivalent || this.end_; - - /** @private {AutomationNode|undefined} */ - this.endContainer_; - - // Update |startIndex| and |endIndex| if the calls above to - // cursors.Cursor.deepEquivalent results in cursors to different container - // nodes. The cursors can point directly to inline text boxes, in which case - // we should not adjust the container start or end index. - if (!AutomationPredicate.text(startNode) || - (this.start_.node !== startNode && - this.start_.node.parent !== startNode)) { - startIndex = - (this.start_.index === cursors.NODE_INDEX && this.start_.node.name) ? - this.start_.node.name.length : - this.start_.index; - } - - if (!AutomationPredicate.text(endNode) || - (this.end_.node !== endNode && this.end_.node.parent !== endNode)) { - endIndex = - (this.end_.index === cursors.NODE_INDEX && this.end_.node.name) ? - this.end_.node.name.length : - this.end_.index; - } - - /** @private {number} */ - this.localContainerStartOffset_ = startIndex; - /** @private {number} */ - this.localContainerEndOffset_ = endIndex; - - // Computed members. - /** @private {Spannable} */ - this.value_; - /** @private {AutomationNode|undefined} */ - this.lineStart_; - /** @private {AutomationNode|undefined} */ - this.lineEnd_; - /** @private {AutomationNode|undefined} */ - this.startContainer_; - /** @private {string} */ - this.startContainerValue_ = ''; - /** @private {AutomationNode|undefined} */ - this.lineStartContainer_; - /** @private {number} */ - this.localLineStartContainerOffset_ = 0; - /** @private {AutomationNode|undefined} */ - this.lineEndContainer_; - /** @private {number} */ - this.localLineEndContainerOffset_ = 0; - /** @type {RecoveryStrategy} */ - this.lineStartContainerRecovery_; - - this.computeLineData_(opt_baseLineOnStart); - } - - /** @private */ - computeLineData_(opt_baseLineOnStart) { - // Note that we calculate the line based only upon |start_| or - // |end_| even if they do not fall on the same line. It is up to - // the caller to specify which end to base this line upon since it requires - // reasoning about two lines. - let nameLen = 0; - const lineBase = opt_baseLineOnStart ? this.start_ : this.end_; - const lineExtend = opt_baseLineOnStart ? this.end_ : this.start_; - - if (lineBase.node.name) { - nameLen = lineBase.node.name.length; - } - - this.value_ = new Spannable(lineBase.node.name || '', lineBase); - if (lineBase.node === lineExtend.node) { - this.value_.setSpan(lineExtend, 0, nameLen); - } - - this.startContainer_ = this.start_.node; - if (this.startContainer_.role === RoleType.INLINE_TEXT_BOX) { - this.startContainer_ = this.startContainer_.parent; - } - this.startContainerValue_ = - this.startContainer_.role === RoleType.TEXT_FIELD ? - this.startContainer_.value || '' : - this.startContainer_.name || ''; - this.endContainer_ = this.end_.node; - if (this.endContainer_.role === RoleType.INLINE_TEXT_BOX) { - this.endContainer_ = this.endContainer_.parent; - } - - // Initialize defaults. - this.lineStart_ = lineBase.node; - this.lineEnd_ = this.lineStart_; - this.lineStartContainer_ = this.lineStart_.parent; - this.lineEndContainer_ = this.lineStart_.parent; - - // Annotate each chunk with its associated inline text box node. - this.value_.setSpan(this.lineStart_, 0, nameLen); - - // Also, track the nodes necessary for selection (either their parents, in - // the case of inline text boxes, or the node itself). - const parents = [this.startContainer_]; - - // Compute the start of line. - let lineStart = this.lineStart_; - - // Hack: note underlying bugs require these hacks. - while ((lineStart.previousOnLine && lineStart.previousOnLine.role) || - (lineStart.previousSibling && lineStart.previousSibling.lastChild && - lineStart.previousSibling.lastChild.nextOnLine === lineStart)) { - if (lineStart.previousOnLine) { - lineStart = lineStart.previousOnLine; - } else { - lineStart = lineStart.previousSibling.lastChild; - } - - this.lineStart_ = lineStart; - - if (lineStart.role !== RoleType.INLINE_TEXT_BOX) { - parents.unshift(lineStart); - } else if (parents[0] !== lineStart.parent) { - parents.unshift(lineStart.parent); - } - - const prepend = new Spannable(lineStart.name, lineStart); - prepend.append(this.value_); - this.value_ = prepend; - } - this.lineStartContainer_ = this.lineStart_.parent; - - let lineEnd = this.lineEnd_; - - // Hack: note underlying bugs require these hacks. - while ((lineEnd.nextOnLine && lineEnd.nextOnLine.role) || - (lineEnd.nextSibling && - lineEnd.nextSibling.previousOnLine === lineEnd)) { - if (lineEnd.nextOnLine) { - lineEnd = lineEnd.nextOnLine; - } else { - lineEnd = lineEnd.nextSibling.firstChild; - } - - this.lineEnd_ = lineEnd; - - if (lineEnd.role !== RoleType.INLINE_TEXT_BOX) { - parents.push(this.lineEnd_); - } else if (parents[parents.length - 1] !== lineEnd.parent) { - parents.push(this.lineEnd_.parent); - } - - let annotation = lineEnd; - if (lineEnd === this.end_.node) { - annotation = this.end_; - } - - this.value_.append(new Spannable(lineEnd.name, annotation)); - } - this.lineEndContainer_ = this.lineEnd_.parent; - - // Finally, annotate with all parent static texts as NodeSpan's so that - // braille routing can key properly into the node with an offset. - // Note that both line start and end needs to account for - // potential offsets into the static texts as follows. - let textCountBeforeLineStart = 0, textCountAfterLineEnd = 0; - let finder = this.lineStart_; - while (finder.previousSibling) { - finder = finder.previousSibling; - textCountBeforeLineStart += finder.name ? finder.name.length : 0; - } - this.localLineStartContainerOffset_ = textCountBeforeLineStart; - - if (this.lineStartContainer_) { - this.lineStartContainerRecovery_ = - new TreePathRecoveryStrategy(this.lineStartContainer_); - } - - finder = this.lineEnd_; - while (finder.nextSibling) { - finder = finder.nextSibling; - textCountAfterLineEnd += finder.name ? finder.name.length : 0; - } - - if (this.lineEndContainer_.name) { - this.localLineEndContainerOffset_ = - this.lineEndContainer_.name.length - textCountAfterLineEnd; - } - - let len = 0; - for (let i = 0; i < parents.length; i++) { - const parent = parents[i]; - - if (!parent.name) { - continue; - } - - const prevLen = len; - - let currentLen = parent.name.length; - let offset = 0; - - // Subtract off the text count before when at the start of line. - if (i === 0) { - currentLen -= textCountBeforeLineStart; - offset = textCountBeforeLineStart; - } - - // Subtract text count after when at the end of the line. - if (i === parents.length - 1) { - currentLen -= textCountAfterLineEnd; - } - - len += currentLen; - - try { - this.value_.setSpan(new Output.NodeSpan(parent, offset), prevLen, len); - - // Also, annotate this span if it is associated with line containre. - if (parent === this.startContainer_) { - this.value_.setSpan(parent, prevLen, len); - } - } catch (e) { - } - } - } - - /** - * Gets the selection offset based on the text content of this line. - * @return {number} - */ - get startOffset() { - // It is possible that the start cursor points to content before this line - // (e.g. in a multi-line selection). - try { - return this.value_.getSpanStart(this.start_) + - (this.start_.index === cursors.NODE_INDEX ? 0 : this.start_.index); - } catch (e) { - // When that happens, fall back to the start of this line. - return 0; - } - } - - /** - * Gets the selection offset based on the text content of this line. - * @return {number} - */ - get endOffset() { - try { - return this.value_.getSpanStart(this.end_) + - (this.end_.index === cursors.NODE_INDEX ? 0 : this.end_.index); - } catch (e) { - return this.value_.length; - } - } - - /** - * Gets the selection offset based on the parent's text. - * The parent is expected to be static text. - * @return {number} - */ - get localStartOffset() { - return this.localContainerStartOffset_; - } - - /** - * Gets the selection offset based on the parent's text. - * The parent is expected to be static text. - * @return {number} - */ - get localEndOffset() { - return this.localContainerEndOffset_; - } - - /** - * Gets the start offset of the container, relative to the line text - * content. The container refers to the static text parenting the inline - * text box. - * @return {number} - */ - get containerStartOffset() { - return this.value_.getSpanStart(this.startContainer_); - } - - /** - * Gets the end offset of the container, relative to the line text content. - * The container refers to the static text parenting the inline text box. - * @return {number} - */ - get containerEndOffset() { - return this.value_.getSpanEnd(this.startContainer_) - 1; - } - - /** - * The text content of this line. - * @return {string} The text of this line. - */ - get text() { - return this.value_.toString(); - } - - /** @return {string} */ - get selectedText() { - return this.value_.toString().substring(this.startOffset, this.endOffset); - } - - /** @return {boolean} */ - hasCollapsedSelection() { - return this.start_.equals(this.end_); - } - - /** - * Returns whether this line has selection over text nodes. - */ - hasTextSelection() { - if (this.start_.node && this.end_.node) { - return AutomationPredicate.text(this.start_.node) && - AutomationPredicate.text(this.end_.node); - } - } - - /** - * Returns true if |otherLine| surrounds the same line as |this|. Note that - * the contents of the line might be different. - * @param {editing.EditableLine} otherLine - * @return {boolean} - */ - isSameLine(otherLine) { - // Equality is intentionally loose here as any of the state nodes can be - // invalidated at any time. We rely upon the start/anchor of the line - // staying the same. - return (otherLine.lineStartContainer_ === this.lineStartContainer_ && - otherLine.localLineStartContainerOffset_ === - this.localLineStartContainerOffset_) || - (otherLine.lineEndContainer_ === this.lineEndContainer_ && - otherLine.localLineEndContainerOffset_ === - this.localLineEndContainerOffset_) || - (otherLine.lineStartContainerRecovery_.node === - this.lineStartContainerRecovery_.node && - otherLine.localLineStartContainerOffset_ === - this.localLineStartContainerOffset_); - } - - /** - * Returns true if |otherLine| surrounds the same line as |this| and has the - * same selection. - * @param {editing.EditableLine} otherLine - * @return {boolean} - */ - isSameLineAndSelection(otherLine) { - return this.isSameLine(otherLine) && - this.startOffset === otherLine.startOffset && - this.endOffset === otherLine.endOffset; - } - - /** - * Returns whether this line comes before |otherLine| in document order. - * @return {boolean} - */ - isBeforeLine(otherLine) { - if (this.isSameLine(otherLine) || !this.lineStartContainer_ || - !otherLine.lineStartContainer_) { - return false; - } - return AutomationUtil.getDirection( - this.lineStartContainer_, otherLine.lineStartContainer_) === - Dir.FORWARD; - } - - /** - * Performs a validation that this line still refers to a line given its - * internally tracked state. - */ - isValidLine() { - if (!this.lineStartContainer_ || !this.lineEndContainer_) { - return false; - } - - const start = new cursors.Cursor( - this.lineStartContainer_, this.localLineStartContainerOffset_); - const end = new cursors.Cursor( - this.lineEndContainer_, this.localLineEndContainerOffset_ - 1); - const localStart = start.deepEquivalent || start; - const localEnd = end.deepEquivalent || end; - const localStartNode = localStart.node; - const localEndNode = localEnd.node; - - // Unfortunately, there are asymmetric errors in lines, so we need to - // check in both directions. - let testStartNode = localStartNode; - do { - if (testStartNode === localEndNode) { - return true; - } - - // Hack/workaround for broken *OnLine links. - if (testStartNode.nextOnLine && testStartNode.nextOnLine.role) { - testStartNode = testStartNode.nextOnLine; - } else if ( - testStartNode.nextSibling && - testStartNode.nextSibling.previousOnLine === testStartNode) { - testStartNode = testStartNode.nextSibling; - } else { - break; - } - } while (testStartNode); - - let testEndNode = localEndNode; - do { - if (testEndNode === localStartNode) { - return true; - } - - // Hack/workaround for broken *OnLine links. - if (testEndNode.previousOnLine && testEndNode.previousOnLine.role) { - testEndNode = testEndNode.previousOnLine; - } else if ( - testEndNode.previousSibling && - testEndNode.previousSibling.nextOnLine === testEndNode) { - testEndNode = testEndNode.previousSibling; - } else { - break; - } - } while (testEndNode); - - return false; - } -}; }); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing_test.js similarity index 99% rename from chrome/browser/resources/chromeos/accessibility/chromevox/background/editing_test.js rename to chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing_test.js index 743a534..9083d69 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editing_test.js
@@ -267,7 +267,8 @@ ` <div role="textbox" contenteditable> <p style="font-size:20px; font-family:times"> - <b style="color:#ff0000">Move</b> <i>through</i> <u style="font-family:georgia">text</u> + <b style="color:#ff0000">Move</b> + <i>through</i> <u style="font-family:georgia">text</u> by <strike style="font-size:12px; color:#0000ff">character</strike> <a href="#">test</a>! </p>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/intent_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/intent_handler.js new file mode 100644 index 0000000..4ae374f --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/intent_handler.js
@@ -0,0 +1,120 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Handles automation intents for speech feedback. + */ + +goog.provide('IntentHandler'); + +goog.require('editing.EditableLine'); + +goog.scope(function() { +const AutomationIntent = chrome.automation.AutomationIntent; +const IntentCommandType = chrome.automation.IntentCommandType; +const IntentTextBoundaryType = chrome.automation.IntentTextBoundaryType; + +/** + * A stateless class that turns intents into speech. + */ +IntentHandler = class { + /** + * Called when intents are received from an AutomationEvent. + * @param {!Array<AutomationIntent>} intents + * @param {!editing.EditableLine} cur The current line. + * @param {editing.EditableLine} prev The previous line. + * @return {boolean} Whether intents are handled. + */ + static onIntents(intents, cur, prev) { + if (intents.length === 0) { + return false; + } + + // Currently, discard all other intents once one is handled. + for (let i = 0; i < intents.length; i++) { + if (IntentHandler.onIntent(intents[i], cur, prev)) { + return true; + } + } + + return false; + } + + /** + * Called when an intent is received. + * @param {!AutomationIntent} intent + * @param {!editing.EditableLine} cur The current line. + * @param {editing.EditableLine} prev The previous line. + * @return {boolean} Whether the intent was handled. + */ + static onIntent(intent, cur, prev) { + switch (intent.command) { + case IntentCommandType.MOVE_SELECTION: + return IntentHandler.onMoveSelection(intent, cur, prev); + + // TODO: implement support. + case IntentCommandType.CLEAR_SELECTION: + case IntentCommandType.DELETE: + case IntentCommandType.DICTATE: + case IntentCommandType.EXTEND_SELECTION: + case IntentCommandType.FORMAT: + case IntentCommandType.HISTORY: + case IntentCommandType.INSERT: + case IntentCommandType.MARKER: + case IntentCommandType.SET_SELECTION: + break; + } + + return false; + } + + /** + * Called when the text selection moves. + * @param {!AutomationIntent} intent A move selection + * intent. + * @param {!editing.EditableLine} cur The current line. + * @param {editing.EditableLine} prev The previous line. + * @return {boolean} Whether the intent was handled. + */ + static onMoveSelection(intent, cur, prev) { + switch (intent.textBoundary) { + case IntentTextBoundaryType.CHARACTER: + // Read character to the right of the cursor. It is assumed to be a new + // line if empty. + // TODO: detect when this is the end of the document; read "end of text" + // if so. + ChromeVox.tts.speak( + cur.text.substring(cur.startOffset, cur.startOffset + 1) || '\n', + QueueMode.CATEGORY_FLUSH); + return true; + + case IntentTextBoundaryType.LINE_END: + case IntentTextBoundaryType.LINE_START: + case IntentTextBoundaryType.LINE_START_OR_END: + cur.speakLine(prev); + return true; + + // TODO: implement support. + case IntentTextBoundaryType.FORMAT: + case IntentTextBoundaryType.OBJECT: + case IntentTextBoundaryType.PAGE_END: + case IntentTextBoundaryType.PAGE_START: + case IntentTextBoundaryType.PAGE_START_OR_END: + case IntentTextBoundaryType.PARAGRAPH_END: + case IntentTextBoundaryType.PARAGRAPH_START: + case IntentTextBoundaryType.PARAGRAPH_START_OR_END: + case IntentTextBoundaryType.SENTENCE_END: + case IntentTextBoundaryType.SENTENCE_START: + case IntentTextBoundaryType.SENTENCE_START_OR_END: + case IntentTextBoundaryType.WEB_PAGE: + case IntentTextBoundaryType.WORD_END: + case IntentTextBoundaryType.WORD_START: + case IntentTextBoundaryType.WORD_START_OR_END: + break; + } + + return false; + } +}; +}); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/common/gdocs_script.js b/chrome/browser/resources/chromeos/accessibility/common/gdocs_script.js index 0e265b99..5a9cfcca 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/gdocs_script.js +++ b/chrome/browser/resources/chromeos/accessibility/common/gdocs_script.js
@@ -4,12 +4,15 @@ var tries = 10; -// Google Docs isn't compatible with non-screen reader accessibility services by -// default because in order to provide screen reader support, most of the -// rendered document has aria-hidden set on it, which has the side effect of -// hiding it from non-screen reader accessibility features too. Fix it by -// changing aria-hidden to false. Try multiple times in case the page isn't -// fully loaded when the content script runs. +function triggerDocsHtmlFallbackMode() { + const scriptContents = ` + window['_docs_force_html_by_ext'] = "${chrome.runtime.id}"; + `; + const script = document.createElement('script'); + script.innerHTML = scriptContents; + document.body.appendChild(script); +} + function RemoveAriaHiddenFromGoogleDocsContent() { var element = document.querySelector('.kix-zoomdocumentplugin-outer'); if (element) { @@ -22,4 +25,15 @@ } } +// Docs will soon only render its contents in canvas. As a stop gap measure, +// trigger Docs' fallback html rendering mode. This needs to run within the +// page's context, so install a script to be executed. +triggerDocsHtmlFallbackMode(); + +// Google Docs isn't compatible with non-screen reader accessibility services by +// default because in order to provide screen reader support, most of the +// rendered document has aria-hidden set on it, which has the side effect of +// hiding it from non-screen reader accessibility features too. Fix it by +// changing aria-hidden to false. Try multiple times in case the page isn't +// fully loaded when the content script runs. RemoveAriaHiddenFromGoogleDocsContent();
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils.js index 83855261..204efc6 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils.js
@@ -547,6 +547,112 @@ } /** + * Gets the remaining content of a paragraph with an assigned position. The + * position is defined by the |charIndex| to the text of |nodeGroup|. If + * |direction| is set to forward, we will look for trailing content after the + * position. Otherwise, we will get the leading content before the position. + * The remaining content is returned as a list of nodes with offset. + * @param {!ParagraphUtils.NodeGroup} nodeGroup The nodeGroup of the assigned + * position. The nodeGroup may contain the content of the entire paragraph + * or only a part of the paragraph. + * @param {number} charIndex The char index of the position. The index is + * relative to the text content of the |nodeGroup|. This index is + * inclusive for forward searching: if we set |direction| to forward with + * a 0 |charIndex|, we will get the remaining content of the paragraph + * including all the content in the input |nodeGroup|. However, it is + * exclusive for backward searching: when searching backward with a 0 + * |charIndex|, we will exclude all the content in the input |nodeGroup|. + * @param {constants.Dir} direction + * @return {!{nodes: !Array<!AutomationNode>, + * offset: number}} + * nodes: the nodes that have the remaining content. + * offset: the offset for the nodes. When searching forward, the offset is + * into the name of the first node, and marks the start index of the remaining + * content in the first node, inclusively. For example, "Hello" with an offset + * 3 indicates that the remaining content is "lo". Otherwise, the offset is + * into the name of the last node, and marks the end index of the remaining + * content in the last node, exclusively. For example, "Hello" with an offset + * 3 indicates that the remaining content is "Hel". + */ + static getNextNodesInParagraphFromNodeGroup(nodeGroup, charIndex, direction) { + if (nodeGroup.nodes.length === 0) { + return {nodes: [], offset: -1}; + } + let {node: startNode, offset} = + ParagraphUtils.findNodeFromNodeGroupByCharIndex(nodeGroup, charIndex); + + if (direction === constants.Dir.BACKWARD) { + // If we did not find a node for the charIndex, we use the first node of + // the current node group and set offset to 0. This enables us to get all + // the content before the current node group in this paragraph. + if (!startNode) { + const firstNode = nodeGroup.nodes[0].node; + const firstChildOfFirstNode = NodeUtils.getFirstLeafChild(firstNode); + startNode = firstChildOfFirstNode || firstNode; + offset = 0; + } + + // Gets all the nodes before the startNode. We include the start node + // if it is not empty. Note that this is based on the assumption that + // this function will still include nodes with overflow text. + const leadingNodes = + NodeUtils.getNextNodesInParagraph(startNode, constants.Dir.BACKWARD); + const textInStartNode = + ParagraphUtils.getNodeName(startNode).substr(0, offset); + if (!ParagraphUtils.isWhitespace(textInStartNode)) { + leadingNodes.push(startNode); + return {nodes: leadingNodes, offset}; + } + if (leadingNodes.length === 0) { + return {nodes: [], offset: -1}; + } + // Returns all the nodes once we find a valid one among them. + for (const node of leadingNodes) { + if (NodeUtils.isValidLeafNode(node)) { + const lastLeadingNodeName = + ParagraphUtils.getNodeName(leadingNodes[leadingNodes.length - 1]); + return {nodes: leadingNodes, offset: lastLeadingNodeName.length}; + } + } + return {nodes: [], offset: -1}; + } + + // If we search forward, we use the start node as anchor and look for + // remaining content. If we did not find a node for the charIndex, we use + // the last node of the current node group as the starting node and set + // offset to the length of the node's name. This enables us to get all the + // content within this paragraph but after the current node group. + if (!startNode) { + const lastNode = nodeGroup.nodes[nodeGroup.nodes.length - 1].node; + const lastChildOfLastNode = NodeUtils.getLastLeafChild(lastNode); + startNode = lastChildOfLastNode || lastNode; + offset = ParagraphUtils.getNodeName(startNode).length; + } + + // Gets all the trailing nodes after the startNode. We include the start + // node if it is not empty. Note that this is based on the assumption that + // this function will still include nodes with overflow text. + const trailingNodes = + NodeUtils.getNextNodesInParagraph(startNode, constants.Dir.FORWARD); + const textInStartNode = + ParagraphUtils.getNodeName(startNode).substr(offset); + if (!ParagraphUtils.isWhitespace(textInStartNode)) { + const nodes = [startNode, ...trailingNodes]; + return {nodes, offset}; + } + if (trailingNodes.length === 0) { + return {nodes: [], offset: -1}; + } + // Returns all the nodes once we find a valid one among them. + for (const node of trailingNodes) { + if (NodeUtils.isValidLeafNode(node)) { + return {nodes: trailingNodes, offset: 0}; + } + } + return {nodes: [], offset: -1}; + } + + /** * @param {!AutomationNode} node * @return {boolean} Whether the given node is a valid leaf node that is can * be ingested by Select-to-speak.
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils_unittest.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils_unittest.js index e460083..d57859a7 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils_unittest.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/node_utils_unittest.js
@@ -830,6 +830,180 @@ assertEquals(result[2], text5); }); +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_forward', function() { + // The nodeGroup has four inline text nodes and one static text node. + // Their starting indexes are 0, 9, 20, 30, and 51. + const nodeGroup = generateTestNodeGroup(); + + let result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 0 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 5); + assertEquals(result.offset, 0); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 5 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 5); + assertEquals(result.offset, 5); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 9 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 4); + assertEquals(result.offset, 0); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 25 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 3); + assertEquals(result.offset, 5); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 51 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.offset, 0); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 100 /* charIndex */, + constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 0); + }); + +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_backward', function() { + // The nodeGroup has four inline text nodes and one static text node. + // Their starting indexes are 0, 9, 20, 30, and 51. + const nodeGroup = generateTestNodeGroup(); + + let result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 0 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 0); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 5 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.offset, 5); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 9 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.offset, 9); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 25 /* charIndex */, + constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 3); + assertEquals(result.offset, 5); + + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 51 /* charIndex */, + constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 4); + assertEquals(result.offset, 20); + + // The charIndex is out of the range of nodeGroup. It will try to get all + // the content before the nodeGroup. In this case, there is nothing. + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 100 /* charIndex */, + constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 0); + }); + +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_forwardWithEmptyTail', function() { + // The nodeGroup consists of three inline text nodes: "Hello", "world ", + // and " ". + const nodeGroup = generateTestNodeGroupWithEmptyTail(); + + // We can find the non-empty node at this charIndex but there is actually + // no text content afterwards. + const nodeWithOffset = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 11 /* charIndex */); + assertEquals(nodeWithOffset.node.name, 'world '); + assertEquals(nodeWithOffset.offset, 5); + + let result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 11 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 0); + + // If we decrease the charIndex, we will get the node with 'world ' but + // not any empty node. + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 10 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.nodes[0].name, 'world '); + }); + +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_backwardWithEmptyHeads', function() { + // The nodeGroup consists of three inline text nodes: " ", " Hello", + // "world". + const nodeGroup = generateTestNodeGroupWithEmptyHead(); + + // We can find the non-empty node at this charIndex but there is actually + // no text content before this position. + const nodeWithOffset = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 2 /* charIndex */); + assertEquals(nodeWithOffset.node.name, ' Hello'); + assertEquals(nodeWithOffset.offset, 1); + + let result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 2 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 0); + + // If we increase the charIndex, we will get the node with ' Hello' but + // not any empty node. + result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 3 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.nodes[0].name, ' Hello'); + }); + +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_forwardFromPartialParagraph', + function() { + // The nodeGroup consists only one static text node, which is "one". The + // entire paragraph has three static text nodes: "Sentence", "one", + // "here". + const nodeGroup = generateTestNodeGroupFromPartialParagraph(); + + // After reading "one", the TTS events will set charIndex to 3. Finding + // the static text node from the node group will return null. + const nodeWithOffset = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 3 /* charIndex */); + assertEquals(nodeWithOffset.node, null); + + const result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 3 /* charIndex */, constants.Dir.FORWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.offset, 0); + }); + +TEST_F( + 'SelectToSpeakNodeUtilsUnitTest', + 'getNextNodesInParagraphFromNodeGroup_backwardFromPartialParagraph', + function() { + // The nodeGroup consists only one static text node, which is "one". The + // entire paragraph has three static text nodes: "Sentence", "one", + // "here". + const nodeGroup = generateTestNodeGroupFromPartialParagraph(); + + // After reading "one", the TTS events will set charIndex to 3. Finding + // the static text node from the node group will return null. + const nodeWithOffset = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 3 /* charIndex */); + assertEquals(nodeWithOffset.node, null); + + const result = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, 3 /* charIndex */, constants.Dir.BACKWARD /* direction */); + assertEquals(result.nodes.length, 1); + assertEquals(result.nodes[0].name, 'Sentence'); + assertEquals(result.offset, 8); + }); + /** * Creates a AutomationNode-like object. * @param {!Object} properties @@ -840,7 +1014,8 @@ htmlAttributes: [], state: {}, children: [], - location: {}, + unclippedLocation: {left: 20, top: 10, width: 100, height: 50}, + location: {left: 20, top: 10, width: 100, height: 50}, }, properties); @@ -858,4 +1033,125 @@ parent.lastChild = node; } return node; +} + +/** + * Creates a nodeGroup for test purpose. + * @return {!ParagraphUtils.NodeGroup} + */ +function generateTestNodeGroup() { + const root = createMockNode({role: 'rootWebArea'}); + const paragraph = + createMockNode({role: 'paragraph', display: 'block', parent: root, root}); + const text1 = createMockNode( + {name: 'The first sentence.', role: 'staticText', parent: paragraph}); + const inlineText1 = createMockNode({ + role: 'inlineTextBox', + name: 'The first', + indexInParent: 0, + parent: text1 + }); + const inlineText2 = createMockNode({ + role: 'inlineTextBox', + name: ' sentence.', + indexInParent: 1, + parent: text1 + }); + + const text2 = createMockNode({ + name: 'The second sentence is longer.', + role: 'staticText', + parent: paragraph + }); + const inlineText3 = createMockNode({ + role: 'inlineTextBox', + name: 'The second', + indexInParent: 0, + parent: text2 + }); + const inlineText4 = createMockNode({ + role: 'inlineTextBox', + name: ' sentence is longer.', + indexInParent: 1, + parent: text2 + }); + + const text3 = createMockNode( + {name: 'No child sentence.', role: 'staticText', parent: paragraph}); + + return ParagraphUtils.buildNodeGroup( + [inlineText1, inlineText2, inlineText3, inlineText4, text3], 0, + false /* do not split on language */); +} + +/** + * Creates a nodeGroup that has an empty tail (i.e., "Hello world "). + * @return {!ParagraphUtils.NodeGroup} + */ +function generateTestNodeGroupWithEmptyTail() { + const root = createMockNode({role: 'rootWebArea'}); + const paragraph = + createMockNode({role: 'paragraph', display: 'block', parent: root, root}); + const text1 = + createMockNode({name: 'Hello', role: 'staticText', parent: paragraph}); + const inlineText1 = createMockNode( + {role: 'inlineTextBox', name: 'Hello', indexInParent: 0, parent: text1}); + + const text2 = + createMockNode({name: 'world ', role: 'staticText', parent: paragraph}); + const inlineText2 = createMockNode( + {role: 'inlineTextBox', name: 'world ', indexInParent: 0, parent: text2}); + const inlineText3 = createMockNode( + {role: 'inlineTextBox', name: ' ', indexInParent: 1, parent: text2}); + + return ParagraphUtils.buildNodeGroup( + [inlineText1, inlineText2, inlineText3], 0, + false /* do not split on language */); +} + +/** + * Creates a nodeGroup that has an empty head (i.e., " Hello world"). + * @return {!ParagraphUtils.NodeGroup} + */ +function generateTestNodeGroupWithEmptyHead() { + const root = createMockNode({role: 'rootWebArea'}); + const paragraph = + createMockNode({role: 'paragraph', display: 'block', parent: root, root}); + const text1 = + createMockNode({name: ' Hello', role: 'staticText', parent: paragraph}); + const inlineText1 = createMockNode( + {role: 'inlineTextBox', name: ' ', indexInParent: 0, parent: text1}); + const inlineText2 = createMockNode( + {role: 'inlineTextBox', name: ' Hello', indexInParent: 1, parent: text1}); + + const text2 = + createMockNode({name: 'world ', role: 'staticText', parent: paragraph}); + const inlineText3 = createMockNode( + {role: 'inlineTextBox', name: 'world', indexInParent: 1, parent: text2}); + + return ParagraphUtils.buildNodeGroup( + [inlineText1, inlineText2, inlineText3], 0, + false /* do not split on language */); +} + +/** + * Creates a nodeGroup that only has a part of the paragraph (e.g., the "one" in + * <p>Sentence <span>one</span> here</p>). + * @return {!ParagraphUtils.NodeGroup} + */ +function generateTestNodeGroupFromPartialParagraph() { + const root = createMockNode({role: 'rootWebArea'}); + const paragraph = + createMockNode({role: 'paragraph', display: 'block', parent: root, root}); + const text1 = + createMockNode({name: 'Sentence', role: 'staticText', parent: paragraph}); + + const text2 = + createMockNode({name: 'one', role: 'staticText', parent: paragraph}); + + const text3 = + createMockNode({name: 'here', role: 'staticText', parent: paragraph}); + + return ParagraphUtils.buildNodeGroup( + [text2], 0, false /* do not split on language */); } \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js index cd0a0d2..fe2f669 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils.js
@@ -244,6 +244,8 @@ /** * Determines the index into the parent name at which the inlineTextBox * node name begins. + * TODO(leileilei@google.com): Corrects the annotation of |inlineTextNode| + * to non-nullable. * @param {AutomationNode} inlineTextNode An inlineTextBox type node. * @return {number} The character index into the parent node at which * this node begins. @@ -314,15 +316,21 @@ * @param {Array<!AutomationNode>} nodes List of automation nodes to use. * @param {number} index The index into nodes at which to start. * @param {{splitOnLanguage: (boolean|undefined), - * clipOverflowWords: (boolean|undefined)}=} opt_options - * splitOnLanguage: flag to determine if we should split nodes - * up based on language. + * splitOnParagraph: (boolean|undefined), + * clipOverflowWords: (boolean|undefined)}=} options + * splitOnLanguage: flag to determine if we should split nodes up based on + * language. If this is not passed, default to false. + * splitOnParagraph: flag to determine if we should split nodes up based + * on paragraph. If this is not passed, default to true. * clipOverflowWords: Whether to clip generated text. * @return {ParagraphUtils.NodeGroup} info about the node group */ - static buildNodeGroup(nodes, index, opt_options) { - const options = opt_options || {}; + static buildNodeGroup(nodes, index, options) { + options = options || {}; const splitOnLanguage = options.splitOnLanguage || false; + const splitOnParagraph = options.splitOnParagraph === undefined ? + true : + options.splitOnParagraph; const clipOverflowWords = options.clipOverflowWords || false; let node = nodes[index]; let next = nodes[index + 1]; @@ -391,9 +399,10 @@ // Stop if any of following is true: // 1. we have no more nodes to process. - // 2. the next node is not part of the same paragraph. + // 2. we need to check for a paragraph split and if the next node is not + // part of the same paragraph. if (index + 1 >= nodes.length || - !ParagraphUtils.inSameParagraph(node, next)) { + (splitOnParagraph && !ParagraphUtils.inSameParagraph(node, next))) { break; } @@ -417,6 +426,106 @@ result.endIndex = index; return result; } + + /** + * Builds a single node group that contains all the input |nodes|. In + * addition, this function will transform the provided node offsets to values + * that are relative to the text of the resulting node group. This function + * can be used to check the sentence boundaries across all the input nodes. + * @param {!Array<!AutomationNode>} nodes The nodes for the selected content. + * @param {number=} opt_startIndex The index into the first node's text at + * which the selected content starts. + * @param {number=} opt_endIndex The index into the last node's text at which + * the selected content ends. + * @return {!{nodeGroup: ParagraphUtils.NodeGroup, + * startIndexInGroup: (number|undefined), + * endIndexInGroup: (number|undefined)}} + * nodeGroup: The node group that contains all the input |nodes|. The node + * group will not consider any language difference or paragraph split. + * startOffsetInGroup: The index into the node group's text at which the + * selected content starts. + * endOffsetInGroup: The index into the node group's text at which the + * selected content ends. + */ + static buildSingleNodeGroupWithOffset(nodes, opt_startIndex, opt_endIndex) { + const nodeGroup = ParagraphUtils.buildNodeGroup( + nodes, 0 /* index */, + {splitOnLanguage: false, splitOnParagraph: false}); + if (opt_startIndex !== undefined) { + // The first node of the NodeGroup may not be at the beginning of the + // parent of the NodeGroup. (e.g., an inlineText in its staticText + // parent). Thus, we need to adjust the |opt_startIndex|. + const firstNodeHasInlineText = + nodeGroup.nodes.length > 0 && nodeGroup.nodes[0].hasInlineText; + const startIndexInNodeParent = firstNodeHasInlineText ? + ParagraphUtils.getStartCharIndexInParent(nodes[0]) : + 0; + opt_startIndex += startIndexInNodeParent + nodeGroup.nodes[0].startChar; + } + if (opt_endIndex !== undefined) { + // Similarly, |opt_endIndex| needs to be adjusted. + const lastNodeHasInlineText = nodeGroup.nodes.length > 0 && + nodeGroup.nodes[nodeGroup.nodes.length - 1].hasInlineText; + const startIndexInNodeParent = lastNodeHasInlineText ? + ParagraphUtils.getStartCharIndexInParent(nodes[0]) : + 0; + opt_endIndex += startIndexInNodeParent + + nodeGroup.nodes[nodeGroup.nodes.length - 1].startChar; + } + + return { + nodeGroup, + startIndexInGroup: opt_startIndex, + endIndexInGroup: opt_endIndex + }; + } + + /** + * Finds the AutomationNode that appears at the given character index within + * the |nodeGroup|. + * @param {!ParagraphUtils.NodeGroup} nodeGroup The nodeGroup that has the + * nodeGroupItem. + * @param {number} charIndex The char index into the nodeGroup's text. The + * index is relative to the start of the |nodeGroup|. + * @return {!{node: ?AutomationNode, + * offset: number}} + * node: the AutomationNode within the |nodeGroup| that appears at + * |charIndex|. For a static text node that has inline text nodes, we will + * return the inline text node corresponding to the |charIndex|. + * offset: the offset indicating the position of the |charIndex| within + * the found nodeGroupItem. The offset is relative to the start of the |node|. + */ + static findNodeFromNodeGroupByCharIndex(nodeGroup, charIndex) { + for (const currentNodeGroupItem of nodeGroup.nodes) { + const currentNode = currentNodeGroupItem.node; + const currentNodeNameLength = + ParagraphUtils.getNodeName(currentNode).length; + // We iterate over each nodeGroupItem until the |charIndex| is pointing + // before the current node's name. + if (currentNodeGroupItem.startChar + currentNodeNameLength > charIndex) { + // The currentNodeOffset is the position of the |charIndex| within the + // current nodeGroupItem. + const currentNodeOffset = charIndex - currentNodeGroupItem.startChar; + if (!currentNodeGroupItem.hasInlineText) { + // If the nodeGroupItem does not have inline text, we return the + // corresponding node and the current offset. + return {node: currentNode, offset: currentNodeOffset}; + } + + const inlineTextNode = + ParagraphUtils.findInlineTextNodeByCharacterIndex( + currentNode, currentNodeOffset); + + return inlineTextNode ? { + node: inlineTextNode, + offset: currentNodeOffset - + ParagraphUtils.getStartCharIndexInParent(inlineTextNode) + } : + {node: currentNode, offset: currentNodeOffset}; + } + } + return {node: null, offset: 0}; + } } @@ -438,7 +547,7 @@ /** * List of nodes in this paragraph in order. - * @type {Array<ParagraphUtils.NodeGroupItem>} + * @type {!Array<ParagraphUtils.NodeGroupItem>} */ this.nodes = [];
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils_unittest.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils_unittest.js index eb2dfcf23..82c46834 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils_unittest.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/paragraph_utils_unittest.js
@@ -248,6 +248,33 @@ }); TEST_F( + 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupAcrossParagraphs', + function() { + const root = {role: 'rootWebArea'}; + const paragraph1 = + {role: 'paragraph', display: 'block', parent: root, root}; + const text1 = + {role: 'staticText', parent: paragraph1, name: 'text1', root}; + const text2 = + {role: 'staticText', parent: paragraph1, name: 'text2', root}; + const paragraph2 = + {role: 'paragraph', display: 'block', parent: root, root}; + const text3 = + {role: 'staticText', parent: paragraph2, name: 'text3', root}; + const result = ParagraphUtils.buildNodeGroup( + [text1, text2, text3], 0, {splitOnParagraph: false}); + assertEquals('text1 text2 text3 ', result.text); + assertEquals(2, result.endIndex); + assertEquals(3, result.nodes.length); + assertEquals(0, result.nodes[0].startChar); + assertEquals(text1, result.nodes[0].node); + assertEquals(6, result.nodes[1].startChar); + assertEquals(text2, result.nodes[1].node); + assertEquals(12, result.nodes[2].startChar); + assertEquals(text3, result.nodes[2].node); + }); + +TEST_F( 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtLanguageBoundary', function() { const splitOnLanguage = true; @@ -484,3 +511,168 @@ [inline1, inline2], 0, {splitOnLanguage: false}); assertEquals('Hello, world! ', result.text); }); + +TEST_F( + 'SelectToSpeakParagraphUnitTest', 'findNodeFromNodeGroupByCharIndex', + function() { + // The array has four inline text nodes and one static text node. + const nodeGroup = + ParagraphUtils.buildNodeGroup(generateNodesForParagraph(), 0); + // Start index = 0 + const firstInline = 'The first'; + // Start index = 9 + const secondInline = ' sentence.'; + // Start index = 20 + const thirdInline = 'The second'; + // Start index = 30 + const fourthInline = ' sentence is longer.'; + // Start index = 51 + const thirdStatic = 'No child sentence.'; + + let result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 0 /* charIndex */); + assertEquals(result.node.name, firstInline); + assertEquals(result.offset, 0); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 3 /* charIndex */); + assertEquals(result.node.name, firstInline); + assertEquals(result.offset, 3); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 10 /* charIndex */); + assertEquals(result.node.name, secondInline); + assertEquals(result.offset, 1); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 20 /* charIndex */); + assertEquals(result.node.name, thirdInline); + assertEquals(result.offset, 0); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 33 /* charIndex */); + assertEquals(result.node.name, fourthInline); + assertEquals(result.offset, 3); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 52 /* charIndex */); + assertEquals(result.node.name, thirdStatic); + assertEquals(result.offset, 1); + + result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( + nodeGroup, 100 /* charIndex */); + assertEquals(result.node, null); + }); + +TEST_F( + 'SelectToSpeakParagraphUnitTest', 'BuildSingleNodeGroupWithOffset', + function() { + // The array has four inline text nodes and one static text node. + // Their starting indexes are 0, 9, 20, 30, and 51. + const nodes = generateNodesForParagraph(); + // Start index = 0 + const firstInline = 'The first'; + // Start index = 9 + const secondInline = ' sentence.'; + const firstSentence = firstInline + secondInline + ' '; + // Start index = 20 + const thirdInline = 'The second'; + // Start index = 30 + const fourthInline = ' sentence is longer.'; + const secondSentence = thirdInline + fourthInline + ' '; + // Start index = 51 + const thirdStatic = 'No child sentence.'; + const thirdSentence = thirdStatic + ' '; + + let nodeGroup, startIndexInGroup, endIndexInGroup; + ({nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset(nodes)); + assertEquals( + nodeGroup.text, firstSentence + secondSentence + thirdSentence); + assertEquals(startIndexInGroup, undefined); + assertEquals(endIndexInGroup, undefined); + + ({nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset( + nodes, 5 /* startIndex */)); + assertEquals( + nodeGroup.text, firstSentence + secondSentence + thirdSentence); + assertEquals(startIndexInGroup, 5); + assertEquals(endIndexInGroup, undefined); + + ({nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset( + nodes.slice(1), 0 /* startIndex */)); + assertEquals( + nodeGroup.text, firstSentence + secondSentence + thirdSentence); + assertEquals(startIndexInGroup, 9); + assertEquals(endIndexInGroup, undefined); + + ({nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset( + nodes.slice(2, 5), 1 /* startIndex */, 1 /* endIndex */)); + assertEquals(nodeGroup.text, secondSentence + thirdSentence); + assertEquals(startIndexInGroup, 1); + assertEquals(endIndexInGroup, 32); + + ({nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset( + nodes.slice(4, 5), undefined, 5 /* endIndex */)); + assertEquals(nodeGroup.text, thirdSentence); + assertEquals(startIndexInGroup, undefined); + assertEquals(endIndexInGroup, 5); + }); + +/** + * Creates an array of nodes that represents a paragraph. + * @return {Array<AutomationNode>} + */ +function generateNodesForParagraph() { + const root = {role: 'rootWebArea'}; + const paragraph = {role: 'paragraph', display: 'block', parent: root, root}; + const text1 = { + name: 'The first sentence.', + role: 'staticText', + parent: paragraph + }; + const inlineText1 = { + role: 'inlineTextBox', + name: 'The first', + indexInParent: 0, + parent: text1 + }; + const inlineText2 = { + role: 'inlineTextBox', + name: ' sentence.', + indexInParent: 1, + parent: text1 + }; + text1.children = [inlineText1, inlineText2]; + + const text2 = { + name: 'The second sentence is longer.', + role: 'staticText', + parent: paragraph + }; + const inlineText3 = { + role: 'inlineTextBox', + name: 'The second', + indexInParent: 0, + parent: text2 + }; + const inlineText4 = { + role: 'inlineTextBox', + name: ' sentence is longer.', + indexInParent: 1, + parent: text2 + }; + text2.children = [inlineText3, inlineText4]; + + const text3 = { + name: 'No child sentence.', + role: 'staticText', + parent: paragraph + }; + + return [inlineText1, inlineText2, inlineText3, inlineText4, text3]; +} \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js index a03f81e..0419f2c 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
@@ -145,17 +145,15 @@ this.currentNodeWord_ = null; /** - * There are five navigation state variables: |currentNodes|, - * |currentNodeGroupStartNodeIndex|, |currentCharIndex|, - * |currentStartCharIndex|, |currentEndCharIndex|. These variables enable - * us to separate the functionalities of node enqueuing, navigation - * control, and TTS playing. + * These navigation state variables enable us to separate the + * functionalities of node enqueueing, navigation control, and TTS playback. * @private {!{currentNodes:!Array<AutomationNode>, * currentNodeGroupStartNodeIndex: number, * currentCharIndex: number, * currentStartCharIndex: (number|undefined), * currentEndCharIndex: (number|undefined), * supportsNavigationPanel: boolean}} + * isUserSelectedContent: boolean}} */ this.navigationState_ = { /** @@ -196,6 +194,14 @@ * Whether the current nodes support use of the navigation panel. */ supportsNavigationPanel: true, + + /** + * Whether we are reading user-selected content. True if the current + * content is from mouse or keyboard selection. False if the current + * content is processed by the navigation features like paragraph + * navigation, sentence navigation, pause and resume. + */ + isUserSelectedContent: false, }; /** @@ -338,7 +344,8 @@ // expand to entire paragraph. nodes = NodeUtils.getAllNodesInParagraph(nodes[0]); } - this.startSpeechQueue_(nodes, {clearFocusRing: true}); + this.startSpeechQueue_( + nodes, {clearFocusRing: true, isUserSelectedContent: true}); MetricsUtils.recordStartEvent( MetricsUtils.StartSpeechMethod.MOUSE, this.prefsManager_); }.bind(this)); @@ -496,14 +503,17 @@ // The node at the last position was not added to the list, perhaps it // was whitespace or invisible. Clear the ending offset because it // relates to a node that doesn't exist. - this.startSpeechQueue_( - nodes, - {clearFocusRing: true, startCharIndex: firstPosition.offset}); + this.startSpeechQueue_(nodes, { + clearFocusRing: true, + startCharIndex: firstPosition.offset, + isUserSelectedContent: true + }); } else { this.startSpeechQueue_(nodes, { clearFocusRing: true, startCharIndex: firstPosition.offset, - endCharIndex: lastPosition.offset + endCharIndex: lastPosition.offset, + isUserSelectedContent: true }); } this.initializeScrollingToOffscreenNodes_(focusedNode.root); @@ -622,7 +632,8 @@ * Set |this.ttsPaused_| and |this.state_| according to pause status. * @param {boolean} shouldPause whether the TTS is on pause or speaking. * @private - * TODO(leileilei): use SelectToSpeakState.PAUSE to indicate the status. + * TODO(leileilei): use SelectToSpeakState.PAUSE to indicate the status and + * consider refactoring the name of this function. */ updatePauseStatusFromTtsEvent_(shouldPause) { this.ttsPaused_ = shouldPause; @@ -650,11 +661,22 @@ resolve(); }; chrome.tts.stop(); + // If the user triggers pause_() or navigation features that use pause_() + // (e.g., sentence navigation), the following reading content will not be + // user-selected content. This enables us to distinguish between a user- + // trigger pause from the auto pause happening at the end of user-selected + // content. + this.navigationState_.isUserSelectedContent = false; }); } /** - * Resume the TTS from the beginning of the current sentence. + * Resume the TTS. If there is no remaining content in this paragraph, we will + * navigate to the next paragraph. If there is still content in this + * paragraph, STS behaves differently depending on the resume status. If we + * resume from a user-trigger pause, we will resume from the start of the + * current sentence. If we resume from the end of user-selected content, we + * will continue reading remaining content. * @private */ resume_() { @@ -662,20 +684,36 @@ if (!this.isPaused_()) { return; } - if (!SentenceUtils.isSentenceStart( - this.currentNodeGroup_, this.navigationState_.currentCharIndex)) { - // If the current position is not a sentence start, move to the start of - // the current sentence. - const currentSentenceStart = SentenceUtils.getSentenceStart( - this.currentNodeGroup_, this.navigationState_.currentCharIndex, - constants.Dir.BACKWARD); - // Only navigate to the current sentence start if it exists, otherwise - // move to the beginning of the current nodeGroup. - // TODO(leileilei): check if the 0 char index would cause issues. - this.navigationState_.currentCharIndex = - currentSentenceStart === null ? 0 : currentSentenceStart; + // If there is no processed node group, that means the user has not selected + // anything. Ignore the resume command. + if (!this.currentNodeGroup_) { + return; } - this.startCurrentNodeGroup_(); + const {nodes: remainingNodes, offset} = + NodeUtils.getNextNodesInParagraphFromNodeGroup( + this.currentNodeGroup_, this.navigationState_.currentCharIndex, + constants.Dir.FORWARD); + // There is no remaining nodes in this paragraph so we navigate to the next + // paragraph. + if (remainingNodes.length === 0) { + this.navigateToNextParagraph_(constants.Dir.FORWARD); + return; + } + + if (this.navigationState_.isUserSelectedContent || + SentenceUtils.isSentenceStart( + this.currentNodeGroup_, this.navigationState_.currentCharIndex)) { + // If we are resuming from the end of user-selected content or if we are + // at the start of the current sentence, we should start reading the + // remaining content. + this.startSpeechQueue_( + remainingNodes, {clearFocusRing: false, startCharIndex: offset}); + return; + } + + // If the current position is not a sentence start, navigate to the start of + // this sentence. + this.navigateToNextSentence_(constants.Dir.BACKWARD); } /** @@ -707,6 +745,7 @@ currentStartCharIndex: undefined, currentEndCharIndex: undefined, supportsNavigationPanel: true, + isUserSelectedContent: false, }; } @@ -974,30 +1013,175 @@ } /** - * Navigate to the next sentence. - * @param {constants.Dir} direction whether to find the next sentence or - * previous sentence. + * Navigates to the next sentence. First, we search the next sentence in the + * current node group. If we do not find one, we will search within the + * remaining content in the current paragraph (i.e., text block). If this + * still fails, we will search the next paragraph. + * @param {constants.Dir} direction Direction to search for the next sentence. + * If set to forward, we look for the sentence start after the current + * position. Otherwise, we look for the sentence start before the current + * position. * @private */ async navigateToNextSentence_(direction) { // An empty node group is not expected and means that the user has not // enqueued any text. - if (this.currentNodeGroup_ === null) { + if (!this.currentNodeGroup_) { return; } - await this.pause_(); - const nextSentenceStartInCurrentNodeGroup = SentenceUtils.getSentenceStart( + if (!this.isPaused_()) { + await this.pause_(); + } + + // Check the next sentence start within this node group. + if (this.navigateToNextSentenceWithinNodeGroup_( + this.currentNodeGroup_, this.navigationState_.currentCharIndex, + direction)) { + return; + } + + // If there is no sentence start at the current node group, look for the + // content within this paragraph. First, we get the remaining content in + // the paragraph. The returned offset marks the char index of the current + // position in the paragraph. When searching forward, the offset is the + // char index pointing to the beginning of the remaining content. When + // searching backward, the offset is the char index pointing to the char + // after the remaining content. + const {nodes, offset} = NodeUtils.getNextNodesInParagraphFromNodeGroup( this.currentNodeGroup_, this.navigationState_.currentCharIndex, direction); - if (nextSentenceStartInCurrentNodeGroup === null) { - // TODO(leileilei): if there is no sentence in the current node group, - // move to the next one. - } else { - this.navigationState_.currentCharIndex = - nextSentenceStartInCurrentNodeGroup; + // If we have reached to the end of a paragraph, navigate to the next + // paragraph. + if (nodes.length === 0) { + this.navigateToNextSentenceInNextParagraph_(direction); + return; } - this.resume_(); + // Get the node group for the remaining content in the paragraph. If we are + // looking for the content after the current position, set startIndex as + // offset. Otherwise, set endIndex as offset. + const startIndex = direction === constants.Dir.FORWARD ? offset : undefined; + const endIndex = direction === constants.Dir.FORWARD ? undefined : offset; + const {nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset( + nodes, startIndex, endIndex); + // Search in the remaining content. + const charIndex = direction === constants.Dir.FORWARD ? startIndexInGroup : + endIndexInGroup; + // The charIndex is guaranteed to be valid at this point, although the + // closure compiler is not able to detect it as a valid number. + if (charIndex === undefined) { + console.warn('Navigate sentence with an invalid char index', charIndex); + return; + } + if (this.navigateToNextSentenceWithinNodeGroup_( + nodeGroup, charIndex, direction)) { + return; + } + + // If there is no sentence start within this paragraph, navigate to the next + // one. + this.navigateToNextSentenceInNextParagraph_(direction); + } + + /** + * Navigates to the next sentence within the |nodeGroup|. If the |direction| + * is set to forward, it will navigate to the sentence start after the + * |startCharIndex|. Otherwise, it will look for the sentence start before the + * |startCharIndex|. + * @param {ParagraphUtils.NodeGroup} nodeGroup + * @param {number} startCharIndex The char index that we start from. This + * index is relative to the text content of this node group and is + * exclusive: if a sentence start at 0 and we search with a 0 + * |startCharIndex|, this function will return the next sentence start + * after 0 if we search forward. + * @param {constants.Dir} direction + * @return {boolean} Whether we have found a sentence start in the given node + * group. If we found the sentence start, we will start TTS. + * @private + */ + navigateToNextSentenceWithinNodeGroup_(nodeGroup, startCharIndex, direction) { + if (!nodeGroup) { + return false; + } + const nextSentenceStart = + SentenceUtils.getSentenceStart(nodeGroup, startCharIndex, direction); + if (nextSentenceStart === null) { + return false; + } + + // Get the content between the sentence start and the end of the paragraph. + const {nodes, offset} = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, nextSentenceStart, constants.Dir.FORWARD); + if (nodes.length === 0) { + // There is no remaining content. Move to the next paragraph. This is + // unexpected since we already found a sentence start, which indicates + // there should be some content to read. + this.navigateToNextSentenceInNextParagraph_(direction); + } else { + this.startSpeechQueue_( + nodes, {clearFocusRing: false, startCharIndex: offset}); + } + return true; + } + + /** + * Navigates to the next sentence in the next text block in the given + * direction. If the |direction| is set to forward, it will navigate to the + * start of the following text block. Otherwise, it will look for the last + * sentence in the previous text block. This function will also start TTS + * regardless of whether we have found a sentence start in the text block. + * @param {constants.Dir} direction + * @private + */ + navigateToNextSentenceInNextParagraph_(direction) { + const paragraphNodes = this.locateNodesForNextParagraph_(direction); + if (paragraphNodes.length === 0) { + return; + } + // Ensure the first node in the paragraph is visible. + paragraphNodes[0].makeVisible(); + + if (direction === constants.Dir.FORWARD) { + // If we are looking for the sentence start in the following text block, + // start reading the nodes. + this.startSpeechQueue_(paragraphNodes); + return; + } + + // If we are looking for the previous sentence start, search the last + // sentence in the previous text block. Get the node group for the previous + // text block. The returned startIndexInGroup and endIndexInGroup are + // unused. + const {nodeGroup, startIndexInGroup, endIndexInGroup} = + ParagraphUtils.buildSingleNodeGroupWithOffset(paragraphNodes); + // We search backward for the sentence start before the end of the text + // block. + const searchOffset = nodeGroup.text.length; + const sentenceStartIndex = SentenceUtils.getSentenceStart( + nodeGroup, searchOffset, constants.Dir.BACKWARD); + // If there is no sentence start in the previous text block, start reading + // the block. + if (sentenceStartIndex === null) { + this.startSpeechQueue_(paragraphNodes); + return; + } + // Gets the remaining content between the sentence start till the end of the + // text block. The offset is the start char index for the first node in the + // remaining content. + const {nodes, offset} = NodeUtils.getNextNodesInParagraphFromNodeGroup( + nodeGroup, sentenceStartIndex, constants.Dir.FORWARD); + if (nodes.length === 0) { + // If there is no remaining content, start reading the block. This is + // unexpected since we already found a sentence start, which indicates + // there should be some content to read. + this.startSpeechQueue_(paragraphNodes); + return; + } + // Reads the remaining content from the sentence start till the end of the + // block. + this.startSpeechQueue_( + nodes, {clearFocusRing: false, startCharIndex: offset}); } /** @@ -1011,6 +1195,26 @@ await this.pause_(); } + const nodes = this.locateNodesForNextParagraph_(direction); + if (nodes.length === 0) { + return; + } + // Ensure the first node in the paragraph is visible. + nodes[0].makeVisible(); + + this.startSpeechQueue_(nodes); + } + + /** + * Finds the nodes for the next text block in the given direction. This + * function is based on |NodeUtils.getNextParagraph| but provides additional + * checks on the anchor node used for searchiong. + * @param {constants.Dir} direction + * @return {Array<!AutomationNode>} A list of nodes for the next block in the + * given direction. + * @private + */ + locateNodesForNextParagraph_(direction) { // Use current block parent as starting point to navigate from. If it is not // a valid block, then use one of the nodes that are currently activated. let node = this.currentBlockParent_; @@ -1020,25 +1224,22 @@ } if (node === null) { // Could not find any nodes to navigate from. - return; + return []; } // Retrieve the nodes that make up the next/prev paragraph. const nextParagraphNodes = NodeUtils.getNextParagraph(node, direction); if (nextParagraphNodes.length === 0) { // Cannot find any valid nodes in given direction. - return; + return []; } if (AutomationUtil.getAncestors(nextParagraphNodes[0]) .find((n) => this.isPanel_(n))) { // Do not navigate to Select-to-speak panel. - return; + return []; } - // Ensure the first node in the paragraph is visible. - nextParagraphNodes[0].makeVisible(); - - this.startSpeechQueue_(nextParagraphNodes); + return nextParagraphNodes; } /** @@ -1086,11 +1287,12 @@ * Enqueue nodes to TTS queue and start TTS. This function can be used for * adding nodes, either from user selection (e.g., mouse selection) or * navigation control (e.g., next paragraph). This function will overwrite - * |currentNodes| and start TTS according to the offsets. - * @param {Array<AutomationNode>} nodes The nodes to speak. - * @param {{clearFocusRing: (boolean|undefined), + * |this.navigationState_| and start TTS according to the offsets. + * @param {!Array<AutomationNode>} nodes The nodes to speak. + * @param {!{clearFocusRing: (boolean|undefined), * startCharIndex: (number|undefined), - * endCharIndex: (number|undefined)}=} opt_params + * endCharIndex: (number|undefined), + * isUserSelectedContent: (boolean|undefined)}=} opt_params * clearFocusRing: Whether to clear the focus ring or not. For example, we * need to clear the focus ring when starting from scratch but we do not need * to clear the focus ring when resuming from a previous pause. If this is not @@ -1099,6 +1301,8 @@ * speaking. If this is not passed, will start at 0. * endCharIndex: The index into the last node's text at which to end * speech. If this is not passed, will stop at the end. + * isUserSelectedContent: Whether the content is from user selection. If + * this is not passed, will default to false. * @private */ startSpeechQueue_(nodes, opt_params) { @@ -1106,6 +1310,7 @@ const clearFocusRing = params.clearFocusRing || false; let startCharIndex = params.startCharIndex; let endCharIndex = params.endCharIndex; + const isUserSelectedContent = params.isUserSelectedContent || false; this.prepareForSpeech_(clearFocusRing /* clear the focus ring */); @@ -1136,6 +1341,7 @@ currentStartCharIndex: startCharIndex, currentEndCharIndex: endCharIndex, supportsNavigationPanel: this.isNavigationPanelSupported_(nodes), + isUserSelectedContent, }; // Play TTS according to the current state variables. @@ -1216,9 +1422,9 @@ } if (nodeGroup.nodes.length === 0 && !isLastNodeGroup) { - // If the current nodeGroup is empty, we start the next nodeGroup after - // the current start node index. - this.startNodeGroupAfter_( + // If the current nodeGroup is empty, we end this node group early, as if + // we have completed this node group. + this.onNodeGroupSpeakingCompleted_( currentNodeGroupStartNodeIndex /* currentNodeGroupEndIndex */); } @@ -1287,13 +1493,8 @@ this.updatePauseStatusFromTtsEvent_(true /* shouldPause */); } } else if (event.type === 'end') { - const ttsStarted = this.startNodeGroupAfter_( + this.onNodeGroupSpeakingCompleted_( nodeGroup.endIndex /* currentNodeGroupEndIndex */); - if (!ttsStarted && this.shouldShowNavigationControls_()) { - // Should be in a 'paused' state once we reach the end of the node - // queue. - this.updatePauseStatusFromTtsEvent_(true /* shouldPause */); - } } else if (event.type === 'word') { this.onTtsWordEvent_(event, nodeGroup); } @@ -1302,25 +1503,32 @@ } /** - * Start speaking the next node group indicated by the end index. + * When a node group is completed, we start speaking the next node group + * indicated by the end index. If we have reached the last node group, this + * function will update STS status depending whether the navigation feature is + * enabled. * @param {number} currentNodeGroupEndIndex the index of the last node in the * current node group. The index is relative to * |this.navigationState_.currentNodes|. - * @return {boolean} Whether TTS was started. */ - startNodeGroupAfter_(currentNodeGroupEndIndex) { + onNodeGroupSpeakingCompleted_(currentNodeGroupEndIndex) { + // Update the current char index to the end of the text content in this + // nodeGroup. + const nodeGroupText = + (this.currentNodeGroup_ && this.currentNodeGroup_.text) || ''; + this.navigationState_.currentCharIndex = nodeGroupText.trimEnd().length; + const isLastNodeGroup = (currentNodeGroupEndIndex === this.navigationState_.currentNodes.length - 1); if (isLastNodeGroup) { - // TODO (leileilei): If the navigation control is enabled, we need to - // enqueue the content between the end of the user's selection to the end - // of the paragraph. If there are no nodes in the current NodeGroup. - // navigate to the next paragraph. if (!this.shouldShowNavigationControls_()) { this.onStateChanged_(SelectToSpeakState.INACTIVE); } - return false; + // If navigation features are enabled, we should turn the pause status to + // true so that the user can hit resume to continue. + this.updatePauseStatusFromTtsEvent_(true /* shouldPause */); + return; } // Navigate to the next NodeGroup. Don't change |currentNodes|, @@ -1330,7 +1538,6 @@ currentNodeGroupEndIndex + 1; // Play TTS. this.startCurrentNodeGroup_(); - return true; } /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js index 13848c9..c4d2507 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js
@@ -276,6 +276,68 @@ }); }); +TEST_F( + 'SelectToSpeakNavigationControlTest', 'NextSentenceWithinParagraph', + function() { + const bodyHtml = ` + <p id="p1">Sent 1. <span id="s1">Sent 2.</span> Sent 3. Sent 4.</p> + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('s1', bodyHtml), () => { + this.triggerReadSelectedText(); + + // Speaks the first word. + this.mockTts.speakUntilCharIndex(5); + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 2.'); + + // Hitting next sentence will start from the next sentence. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction + .NEXT_SENTENCE); + this.waitOneEventLoop(() => { + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 3. Sent 4.'); + }); + }); + }); + +TEST_F( + 'SelectToSpeakNavigationControlTest', 'NextSentenceAcrossParagraph', + function() { + const bodyHtml = ` + <p id="p1">Sent 1.</p> + <p id="p2">Sent 2. Sent 3.</p>' + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('p1', bodyHtml), () => { + this.triggerReadSelectedText(); + + // Speaks the first word. + this.mockTts.speakUntilCharIndex(5); + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 1.'); + + // Hitting next sentence will star from the next paragraph as there + // is no more sentence in the current paragraph. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction + .NEXT_SENTENCE); + this.waitOneEventLoop(() => { + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 2. Sent 3.'); + }); + }); + }); + TEST_F('SelectToSpeakNavigationControlTest', 'PrevSentence', function() { const bodyHtml = ` <p id="p1">First sentence. Second sentence. Third sentence.</p>' @@ -305,6 +367,69 @@ }); TEST_F( + 'SelectToSpeakNavigationControlTest', 'PrevSentenceWithinParagraph', + function() { + const bodyHtml = ` + <p id="p1">Sent 0. Sent 1. <span id="s1">Sent 2.</span> Sent 3.</p> + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('s1', bodyHtml), () => { + this.triggerReadSelectedText(); + + // Supposing we are at the start of the sentence. + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 2.'); + + // Hitting previous sentence will start from the previous sentence. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction + .PREVIOUS_SENTENCE); + this.waitOneEventLoop(() => { + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], + 'Sent 1. Sent 2. Sent 3.'); + }); + }); + }); + +TEST_F( + 'SelectToSpeakNavigationControlTest', 'PrevSentenceAcrossParagraph', + function() { + const bodyHtml = ` + <p id="p1">Sent 1. Sent 2.</p> + <p id="p2">Sent 3.</p>' + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('p2', bodyHtml), () => { + this.triggerReadSelectedText(); + + // We are at the start of the sentence. + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 3.'); + + // Hitting previous sentence will start from the last sentence in + // the previous paragraph as there is no more sentence in the + // current paragraph. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction + .PREVIOUS_SENTENCE); + this.waitOneEventLoop(() => { + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Sent 2.'); + }); + }); + }); + +// TODO(https://crbug.com/1157817): Fix Flaky Test. +TEST_F( 'SelectToSpeakNavigationControlTest', 'ChangeSpeedWhilePlaying', function() { chrome.settingsPrivate.setPref('settings.tts.speech_rate', 1.2); @@ -323,8 +448,7 @@ this.mockTts.pendingUtterances()[0], 'Paragraph 1'); assertEquals(this.mockTts.getOptions().rate, 1.2); - // Changing speed will resume where we left off with selected speech - // rate. + // Changing speed will resume at the start of the current sentence. selectToSpeak.onSelectToSpeakPanelAction_( chrome.accessibilityPrivate.SelectToSpeakPanelAction .CHANGE_SPEED, @@ -385,3 +509,51 @@ }, 0)); }); }); + +TEST_F( + 'SelectToSpeakNavigationControlTest', 'ResumeAtTheEndOfParagraph', + function() { + const bodyHtml = ` + <p id="p1">Paragraph 1</p> + <p id="p2">Paragraph 2</p> + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('p1', bodyHtml), () => { + this.triggerReadSelectedText(); + + // Finishes the current utterance. + this.mockTts.finishPendingUtterance(); + + // Hitting resume will start the next paragraph. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction.RESUME); + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], 'Paragraph 2'); + }); + }); + +TEST_F( + 'SelectToSpeakNavigationControlTest', 'ResumeAtTheEndOfUserSelection', + function() { + const bodyHtml = ` + <p id="p1">Sentence <span id="s1">one</span>. Sentence two.</p> + <p id="p2">Paragraph 2</p> + `; + this.runWithLoadedTree( + this.generateHtmlWithSelectedElement('s1', bodyHtml), () => { + this.triggerReadSelectedText(); + + // Finishes the current utterance. + this.mockTts.finishPendingUtterance(); + + // Hitting resume will start the remaining content. + selectToSpeak.onSelectToSpeakPanelAction_( + chrome.accessibilityPrivate.SelectToSpeakPanelAction.RESUME); + assertTrue(this.mockTts.currentlySpeaking()); + assertEquals(this.mockTts.pendingUtterances().length, 1); + this.assertEqualsCollapseWhitespace( + this.mockTts.pendingUtterances()[0], '. Sentence two.'); + }); + }); \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/select_to_speak_manifest.json.jinja2 index f15d52a..cca4540 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak_manifest.json.jinja2 +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak_manifest.json.jinja2
@@ -58,5 +58,6 @@ "common/gdocs_script.js" ] } - ] + ], + "run_at": "document_start" }
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2 index 403f41d..ae49b0a 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2 +++ b/chrome/browser/resources/chromeos/accessibility/switch_access_manifest.json.jinja2
@@ -76,5 +76,6 @@ "common/gdocs_script.js" ] } - ] + ], + "run_at": "document_start" }
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index bb065af..1b0cd16 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -1068,7 +1068,7 @@ chrome.send('completeAuthentication', [ credentials.gaiaId, credentials.email, credentials.password, credentials.usingSAML, credentials.services, - credentials.passwordAttributes + credentials.passwordAttributes, credentials.syncTrustedVaultKeys || {} ]); }
diff --git a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js index e437adc..6420c00 100644 --- a/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js +++ b/chrome/browser/resources/chromeos/login/security_token_pin_browsertest.js
@@ -12,7 +12,7 @@ GEN('#include "content/public/test/browser_test.h"'); -var PolymerSecurityTokenPinTest = class extends PolymerTest { +var PolymerSecurityTokenPinTest = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return 'chrome://oobe/login';
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js index dae3c2f..7bc43895 100644 --- a/chrome/browser/resources/gaia_auth_host/authenticator.js +++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -29,6 +29,25 @@ /* #ignore */ 'use strict'; /** + * Individual sync trusted vault key. + * @typedef {{ + * keyMaterial: ArrayBuffer, + * version: number, + * }} + */ + /* #export */ let SyncTrustedVaultKey; + + /** + * Sync trusted vault encryption keys optionally passed with 'authCompleted' + * message. + * @typedef {{ + * encryptionKeys: Array<SyncTrustedVaultKey>, + * trustedPublicKeys: Array<SyncTrustedVaultKey> + * }} + */ + /* #export */ let SyncTrustedVaultKeys; + + /** * Credentials passed with 'authCompleted' message. * @typedef {{ * email: string, @@ -41,7 +60,8 @@ * sessionIndex: string, * trusted: boolean, * services: Array, - * passwordAttributes: !PasswordAttributes + * passwordAttributes: !PasswordAttributes, + * syncTrustedVaultKeys: !SyncTrustedVaultKeys * }} */ /* #export */ let AuthCompletedCredentials; @@ -67,6 +87,7 @@ * flow: string, * ignoreCrOSIdpSetting: boolean, * enableGaiaActionButtons: boolean, + * enableSyncTrustedVaultKeys: boolean, * enterpriseEnrollmentDomain: string, * samlAclUrl: string, * isSupervisedUser: boolean, @@ -126,7 +147,11 @@ // If this set to |false|, |confirmPasswordCallback| is // not called before dispatching |authCopleted|. // Default is |true|. - 'flow', // One of 'default', 'enterprise', or 'theftprotection'. + 'enableSyncTrustedVaultKeys', // Whether the host is interested in getting + // sync trusted vault keys. + // Default is |false|. + 'flow', // One of 'default', 'enterprise', or + // 'theftprotection'. 'enterpriseDisplayDomain', // Current domain name to be displayed. 'enterpriseDomainManager', // Manager of the current domain. Can be // either a domain name (foo.com) or an email @@ -280,6 +305,12 @@ }, 'exit'(msg) { this.dispatchEvent(new CustomEvent('exit')); + }, + 'syncTrustedVaultKeys'(msg) { + if (!this.enableSyncTrustedVaultKeys_) { + return; + } + this.syncTrustedVaultKeys_ = msg.value; } }; @@ -356,6 +387,7 @@ */ this.getIsSamlUserPasswordlessCallback = null; this.needPassword = true; + this.enableSyncTrustedVaultKeys_ = false; this.services_ = null; /** * Caches the result of |getIsSamlUserPasswordlessCallback| invocation for @@ -367,6 +399,8 @@ /** @private {boolean} */ this.isConstrainedWindow_ = false; this.samlAclUrl_ = null; + /** @private {?SyncTrustedVaultKeys} */ + this.syncTrustedVaultKeys_ = null; window.addEventListener( 'message', this.onMessageFromWebview_.bind(this), false); @@ -405,6 +439,7 @@ this.videoEnabled = false; this.services_ = null; this.isSamlUserPasswordless_ = null; + this.syncTrustedVaultKeys_ = null; } /** @@ -569,6 +604,7 @@ this.clientId_ = data.clientId; this.dontResizeNonEmbeddedPages = data.dontResizeNonEmbeddedPages; this.enableGaiaActionButtons_ = data.enableGaiaActionButtons; + this.enableSyncTrustedVaultKeys_ = !!data.enableSyncTrustedVaultKeys; this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; @@ -717,6 +753,9 @@ if (data.isDeviceOwner) { url = appendParam(url, 'is_device_owner', '1'); } + if (data.enableSyncTrustedVaultKeys) { + url = appendParam(url, 'szkr', '1'); + } return url; } @@ -1141,7 +1180,8 @@ sessionIndex: this.sessionIndex_ || '', trusted: this.trusted_, services: this.services_ || [], - passwordAttributes: passwordAttributes + passwordAttributes: passwordAttributes, + syncTrustedVaultKeys: this.syncTrustedVaultKeys_ || {} } })); this.resetStates();
diff --git a/chrome/browser/resources/history/history_item.html b/chrome/browser/resources/history/history_item.html index 89b3ee7..9a62b0c0 100644 --- a/chrome/browser/resources/history/history_item.html +++ b/chrome/browser/resources/history/history_item.html
@@ -179,7 +179,8 @@ <a href="[[item.url]]" id="link" class="website-link" focus-row-control focus-type="link" title="[[item.title]]" on-click="onLinkClick_" - on-contextmenu="onLinkRightClick_"> + on-contextmenu="onLinkRightClick_" + aria-describedby$="[[ariaDescribedByForHeading_]]"> <div class="website-icon" id="icon"></div> <history-searched-label class="website-title" title="[[item.title]]" search-term="[[searchTerm]]"></history-searched-label> @@ -192,7 +193,8 @@ <cr-icon-button id="bookmark-star" iron-icon="cr:star" focus-row-control focus-type="star" title="$i18n{removeBookmark}" - on-click="onRemoveBookmarkTap_"> + on-click="onRemoveBookmarkTap_" + aria-describedby$="[[ariaDescribedByForHeading_]]"> </cr-icon-button> </div> </template> @@ -201,7 +203,9 @@ <cr-icon-button id="menu-button" iron-icon="cr:more-vert" focus-row-control focus-type="cr-menu-button" title="$i18n{actionMenuDescription}" on-click="onMenuButtonTap_" - aria-haspopup="menu"></cr-icon-button> + aria-haspopup="menu" + aria-describedby$="[[ariaDescribedByForHeading_]]"> + </cr-icon-button> </div> </div> <div id="time-gap-separator" hidden="[[!hasTimeGap]]"></div>
diff --git a/chrome/browser/resources/history/history_item.js b/chrome/browser/resources/history/history_item.js index e5b0e029..9a651df9 100644 --- a/chrome/browser/resources/history/history_item.js +++ b/chrome/browser/resources/history/history_item.js
@@ -83,6 +83,12 @@ type: Boolean, value: true, }, + + /** @private */ + ariaDescribedByForHeading_: { + type: String, + computed: 'getAriaDescribedByForHeading_(isCardStart, isCardEnd)', + }, }, hostAttributes: {'role': 'row'}, @@ -189,12 +195,28 @@ getEntrySummary_() { const item = this.item; return loadTimeData.getStringF( - 'entrySummary', item.dateTimeOfDay, + 'entrySummary', + this.isCardStart || this.isCardEnd ? + this.cardTitle_( + this.numberOfItems, item.dateRelativeDay, this.searchTerm) : + '', + item.dateTimeOfDay, item.starred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain); }, /** + * The first and last rows of a card have a described-by field pointing to + * the date header, to make sure users know if they have jumped between cards + * when navigating up or down with the keyboard. + * @private + * @return {string} + */ + getAriaDescribedByForHeading_() { + return this.isCardStart || this.isCardEnd ? 'date-accessed' : ''; + }, + + /** * @param {boolean} selected * @return {string} * @private
diff --git a/chrome/browser/resources/interventions_internals/BUILD.gn b/chrome/browser/resources/interventions_internals/BUILD.gn index 0b1deb57..b103864 100644 --- a/chrome/browser/resources/interventions_internals/BUILD.gn +++ b/chrome/browser/resources/interventions_internals/BUILD.gn
@@ -5,14 +5,14 @@ import("//third_party/closure_compiler/compile_js.gni") js_type_check("closure_compile") { + uses_js_modules = true deps = [ ":index" ] } js_library("index") { deps = [ "//chrome/browser/ui/webui/interventions_internals:mojo_bindings_js_library_for_compile", - "//ui/webui/resources/js:assert", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:util", + "//ui/webui/resources/js:assert.m", + "//ui/webui/resources/js:util.m", ] }
diff --git a/chrome/browser/resources/interventions_internals/index.html b/chrome/browser/resources/interventions_internals/index.html index 0e1492c..3fa9266 100644 --- a/chrome/browser/resources/interventions_internals/index.html +++ b/chrome/browser/resources/interventions_internals/index.html
@@ -4,14 +4,7 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Interventions-Internals</title> - <script src="chrome://resources/js/cr.js"></script> - <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script> - <script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script> - <script src="chrome://resources/js/assert.js"></script> - <script src="chrome://resources/js/util.js"></script> - <script src="chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom-lite.js"> - </script> - <script src="index.js"></script> + <script type="module" src="index.js"></script> <link rel="stylesheet" type="text/css" href="index.css"> </head>
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js index 410aca9..1ff7876f 100644 --- a/chrome/browser/resources/interventions_internals/index.js +++ b/chrome/browser/resources/interventions_internals/index.js
@@ -2,11 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +import 'chrome://resources/mojo/url/mojom/url.mojom-lite.js'; +import './chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom-lite.js'; + +import {assert} from 'chrome://resources/js/assert.m.js'; +import {$} from 'chrome://resources/js/util.m.js'; + /** The columns that are used to find rows that contain the keyword. */ const ENABLE_BLOCKLIST_BUTTON = 'Enable Blocklist'; const IGNORE_BLOCKLIST_BUTTON = 'Ignore Blocklist'; const IGNORE_BLOCKLIST_MESSAGE = 'Blocklist decisions are ignored.'; const URL_THRESHOLD = 40; // Maximum URL length +// Export on |window| for tests. +window.URL_THRESHOLD = URL_THRESHOLD; window.logTableMap = {}; @@ -44,6 +53,8 @@ const millisec = getPaddedValue(date.getMilliseconds(), 3); return dateString + ' ' + hour + ':' + min + ':' + sec + '.' + millisec; } +// Export on |window| for tests. +window.getTimeFormat = getTimeFormat; /** * Append a button to |element|, so that when the button is clicked, the @@ -454,6 +465,8 @@ const InterventionsInternalPageImpl = function() { this.receiver_ = new mojom.InterventionsInternalsPageReceiver(this); }; +// Export on |window| for tests. +window.InterventionsInternalPageImpl = InterventionsInternalPageImpl; InterventionsInternalPageImpl.prototype = { /** @@ -594,7 +607,6 @@ }, }; -cr.define('interventions_internals', () => { let pageHandler = null; function init(handler) { @@ -674,10 +686,6 @@ }); } - return { - init: init, - }; -}); window.setupFn = window.setupFn || function() { return Promise.resolve(); @@ -702,6 +710,6 @@ pageHandler.setClientPage(pageImpl.bindNewPipeAndPassRemote()); } - interventions_internals.init(pageHandler); + init(pageHandler); }); });
diff --git a/chrome/browser/resources/pdf/controller.js b/chrome/browser/resources/pdf/controller.js index c53bda67e..d7752dc 100644 --- a/chrome/browser/resources/pdf/controller.js +++ b/chrome/browser/resources/pdf/controller.js
@@ -431,6 +431,14 @@ }); } + /** @param {boolean} enableReadOnly */ + setReadOnly(enableReadOnly) { + this.postMessage_({ + type: 'setReadOnly', + enableReadOnly: enableReadOnly, + }); + } + /** @override */ save(requestType) { const resolver = new PromiseResolver();
diff --git a/chrome/browser/resources/pdf/elements/viewer-download-controls.html b/chrome/browser/resources/pdf/elements/viewer-download-controls.html index 462b904..7a3a0ba 100644 --- a/chrome/browser/resources/pdf/elements/viewer-download-controls.html +++ b/chrome/browser/resources/pdf/elements/viewer-download-controls.html
@@ -1,4 +1,8 @@ <style include="pdf-shared"> + :host { + display: contents; + } + cr-action-menu::part(dialog) { position: fixed; top: 48px;
diff --git a/chrome/browser/resources/pdf/elements/viewer-page-selector.html b/chrome/browser/resources/pdf/elements/viewer-page-selector.html index a326cf35..0e44e5b 100644 --- a/chrome/browser/resources/pdf/elements/viewer-page-selector.html +++ b/chrome/browser/resources/pdf/elements/viewer-page-selector.html
@@ -37,7 +37,7 @@ margin: 0 var(--page-selector-spacing); } </style> - <input type="text" id="pageselector" value="[[pageNo]]" + <input part="input" type="text" id="pageselector" value="[[pageNo]]" on-pointerup="select" on-input="onInput_" on-change="pageNoCommitted" aria-label="$i18n{labelPageNumber}"> <span id="divider">/</span>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html index fd1a4171..0a886431 100644 --- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html +++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html
@@ -48,17 +48,28 @@ flex: 1; } + #center { + align-items: center; + display: flex; + } + #end { + display: flex; + justify-content: flex-end; padding-inline-start: 20px; text-align: end; white-space: nowrap; } + .vertical-separator { + background: rgba(255, 255, 255, 0.3); + height: 15px; + width: 1px; + } + #zoom-controls { - border-inline-end: 1px solid rgba(255, 255, 255, 0.3); - border-inline-start: 1px solid rgba(255, 255, 255, 0.3); - margin-inline-end: 12px; - margin-inline-start: 20px; + align-items: center; + display: flex; padding: 0 4px; } @@ -94,6 +105,12 @@ viewer-page-selector { display: inline-flex; height: 36px; /* Matching default --cr-icon-button-size */ + margin-inline-end: 20px; + } + + viewer-page-selector::part(input), + input { + max-height: var(--viewer-pdf-toolbar-height); } input { @@ -110,6 +127,10 @@ width: 5ch; } + #fit { + margin-inline-start: 12px; + } + paper-progress { --paper-progress-active-color: var(--google-blue-refresh-300); --paper-progress-container-color: transparent; @@ -188,6 +209,7 @@ <div id="center"> <viewer-page-selector doc-length="[[docLength]]" page-no="[[pageNo]]"> </viewer-page-selector> + <span class="vertical-separator"></span> <span id="zoom-controls"> <cr-icon-button iron-icon="pdf:remove" title="$i18n{tooltipZoomOut}" disabled="[[isAtMinimumZoom_(zoomBounds.min, viewportZoomPercent_)]]" @@ -203,6 +225,7 @@ aria-label="$i18n{tooltipZoomIn}" on-click="onZoomInClick_"> </cr-icon-button> </span> + <span class="vertical-separator"></span> <cr-icon-button id="fit" iron-icon="[[fitToButtonIcon_]]" title="[[getFitToButtonTooltip_('$i18nPolymer{tooltipFitToPage}', '$i18nPolymer{tooltipFitToWidth}',
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js index d6aabeb..526f068 100644 --- a/chrome/browser/resources/pdf/pdf_viewer.js +++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -726,9 +726,15 @@ // Add a 'wheel' listener, only while in Presentation mode. scroller.addEventListener('wheel', onWheel); + + // Restrict the content to read only (e.g. disable forms and links). + this.pluginController_.setReadOnly(true); + + // Revert back to the normal state when exiting Presentation mode. eventToPromise('fullscreenchange', scroller).then(() => { assert(document.fullscreenElement === null); scroller.removeEventListener('wheel', onWheel); + this.pluginController_.setReadOnly(false); }); // Nothing else to do here. The viewport will be updated as a result
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index c364409..7513988 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -297,6 +297,7 @@ "chromeos/ambient_mode_page/ambient_mode_browser_proxy.m.js", "chromeos/ambient_mode_page/ambient_mode_page.m.js", "chromeos/ambient_mode_page/ambient_mode_photos_page.m.js", + "chromeos/ambient_mode_page/art_album_dialog.m.js", "chromeos/ambient_mode_page/constants.m.js", "chromeos/ambient_mode_page/topic_source_item.m.js", "chromeos/ambient_mode_page/topic_source_list.m.js", @@ -505,6 +506,8 @@ "chromeos/ambient_mode_page/ambient_mode_page.js", "chromeos/ambient_mode_page/ambient_mode_photos_page.html", "chromeos/ambient_mode_page/ambient_mode_photos_page.js", + "chromeos/ambient_mode_page/art_album_dialog.html", + "chromeos/ambient_mode_page/art_album_dialog.js", "chromeos/ambient_mode_page/constants.html", "chromeos/ambient_mode_page/constants.js", "chromeos/ambient_mode_page/topic_source_item.html",
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn index 1af112c6..1eeb4503 100644 --- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn
@@ -14,6 +14,7 @@ ":ambient_mode_browser_proxy", ":ambient_mode_page", ":ambient_mode_photos_page", + ":art_album_dialog", ":constants", ":topic_source_item", ":topic_source_list", @@ -90,6 +91,13 @@ ] } +js_library("art_album_dialog") { + deps = [ + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", + ] +} + js_type_check("closure_compile_module") { is_polymer3 = true deps = [ @@ -98,6 +106,7 @@ ":ambient_mode_browser_proxy.m", ":ambient_mode_page.m", ":ambient_mode_photos_page.m", + ":art_album_dialog.m", ":topic_source_item.m", ":topic_source_list.m", ] @@ -185,12 +194,22 @@ extra_deps = [ ":album_list_module" ] } +js_library("art_album_dialog.m") { + sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.m.js" ] + deps = [ + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", + ] + extra_deps = [ ":art_album_dialog_module" ] +} + group("polymer3_elements") { public_deps = [ ":album_item_module", ":album_list_module", ":ambient_mode_page_module", ":ambient_mode_photos_page_module", + ":art_album_dialog_module", ":modulize", ":topic_source_item_module", ":topic_source_list_module", @@ -212,8 +231,9 @@ html_type = "dom-module" migrated_imports = os_settings_migrated_imports namespace_rewrites = os_settings_namespace_rewrites - auto_imports = os_settings_auto_imports + - [ "ui/webui/resources/html/assert.html|assertNotReached" ] + auto_imports = + os_settings_auto_imports + + [ "ui/webui/resources/html/assert.html|assert,assertNotReached" ] } polymer_modulizer("topic_source_item") { @@ -252,6 +272,15 @@ auto_imports = os_settings_auto_imports } +polymer_modulizer("art_album_dialog") { + js_file = "art_album_dialog.js" + html_file = "art_album_dialog.html" + html_type = "dom-module" + migrated_imports = os_settings_migrated_imports + namespace_rewrites = os_settings_namespace_rewrites + auto_imports = os_settings_auto_imports +} + js_modulizer("modulize") { input_files = [ "ambient_mode_browser_proxy.js",
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.html b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.html index 0a20189..4399ce56 100644 --- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.html +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.html
@@ -2,6 +2,7 @@ <link rel="import" href="album_list.html"> <link rel="import" href="ambient_mode_browser_proxy.html"> +<link rel="import" href="art_album_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/load_time_data.html"> @@ -33,6 +34,10 @@ </settings-localized-link> </template> + <template is="dom-if" if="[[showArtAlbumDialog_]]" restamp> + <art-album-dialog on-close="onArtAlbumDialogClose_"></art-album-dialog> + </template> + <!-- Text based album selection. --> <template is="dom-if" if="[[!photoPreviewEnabled]]"> <iron-list id="albums" class="list-frame" items="[[albums]]">
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js index c88d9c3..4421621f 100644 --- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_photos_page.js
@@ -34,6 +34,12 @@ // Set to null to differentiate from an empty album. value: null, }, + + /** @private */ + showArtAlbumDialog_: { + type: Boolean, + value: false, + } }, listeners: { @@ -145,17 +151,39 @@ */ onSelectedAlbumsChanged_(event) { const albums = []; - this.albums.forEach(/** @param {AmbientModeAlbum} album */ (album) => { + let eventAlbumIndex = -1; + for (let i = 0; i < this.albums.length; ++i) { + const album = this.albums[i]; if (album.checked) { albums.push({albumId: album.albumId}); } - }); + + if (album.albumId === event.detail.albumId) { + eventAlbumIndex = i; + } + } + + assert(eventAlbumIndex >= 0, 'Wrong album index.'); + + // For art gallery, cannot deselect the last album. Show a dialog to users + // and select the album automatically. + if (this.topicSource === AmbientModeTopicSource.ART_GALLERY && + albums.length === 0) { + this.showArtAlbumDialog_ = true; + this.set('albums.' + eventAlbumIndex + '.checked', true); + return; + } this.browserProxy_.setSelectedAlbums( {topicSource: this.topicSource, albums: albums}); }, /** @private */ + onArtAlbumDialogClose_() { + this.showArtAlbumDialog_ = false; + }, + + /** @private */ onCheckboxChange_() { const checkboxes = this.$$('#albums').querySelectorAll('cr-checkbox'); const albums = [];
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.html b/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.html new file mode 100644 index 0000000..c5c0eef --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.html
@@ -0,0 +1,27 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="../../settings_shared_css.html"> +<link rel="import" href="../../i18n_setup.html"> + +<dom-module id="art-album-dialog"> + <template> + <style include="settings-shared"> + cr-dialog::part(dialog) { + min-width: 288px; + width: 288px; + } + </style> + <cr-dialog id="dialog"> + <div slot="body">$i18n{ambientModeLastArtAlbumMessage}</div> + <div slot="button-container"> + <cr-button class="action-button" on-click="onClose_"> + $i18n{ambientModeArtAlbumDialogCloseButtonLabel} + </cr-button> + </div> + </cr-dialog> + </template> + <script src="art_album_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.js b/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.js new file mode 100644 index 0000000..9b439102 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/art_album_dialog.js
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Polymer element for displaying information for art albums. + */ + +Polymer({ + is: 'art-album-dialog', + + behaviors: [I18nBehavior], + + /** @override */ + attached() { + this.$.dialog.showModal(); + }, + + /** + * Closes the dialog. + * @private + */ + onClose_() { + if (this.$.dialog.open) { + this.$.dialog.close(); + } + }, +});
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html b/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html index 23e65ae..b735451 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/esim_remove_profile_dialog.html
@@ -9,6 +9,10 @@ <dom-module id="esim-remove-profile-dialog"> <template> <style> + :host { + --cr-dialog-width: 324px; + } + #cancel { margin-inline-end: 8px; }
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/esim_rename_dialog.html b/chrome/browser/resources/settings/chromeos/internet_page/esim_rename_dialog.html index 7dddd5e..e567ae3 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/esim_rename_dialog.html +++ b/chrome/browser/resources/settings/chromeos/internet_page/esim_rename_dialog.html
@@ -9,6 +9,10 @@ <dom-module id="esim-rename-dialog"> <template> <style> + :host { + --cr-dialog-width: 324px; + } + #cancel { margin-inline-end: 8px; }
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js index ee83a0a..92356f0c 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
@@ -108,6 +108,9 @@ if (deviceState.deviceState === mojom.DeviceStateType.kDisabling) { return this.i18n('internetDeviceDisabling'); } + if (deviceState.deviceState === mojom.DeviceStateType.kInhibited) { + return this.i18n('internetDeviceBusy'); + } } else if (deviceState.type === mojom.NetworkType.kTether) { if (deviceState.deviceState === mojom.DeviceStateType.kUninitialized) { return this.i18n('tetherEnableBluetooth'); @@ -267,6 +270,7 @@ enableToggleIsEnabled_(deviceState) { return this.enableToggleIsVisible_(deviceState) && deviceState.deviceState !== mojom.DeviceStateType.kProhibited && + deviceState.deviceState !== mojom.DeviceStateType.kInhibited && !OncMojo.deviceStateIsIntermediate(deviceState.deviceState); },
diff --git a/chrome/browser/resources/webui_js_error/webui_js_error.html b/chrome/browser/resources/webui_js_error/webui_js_error.html index 4daeb2c..780cc0f 100644 --- a/chrome/browser/resources/webui_js_error/webui_js_error.html +++ b/chrome/browser/resources/webui_js_error/webui_js_error.html
@@ -21,9 +21,11 @@ This page generates a JavaScript error on load. Other types of errors can be generated with the buttons: <div> <!-- Ids are referenced in integration tests, including tast tests --> - <button id="error-button">Log Error</button> - <button id="exception-button">Throw Uncaught Error</button> - <button id="promise-button">Unhandled Promise Rejection</button> + <button id="error-button" accesskey="l">Log Error</button> + <button id="exception-button" accesskey="t">Throw Uncaught Error</button> + <button id="promise-button" accesskey="p"> + Unhandled Promise Rejection + </button> </div> <script src="chrome://resources/js/assert.js"></script> <script src="chrome://resources/js/util.js"></script>
diff --git a/chrome/browser/resources/webui_js_error/webui_js_error.js b/chrome/browser/resources/webui_js_error/webui_js_error.js index da46cef..a5cec78 100644 --- a/chrome/browser/resources/webui_js_error/webui_js_error.js +++ b/chrome/browser/resources/webui_js_error/webui_js_error.js
@@ -13,13 +13,13 @@ /** * Logs an error when called. This is the "during page load" error. */ -function logsErrorDuringPageLoad() { +function logsErrorDuringPageLoadOuter() { logsErrorDuringPageLoadInner(); } /** * Logs an error when called. This is a separate function from - * logsErrorDuringPageLoad() so that we get an interesting stack. + * logsErrorDuringPageLoadOuter() so that we get an interesting stack. */ function logsErrorDuringPageLoadInner() { console.error('WebUI JS Error: printing error on page load'); @@ -28,13 +28,13 @@ /** * Logs an error when called. This is the "from button click" error. */ -function logsErrorFromButtonClick() { +function logsErrorFromButtonClickHandler() { logsErrorFromButtonClickInner(); } /** * Logs an error when called. This is a separate function from - * logsErrorFromButtonClick() so that we get an interesting stack. + * logsErrorFromButtonClickHandler() so that we get an interesting stack. */ function logsErrorFromButtonClickInner() { console.error('WebUI JS Error: printing error on button click'); @@ -43,13 +43,13 @@ /** * Throws an exception when called. */ -function throwException() { +function throwExceptionHandler() { throwExceptionInner(); } /** * Throws an exception when called. This is a separate function from - * throwException() so that we get an interesting stack. + * throwExceptionHandler() so that we get an interesting stack. */ function throwExceptionInner() { throw new Error('WebUI JS Error: exception button clicked'); @@ -77,7 +77,7 @@ promise.then(promiseSuccessful); } -$('error-button').onclick = logsErrorFromButtonClick; -$('exception-button').onclick = throwException; +$('error-button').onclick = logsErrorFromButtonClickHandler; +$('exception-button').onclick = throwExceptionHandler; $('promise-button').onclick = unhandledPromiseRejection; -logsErrorDuringPageLoad(); +logsErrorDuringPageLoadOuter();
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc index d0de93e..ad28078 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
@@ -213,21 +213,30 @@ return; } + // Make copies of the connector and DM token since |request| is about to move. auto connector = request->analysis_connector(); + std::string dm_token = request->device_token(); + TokenAndConnector token_and_connector = {dm_token, connector}; - if (!can_upload_enterprise_data_.contains(request->analysis_connector())) { + if (dm_token.empty()) { + MaybeUploadForDeepScanningCallback(std::move(request), + /*authorized*/ false); + return; + } + + if (!can_upload_enterprise_data_.contains(token_and_connector)) { // Get the URL first since |request| is about to move. GURL url = request->GetUrlWithParams(); IsAuthorized( std::move(url), base::BindOnce(&BinaryUploadService::MaybeUploadForDeepScanningCallback, weakptr_factory_.GetWeakPtr(), std::move(request)), - connector); + dm_token, connector); return; } - MaybeUploadForDeepScanningCallback(std::move(request), - can_upload_enterprise_data_[connector]); + MaybeUploadForDeepScanningCallback( + std::move(request), can_upload_enterprise_data_[token_and_connector]); } void BinaryUploadService::MaybeUploadForDeepScanningCallback( @@ -427,6 +436,7 @@ void BinaryUploadService::FinishRequestCleanup(Request* request, const std::string& instance_id) { + std::string dm_token = request->device_token(); auto connector = request->analysis_connector(); active_requests_.erase(request); active_timers_.erase(request); @@ -443,26 +453,29 @@ binary_fcm_service_->UnregisterInstanceID( instance_id, base::BindOnce(&BinaryUploadService::InstanceIDUnregisteredCallback, - weakptr_factory_.GetWeakPtr(), connector)); + weakptr_factory_.GetWeakPtr(), dm_token, connector)); } else { // |binary_fcm_service_| can be null in tests, but // InstanceIDUnregisteredCallback should be called anyway so the requests // waiting on authentication can complete. - InstanceIDUnregisteredCallback(connector, true); + InstanceIDUnregisteredCallback(dm_token, connector, true); } active_tokens_.erase(token_it); } void BinaryUploadService::InstanceIDUnregisteredCallback( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector, bool) { + TokenAndConnector token_and_connector = {dm_token, connector}; // Calling RunAuthorizationCallbacks after the instance ID of the initial // authentication is unregistered avoids registration/unregistration conflicts // with normal requests. - if (!authorization_callbacks_.empty() && - can_upload_enterprise_data_.contains(connector)) { - RunAuthorizationCallbacks(connector); + if (authorization_callbacks_.contains(token_and_connector) && + !authorization_callbacks_[token_and_connector].empty() && + can_upload_enterprise_data_.contains(token_and_connector)) { + RunAuthorizationCallbacks(dm_token, connector); } } @@ -658,6 +671,7 @@ void BinaryUploadService::IsAuthorized( const GURL& url, AuthorizationCallback callback, + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector) { // Start |timer_| on the first call to IsAuthorized. This is necessary in // order to invalidate the authorization every 24 hours. @@ -668,63 +682,60 @@ weakptr_factory_.GetWeakPtr(), url)); } - if (!can_upload_enterprise_data_.contains(connector)) { + TokenAndConnector token_and_connector = {dm_token, connector}; + if (!can_upload_enterprise_data_.contains(token_and_connector)) { // Send a request to check if the browser can upload data. - authorization_callbacks_.push_back(std::move(callback)); - if (!pending_validate_data_upload_request_) { - auto dm_token = policy::GetDMToken(profile_); - if (!dm_token.is_valid()) { - can_upload_enterprise_data_[connector] = false; - RunAuthorizationCallbacks(connector); - return; - } - - pending_validate_data_upload_request_ = true; + authorization_callbacks_[token_and_connector].push_back( + std::move(callback)); + if (!pending_validate_data_upload_request_.contains(token_and_connector)) { + pending_validate_data_upload_request_.insert(token_and_connector); auto request = std::make_unique<ValidateDataUploadRequest>( base::BindOnce( &BinaryUploadService::ValidateDataUploadRequestConnectorCallback, - weakptr_factory_.GetWeakPtr(), connector), + weakptr_factory_.GetWeakPtr(), dm_token, connector), url); - request->set_device_token(dm_token.value()); + request->set_device_token(dm_token); request->set_analysis_connector(connector); UploadForDeepScanning(std::move(request)); } return; } - std::move(callback).Run(can_upload_enterprise_data_[connector]); + std::move(callback).Run(can_upload_enterprise_data_[token_and_connector]); } void BinaryUploadService::ValidateDataUploadRequestConnectorCallback( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector, BinaryUploadService::Result result, enterprise_connectors::ContentAnalysisResponse response) { - pending_validate_data_upload_request_ = false; - can_upload_enterprise_data_[connector] = + TokenAndConnector token_and_connector = {dm_token, connector}; + pending_validate_data_upload_request_.erase(token_and_connector); + can_upload_enterprise_data_[token_and_connector] = (result == BinaryUploadService::Result::SUCCESS); } void BinaryUploadService::RunAuthorizationCallbacks( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector) { - DCHECK(can_upload_enterprise_data_.contains(connector)); - for (auto& callback : authorization_callbacks_) { - std::move(callback).Run(can_upload_enterprise_data_[connector]); + TokenAndConnector token_and_connector = {dm_token, connector}; + DCHECK(can_upload_enterprise_data_.contains(token_and_connector)); + + auto it = authorization_callbacks_[token_and_connector].begin(); + while (it != authorization_callbacks_[token_and_connector].end()) { + std::move(*it).Run(can_upload_enterprise_data_[token_and_connector]); + it = authorization_callbacks_[token_and_connector].erase(it); } - authorization_callbacks_.clear(); } void BinaryUploadService::ResetAuthorizationData(const GURL& url) { // Clearing |can_upload_enterprise_data_| will make the next // call to IsAuthorized send out a request to validate data uploads. - can_upload_enterprise_data_.clear(); - - // Call IsAuthorized to update |can_upload_enterprise_data_| right away. - for (enterprise_connectors::AnalysisConnector connector : - {enterprise_connectors::AnalysisConnector:: - ANALYSIS_CONNECTOR_UNSPECIFIED, - enterprise_connectors::AnalysisConnector::FILE_DOWNLOADED, - enterprise_connectors::AnalysisConnector::FILE_ATTACHED, - enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY}) { - IsAuthorized(url, base::DoNothing(), connector); + auto it = can_upload_enterprise_data_.begin(); + while (it != can_upload_enterprise_data_.end()) { + std::string dm_token = it->first.first; + enterprise_connectors::AnalysisConnector connector = it->first.second; + it = can_upload_enterprise_data_.erase(it); + IsAuthorized(url, base::DoNothing(), dm_token, connector); } } @@ -733,14 +744,16 @@ binary_fcm_service_->Shutdown(); } -void BinaryUploadService::SetAuthForTesting(bool authorized) { +void BinaryUploadService::SetAuthForTesting(const std::string& dm_token, + bool authorized) { for (enterprise_connectors::AnalysisConnector connector : {enterprise_connectors::AnalysisConnector:: ANALYSIS_CONNECTOR_UNSPECIFIED, enterprise_connectors::AnalysisConnector::FILE_DOWNLOADED, enterprise_connectors::AnalysisConnector::FILE_ATTACHED, enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY}) { - can_upload_enterprise_data_[connector] = authorized; + TokenAndConnector token_and_connector = {dm_token, connector}; + can_upload_enterprise_data_[token_and_connector] = authorized; } }
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h index 2ae27801..c3c6c69 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
@@ -9,9 +9,11 @@ #include <memory> #include <string> #include <unordered_map> +#include <utility> #include "base/callback.h" #include "base/callback_forward.h" +#include "base/containers/flat_set.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" @@ -186,14 +188,17 @@ // authorized to upload data, otherwise queue the request. virtual void MaybeUploadForDeepScanning(std::unique_ptr<Request> request); - // Indicates whether the browser is allowed to upload data. + // Indicates whether the DM token/Connector combination is allowed to upload + // data. using AuthorizationCallback = base::OnceCallback<void(bool)>; void IsAuthorized(const GURL& url, AuthorizationCallback callback, + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector); - // Run every callback in |authorization_callbacks_| and empty it. + // Run every matching callback in |authorization_callbacks_| and remove them. void RunAuthorizationCallbacks( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector); // Resets |can_upload_data_|. Called every 24 hour by |timer_|. @@ -203,7 +208,7 @@ void Shutdown() override; // Sets |can_upload_data_| for tests. - void SetAuthForTesting(bool authorized); + void SetAuthForTesting(const std::string& dm_token, bool authorized); // Returns the URL that requests are uploaded to. Scans for enterprise go to a // different URL than scans for Advanced Protection users. @@ -215,6 +220,8 @@ enterprise_connectors::ContentAnalysisResponse response); private: + using TokenAndConnector = + std::pair<std::string, enterprise_connectors::AnalysisConnector>; friend class BinaryUploadServiceTest; // Upload the given file contents for deep scanning. The results will be @@ -246,12 +253,14 @@ // Callback once the response from the backend is received. void ValidateDataUploadRequestConnectorCallback( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector, BinaryUploadService::Result result, enterprise_connectors::ContentAnalysisResponse response); // Callback once a request's instance ID is unregistered. void InstanceIDUnregisteredCallback( + const std::string& dm_token, enterprise_connectors::AnalysisConnector connector, bool); @@ -284,22 +293,19 @@ enterprise_connectors::ContentAnalysisResponse::Result>> received_connector_results_; - // Indicates whether this browser can upload data for enterprise requests. - // Advanced Protection scans are validated using the user's Advanced - // Protection enrollment status. - // base::nullopt means the response from the backend has not been received - // yet. - // true means the response indicates data can be uploaded. - // false means the response indicates data cannot be uploaded. - base::flat_map<enterprise_connectors::AnalysisConnector, bool> - can_upload_enterprise_data_; + // Indicates whether this DM token + Connector combination can be used to + // upload data for enterprise requests. Advanced Protection scans are + // validated using the user's Advanced Protection enrollment status. + base::flat_map<TokenAndConnector, bool> can_upload_enterprise_data_; - // Callbacks waiting on IsAuthorized request. - std::list<base::OnceCallback<void(bool)>> authorization_callbacks_; + // Callbacks waiting on IsAuthorized request. These are organized by DM token + // and Connector. + base::flat_map<TokenAndConnector, std::list<base::OnceCallback<void(bool)>>> + authorization_callbacks_; // Indicates if this service is waiting on the backend to validate event // reporting. Used to avoid spamming the backend. - bool pending_validate_data_upload_request_ = false; + base::flat_set<TokenAndConnector> pending_validate_data_upload_request_; // Ensures we validate the browser is registered with the backend every 24 // hours.
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc index 12b6ac1..c91679b 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc +++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
@@ -145,7 +145,7 @@ void UploadForDeepScanning( std::unique_ptr<BinaryUploadService::Request> request, bool authorized_for_enterprise = true) { - service_->SetAuthForTesting(authorized_for_enterprise); + service_->SetAuthForTesting("fake_device_token", authorized_for_enterprise); service_->MaybeUploadForDeepScanning(std::move(request)); } @@ -486,11 +486,32 @@ // The 24 hours timer should be started on the first IsAuthorized call. ValidateAuthorizationTimerIdle(); service_->IsAuthorized( - GURL(), base::DoNothing(), + GURL(), base::DoNothing(), "fake_device_token", enterprise_connectors::AnalysisConnector::ANALYSIS_CONNECTOR_UNSPECIFIED); ValidateAuthorizationTimerStarted(); } +TEST_F(BinaryUploadServiceTest, IsAuthorizedMultipleDMTokens) { + service_->SetAuthForTesting("valid_dm_token", true); + service_->SetAuthForTesting("invalid_dm_token", false); + + for (auto connector : + {enterprise_connectors::AnalysisConnector:: + ANALYSIS_CONNECTOR_UNSPECIFIED, + enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY, + enterprise_connectors::AnalysisConnector::FILE_ATTACHED, + enterprise_connectors::AnalysisConnector::FILE_DOWNLOADED}) { + service_->IsAuthorized(GURL(), base::BindOnce([](bool authorized) { + EXPECT_TRUE(authorized); + }), + "valid_dm_token", connector); + service_->IsAuthorized(GURL(), base::BindOnce([](bool authorized) { + EXPECT_FALSE(authorized); + }), + "invalid_dm_token", connector); + } +} + TEST_F(BinaryUploadServiceTest, AdvancedProtectionMalwareRequestAuthorized) { AdvancedProtectionStatusManagerFactory::GetForProfile(&profile_) ->SetAdvancedProtectionStatusForTesting(/*enrolled=*/true);
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h index fef3ee91..0109ab8 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_browsertest_base.h
@@ -49,10 +49,8 @@ const std::vector<base::FilePath>& created_file_paths() const; - protected: - base::test::ScopedFeatureList scoped_feature_list_; - private: + base::test::ScopedFeatureList scoped_feature_list_; base::RepeatingClosure quit_closure_; enterprise_connectors::ContentAnalysisResponse connector_status_callback_response_;
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 e85bf92..faf17c7e 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
@@ -13,7 +13,6 @@ #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h" -#include "components/policy/core/common/policy_types.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "content/public/browser/browser_context.h" @@ -344,22 +343,16 @@ void SetAnalysisConnector(PrefService* prefs, enterprise_connectors::AnalysisConnector connector, - const std::string& pref_value, - bool machine_scope) { + const std::string& pref_value) { ListPrefUpdate settings_list(prefs, ConnectorPref(connector)); DCHECK(settings_list.Get()); if (!settings_list->empty()) settings_list->Clear(); settings_list->Append(*base::JSONReader::Read(pref_value)); - prefs->SetInteger( - ConnectorScopePref(connector), - machine_scope ? policy::POLICY_SCOPE_MACHINE : policy::POLICY_SCOPE_USER); } -void SetOnSecurityEventReporting(PrefService* prefs, - bool enabled, - bool machine_scope) { +void SetOnSecurityEventReporting(PrefService* prefs, bool enabled) { ListPrefUpdate settings_list(prefs, enterprise_connectors::kOnSecurityEventPref); DCHECK(settings_list.Get()); @@ -371,22 +364,18 @@ base::Value("google")); settings_list->Append(std::move(settings)); } - prefs->SetInteger(enterprise_connectors::kOnSecurityEventScopePref, - machine_scope ? policy::POLICY_SCOPE_MACHINE - : policy::POLICY_SCOPE_USER); } else { settings_list->ClearList(); - prefs->ClearPref(enterprise_connectors::kOnSecurityEventScopePref); } } void ClearAnalysisConnector( PrefService* prefs, + enterprise_connectors::AnalysisConnector connector) { ListPrefUpdate settings_list(prefs, ConnectorPref(connector)); DCHECK(settings_list.Get()); settings_list->Clear(); - prefs->ClearPref(ConnectorScopePref(connector)); } } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h index 84dac14..7fd6b00e 100644 --- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h +++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
@@ -148,11 +148,8 @@ // Helper functions that set Connector policies for testing. void SetAnalysisConnector(PrefService* prefs, enterprise_connectors::AnalysisConnector connector, - const std::string& pref_value, - bool machine_scope = true); -void SetOnSecurityEventReporting(PrefService* prefs, - bool enabled, - bool machine_scope = true); + const std::string& pref_value); +void SetOnSecurityEventReporting(PrefService* prefs, bool enabled); void ClearAnalysisConnector(PrefService* prefs, enterprise_connectors::AnalysisConnector connector);
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 adf5f154..a0b5a36 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_browsertest.cc
@@ -285,7 +285,7 @@ void AuthorizeForDeepScanning() { BinaryUploadServiceFactory::GetForProfile(browser()->profile()) - ->SetAuthForTesting(/*authorized=*/true); + ->SetAuthForTesting("dm_token", /*authorized=*/true); } private:
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc index 01f74db..f49e3f07 100644 --- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
@@ -440,7 +440,7 @@ ->SetIdentityManagerForTesting( identity_test_environment_.identity_manager()); download_protection_service_.GetFakeBinaryUploadService() - ->SetAuthForTesting(true); + ->SetAuthForTesting("dm_token", true); SetOnSecurityEventReporting(profile_->GetPrefs(), true); EnableAllFeatures();
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc index 449e4778e..fd2058df 100644 --- a/chrome/browser/search_engines/template_url_service_unittest.cc +++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -736,8 +736,9 @@ const std::string search_url = "http://www.google.com/foo/bar"; const std::string suggest_url = "http://www.google.com/suggest"; const std::string favicon_url = "http://favicon.url"; - TemplateURL* t_url = model()->CreateOrUpdateTemplateURLFromPlayAPIData( + TemplateURL* t_url = model()->CreatePlayAPISearchEngine( short_name, keyword, search_url, suggest_url, favicon_url); + ASSERT_TRUE(t_url); ASSERT_EQ(short_name, t_url->short_name()); ASSERT_EQ(keyword, t_url->keyword()); ASSERT_EQ(search_url, t_url->url()); @@ -770,14 +771,15 @@ data.date_created = Time::FromTimeT(100); data.last_modified = Time::FromTimeT(100); data.last_visited = Time::FromTimeT(100); + // Play API only replaces safe_for_autoreplace engines. + data.safe_for_autoreplace = true; TemplateURL* t_url = model()->Add(std::make_unique<TemplateURL>(data)); VerifyObserverCount(1); base::RunLoop().RunUntilIdle(); - Time now = Time::Now(); auto clock = std::make_unique<base::SimpleTestClock>(); - clock->SetNow(now); + clock->SetNow(base::Time::FromTimeT(200)); model()->set_clock(std::move(clock)); // Reset the short name and url and make sure it takes. @@ -785,10 +787,13 @@ const std::string new_search_url = "new_url"; const std::string new_suggest_url = "new_suggest_url"; const std::string new_favicon_url = "new_favicon_url"; - TemplateURL* updated_turl = model()->CreateOrUpdateTemplateURLFromPlayAPIData( - new_short_name, keyword, new_search_url, new_suggest_url, - new_favicon_url); - ASSERT_EQ(t_url, updated_turl); + + // The update creates a new Play API engine and deletes the old replaceable + // one. + t_url = model()->CreatePlayAPISearchEngine(new_short_name, keyword, + new_search_url, new_suggest_url, + new_favicon_url); + ASSERT_TRUE(t_url); ASSERT_EQ(new_short_name, t_url->short_name()); ASSERT_EQ(keyword, t_url->keyword()); ASSERT_EQ(new_search_url, t_url->url()); @@ -947,7 +952,7 @@ model()->SetUserSelectedDefaultSearchProvider(user_dse); EXPECT_EQ(user_dse, model()->GetDefaultSearchProvider()); - // Remove bing. + // Remove bing. It will not be restored because of the extension below. TemplateURL* bing = model()->GetTemplateURLForKeyword( ASCIIToUTF16("bing.com")); ASSERT_TRUE(bing); @@ -959,6 +964,14 @@ "http://abcdefg", Time()); EXPECT_TRUE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("bing.com"))); + // Remove yahoo. It will be restored later, but for now verify we removed it. + TemplateURL* yahoo = + model()->GetTemplateURLForKeyword(ASCIIToUTF16("yahoo.com")); + ASSERT_TRUE(yahoo); + model()->Remove(yahoo); + EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("yahoo.com"))); + + // Now perform the actual repair that should restore Yahoo. model()->RepairPrepopulatedSearchEngines(); // Google is default. @@ -968,11 +981,21 @@ EXPECT_EQ("www.google.com", google->GenerateSearchURL(model()->search_terms_data()).host()); - // Bing was repaired. - bing = - model()->FindNonExtensionTemplateURLForKeyword(ASCIIToUTF16("bing.com")); - ASSERT_TRUE(bing); - EXPECT_EQ(TemplateURL::NORMAL, bing->type()); + // Bing was repaired, but the NORMAL engine is still gone because the bing + // extension caused the prepopulated engine to be auto-deleted. + bing = nullptr; + for (TemplateURL* turl : model()->GetTemplateURLs()) { + if (turl->keyword() == ASCIIToUTF16("bing.com") && + turl->type() == TemplateURL::NORMAL) { + bing = turl; + break; + } + } + EXPECT_FALSE(bing); + + // Yahoo was repaired and is now restored. + yahoo = model()->GetTemplateURLForKeyword(ASCIIToUTF16("yahoo.com")); + EXPECT_TRUE(yahoo); // User search engine is preserved. EXPECT_EQ(user_dse, model()->GetTemplateURLForHost("www.goo.com"));
diff --git a/chrome/browser/sessions/session_restore_stats_collector.cc b/chrome/browser/sessions/session_restore_stats_collector.cc index b1a93c4..f6dbe54 100644 --- a/chrome/browser/sessions/session_restore_stats_collector.cc +++ b/chrome/browser/sessions/session_restore_stats_collector.cc
@@ -176,11 +176,11 @@ void SessionRestoreStatsCollector::RenderWidgetHostDestroyed( content::RenderWidgetHost* widget_host) { + observer_.Remove(widget_host); + auto* tab_state = GetTabState(widget_host); - if (tab_state) { - observer_.Remove(tab_state->observed_host); + if (tab_state) tab_state->observed_host = nullptr; - } } void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) {
diff --git a/chrome/browser/subresource_redirect/subresource_redirect_observer.cc b/chrome/browser/subresource_redirect/subresource_redirect_observer.cc index 0f26778..a70d7da 100644 --- a/chrome/browser/subresource_redirect/subresource_redirect_observer.cc +++ b/chrome/browser/subresource_redirect/subresource_redirect_observer.cc
@@ -7,6 +7,7 @@ #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/subresource_redirect/origin_robots_rules_cache.h" #include "chrome/browser/subresource_redirect/subresource_redirect_util.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" #include "components/optimization_guide/proto/performance_hints_metadata.pb.h" @@ -47,6 +48,7 @@ mojom::CompressPublicImagesHintsPtr images_hints) { mojo::AssociatedRemote<mojom::SubresourceRedirectHintsReceiver> hints_receiver; + DCHECK(ShouldEnablePublicImageHintsBasedCompression()); if (render_frame_host->GetRemoteAssociatedInterfaces()) { render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface( @@ -55,12 +57,39 @@ } } +void UpdateRobotsRules( + mojom::SubresourceRedirectService::GetRobotsRulesCallback callback, + base::Optional<std::string> robots_rules_proto) { + std::move(callback).Run(robots_rules_proto); +} + } // namespace +SubresourceRedirectDocumentHost::SubresourceRedirectDocumentHost( + content::RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host) {} + +SubresourceRedirectDocumentHost::~SubresourceRedirectDocumentHost() = default; + +RENDER_DOCUMENT_HOST_USER_DATA_KEY_IMPL(SubresourceRedirectDocumentHost) + +void SubresourceRedirectDocumentHost::GetAndUpdateRobotsRules( + const url::Origin& origin, + OriginRobotsRulesCache* rules_cache, + mojom::SubresourceRedirectService::GetRobotsRulesCallback callback) { + if (!rules_cache) { + std::move(callback).Run(base::nullopt); + return; + } + rules_cache->GetRobotsRules( + origin, base::BindOnce(&UpdateRobotsRules, std::move(callback))); +} + // static void SubresourceRedirectObserver::MaybeCreateForWebContents( content::WebContents* web_contents) { - if (ShouldEnablePublicImageHintsBasedCompression() && + if ((ShouldEnablePublicImageHintsBasedCompression() || + ShouldEnableLoginRobotsCheckedCompression()) && IsLiteModeEnabled(web_contents)) { SubresourceRedirectObserver::CreateForWebContents(web_contents); } @@ -81,12 +110,14 @@ content::WebContents* web_contents) : content::WebContentsObserver(web_contents), receivers_(web_contents, this) { - DCHECK(ShouldEnablePublicImageHintsBasedCompression()); - auto* optimization_guide_decider = - GetOptimizationGuideDeciderFromWebContents(web_contents); - if (optimization_guide_decider) { - optimization_guide_decider->RegisterOptimizationTypes( - {optimization_guide::proto::COMPRESS_PUBLIC_IMAGES}); + DCHECK(ShouldEnablePublicImageHintsBasedCompression() || + ShouldEnableLoginRobotsCheckedCompression()); + if (ShouldEnablePublicImageHintsBasedCompression()) { + if (auto* optimization_guide_decider = + GetOptimizationGuideDeciderFromWebContents(web_contents)) { + optimization_guide_decider->RegisterOptimizationTypes( + {optimization_guide::proto::COMPRESS_PUBLIC_IMAGES}); + } } } @@ -95,23 +126,37 @@ void SubresourceRedirectObserver::DidFinishNavigation( content::NavigationHandle* navigation_handle) { DCHECK(navigation_handle); - DCHECK(ShouldEnablePublicImageHintsBasedCompression()); if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted() || - navigation_handle->IsSameDocument()) { + navigation_handle->IsSameDocument() || + !navigation_handle->GetRenderFrameHost()) { return; } if (!IsLiteModeEnabled(web_contents())) return; + // Set to disable compression by default for this navigation. is_https_image_compression_applied_ = false; if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()) return; if (!ShowInfoBarAndGetImageCompressionState(web_contents(), - navigation_handle)) + navigation_handle)) { return; + } + + // Handle login robots based compression mode. + if (ShouldEnableLoginRobotsCheckedCompression()) { + SubresourceRedirectDocumentHost::GetOrCreateForCurrentDocument( + navigation_handle->GetRenderFrameHost()); + // TODO(1149853): Handle whether page is logged-in and disable compression. + is_https_image_compression_applied_ = true; + return; + } + + // Handle public image hints based compression mode. + DCHECK(ShouldEnablePublicImageHintsBasedCompression()); auto* optimization_guide_decider = GetOptimizationGuideDeciderFromWebContents( navigation_handle->GetWebContents()); @@ -120,9 +165,6 @@ content::RenderFrameHost* render_frame_host = navigation_handle->GetRenderFrameHost(); - if (!render_frame_host || !render_frame_host->GetProcess()) - return; - optimization_guide_decider->CanApplyOptimizationAsync( navigation_handle, optimization_guide::proto::COMPRESS_PUBLIC_IMAGES, base::BindOnce( @@ -137,6 +179,8 @@ content::GlobalFrameRoutingId render_frame_host_routing_id, optimization_guide::OptimizationGuideDecision decision, const optimization_guide::OptimizationMetadata& optimization_metadata) { + DCHECK(ShouldEnablePublicImageHintsBasedCompression()); + // Clear |is_https_image_compression_applied_| since it may be set to true // when multiple navigations are starting and image hints is received for // the first one. @@ -176,6 +220,30 @@ retry_after); } +void SubresourceRedirectObserver::GetRobotsRules( + const url::Origin& origin, + mojom::SubresourceRedirectService::GetRobotsRulesCallback callback) { + DCHECK(ShouldEnableLoginRobotsCheckedCompression()); + DCHECK(!origin.opaque()); + if (!web_contents()) { + std::move(callback).Run(base::nullopt); + return; + } + + // SubresourceRedirectDocumentHost could be null when suresource redirect is + // disabled for this document. + auto* subresource_redirect_document_host = + SubresourceRedirectDocumentHost::GetForCurrentDocument( + web_contents()->GetMainFrame()); + if (!subresource_redirect_document_host) { + std::move(callback).Run(base::nullopt); + return; + } + + subresource_redirect_document_host->GetAndUpdateRobotsRules( + origin, GetOriginRobotsRulesCache(web_contents()), std::move(callback)); +} + WEB_CONTENTS_USER_DATA_KEY_IMPL(SubresourceRedirectObserver) } // namespace subresource_redirect
diff --git a/chrome/browser/subresource_redirect/subresource_redirect_observer.h b/chrome/browser/subresource_redirect/subresource_redirect_observer.h index e59e70e9..c1d4bcd8 100644 --- a/chrome/browser/subresource_redirect/subresource_redirect_observer.h +++ b/chrome/browser/subresource_redirect/subresource_redirect_observer.h
@@ -8,9 +8,11 @@ #include "base/macros.h" #include "chrome/common/subresource_redirect_service.mojom.h" #include "components/optimization_guide/optimization_guide_decider.h" +#include "content/public/browser/render_document_host_user_data.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_receiver_set.h" #include "content/public/browser/web_contents_user_data.h" +#include "url/origin.h" namespace content { class NavigationHandle; @@ -19,6 +21,38 @@ namespace subresource_redirect { +class OriginRobotsRulesCache; + +// Contains the subresource redirect scoped to document's lifetime. This gets +// created when navigation commits and lives until a different navigation +// happens or the web contents is destroyed. +class SubresourceRedirectDocumentHost + : public content::RenderDocumentHostUserData< + SubresourceRedirectDocumentHost> { + public: + ~SubresourceRedirectDocumentHost() override; + SubresourceRedirectDocumentHost(const SubresourceRedirectDocumentHost&) = + delete; + SubresourceRedirectDocumentHost& operator=( + const SubresourceRedirectDocumentHost&) = delete; + + // Gets the robots rules for |origin| from the |rules_cache| and invokes the + // |callback|. + void GetAndUpdateRobotsRules( + const url::Origin& origin, + OriginRobotsRulesCache* rules_cache, + mojom::SubresourceRedirectService::GetRobotsRulesCallback callback); + + private: + explicit SubresourceRedirectDocumentHost( + content::RenderFrameHost* render_frame_host); + friend class content::RenderDocumentHostUserData< + SubresourceRedirectDocumentHost>; + + content::RenderFrameHost* render_frame_host_; + RENDER_DOCUMENT_HOST_USER_DATA_KEY_DECL(); +}; + // Sends the public image URL hints to renderer. class SubresourceRedirectObserver : public content::WebContentsObserver, @@ -48,6 +82,9 @@ // mojom::SubresourceRedirectService void NotifyCompressedImageFetchFailed(base::TimeDelta retry_after) override; + void GetRobotsRules(const url::Origin& origin, + mojom::SubresourceRedirectService::GetRobotsRulesCallback + callback) override; // Invoked when the OptimizationGuideKeyedService has sufficient information // to make a decision for whether we can send resource loading image hints.
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java index 9157073..d80427e3 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.tab.state; -import android.os.SystemClock; - import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -39,13 +37,15 @@ private static final String TAG = "PTD"; private static final Map<String, List<Callback>> sCachedCallbacks = new HashMap<>(); private static final long NEEDS_UPDATE_DISABLED = Long.MAX_VALUE; + private static final long LAST_UPDATE_UNKNOWN = 0; protected final Tab mTab; private final PersistedTabDataStorage mPersistedTabDataStorage; private final String mPersistedTabDataId; - private long mLastUpdatedMs; + private long mLastUpdatedMs = LAST_UPDATE_UNKNOWN; @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) public ObservableSupplierImpl<Boolean> mIsTabSaveEnabledSupplier; private Callback<Boolean> mTabSaveEnabledToggleCallback; + private boolean mFirstSaveDone; /** * @param tab {@link Tab} {@link PersistedTabData} is being stored for @@ -84,7 +84,9 @@ PersistedTabDataConfiguration config = PersistedTabDataConfiguration.get(clazz, tab.isIncognito()); T persistedTabData = factory.create(data, config.getStorage(), config.getId()); - setUserData(tab, clazz, persistedTabData); + if (persistedTabData != null) { + setUserData(tab, clazz, persistedTabData); + } return persistedTabData; } @@ -153,7 +155,7 @@ private static void updateLastUpdatedMs(PersistedTabData persistedTabData) { if (persistedTabData != null) { - persistedTabData.setLastUpdatedMs(SystemClock.uptimeMillis()); + persistedTabData.setLastUpdatedMs(System.currentTimeMillis()); } } @@ -164,7 +166,10 @@ if (getTimeToLiveMs() == NEEDS_UPDATE_DISABLED) { return false; } - return mLastUpdatedMs + getTimeToLiveMs() < SystemClock.uptimeMillis(); + if (mLastUpdatedMs == LAST_UPDATE_UNKNOWN) { + return true; + } + return mLastUpdatedMs + getTimeToLiveMs() < System.currentTimeMillis(); } private static <T extends PersistedTabData> void onPersistedTabDataResult( @@ -338,10 +343,21 @@ mTabSaveEnabledToggleCallback = (isTabSaveEnabled) -> { if (isTabSaveEnabled) { save(); - } else { + mFirstSaveDone = true; + } else if (mFirstSaveDone) { delete(); } }; mIsTabSaveEnabledSupplier.addObserver(mTabSaveEnabledToggleCallback); } + + /** + * Delete all {@link PersistedTabData} when a {@link Tab} is closed. + */ + public static void onTabClose(Tab tab) { + tab.setIsTabSaveEnabled(false); + if (ShoppingPersistedTabData.from(tab) != null) { + ShoppingPersistedTabData.from(tab).disableSaving(); + } + } }
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java index 75f59a4..303fcc0 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
@@ -18,8 +18,10 @@ import org.chromium.base.LocaleUtils; import org.chromium.base.Log; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.proto.ShoppingPersistedTabData.ShoppingPersistedTabDataProto; import org.chromium.components.payments.CurrencyFormatter; @@ -78,6 +80,13 @@ private String mCurrencyCode; + @VisibleForTesting + protected ObservableSupplierImpl<Boolean> mIsTabSaveEnabledSupplier = + new ObservableSupplierImpl<>(); + + @VisibleForTesting + protected EmptyTabObserver mUrlUpdatedObserver; + /** * A price drop for the offer {@link ShoppingPersistedTabData} * refers to @@ -119,11 +128,32 @@ .getStorage(), PersistedTabDataConfiguration.get(ShoppingPersistedTabData.class, tab.isIncognito()) .getId()); + setupPersistence(tab); } private ShoppingPersistedTabData( Tab tab, byte[] data, PersistedTabDataStorage storage, String persistedTabDataId) { super(tab, data, storage, persistedTabDataId); + setupPersistence(tab); + } + + private void setupPersistence(Tab tab) { + // ShoppingPersistedTabData is not saved by default - only when its fields are populated + // (after a successful endpoint repsonse) + disableSaving(); + registerIsTabSaveEnabledSupplier(mIsTabSaveEnabledSupplier); + mUrlUpdatedObserver = new EmptyTabObserver() { + // When the URL is updated, the ShoppingPersistedTabData is redundant and should be + // cleaned up. + @Override + public void onUrlUpdated(Tab tab) { + disableSaving(); + if (tab.getUserDataHost().getUserData(ShoppingPersistedTabData.class) != null) { + tab.getUserDataHost().removeUserData(ShoppingPersistedTabData.class); + } + } + }; + tab.addObserver(mUrlUpdatedObserver); } /** @@ -156,6 +186,13 @@ } /** + * @return {@link ShoppingPersistedTabData} from {@link UserDataHost} + */ + public static ShoppingPersistedTabData from(Tab tab) { + return from(tab, USER_DATA_KEY); + } + + /** * Whether a BuyableProductAnnotation was found or not */ @IntDef({FoundBuyableProductAnnotation.NOT_FOUND, FoundBuyableProductAnnotation.FOUND}) @@ -166,6 +203,21 @@ int NUM_ENTRIES = 2; } + /** + * Enable saving of {@link ShoppingPersistedTabData} + */ + protected void enableSaving() { + mIsTabSaveEnabledSupplier.set(true); + } + + /** + * Disable saving of {@link ShoppingPersistedTabData}. Deletes previously saved {@link + * ShoppingPersistedTabData} as well. + */ + public void disableSaving() { + mIsTabSaveEnabledSupplier.set(false); + } + private static ShoppingPersistedTabData build(Tab tab, String responseString, ShoppingPersistedTabData previousShoppingPersistedTabData) { ShoppingPersistedTabData res = new ShoppingPersistedTabData(tab); @@ -182,6 +234,7 @@ res.setPriceMicros(Long.parseLong(priceMetadata.getString(AMOUNT_MICROS_KEY)), previousShoppingPersistedTabData); res.setCurrencyCode(priceMetadata.getString(CURRENCY_CODE_KEY)); + res.setLastUpdatedMs(System.currentTimeMillis()); foundBuyableProductAnnotation = FoundBuyableProductAnnotation.FOUND; break; } @@ -197,7 +250,13 @@ RecordHistogram.recordEnumeratedHistogram( "Tabs.ShoppingPersistedTabData.FoundBuyableProductAnnotation", foundBuyableProductAnnotation, FoundBuyableProductAnnotation.NUM_ENTRIES); - return res; + // Only persist this ShoppingPersistedTabData if it was correctly populated from the + // response + if (foundBuyableProductAnnotation == FoundBuyableProductAnnotation.FOUND) { + res.enableSaving(); + return res; + } + return null; } /** @@ -224,6 +283,7 @@ protected void setCurrencyCode(String currencyCode) { mCurrencyCode = currencyCode; + save(); } @VisibleForTesting @@ -234,6 +294,7 @@ @VisibleForTesting protected void setPreviousPriceMicros(long previousPriceMicros) { mPreviousPriceMicros = previousPriceMicros; + save(); } @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @@ -333,6 +394,10 @@ @Override public boolean deserialize(@Nullable byte[] bytes) { // TODO(crbug.com/1135573) add in metrics for serialize and deserialize + // Do not attempt to deserialize if the bytes are null + if (bytes == null) { + return false; + } try { ShoppingPersistedTabDataProto shoppingPersistedTabDataProto = ShoppingPersistedTabDataProto.parseFrom(bytes); @@ -375,4 +440,10 @@ public void setLastPriceChangeTimeMsForTesting(long lastPriceChangeTimeMs) { mLastPriceChangeTimeMs = lastPriceChangeTimeMs; } + + @Override + public void destroy() { + mTab.removeObserver(mUrlUpdatedObserver); + super.destroy(); + } } \ No newline at end of file
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e58796be..32c61bbd 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -264,10 +264,10 @@ "webui/omnibox/omnibox_page_handler.h", "webui/omnibox/omnibox_ui.cc", "webui/omnibox/omnibox_ui.h", - "webui/policy_ui.cc", - "webui/policy_ui.h", - "webui/policy_ui_handler.cc", - "webui/policy_ui_handler.h", + "webui/policy/policy_ui.cc", + "webui/policy/policy_ui.h", + "webui/policy/policy_ui_handler.cc", + "webui/policy/policy_ui_handler.h", "webui/predictors/predictors_handler.cc", "webui/predictors/predictors_handler.h", "webui/predictors/predictors_ui.cc", @@ -284,10 +284,10 @@ "webui/quota_internals/quota_internals_ui.h", "webui/signin_internals_ui.cc", "webui/signin_internals_ui.h", - "webui/sync_internals_message_handler.cc", - "webui/sync_internals_message_handler.h", - "webui/sync_internals_ui.cc", - "webui/sync_internals_ui.h", + "webui/sync_internals/sync_internals_message_handler.cc", + "webui/sync_internals/sync_internals_message_handler.h", + "webui/sync_internals/sync_internals_ui.cc", + "webui/sync_internals/sync_internals_ui.h", "webui/test_files_request_filter.cc", "webui/test_files_request_filter.h", "webui/translate_internals/chrome_translate_internals_handler.cc", @@ -2716,6 +2716,7 @@ "//components/session_manager/core", "//components/user_manager", "//google_apis/drive", + "//media/capture:capture_lib", "//mojo/public/js:resources_grit", "//services/audio/public/mojom", "//services/data_decoder/public/cpp",
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDeps.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDeps.java index f664cabd..56acd02 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDeps.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoDeps.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.ui.default_browser_promo; -import static org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoManager.P_NO_DEFAULT_PROMO_STRATEGY; - import android.annotation.SuppressLint; import android.app.Activity; import android.app.role.RoleManager; @@ -23,7 +21,6 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils.DefaultBrowserPromoAction; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils.DefaultBrowserState; import java.util.concurrent.TimeUnit; @@ -162,24 +159,13 @@ return Build.VERSION.SDK_INT; } - int promoActionOnP() { - String promoOnP = ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO, P_NO_DEFAULT_PROMO_STRATEGY); - if (TextUtils.equals(promoOnP, "disabled")) { - return DefaultBrowserPromoAction.NO_ACTION; - } else if (TextUtils.equals(promoOnP, "system_settings")) { - return DefaultBrowserPromoAction.SYSTEM_SETTINGS; - } else { - return DefaultBrowserPromoAction.DISAMBIGUATION_SHEET; - } - } - @SuppressLint("NewApi") boolean isRoleAvailable(Activity activity) { if (getSDKInt() < Build.VERSION_CODES.Q) { return false; } RoleManager roleManager = (RoleManager) activity.getSystemService(Context.ROLE_SERVICE); + if (roleManager == null) return false; boolean isRoleAvailable = roleManager.isRoleAvailable(RoleManager.ROLE_BROWSER); boolean isRoleHeld = roleManager.isRoleHeld(RoleManager.ROLE_BROWSER); return isRoleAvailable && !isRoleHeld;
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java index 4c4e589..9deb0e83 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManager.java
@@ -9,17 +9,10 @@ import android.app.role.RoleManager; import android.content.Context; import android.content.Intent; -import android.net.Uri; -import android.provider.Settings; import androidx.annotation.VisibleForTesting; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.lifecycle.Destroyable; -import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver; -import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; -import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoDialog.DialogStyle; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoMetrics.UIDismissalReason; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils.DefaultBrowserState; @@ -29,35 +22,29 @@ * Manage all types of default browser promo dialogs and listen to the activity state change to * trigger dialogs. */ -public class DefaultBrowserPromoManager implements PauseResumeWithNativeObserver, Destroyable { +public class DefaultBrowserPromoManager { private static final String SKIP_PRIMER_PARAM = "skip_primer"; - private static final String DISAMBIGUATION_PROMO_URL = "disambiguation_promo_url"; static final String P_NO_DEFAULT_PROMO_STRATEGY = "p_no_default_promo"; private final Activity mActivity; private DefaultBrowserPromoDialog mDialog; private @DefaultBrowserState int mCurrentState; - private @DialogStyle Integer mPromoStyle; - private ActivityLifecycleDispatcher mDispatcher; private WindowAndroid mWindowAndroid; /** * @param activity Activity to show promo dialogs. - * @param dispatcher The {@link ActivityLifecycleDispatcher} of the current activity. * @param windowAndroid The {@link WindowAndroid} for sending an intent. * @param currentState The current {@link DefaultBrowserState} in the system. */ - public DefaultBrowserPromoManager(Activity activity, ActivityLifecycleDispatcher dispatcher, - WindowAndroid windowAndroid, @DefaultBrowserState int currentState) { + public DefaultBrowserPromoManager( + Activity activity, WindowAndroid windowAndroid, @DefaultBrowserState int currentState) { mActivity = activity; - mDispatcher = dispatcher; mWindowAndroid = windowAndroid; mCurrentState = currentState; } @SuppressLint({"WrongConstant", "NewApi"}) void promoByRoleManager() { - mPromoStyle = DialogStyle.ROLE_MANAGER; boolean shouldSkipPrimer = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO, SKIP_PRIMER_PARAM, false); Runnable onOK = () -> { @@ -75,7 +62,6 @@ DefaultBrowserPromoMetrics.recordOutcome(mCurrentState, DefaultBrowserPromoDeps.getInstance().getCurrentDefaultBrowserState()); }, null); - destroy(); }; if (shouldSkipPrimer) { onOK.run(); @@ -84,82 +70,16 @@ } } - void promoBySystemSettings() { - mPromoStyle = DialogStyle.SYSTEM_SETTINGS; - showDialog(DefaultBrowserPromoDialog.DialogStyle.SYSTEM_SETTINGS, () -> { - // Users are leaving Chrome, so the app may be shut down or killed in the background. - // Save state to pref for checking result on the next app start up. - SharedPreferencesManager.getInstance().writeBoolean( - ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_PROMOED_BY_SYSTEM_SETTINGS, true); - SharedPreferencesManager.getInstance().writeInt( - ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_LAST_DEFAULT_STATE, mCurrentState); - DefaultBrowserPromoMetrics.recordUiDismissalReason( - mCurrentState, UIDismissalReason.CHANGE_DEFAULT); - - Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS); - mActivity.startActivity(intent); - }); - } - - void promoByDisambiguationSheet() { - mPromoStyle = DialogStyle.DISAMBIGUATION_SHEET; - showDialog(DialogStyle.DISAMBIGUATION_SHEET, () -> { - DefaultBrowserPromoMetrics.recordUiDismissalReason( - mCurrentState, UIDismissalReason.CHANGE_DEFAULT); - - Intent intent = new Intent(); - String url = ChromeFeatureList.getFieldTrialParamByFeature( - ChromeFeatureList.ANDROID_DEFAULT_BROWSER_PROMO, DISAMBIGUATION_PROMO_URL); - if (url != null && !url.isEmpty()) { - intent.setAction(Intent.ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setData(Uri.parse(url)); - } else { - intent.setAction(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_APP_BROWSER); - } - intent.putExtra(DefaultBrowserPromoUtils.getDisambiguationSheetPromoedKey(), true); - mActivity.startActivity(intent); - }); - } - private void showDialog(@DialogStyle int style, Runnable okCallback) { mDialog = DefaultBrowserPromoDialog.createDialog(mActivity, style, okCallback, () -> { DefaultBrowserPromoMetrics.recordUiDismissalReason( mCurrentState, UIDismissalReason.NO_THANKS); - destroy(); }); DefaultBrowserPromoMetrics.recordDialogShow(mCurrentState); - mDispatcher.register(this); mDialog.show(); } - @Override - public void onResumeWithNative() { - // TODO(crbug.com/1090103): Edge case: user might shut down chrome when disambiguation sheet - // or role manager dialog is shown, leading to no metrics recording. - if (mPromoStyle == null) return; - if (mPromoStyle == DialogStyle.DISAMBIGUATION_SHEET) { - DefaultBrowserPromoMetrics.recordOutcome(mCurrentState, - DefaultBrowserPromoDeps.getInstance().getCurrentDefaultBrowserState()); - destroy(); - } else if (mPromoStyle == DialogStyle.SYSTEM_SETTINGS) { - // Result may also be confirmed on start up of chrome tabbed activity. - DefaultBrowserPromoUtils.maybeRecordOutcomeOnStart(); - destroy(); - } - } - - @Override - public void onPauseWithNative() {} - - @Override - public void destroy() { - mPromoStyle = null; - mDispatcher.unregister(this); - } - @VisibleForTesting DefaultBrowserPromoDialog getDialogForTesting() { return mDialog;
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManagerTest.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManagerTest.java index e16f75b..24a29b00 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManagerTest.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoManagerTest.java
@@ -23,8 +23,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.lifecycle.LifecycleObserver; import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils.DefaultBrowserState; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.browser_ui.widget.PromoDialog; @@ -50,23 +48,8 @@ super.setUpTest(); mActivity = getActivity(); mWindowAndroid = TestThreadUtils.runOnUiThreadBlocking(() -> new WindowAndroid(mActivity)); - mManager = new DefaultBrowserPromoManager(mActivity, new ActivityLifecycleDispatcher() { - @Override - public void register(LifecycleObserver observer) {} - - @Override - public void unregister(LifecycleObserver observer) {} - - @Override - public int getCurrentActivityState() { - return 0; - } - - @Override - public boolean isNativeInitializationFinished() { - return false; - } - }, mWindowAndroid, DefaultBrowserState.NO_DEFAULT); + mManager = new DefaultBrowserPromoManager( + mActivity, mWindowAndroid, DefaultBrowserState.NO_DEFAULT); mAppName = BuildInfo.getInstance().hostPackageLabel; // Enabling feature can assign a default value to the fieldtrial param. FeatureList.setTestFeatures(Collections.EMPTY_MAP); @@ -107,67 +90,6 @@ checkDialogVisibility(); } - @Test - @MediumTest - public void testPromoBySystemSettingsOnP() { - TestThreadUtils.runOnUiThreadBlocking(() -> { mManager.promoBySystemSettings(); }); - DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting(); - Assert.assertEquals( - "Dialog should be of system settings style on P-, when there is another default in system", - dialog.getDialogStyleForTesting(), - DefaultBrowserPromoDialog.DialogStyle.SYSTEM_SETTINGS); - - // test role manager style - PromoDialog.DialogParams params = dialog.getDialogParams(); - Assert.assertEquals( - mActivity.getString(R.string.default_browser_promo_dialog_title, mAppName), - params.headerCharSequence); - - Assert.assertEquals( - mActivity.getString(R.string.default_browser_promo_dialog_desc, mAppName) + "\n\n" - + mActivity.getString( - R.string.default_browser_promo_dialog_system_settings_steps, - mAppName), - params.subheaderCharSequence); - - Assert.assertEquals( - mActivity.getString(R.string.default_browser_promo_dialog_go_to_settings_button), - params.primaryButtonCharSequence); - - checkDialogVisibility(); - } - - @Test - @MediumTest - public void testPromoByDisambiguationSheet() { - TestThreadUtils.runOnUiThreadBlocking(() -> { mManager.promoByDisambiguationSheet(); }); - DefaultBrowserPromoDialog dialog = mManager.getDialogForTesting(); - Assert.assertEquals( - "Dialog should be of disambiguation sheet style on P-, when there is no default in system", - dialog.getDialogStyleForTesting(), - DefaultBrowserPromoDialog.DialogStyle.DISAMBIGUATION_SHEET); - - // test role manager style - PromoDialog.DialogParams params = dialog.getDialogParams(); - Assert.assertEquals( - mActivity.getString(R.string.default_browser_promo_dialog_title, mAppName), - params.headerCharSequence); - - Assert.assertEquals( - mActivity.getString(R.string.default_browser_promo_dialog_desc, mAppName) + "\n\n" - + mActivity.getString( - R.string.default_browser_promo_dialog_disambiguation_sheet_steps, - mAppName), - params.subheaderCharSequence); - - Assert.assertEquals( - mActivity.getString( - R.string.default_browser_promo_dialog_choose_chrome_button, mAppName), - params.primaryButtonCharSequence); - - checkDialogVisibility(); - } - private void checkDialogVisibility() { onView(withId(R.id.promo_dialog_layout)).check(matches(isDisplayed())); // dismiss the dialog
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoMetrics.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoMetrics.java index 759a780..f1d64216 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoMetrics.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoMetrics.java
@@ -76,10 +76,4 @@ : "Android.DefaultBrowserPromo.Outcome.OtherDefault"; RecordHistogram.recordEnumeratedHistogram(name, newState, DefaultBrowserState.NUM_ENTRIES); } - - static void recordLaunchedByDisambiguationSheet(@DefaultBrowserState int currentState) { - RecordHistogram.recordEnumeratedHistogram( - "Android.DefaultBrowserPromo.IntentReceivedFromDisambiguationSheet", currentState, - DefaultBrowserState.NUM_ENTRIES); - } }
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java index fec608d5..072e2e0 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtils.java
@@ -5,16 +5,12 @@ package org.chromium.chrome.browser.ui.default_browser_promo; import android.app.Activity; -import android.content.Intent; import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Build; import androidx.annotation.IntDef; import org.chromium.base.ContextUtils; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.ui.base.WindowAndroid; @@ -59,26 +55,19 @@ * launch promo if a promo dialog has been decided to display. * * @param activity The context. - * @param dispatcher The {@link ActivityLifecycleDispatcher} of the current activity. * @param windowAndroid The {@link WindowAndroid} for sending an intent. * @return True if promo dialog will be displayed. */ - public static boolean prepareLaunchPromoIfNeeded(Activity activity, - ActivityLifecycleDispatcher dispatcher, WindowAndroid windowAndroid) { + public static boolean prepareLaunchPromoIfNeeded( + Activity activity, WindowAndroid windowAndroid) { DefaultBrowserPromoDeps deps = DefaultBrowserPromoDeps.getInstance(); int action = decideNextAction(deps, activity); if (action == DefaultBrowserPromoAction.NO_ACTION) return false; deps.incrementPromoCount(); deps.recordPromoTime(); DefaultBrowserPromoManager manager = new DefaultBrowserPromoManager( - activity, dispatcher, windowAndroid, deps.getCurrentDefaultBrowserState()); - if (action == DefaultBrowserPromoAction.ROLE_MANAGER) { - manager.promoByRoleManager(); - } else if (action == DefaultBrowserPromoAction.SYSTEM_SETTINGS) { - manager.promoBySystemSettings(); - } else if (action == DefaultBrowserPromoAction.DISAMBIGUATION_SHEET) { - manager.promoByDisambiguationSheet(); - } + activity, windowAndroid, deps.getCurrentDefaultBrowserState()); + manager.promoByRoleManager(); return true; } @@ -99,6 +88,9 @@ if (!deps.isFeatureEnabled()) { return DefaultBrowserPromoAction.NO_ACTION; } + if (!deps.isRoleAvailable(activity)) { + return DefaultBrowserPromoAction.NO_ACTION; + } // Criteria 1 if (deps.getPromoCount() >= deps.getMaxPromoCount()) { return DefaultBrowserPromoAction.NO_ACTION; @@ -125,29 +117,18 @@ // Criteria 4 if (deps.isChromeStable() && deps.isChromePreStableInstalled()) { action = DefaultBrowserPromoAction.NO_ACTION; - } else if (deps.getSDKInt() >= Build.VERSION_CODES.Q) { - action = DefaultBrowserPromoAction.ROLE_MANAGER; } else { - action = deps.promoActionOnP(); + action = DefaultBrowserPromoAction.ROLE_MANAGER; } } else { // other default // Criteria 3 if (deps.isCurrentDefaultBrowserChrome(info)) { action = DefaultBrowserPromoAction.NO_ACTION; } else { - action = deps.getSDKInt() >= Build.VERSION_CODES.Q - ? DefaultBrowserPromoAction.ROLE_MANAGER - : DefaultBrowserPromoAction.SYSTEM_SETTINGS; + action = DefaultBrowserPromoAction.ROLE_MANAGER; } } - // Criteria 6 - if (action == DefaultBrowserPromoAction.SYSTEM_SETTINGS - && !deps.doesManageDefaultAppsSettingsActivityExist()) { - action = DefaultBrowserPromoAction.NO_ACTION; - } else if (action == DefaultBrowserPromoAction.ROLE_MANAGER - && !deps.isRoleAvailable(activity)) { - action = DefaultBrowserPromoAction.NO_ACTION; - } + return action; } @@ -179,30 +160,8 @@ ChromePreferenceKeys.DEFAULT_BROWSER_PROMO_PROMOED_BY_SYSTEM_SETTINGS, false); } - /** - * Called on new intent is received on the activity so that we can record some metrics. - */ - public static void onNewIntentReceived(Intent intent) { - boolean promoed = intent.getBooleanExtra(getDisambiguationSheetPromoedKey(), false); - if (promoed) { - DefaultBrowserPromoMetrics.recordLaunchedByDisambiguationSheet( - DefaultBrowserPromoDeps.getInstance().getCurrentDefaultBrowserState()); - } - } - static String getDisambiguationSheetPromoedKey() { return DISAMBIGUATION_SHEET_PROMOED_KEY_PREFIX + ContextUtils.getApplicationContext().getPackageName(); } - - /** - * Remove intent data if this intent is triggered by default browser promo; Otherwise, - * chrome will open a new tab. - */ - public static void maybeRemoveIntentData(Intent intent) { - if (intent.getBooleanExtra(getDisambiguationSheetPromoedKey(), false)) { - // Intent with Uri.EMPTY as data will be ignored by the IntentHandler. - intent.setData(Uri.EMPTY); - } - } }
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java index 83ddb9b..40dd403 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java
@@ -117,8 +117,8 @@ @Test public void testBasicPromo() { setDepsMockWithDefaultValues(); - Assert.assertEquals("Should promo disambiguation sheet on P.", - DefaultBrowserPromoAction.DISAMBIGUATION_SHEET, + Assert.assertEquals("Should promo disambiguation sheet on Q.", + DefaultBrowserPromoAction.ROLE_MANAGER, DefaultBrowserPromoUtils.decideNextAction(mDeps, null)); } @@ -126,7 +126,6 @@ @Test public void testPromo_Q_No_Default() { setDepsMockWithDefaultValues(); - when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.Q); when(mDeps.isRoleAvailable(any())).thenReturn(true); Assert.assertEquals("Should promo role manager when there is no default browser on Q+.", DefaultBrowserPromoAction.ROLE_MANAGER, @@ -136,7 +135,6 @@ @Test public void testPromo_Q_Other_Default() { setDepsMockWithDefaultValues(); - when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.Q); when(mDeps.isRoleAvailable(any())).thenReturn(true); when(mDeps.getDefaultWebBrowserActivityResolveInfo()) .thenReturn(createResolveInfo("android", 1)); @@ -148,46 +146,12 @@ // --- P below --- @Test - public void testPromo_P_otherDefaultSystemSettings() { + public void testNoPromo_P() { setDepsMockWithDefaultValues(); - when(mDeps.getDefaultWebBrowserActivityResolveInfo()) - .thenReturn(createResolveInfo("android", 1)); - when(mDeps.promoActionOnP()).thenReturn(DefaultBrowserPromoAction.SYSTEM_SETTINGS); + when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.P); + when(mDeps.isRoleAvailable(any())).thenCallRealMethod(); Assert.assertEquals( "Should promo system settings when there is another default browser on P-.", - DefaultBrowserPromoAction.SYSTEM_SETTINGS, - DefaultBrowserPromoUtils.decideNextAction(mDeps, null)); - } - - @Test - public void testNoPromo_P_noDefaultNoSystemSettings() { - setDepsMockWithDefaultValues(); - when(mDeps.promoActionOnP()).thenReturn(DefaultBrowserPromoAction.SYSTEM_SETTINGS); - when(mDeps.doesManageDefaultAppsSettingsActivityExist()).thenReturn(false); - Assert.assertEquals( - "Should not promo system settings on P- when target system setting is not available.", - DefaultBrowserPromoAction.NO_ACTION, - DefaultBrowserPromoUtils.decideNextAction(mDeps, null)); - } - - @Test - public void testNoPromo_P_noDefaultDisabled() { - setDepsMockWithDefaultValues(); - when(mDeps.promoActionOnP()).thenReturn(DefaultBrowserPromoAction.NO_ACTION); - Assert.assertEquals( - "Should not promo on P- when promoing on \'no default\' scenario is disabled.", - DefaultBrowserPromoAction.NO_ACTION, - DefaultBrowserPromoUtils.decideNextAction(mDeps, null)); - } - - @Test - public void testNoPromo_otherDefault_M() { - setDepsMockWithDefaultValues(); - when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.M); - when(mDeps.doesManageDefaultAppsSettingsActivityExist()).thenCallRealMethod(); - when(mDeps.getDefaultWebBrowserActivityResolveInfo()) - .thenReturn(createResolveInfo("android", 1)); - Assert.assertEquals("Should not promo on M- when there is another default browser.", DefaultBrowserPromoAction.NO_ACTION, DefaultBrowserPromoUtils.decideNextAction(mDeps, null)); } @@ -271,8 +235,7 @@ when(mDeps.getMinSessionCount()).thenReturn(3); when(mDeps.getSessionCount()).thenReturn(10); when(mDeps.doesManageDefaultAppsSettingsActivityExist()).thenReturn(true); - when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.P); - when(mDeps.promoActionOnP()).thenReturn(DefaultBrowserPromoAction.DISAMBIGUATION_SHEET); + when(mDeps.getSDKInt()).thenReturn(Build.VERSION_CODES.Q); when(mDeps.isChromeStable()).thenReturn(false); when(mDeps.getPromoCount()).thenReturn(0); when(mDeps.getMaxPromoCount()).thenReturn(1); @@ -280,6 +243,7 @@ when(mDeps.getMinPromoInterval()).thenReturn(10); when(mDeps.isChromePreStableInstalled()).thenReturn(false); when(mDeps.isCurrentDefaultBrowserChrome(any())).thenReturn(false); + when(mDeps.isRoleAvailable(any())).thenReturn(true); // No Default when(mDeps.getDefaultWebBrowserActivityResolveInfo()) .thenReturn(createResolveInfo("android", 0));
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc index 6ef1399..9f3fc9f 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.cc
@@ -11,6 +11,7 @@ #include "ash/public/cpp/holding_space/holding_space_prefs.h" #include "base/files/file_path.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/drive/drive_integration_service.h" #include "chrome/browser/chromeos/file_manager/app_id.h" #include "chrome/browser/chromeos/file_manager/fileapi_util.h" #include "chrome/browser/profiles/profile.h" @@ -20,7 +21,9 @@ #include "chrome/browser/ui/ash/holding_space/holding_space_util.h" #include "components/account_id/account_id.h" #include "components/prefs/scoped_user_pref_update.h" +#include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_url.h" +#include "storage/common/file_system/file_system_types.h" namespace ash { @@ -147,8 +150,11 @@ holding_space_metrics::RecordItemAction( {holding_space_item_to_record}, holding_space_metrics::ItemAction::kPin); - AddItem(std::move(holding_space_item)); + + if (file_system_url.type() == storage::kFileSystemTypeDriveFs) { + MakeDriveItemAvailableOffline(file_system_url); + } } void HoldingSpaceKeyedService::RemovePinnedFile( @@ -345,4 +351,23 @@ delegate->NotifyPersistenceRestored(); } +void HoldingSpaceKeyedService::MakeDriveItemAvailableOffline( + const storage::FileSystemURL& file_system_url) { + auto* drive_service = + drive::DriveIntegrationServiceFactory::GetForProfile(profile_); + + bool drive_fs_mounted = drive_service && drive_service->IsMounted(); + if (!drive_fs_mounted) + return; + + if (!drive_service->GetDriveFsInterface()) + return; + + base::FilePath path; + if (drive_service->GetRelativeDrivePath(file_system_url.path(), &path)) { + drive_service->GetDriveFsInterface()->SetPinned(path, true, + base::DoNothing()); + } +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h index c6f144c..4d1eb2a 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h
@@ -123,6 +123,10 @@ // Invoked when holding space persistence has been restored. void OnPersistenceRestored(); + // Pin a drive file for offline access. + void MakeDriveItemAvailableOffline( + const storage::FileSystemURL& file_system_url); + Profile* const profile_; const AccountId account_id_;
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc index d075cd3..cf1f242 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_keyed_service_browsertest.cc
@@ -25,8 +25,10 @@ #include "chrome/browser/chromeos/drive/drive_integration_service.h" #include "chrome/browser/chromeos/drive/drivefs_test_support.h" #include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/chromeos/file_manager/volume_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/component_loader.h" +#include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h" #include "chrome/browser/ui/ash/holding_space/holding_space_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_paths.h" @@ -364,6 +366,10 @@ waiter_loop.Run(); } + drive::DriveIntegrationService* integration_service() { + return integration_service_; + } + private: base::test::ScopedFeatureList scoped_feature_list_; @@ -475,4 +481,45 @@ })); } +// Verifies that drive files pinned to holding space are pinned for offline use. +IN_PROC_BROWSER_TEST_P(HoldingSpaceKeyedServiceBrowserTest, + PinningDriveFilesOfflineAccess) { + // Test only for drive file system type files. + if (GetParam() == FileSystemType::kDownloads) + return; + + const base::FilePath file_path = + CreateTextFile(GetTestMountPoint(), + /*relative_path=*/base::nullopt); + const GURL url = + holding_space_util::ResolveFileSystemUrl(browser()->profile(), file_path); + storage::FileSystemURL file_system_url = + storage::ExternalMountPoints::GetSystemInstance()->CrackURL(url); + ASSERT_TRUE(file_system_url.is_valid()); + ASSERT_EQ(storage::kFileSystemTypeDriveFs, file_system_url.type()); + + // Add item from HoldingSpaceKeyedService to handle the pinning behaviour. + HoldingSpaceKeyedService* const holding_space_service = + HoldingSpaceKeyedServiceFactory::GetInstance()->GetService( + browser()->profile()); + holding_space_service->AddPinnedFile(file_system_url); + + base::FilePath relative_path; + ASSERT_TRUE(integration_service()->GetRelativeDrivePath( + file_system_url.path(), &relative_path)); + base::RunLoop loop; + bool is_pinned = false; + integration_service()->GetDriveFsInterface()->GetMetadata( + relative_path, + base::BindOnce( + [](base::RunLoop* loop, bool* is_pinned, ::drive::FileError error, + drivefs::mojom::FileMetadataPtr metadata) { + *is_pinned = metadata->pinned; + loop->Quit(); + }, + &loop, &is_pinned)); + loop.Run(); + EXPECT_TRUE(is_pinned); +} + } // namespace ash
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc index 8d1882d5..833b53a 100644 --- a/chrome/browser/ui/ash/media_client_impl.cc +++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -7,10 +7,15 @@ #include <utility> #include "ash/public/cpp/media_controller.h" +#include "ash/public/cpp/notification_utils.h" +#include "ash/public/cpp/toast_data.h" +#include "ash/public/cpp/toast_manager.h" #include "base/bind.h" #include "base/check_op.h" +#include "base/feature_list.h" #include "base/location.h" #include "base/single_thread_task_runner.h" +#include "base/strings/utf_string_conversions.h" #include "base/system/sys_info.h" #include "base/task/current_thread.h" #include "base/threading/thread_task_runner_handle.h" @@ -19,6 +24,7 @@ #include "chrome/browser/chromeos/extensions/media_player_event_router.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" +#include "chrome/browser/notifications/system_notification_helper.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" @@ -27,14 +33,19 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/constants/chromeos_features.h" #include "components/user_manager/user_manager.h" +#include "components/vector_icons/vector_icons.h" #include "content/public/browser/media_session.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/process_manager.h" +#include "media/capture/video/chromeos/public/cros_features.h" #include "services/media_session/public/mojom/media_session.mojom.h" +#include "ui/base/l10n/l10n_util.h" using ash::MediaCaptureState; @@ -42,6 +53,27 @@ MediaClientImpl* g_media_client = nullptr; +// The ID for a notification shown when the user tries to use a camera while the +// camera privacy switch is on. +constexpr char kCameraPrivacySwitchOnNotificationId[] = + "ash.media.camera.activity_with_privacy_switch_on"; + +// The notifier ID for a notification shown when the user tries to use a camera +// while the camera privacy switch is on. +constexpr char kCameraPrivacySwitchNotifierId[] = "ash.media.camera"; + +// The ID for the toast shown when the camera privacy switch is turned on. +constexpr char kCameraPrivacySwitchOnToastId[] = + "ash.media.camera.privacy_switch_on"; + +// The ID for the toast shown when the camera privacy switch is turned off. +constexpr char kCameraPrivacySwitchOffToastId[] = + "ash.media.camera.privacy_switch_off"; + +// The amount of time for which the camera privacy switch toasts will remain +// displayed. +constexpr int kCameraPrivacySwitchToastDurationMs = 6 * 1000; + MediaCaptureState& operator|=(MediaCaptureState& lhs, MediaCaptureState rhs) { lhs = static_cast<MediaCaptureState>(static_cast<int>(lhs) | static_cast<int>(rhs)); @@ -143,6 +175,18 @@ chromeos::VmCameraMicManager::Get()->AddObserver(this); + // Camera service does not behave in non ChromeOS environment (e.g. testing, + // linux chromeos). + if (base::SysInfo::IsRunningOnChromeOS() && + base::FeatureList::IsEnabled( + chromeos::features::kCameraPrivacySwitchNotifications) && + media::ShouldUseCrosCameraService()) { + camera_privacy_switch_state_ = media::CameraHalDispatcherImpl::GetInstance() + ->AddCameraPrivacySwitchObserver(this); + media::CameraHalDispatcherImpl::GetInstance()->AddActiveClientObserver( + this); + } + DCHECK(!g_media_client); g_media_client = this; } @@ -157,6 +201,15 @@ BrowserList::RemoveObserver(this); chromeos::VmCameraMicManager::Get()->RemoveObserver(this); + if (base::SysInfo::IsRunningOnChromeOS() && + base::FeatureList::IsEnabled( + chromeos::features::kCameraPrivacySwitchNotifications) && + media::ShouldUseCrosCameraService()) { + media::CameraHalDispatcherImpl::GetInstance() + ->RemoveCameraPrivacySwitchObserver(this); + media::CameraHalDispatcherImpl::GetInstance()->RemoveActiveClientObserver( + this); + } } // static @@ -264,6 +317,68 @@ manager->IsNotificationActive(DeviceType::kMic)); } +void MediaClientImpl::OnCameraPrivacySwitchStatusChanged( + cros::mojom::CameraPrivacySwitchState state) { + camera_privacy_switch_state_ = state; + + // Show camera privacy switch toast. + switch (state) { + case cros::mojom::CameraPrivacySwitchState::UNKNOWN: + break; + case cros::mojom::CameraPrivacySwitchState::ON: { + ash::ToastData toast( + kCameraPrivacySwitchOnToastId, + l10n_util::GetStringUTF16(IDS_CAMERA_PRIVACY_SWITCH_ON_TOAST), + kCameraPrivacySwitchToastDurationMs, + /*dismiss_text=*/base::nullopt, + /*visible_on_lock_screen=*/true); + ash::ToastManager::Get()->Show(toast); + break; + } + case cros::mojom::CameraPrivacySwitchState::OFF: { + ash::ToastData toast( + kCameraPrivacySwitchOffToastId, + l10n_util::GetStringUTF16(IDS_CAMERA_PRIVACY_SWITCH_OFF_TOAST), + kCameraPrivacySwitchToastDurationMs, + /*dismiss_text=*/base::nullopt, + /*visible_on_lock_screen=*/true); + ash::ToastManager::Get()->Show(toast); + break; + } + } + + if (camera_privacy_switch_state_ == + cros::mojom::CameraPrivacySwitchState::OFF) { + SystemNotificationHelper::GetInstance()->Close( + kCameraPrivacySwitchOnNotificationId); + } +} + +void MediaClientImpl::OnActiveClientChange(cros::mojom::CameraClientType type, + bool is_active) { + if (is_active && camera_privacy_switch_state_ == + cros::mojom::CameraPrivacySwitchState::ON) { + std::unique_ptr<message_center::Notification> notification = + ash::CreateSystemNotification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kCameraPrivacySwitchOnNotificationId, + l10n_util::GetStringUTF16( + IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_TITLE), + l10n_util::GetStringUTF16( + IDS_CAMERA_PRIVACY_SWITCH_ON_NOTIFICATION_MESSAGE), + base::string16(), GURL(), + message_center::NotifierId( + message_center::NotifierType::SYSTEM_COMPONENT, + kCameraPrivacySwitchNotifierId), + message_center::RichNotificationData(), + new message_center::HandleNotificationClickDelegate( + base::DoNothing::Repeatedly()), + vector_icons::kVideocamOffIcon, + message_center::SystemNotificationWarningLevel::NORMAL); + SystemNotificationHelper::GetInstance()->Display(*notification); + } +} + void MediaClientImpl::EnableCustomMediaKeyHandler( content::BrowserContext* context, ui::MediaKeysListener::Delegate* delegate) {
diff --git a/chrome/browser/ui/ash/media_client_impl.h b/chrome/browser/ui/ash/media_client_impl.h index 3232a4a..bcdfa9e 100644 --- a/chrome/browser/ui/ash/media_client_impl.h +++ b/chrome/browser/ui/ash/media_client_impl.h
@@ -13,12 +13,16 @@ #include "chrome/browser/chromeos/camera_mic/vm_camera_mic_manager.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/ui/browser_list_observer.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" +#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" #include "ui/base/accelerators/media_keys_listener.h" class MediaClientImpl : public ash::MediaClient, public BrowserListObserver, public chromeos::VmCameraMicManager::Observer, - public MediaCaptureDevicesDispatcher::Observer { + public MediaCaptureDevicesDispatcher::Observer, + public media::CameraPrivacySwitchObserver, + public media::CameraActiveClientObserver { public: MediaClientImpl(); ~MediaClientImpl() override; @@ -57,6 +61,14 @@ void OnVmCameraMicActiveChanged( chromeos::VmCameraMicManager* manager) override; + // media::CameraPrivacySwitchObserver: + void OnCameraPrivacySwitchStatusChanged( + cros::mojom::CameraPrivacySwitchState state) override; + + // media::CameraActiveClientObserver: + void OnActiveClientChange(cros::mojom::CameraClientType type, + bool is_active) override; + // Enables/disables custom media key handling when |context| is the active // browser. Media keys will be forwarded to |delegate|. void EnableCustomMediaKeyHandler(content::BrowserContext* context, @@ -100,6 +112,10 @@ ash::MediaCaptureState vm_media_capture_state_ = ash::MediaCaptureState::kNone; + // The most recent observed camera privacy switch state. + cros::mojom::CameraPrivacySwitchState camera_privacy_switch_state_ = + cros::mojom::CameraPrivacySwitchState::UNKNOWN; + base::WeakPtrFactory<MediaClientImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(MediaClientImpl);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc index cd424a1..7ea3bdfa 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
@@ -32,7 +32,7 @@ namespace { void UnblockOnProfileCreation(Profile::CreateStatus expected_final_status, - const base::Closure& quit_closure, + base::OnceClosure quit_closure, Profile* profile, Profile::CreateStatus status) { // If the status is CREATE_STATUS_CREATED, then the function will be called @@ -41,19 +41,19 @@ return; EXPECT_EQ(expected_final_status, status); - quit_closure.Run(); + std::move(quit_closure).Run(); } -void UnblockOnProfileInitialized(const base::Closure& quit_closure, +void UnblockOnProfileInitialized(base::OnceClosure quit_closure, Profile* profile, Profile::CreateStatus status) { - UnblockOnProfileCreation(Profile::CREATE_STATUS_INITIALIZED, quit_closure, - profile, status); + UnblockOnProfileCreation(Profile::CREATE_STATUS_INITIALIZED, + std::move(quit_closure), profile, status); } -void OnCloseAllBrowsersSucceeded(const base::Closure& quit_closure, +void OnCloseAllBrowsersSucceeded(base::OnceClosure quit_closure, const base::FilePath& path) { - quit_closure.Run(); + std::move(quit_closure).Run(); } void CreateAndSwitchToProfile(const std::string& basepath) { @@ -161,7 +161,8 @@ base::RunLoop run_loop; BrowserList::GetInstance()->CloseAllBrowsersWithProfile( profile, - base::Bind(&OnCloseAllBrowsersSucceeded, run_loop.QuitClosure()), + base::BindRepeating(&OnCloseAllBrowsersSucceeded, + run_loop.QuitClosure()), BrowserList::CloseCallback(), false); }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc index 6946fb33..14996fe3 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
@@ -98,9 +98,9 @@ create_services_subscription_ = BrowserContextDependencyManager::GetInstance() ->RegisterCreateServicesCallbackForTesting( - base::Bind(&StartupBrowserCreatorTriggeredResetTest:: - OnWillCreateBrowserContextServices, - base::Unretained(this))); + base::BindRepeating(&StartupBrowserCreatorTriggeredResetTest:: + OnWillCreateBrowserContextServices, + base::Unretained(this))); } private:
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc index 0b670ba9..aea1863 100644 --- a/chrome/browser/ui/tab_contents/core_tab_helper.cc +++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -212,8 +212,8 @@ return false; return guest_manager->ForEachGuest( - source, base::Bind(&CoreTabHelper::GetStatusTextForWebContents, - status_text)); + source, base::BindRepeating(&CoreTabHelper::GetStatusTextForWebContents, + status_text)); #else // !BUILDFLAG(ENABLE_EXTENSIONS) return false; #endif // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc index 0780ce76..3f8eb9d 100644 --- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc +++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
@@ -107,9 +107,10 @@ content::WebContents* contents) : content::WebContentsObserver(contents), thumbnail_tab_helper_(thumbnail_tab_helper), - readiness_tracker_(contents, - base::Bind(&TabStateTracker::PageReadinessChanged, - base::Unretained(this))) { + readiness_tracker_( + contents, + base::BindRepeating(&TabStateTracker::PageReadinessChanged, + base::Unretained(this))) { visible_ = (web_contents()->GetVisibility() == content::Visibility::VISIBLE); }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc index e2257b6d..a94690ae 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -1634,7 +1634,7 @@ observer_ = std::make_unique<BookmarkContextMenuNotificationObserver>( CreateEventTask(this, &BookmarkBarViewTest17::Step4)); MoveMouseAndPress(clickable_rect.CenterPoint(), ui_controls::RIGHT, - ui_controls::DOWN | ui_controls::UP, base::Closure()); + ui_controls::DOWN | ui_controls::UP, base::OnceClosure()); // Step4 will be invoked by BookmarkContextMenuNotificationObserver. }
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc index 2f8c414..a058f50 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -82,6 +82,7 @@ tab_strip_scroll_container->SetTreatAllScrollEventsAsHorizontal(true); tab_strip_container_ = tab_strip_scroll_container; tab_strip_scroll_container->SetContents(std::move(tab_strip)); + tab_strip_scroll_container->SetDrawOverflowIndicator(true); // This base::Unretained is safe because the callback is called by the // layout manager, which is cleaned up before view children like // |tab_strip_scroll_container| (which owns |tab_strip_|).
diff --git a/chrome/browser/ui/views/hung_renderer_view.cc b/chrome/browser/ui/views/hung_renderer_view.cc index a5ae0f0..febf843 100644 --- a/chrome/browser/ui/views/hung_renderer_view.cc +++ b/chrome/browser/ui/views/hung_renderer_view.cc
@@ -158,6 +158,10 @@ void HungPagesTableModel::RenderWidgetHostDestroyed( content::RenderWidgetHost* widget_host) { + DCHECK(widget_observation_.IsObservingSource(render_widget_host_)); + widget_observation_.Reset(); + render_widget_host_ = nullptr; + // Notify the delegate. delegate_->TabDestroyed(); // WARNING: we've likely been deleted.
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index bb0f2be..0f9f48d4 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -200,6 +200,24 @@ // requests, LocationBarView must have a context menu controller. set_context_menu_controller(omnibox_view_->context_menu_controller()); + RefreshBackground(); + + // Initialize the inline autocomplete view which is visible only when IME is + // turned on. Use the same font with the omnibox and highlighted background. + auto ime_inline_autocomplete_view = std::make_unique<views::Label>( + base::string16(), views::Label::CustomFont{font_list}); + ime_inline_autocomplete_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); + ime_inline_autocomplete_view->SetAutoColorReadabilityEnabled(false); + ime_inline_autocomplete_view->SetBackground(views::CreateSolidBackground( + GetOmniboxColor(GetThemeProvider(), OmniboxPart::LOCATION_BAR_BACKGROUND, + OmniboxPartState::SELECTED))); + ime_inline_autocomplete_view->SetEnabledColor(GetOmniboxColor( + GetThemeProvider(), OmniboxPart::LOCATION_BAR_TEXT_DEFAULT, + OmniboxPartState::SELECTED)); + ime_inline_autocomplete_view->SetVisible(false); + ime_inline_autocomplete_view_ = + AddChildView(std::move(ime_inline_autocomplete_view)); + // Initiate the Omnibox additional-text label. if (OmniboxFieldTrial::RichAutocompletionShowAdditionalText()) { // TODO (manukh) When the titles UI is disabled, @@ -219,24 +237,6 @@ AddChildView(std::move(omnibox_additional_text_view)); } - RefreshBackground(); - - // Initialize the inline autocomplete view which is visible only when IME is - // turned on. Use the same font with the omnibox and highlighted background. - auto ime_inline_autocomplete_view = std::make_unique<views::Label>( - base::string16(), views::Label::CustomFont{font_list}); - ime_inline_autocomplete_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); - ime_inline_autocomplete_view->SetAutoColorReadabilityEnabled(false); - ime_inline_autocomplete_view->SetBackground(views::CreateSolidBackground( - GetOmniboxColor(GetThemeProvider(), OmniboxPart::LOCATION_BAR_BACKGROUND, - OmniboxPartState::SELECTED))); - ime_inline_autocomplete_view->SetEnabledColor(GetOmniboxColor( - GetThemeProvider(), OmniboxPart::LOCATION_BAR_TEXT_DEFAULT, - OmniboxPartState::SELECTED)); - ime_inline_autocomplete_view->SetVisible(false); - ime_inline_autocomplete_view_ = - AddChildView(std::move(ime_inline_autocomplete_view)); - selected_keyword_view_ = AddChildView(std::make_unique<SelectedKeywordView>(this, font_list)); @@ -704,10 +704,11 @@ DCHECK(OmniboxFieldTrial::IsRichAutocompletionEnabled() || text.empty()); if (!OmniboxFieldTrial::RichAutocompletionShowAdditionalText()) return; - auto wrappedText = + auto wrapped_text = text.empty() ? text : base::UTF8ToUTF16("(") + text + base::UTF8ToUTF16(")"); - omnibox_additional_text_view_->SetText(wrappedText); + omnibox_additional_text_view_->SetText(wrapped_text); + omnibox_additional_text_view_->SetVisible(!wrapped_text.empty()); } void LocationBarView::Update(WebContents* contents) { @@ -1230,6 +1231,8 @@ location_icon_view_->SetFontList(font_list); omnibox_view_->SetFontList(font_list); ime_inline_autocomplete_view_->SetFontList(font_list); + if (OmniboxFieldTrial::RichAutocompletionShowAdditionalText()) + omnibox_additional_text_view_->SetFontList(font_list); selected_keyword_view_->SetFontList(font_list); for (ContentSettingImageView* view : content_setting_views_) view->SetFontList(font_list);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index 237669ee..7bbb354 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -365,11 +365,6 @@ // The omnibox view where the user types and the current page URL is displayed // when user input is not in progress. OmniboxViewViews* omnibox_view_ = nullptr; - // The complementary omnibox label displaying the selected suggestion's title - // or URL when the omnibox view is displaying the other and when user input is - // in progress. Will remain a nullptr if the rich autocompletion - // feature flag is disabled. - views::Label* omnibox_additional_text_view_ = nullptr; // Our delegate. Delegate* delegate_; @@ -387,6 +382,12 @@ // we show any autocompletion in a separate field after the OmniboxView. views::Label* ime_inline_autocomplete_view_ = nullptr; + // The complementary omnibox label displaying the selected suggestion's title + // or URL when the omnibox view is displaying the other and when user input is + // in progress. Will remain a nullptr if the rich autocompletion + // feature flag is disabled. + views::Label* omnibox_additional_text_view_ = nullptr; + // The following views are used to provide hints and remind the user as to // what is going in the edit. They are all added a children of the // LocationBarView. At most one is visible at a time. Preference is
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc index 0ff7cb87..0bcb090 100644 --- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -19,6 +19,7 @@ #include "chrome/grit/generated_resources.h" #include "components/omnibox/browser/location_bar_model_util.h" #include "components/payments/content/icon/icon_size.h" +#include "components/payments/content/payments_userdata_key.h" #include "components/payments/content/ssl_validity_checker.h" #include "components/payments/core/features.h" #include "components/payments/core/native_error_strings.h" @@ -239,6 +240,8 @@ auto* web_view = content_view->AddChildView(std::make_unique<views::WebView>(profile_)); Observe(web_view->GetWebContents()); + web_contents()->SetUserData(kPaymentHandlerWebContentsUserDataKey, + std::make_unique<base::SupportsUserData::Data>()); web_contents()->SetDelegate(this); DCHECK_NE(log_.web_contents(), web_contents()); content::PaymentAppProvider::GetOrCreateForWebContents(
diff --git a/chrome/browser/ui/views/tabs/tab_drag_context.h b/chrome/browser/ui/views/tabs/tab_drag_context.h index 6fe3a660..1dbc7326 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_context.h +++ b/chrome/browser/ui/views/tabs/tab_drag_context.h
@@ -85,15 +85,16 @@ // this tabstrip given the DraggedTabView's bounds |dragged_bounds| in // coordinates relative to |attached_tabstrip_| and has had the mirroring // transformation applied. + // |dragged_views| are the view children of |attached_tabstrip_| that are + // part of the drag. // |mouse_has_ever_moved_left| and |mouse_has_ever_moved_right| are used // only in stacked tabs cases. // |group| is set if the drag is originating from a group header, in which // case the entire group is dragged and should not be dropped into other // groups. - // NOTE: this is invoked from Attach() before the tabs have been inserted. virtual int GetInsertionIndexForDraggedBounds( const gfx::Rect& dragged_bounds, - bool attaching, + std::vector<TabSlotView*> dragged_views, int num_dragged_tabs, bool mouse_has_ever_moved_left, bool mouse_has_ever_moved_right,
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 767c541..d82b987 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -844,7 +844,7 @@ if (move_only()) { DragActiveTabStacked(point_in_screen); } else { - MoveAttached(point_in_screen); + MoveAttached(point_in_screen, false); if (tab_strip_changed) { // Move the corresponding window to the front. We do this after the // move as on windows activate triggers a synchronous paint. @@ -920,7 +920,7 @@ Attach(target_context, point_in_screen); current_state_ = DragState::kDraggingTabs; // Move the tabs into position. - MoveAttached(point_in_screen); + MoveAttached(point_in_screen, true); attached_context_->AsView()->GetWidget()->Activate(); } @@ -928,6 +928,7 @@ } Detach(DONT_RELEASE_CAPTURE); Attach(target_context, point_in_screen); + MoveAttached(point_in_screen, true); return DRAG_BROWSER_RESULT_CONTINUE; } @@ -962,7 +963,8 @@ kMoveAttachedSubsequentDelay); } -void TabDragController::MoveAttached(const gfx::Point& point_in_screen) { +void TabDragController::MoveAttached(const gfx::Point& point_in_screen, + bool just_attached) { DCHECK(attached_context_); DCHECK_EQ(current_state_, DragState::kDraggingTabs); @@ -977,14 +979,17 @@ bool did_layout = false; // Update the model, moving the WebContents from one index to another. Do this // only if we have moved a minimum distance since the last reorder (to prevent - // jitter) or if this the first move and the tabs are not consecutive. - if ((abs(point_in_screen.x() - last_move_screen_loc_) > threshold || - (initial_move_ && !AreTabsConsecutive()))) { + // jitter), or if this the first move and the tabs are not consecutive, or if + // we have just attached to a new tabstrip and need to move to the correct + // initial position. + if (just_attached || + (abs(point_in_screen.x() - last_move_screen_loc_) > threshold) || + (initial_move_ && !AreTabsConsecutive())) { TabStripModel* attached_model = attached_context_->GetTabStripModel(); int to_index = attached_context_->GetInsertionIndexForDraggedBounds( - GetDraggedViewTabStripBounds(dragged_view_point), false, - num_dragging_tabs(), mouse_has_ever_moved_left_, - mouse_has_ever_moved_right_, group_); + GetDraggedViewTabStripBounds(dragged_view_point), + GetViewsMatchingDraggedContents(attached_context_), num_dragging_tabs(), + mouse_has_ever_moved_left_, mouse_has_ever_moved_right_, group_); bool do_move = true; // While dragging within a tabstrip the expectation is the insertion index // is based on the left edge of the tabs being dragged. OTOH when dragging @@ -1178,10 +1183,6 @@ selection_model_before_attach_ = attached_context->GetTabStripModel()->selection_model(); - // Inserting counts as a move. We don't want the tabs to jitter when the - // user moves the tab immediately after attaching it. - last_move_screen_loc_ = point_in_screen.x(); - // Register a new group if necessary, so that the insertion index in the // tab strip can be calculated based on the group membership of tabs. if (header_drag_) { @@ -1190,21 +1191,17 @@ source_view_drag_data()->tab_group_data.value().group_visual_data); } - // Figure out where to insert the tab based on the bounds of the dragged - // representation and the ideal bounds of the other Tabs already in the - // strip. ("ideal bounds" are stable even if the Tabs' actual bounds are - // changing due to animation). + // Insert at the beginning of the tabstrip. We'll fix up the insertion + // index in MoveAttached() later. + int index = 0; + attach_index_ = index; + gfx::Point tab_strip_point(point_in_screen); views::View::ConvertPointFromScreen(attached_context_->AsView(), &tab_strip_point); tab_strip_point.set_x( attached_context_->AsView()->GetMirroredXInView(tab_strip_point.x())); tab_strip_point.Offset(0, -mouse_offset_.y()); - int index = attached_context_->GetInsertionIndexForDraggedBounds( - GetDraggedViewTabStripBounds(tab_strip_point), true, - num_dragging_tabs(), mouse_has_ever_moved_left_, - mouse_has_ever_moved_right_, group_); - attach_index_ = index; attach_x_ = tab_strip_point.x(); base::AutoReset<bool> setter(&is_mutating_, true); @@ -1446,7 +1443,7 @@ Attach(tab_strip_to_attach_to_after_exit_, point_in_screen); current_state_ = DragState::kDraggingTabs; // Move the tabs into position. - MoveAttached(point_in_screen); + MoveAttached(point_in_screen, true); attached_context_->AsView()->GetWidget()->Activate(); // Activate may trigger a focus loss, destroying us. if (!ref) @@ -1461,11 +1458,11 @@ gfx::Rect TabDragController::GetDraggedViewTabStripBounds( const gfx::Point& tab_strip_point) { // attached_view is null when inserting into a new context. - // TODO(pkasting): This assumes there is just one tab being dragged, which is - // wrong when dragging multiple tabs; need to check all of |drag_data_|. if (source_view_drag_data()->attached_view) { - return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), - source_view_drag_data()->attached_view->width(), + std::vector<gfx::Rect> all_bounds = + attached_context_->CalculateBoundsForDraggedViews(attached_views_); + int total_width = all_bounds.back().right() - all_bounds.front().x(); + return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), total_width, source_view_drag_data()->attached_view->height()); }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h index fcdf471..41a729c 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.h +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -323,8 +323,9 @@ void MoveAttachedToNextStackedIndex(const gfx::Point& point_in_screen); void MoveAttachedToPreviousStackedIndex(const gfx::Point& point_in_screen); - // Handles dragging tabs while the tabs are attached. - void MoveAttached(const gfx::Point& point_in_screen); + // Handles dragging tabs while the tabs are attached. |just_attached| should + // be true iff this is the first call to MoveAttached after attaching. + void MoveAttached(const gfx::Point& point_in_screen, bool just_attached); // If necessary starts the |move_stacked_timer_|. The timer is started if // close enough to an edge with stacked tabs.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 1fb5c07f..4b6e0e4 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1026,6 +1026,7 @@ // selected tabs joining the end of Tab Group 3. const gfx::Point left_center_fourth_tab = test::GetLeftCenterInScreenCoordinates(tab_strip->tab_at(3)); + ASSERT_TRUE(PressInput(GetCenterInScreenCoordinates(tab_strip->tab_at(3)))); ASSERT_TRUE(DragInputTo(left_center_fourth_tab)); ASSERT_TRUE(ReleaseInput()); @@ -1410,6 +1411,11 @@ EXPECT_TRUE(IsTabDraggingInfoCleared(tab_strip)); EXPECT_TRUE(IsTabDraggingInfoSet(tab_strip2, tab_strip)); + // Drag to the trailing end of the tabstrip to ensure we're in a predictable + // spot within the strip. + StopAnimating(tab_strip2); + ASSERT_TRUE(DragInputTo(GetCenterInScreenCoordinates(tab_strip2->tab_at(1)))); + // Release mouse or touch, stopping the drag session. ASSERT_TRUE(ReleaseInput()); ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive()); @@ -2703,6 +2709,11 @@ ASSERT_TRUE(TabDragController::IsActive()); ASSERT_EQ(1u, browser_list->size()); + // Drag to the trailing end of the tabstrip to ensure we're in a consistent + // spot within the strip. + StopAnimating(tab_strip2); + ASSERT_TRUE(DragInputTo(GetCenterInScreenCoordinates(tab_strip2->tab_at(1)))); + // Release the mouse, stopping the drag session. ASSERT_TRUE(ReleaseInput()); ASSERT_FALSE(tab_strip2->GetDragContext()->IsDragSessionActive());
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 684e149..64ec699 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -8,6 +8,7 @@ #include <algorithm> #include <iterator> +#include <limits> #include <string> #include <utility> #include <vector> @@ -599,7 +600,7 @@ int GetInsertionIndexForDraggedBounds( const gfx::Rect& dragged_bounds, - bool attaching, + std::vector<TabSlotView*> dragged_views, int num_dragged_tabs, bool mouse_has_ever_moved_left, bool mouse_has_ever_moved_right, @@ -624,7 +625,13 @@ } } } else { - index = GetInsertionIndexFrom(dragged_bounds, 0, std::move(group)); + // If we're dragging a group by its header, the first element of + // |dragged_views| is a group header, and the second one is the first tab + // in that group. + int first_dragged_tab_index = + tab_strip_->GetModelIndexOf(dragged_views[group.has_value() ? 1 : 0]); + index = CalculateInsertionIndex(dragged_bounds, first_dragged_tab_index, + num_dragged_tabs, std::move(group)); } if (!index) { const int last_tab_right = ideal_bounds(GetTabCount() - 1).right(); @@ -634,12 +641,9 @@ const Tab* last_visible_tab = tab_strip_->GetLastVisibleTab(); int last_insertion_point = last_visible_tab ? (GetIndexOf(last_visible_tab) + 1) : 0; - if (!attaching) { - // We're not in the process of attaching, so clamp the insertion point to - // keep it within the visible region. - last_insertion_point = - std::max(0, last_insertion_point - num_dragged_tabs); - } + + // Clamp the insertion point to keep it within the visible region. + last_insertion_point = std::max(0, last_insertion_point - num_dragged_tabs); // Ensure the first dragged tab always stays in the visible index range. return std::min(*index, last_insertion_point); @@ -816,6 +820,167 @@ return tab_strip_->ideal_bounds(group); } + // Determines the index to move the dragged tabs to. The dragged tabs must + // already be in the tabstrip. |dragged_bounds| is the union of the bounds + // of the dragged tabs and group header, if any. |first_dragged_tab_index| is + // the current model index in this tabstrip of the first dragged tab. The + // dragged tabs must be in the tabstrip already! + int CalculateInsertionIndex( + const gfx::Rect& dragged_bounds, + int first_dragged_tab_index, + int num_dragged_tabs, + base::Optional<tab_groups::TabGroupId> dragged_group) const { + // This method assumes that the dragged tabs and group are already in the + // tabstrip (i.e. it doesn't support attaching a drag to a new tabstrip). + // This assumption is critical because it means that tab width won't change + // after this method's recommendation is implemented. + + // For each possible insertion index, determine what the ideal bounds of + // the dragged tabs would be at that index. This corresponds to where they + // would slide to if the drag session ended now. We want to insert at the + // index that minimizes the distance between the corresponding ideal bounds + // and the current bounds of the tabs. This is equivalent to minimizing: + // - the distance of the aforementioned slide, + // - the width of the gaps in the tabstrip, or + // - the amount of tab overlap. + int min_distance_index = -1; + int min_distance = std::numeric_limits<int>::max(); + for (int candidate_index = 0; candidate_index <= GetTabCount(); + ++candidate_index) { + if (!IsValidInsertionIndex(candidate_index, first_dragged_tab_index, + num_dragged_tabs, dragged_group)) { + continue; + } + + // If there's a group header here, and we're dragging a group, we might + // end up on either side of that header. Check both cases to find the + // best option. + // TODO(tbergquist): Use this approach to determine if a tab should be + // added to the group. This is calculated elsewhere and may require some + // plumbing and/or duplicated code. + const int left_ideal_x = CalculateIdealX( + candidate_index, first_dragged_tab_index, dragged_bounds); + const int left_distance = std::abs(dragged_bounds.x() - left_ideal_x); + + const int right_ideal_x = + left_ideal_x + CalculateIdealXAdjustmentIfAddedToGroup( + candidate_index, dragged_group); + const int right_distance = std::abs(dragged_bounds.x() - right_ideal_x); + + const int distance = std::min(left_distance, right_distance); + if (distance < min_distance) { + min_distance = distance; + min_distance_index = candidate_index; + } + } + + if (min_distance_index == -1) { + NOTREACHED(); + return 0; + } + + // When moving a tab within a tabstrip, the target index is expressed as if + // the tabs are not in the tabstrip, i.e. it acts like the tabs are first + // removed and then re-inserted at the target index. We need to adjust the + // target index to account for this. + if (min_distance_index > first_dragged_tab_index) + min_distance_index -= num_dragged_tabs; + + return min_distance_index; + } + + // Dragging can't insert tabs into some indices. + bool IsValidInsertionIndex( + int candidate_index, + int first_dragged_tab_index, + int num_dragged_tabs, + base::Optional<tab_groups::TabGroupId> dragged_group) const { + if (candidate_index == 0) + return true; + + // If |candidate_index| is right after one of the tabs we're dragging, + // inserting here would be nonsensical - we can't insert the dragged tabs + // into the middle of the dragged tabs. That's just silly. + if (candidate_index > first_dragged_tab_index && + candidate_index <= first_dragged_tab_index + num_dragged_tabs) { + return false; + } + + // This might be in the middle of a group, which may or may not be fine. + base::Optional<tab_groups::TabGroupId> left_group = + GetTabAt(candidate_index - 1)->group(); + base::Optional<tab_groups::TabGroupId> right_group = + tab_strip_->IsValidModelIndex(candidate_index) + ? GetTabAt(candidate_index)->group() + : base::nullopt; + if (left_group.has_value() && left_group == right_group) { + // Can't drag a group into another group. + if (dragged_group.has_value()) + return false; + // Can't drag a tab into a collapsed group. + if (tab_strip_->controller()->IsGroupCollapsed(left_group.value())) + return false; + } + + return true; + } + + // Determines the x position that the dragged tabs would have if they were + // inserted at |candidate_index|. If there's a group header at that index, + // this assumes the dragged tabs *would not* be inserted into the group, + // and would therefore end up to the left of that header. + int CalculateIdealX(int candidate_index, + int first_dragged_tab_index, + gfx::Rect dragged_bounds) const { + if (candidate_index == 0) + return 0; + + const int tab_overlap = TabStyle::GetTabOverlap(); + + // We'll insert just right of the tab at |candidate_index| - 1. + int ideal_x = ideal_bounds(candidate_index - 1).right(); + + // If the dragged tabs are currently left of |candidate_index|, moving + // them to |candidate_index| would move the tab at |candidate_index| - 1 + // to the left by |num_dragged_tabs| slots. This would change the ideal x + // for the dragged tabs, as well, by the width of the dragged tabs. + if (candidate_index - 1 > first_dragged_tab_index) + ideal_x -= dragged_bounds.width() - tab_overlap; + + return ideal_x - tab_overlap; + } + + // There might be a group starting at |candidate_index|. If there is, + // this determines how the ideal x would change if the dragged tabs were + // added to that group, thereby moving them to that header's right. + int CalculateIdealXAdjustmentIfAddedToGroup( + int candidate_index, + base::Optional<tab_groups::TabGroupId> dragged_group) const { + // If the tab to the right of |candidate_index| is the first tab in a + // (non-collapsed) group, we are sharing this model index with a group + // header. We might end up on either side of it, so we need to check + // both positions. + if (!dragged_group.has_value() && + tab_strip_->IsValidModelIndex(candidate_index)) { + base::Optional<tab_groups::TabGroupId> left_group = + tab_strip_->IsValidModelIndex(candidate_index - 1) + ? GetTabAt(candidate_index - 1)->group() + : base::nullopt; + base::Optional<tab_groups::TabGroupId> right_group = + GetTabAt(candidate_index)->group(); + if (right_group.has_value() && left_group != right_group) { + if (tab_strip_->controller()->IsGroupCollapsed(right_group.value())) + return 0; + const int header_width = + GetTabGroupHeader(*right_group)->bounds().width() - + TabStyle::GetTabOverlap(); + return header_width; + } + } + + return 0; + } + // Used by GetInsertionIndexForDraggedBounds() when the tabstrip is stacked. base::Optional<int> GetInsertionIndexForDraggedBoundsStacked( const gfx::Rect& dragged_bounds, @@ -825,12 +990,11 @@ // Search from the active index to the front of the tabstrip. Do this as // tabs overlap each other from the active index. base::Optional<int> index = - GetInsertionIndexFromReversed(dragged_bounds, active_index); + GetInsertionIndexFromReversedStacked(dragged_bounds, active_index); if (index != active_index) return index; if (!index) - return GetInsertionIndexFrom(dragged_bounds, active_index + 1, - base::nullopt); + return GetInsertionIndexFromStacked(dragged_bounds, active_index + 1); // The position to drag to corresponds to the active tab. If the // next/previous tab is stacked, then shorten the distance used to determine @@ -839,8 +1003,7 @@ // tab. if (active_index + 1 < GetTabCount() && tab_strip_->touch_layout_->IsStacked(active_index + 1)) { - index = GetInsertionIndexFrom(dragged_bounds, active_index + 1, - base::nullopt); + index = GetInsertionIndexFromStacked(dragged_bounds, active_index + 1); if (!index && ShouldDragToNextStackedTab(dragged_bounds, active_index, mouse_has_ever_moved_right)) index = active_index + 1; @@ -854,19 +1017,17 @@ } // Determines the index to insert tabs at. |dragged_bounds| is the bounds of - // the tab being dragged, |start| is the index of the tab to start looking - // from, and |group| is the currently dragged group, if any. The search - // proceeds to the end of the strip. - base::Optional<int> GetInsertionIndexFrom( + // the tab being dragged and |start| is the index of the tab to start looking + // from. The search proceeds to the end of the strip. + base::Optional<int> GetInsertionIndexFromStacked( const gfx::Rect& dragged_bounds, - int start, - base::Optional<tab_groups::TabGroupId> group) const { + int start) const { const int last_tab = GetTabCount() - 1; if (start < 0 || start > last_tab) return base::nullopt; const int dragged_x = GetDraggedX(dragged_bounds); - if ((dragged_x < ideal_bounds(start).x() && !group.has_value()) || + if (dragged_x < ideal_bounds(start).x() || dragged_x > ideal_bounds(last_tab).right()) { return base::nullopt; } @@ -876,13 +1037,8 @@ const gfx::Rect current_bounds = ideal_bounds(i); int current_center = current_bounds.CenterPoint().x(); - base::Optional<tab_groups::TabGroupId> current_group = - tab_strip_->tab_at(i)->group(); - if (current_group.has_value() && - tab_strip_->controller()->IsGroupCollapsed(current_group.value())) { - current_center = ideal_bounds(current_group.value()).CenterPoint().x(); - } else if (dragged_bounds.width() > current_bounds.width() && - dragged_bounds.x() < current_bounds.x()) { + if (dragged_bounds.width() > current_bounds.width() && + dragged_bounds.x() < current_bounds.x()) { current_center -= (dragged_bounds.width() - current_bounds.width()); } @@ -895,13 +1051,12 @@ if (!insertion_index.has_value()) return last_tab + 1; - return GetInsertionIndexWithGroup(dragged_bounds, insertion_index.value(), - std::move(group)); + return insertion_index; } // Like GetInsertionIndexFrom(), but searches backwards from |start| to the // beginning of the strip. - base::Optional<int> GetInsertionIndexFromReversed( + base::Optional<int> GetInsertionIndexFromReversedStacked( const gfx::Rect& dragged_bounds, int start) const { const int dragged_x = GetDraggedX(dragged_bounds); @@ -918,77 +1073,6 @@ return 0; } - // Determines the index to insert at, accounting for the dragging group and - // other groups. |dragged_bounds| is the bounds of the tab being dragged, - // |candidate_index| is the naive insertion index found via - // GetInsertionIndexFrom, and |dragging_group| is the currently dragged - // group, if any. This is distinct from the group membership of the dragging - // tabs, and is only set when dragging by the group's header. - int GetInsertionIndexWithGroup( - const gfx::Rect& dragged_bounds, - int candidate_index, - base::Optional<tab_groups::TabGroupId> dragging_group) const { - if (!dragging_group.has_value()) { - // Collapsed tabs occupy the same space and need additional checks to - // ensure we do not drag into a collapsed group. - base::Optional<tab_groups::TabGroupId> candidate_group = - tab_strip_->tab_at(candidate_index)->group(); - if (candidate_group.has_value() && - tab_strip_->controller()->IsGroupCollapsed(candidate_group.value()) && - tab_strip_->controller()->GetActiveIndex() < candidate_index) { - return tab_strip_->controller() - ->ListTabsInGroup(candidate_group.value()) - .end() - - 1; - } - return candidate_index; - } - - const gfx::Range dragging_tabs = - tab_strip_->controller()->ListTabsInGroup(dragging_group.value()); - base::Optional<tab_groups::TabGroupId> other_group = - tab_strip_->tab_at(candidate_index)->group(); - - // The other group will be the same as the dragging group if the user - // hasn't dragged beyond the boundaries of the current "gap". In this - // case, look ahead to where the dragging group would go, and sample - // the group that's currently there. - if (dragging_group == other_group) { - // |dragging_tabs| can only be empty if dragging in from another window, - // in which case |dragging_group| can't be the same as |other_group|. - DCHECK_GT(dragging_tabs.length(), 0u); - if (candidate_index <= static_cast<int>(dragging_tabs.start()) || - static_cast<int>(dragging_tabs.end()) >= GetTabCount()) - return dragging_tabs.start(); - - other_group = tab_strip_->tab_at(dragging_tabs.end())->group(); - } - - if (!other_group.has_value()) - return candidate_index; - - const gfx::Range other_tabs = - tab_strip_->controller()->ListTabsInGroup(other_group.value()); - - if (other_tabs.length() == 0) - return candidate_index; - - // If the candidate index is in the middle of the other group, instead - // return the nearest insertion index that is not in the other group. - const int other_group_width = - ideal_bounds(other_tabs.end() - 1).right() - - tab_strip_->group_header(other_group.value())->x(); - int left_insertion_index = other_tabs.start(); - if (dragging_tabs.length() > 0 && - dragging_tabs.start() < other_tabs.start()) - left_insertion_index = dragging_tabs.start(); - - if (GetDraggedX(dragged_bounds) < - ideal_bounds(left_insertion_index).x() + other_group_width / 2) - return left_insertion_index; - return left_insertion_index + other_tabs.length(); - } - // Sets the ideal bounds x-coordinates to |positions|. void SetIdealBoundsFromPositions(const std::vector<int>& positions) { if (static_cast<size_t>(GetTabCount()) != positions.size()) @@ -1442,6 +1526,16 @@ } bool TabStrip::ShouldTabBeVisible(const Tab* tab) const { + // When the tabstrip is scrollable, it can grow to accommodate any number of + // tabs, so tabs can never become clipped. + // N.B. Tabs can still be not-visible because they're in a collapsed group, + // but that's handled elsewhere. + // N.B. This is separate from the tab being potentially scrolled offscreen - + // this solely determines whether the tab should be clipped for the + // pre-scrolling overflow behavior. + if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) + return true; + // Detached tabs should always be invisible (as they close). if (tab->detached()) return false; @@ -1450,11 +1544,11 @@ if (stacked_layout_) return true; - // If the tab is currently clipped by the trailing edge of the strip, it - // shouldn't be visible. + // If the tab would be clipped by the trailing edge of the strip, even if the + // tabstrip were resized to its greatest possible width, it shouldn't be + // visible. const int right_edge = tab->bounds().right(); - const int tabstrip_right = - tab->dragging() ? drag_context_->GetTabDragAreaWidth() : width(); + const int tabstrip_right = CalculateAvailableWidthForTabs(); if (right_edge > tabstrip_right) return false; @@ -2626,6 +2720,11 @@ for (const auto& header_pair : group_views_) { TabGroupHeader* const header = header_pair.second->header(); + + // If the header is being dragged manually, skip it. + if (header->dragging() && !bounds_animator_.IsAnimating(header)) + continue; + bounds_animator_.AnimateViewTo( header, layout_helper_->group_header_ideal_bounds().at(header_pair.first),
diff --git a/chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc b/chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc index 1ec9315..7c4f8ff0 100644 --- a/chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc +++ b/chrome/browser/ui/views/tabs/tab_strip_layout_helper.cc
@@ -254,8 +254,7 @@ } break; case ViewType::kGroupHeader: - if (!slot.view->dragging()) - group_header_ideal_bounds_[slot.view->group().value()] = bounds[i]; + group_header_ideal_bounds_[slot.view->group().value()] = bounds[i]; break; } }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_account_icon_container_browsertest.cc b/chrome/browser/ui/views/toolbar/toolbar_account_icon_container_browsertest.cc index 9f25585..a2bba279 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_account_icon_container_browsertest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_account_icon_container_browsertest.cc
@@ -59,10 +59,7 @@ } bool IsHighlighted(ToolbarAccountIconContainerView* container) { - if (container->highlight_animation_.IsClosing()) - return false; - return container->highlight_animation_.IsShowing() || - container->highlight_animation_.GetCurrentValue() == 1.0f; + return container->border_.layer()->GetTargetOpacity() == 1; } private:
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc index 7ff84b2..526f635c 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
@@ -13,6 +13,9 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h" +#include "ui/compositor/paint_recorder.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/canvas.h" #include "ui/native_theme/native_theme.h" #include "ui/views/background.h" #include "ui/views/layout/animating_layout_manager.h" @@ -24,6 +27,38 @@ const char ToolbarIconContainerView::kToolbarIconContainerViewClassName[] = "ToolbarIconContainerView"; +ToolbarIconContainerView::RoundRectBorder::RoundRectBorder(views::View* parent) + : parent_(parent) { + layer_.set_delegate(this); + layer_.SetFillsBoundsOpaquely(false); + layer_.SetFillsBoundsCompletely(false); + layer_.SetOpacity(0); + layer_.SetAnimator(ui::LayerAnimator::CreateImplicitAnimator()); + layer_.GetAnimator()->set_tween_type(gfx::Tween::EASE_OUT); + layer_.SetVisible(true); +} + +void ToolbarIconContainerView::RoundRectBorder::OnPaintLayer( + const ui::PaintContext& context) { + ui::PaintRecorder paint_recorder(context, layer_.size()); + gfx::Canvas* canvas = paint_recorder.canvas(); + + const int radius = ChromeLayoutProvider::Get()->GetCornerRadiusMetric( + views::EMPHASIS_MAXIMUM, layer_.size()); + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(1); + flags.setColor(ToolbarButton::GetDefaultBorderColor(parent_)); + gfx::RectF rect(gfx::SizeF(layer_.size())); + rect.Inset(0.5f, 0.5f); // Pixel edges -> pixel centers. + canvas->DrawRoundRect(rect, radius, flags); +} + +void ToolbarIconContainerView::RoundRectBorder::OnDeviceScaleFactorChanged( + float old_device_scale_factor, + float new_device_scale_factor) {} + // Watches for widget restore (or first show) and resets the animation so icons // don't spuriously "animate in" when a window is shown or restored. See // crbug.com/1106506 for more details. @@ -71,6 +106,11 @@ ToolbarIconContainerView::ToolbarIconContainerView(bool uses_highlight) : uses_highlight_(uses_highlight) { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetFillsBoundsCompletely(false); + AddLayerBeneathView(border_.layer()); + views::AnimatingLayoutManager* animating_layout = SetLayoutManager(std::make_unique<views::AnimatingLayoutManager>()); animating_layout->SetBoundsAnimationMode( @@ -143,6 +183,13 @@ UpdateHighlight(); } +void ToolbarIconContainerView::OnBoundsChanged( + const gfx::Rect& previous_bounds) { + const gfx::Rect bounds = ConvertRectToWidget(GetLocalBounds()); + border_.layer()->SetBounds(bounds); + border_.layer()->SchedulePaint(gfx::Rect(bounds.size())); +} + void ToolbarIconContainerView::OnMouseEntered(const ui::MouseEvent& event) { UpdateHighlight(); } @@ -151,13 +198,6 @@ UpdateHighlight(); } -gfx::Insets ToolbarIconContainerView::GetInsets() const { - // Use empty insets to have the border paint into the view instead of around - // it. This prevents inadvertently increasing its size while the stroke is - // drawn. - return gfx::Insets(); -} - const char* ToolbarIconContainerView::GetClassName() const { return kToolbarIconContainerViewClassName; } @@ -168,15 +208,6 @@ restore_observer_ = std::make_unique<WidgetRestoreObserver>(this); } -void ToolbarIconContainerView::AnimationProgressed( - const gfx::Animation* animation) { - SetHighlightBorder(); -} - -void ToolbarIconContainerView::AnimationEnded(const gfx::Animation* animation) { - SetHighlightBorder(); -} - bool ToolbarIconContainerView::ShouldDisplayHighlight() { if (!uses_highlight_) return false; @@ -206,35 +237,19 @@ } void ToolbarIconContainerView::UpdateHighlight() { - bool showing_before = highlight_animation_.IsShowing(); + bool showing_before = border_.layer()->GetTargetOpacity() == 1; - if (ShouldDisplayHighlight()) { - highlight_animation_.Show(); - } else { - highlight_animation_.Hide(); + { + ui::ScopedLayerAnimationSettings settings(border_.layer()->GetAnimator()); + border_.layer()->SetOpacity(ShouldDisplayHighlight() ? 1 : 0); } - if (showing_before == highlight_animation_.IsShowing()) + if (showing_before == (border_.layer()->GetTargetOpacity() == 1)) return; for (Observer& observer : observers_) observer.OnHighlightChanged(); } -void ToolbarIconContainerView::SetHighlightBorder() { - const float highlight_value = highlight_animation_.GetCurrentValue(); - if (highlight_value > 0.0f) { - SkColor border_color = ToolbarButton::GetDefaultBorderColor(this); - SetBorder(views::CreateRoundedRectBorder( - 1, - ChromeLayoutProvider::Get()->GetCornerRadiusMetric( - views::EMPHASIS_MAXIMUM, size()), - SkColorSetA(border_color, - SkColorGetA(border_color) * highlight_value))); - } else { - SetBorder(nullptr); - } -} - void ToolbarIconContainerView::OnButtonHighlightedChanged( views::Button* button) { if (button->GetHighlighted())
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h index 359708b..42c77e4 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
@@ -8,7 +8,7 @@ #include <list> #include "base/observer_list.h" -#include "ui/gfx/animation/animation_delegate.h" +#include "ui/compositor/layer_delegate.h" #include "ui/views/controls/button/button.h" #include "ui/views/layout/animating_layout_manager.h" #include "ui/views/layout/flex_layout.h" @@ -16,7 +16,6 @@ // A general view container for any type of toolbar icons. class ToolbarIconContainerView : public views::View, - public gfx::AnimationDelegate, public views::ViewObserver { public: class Observer : public base::CheckedObserver { @@ -66,24 +65,41 @@ static const char kToolbarIconContainerViewClassName[]; + protected: + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + private: friend class ToolbarAccountIconContainerViewBrowserTest; + + // Responsible for painting a roundrect border for the owning view. + class RoundRectBorder : public ui::LayerDelegate { + public: + explicit RoundRectBorder(views::View* parent); + RoundRectBorder(const RoundRectBorder&) = delete; + RoundRectBorder& operator=(const RoundRectBorder&) = delete; + + ui::Layer* layer() { return &layer_; } + + // ui::LayerDelegate: + void OnPaintLayer(const ui::PaintContext& context) override; + void OnDeviceScaleFactorChanged(float old_device_scale_factor, + float new_device_scale_factor) override; + + private: + views::View* parent_; + ui::Layer layer_; + }; + class WidgetRestoreObserver; // views::View: void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; - gfx::Insets GetInsets() const override; const char* GetClassName() const override; void AddedToWidget() override; - // gfx::AnimationDelegate: - void AnimationProgressed(const gfx::Animation* animation) override; - void AnimationEnded(const gfx::Animation* animation) override; - bool ShouldDisplayHighlight(); void UpdateHighlight(); - void SetHighlightBorder(); // Called by |button| when its ink drop highlighted state changes. void OnButtonHighlightedChanged(views::Button* button); @@ -104,8 +120,7 @@ // them from this set. std::set<views::Button*> highlighted_buttons_; - // Fade-in/out animation for the highlight border. - gfx::SlideAnimation highlight_animation_{this}; + RoundRectBorder border_{this}; // Tracks when the widget is restored and resets the layout. std::unique_ptr<WidgetRestoreObserver> restore_observer_;
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc index f4c8bd92..04c8fa5 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" @@ -36,31 +37,27 @@ namespace { std::vector<std::string> test_cases = { -#if BUILDFLAG(IS_CHROMEOS_ASH) "navigate_installable,assert_install_icon_shown," "assert_launch_icon_not_shown", "navigate_not_installable,assert_install_icon_not_shown", "navigate_installable,assert_installable,install_omnibox_or_menu," "navigate_browser_in_scope,assert_launch_icon_shown," "assert_install_icon_not_shown", + "navigate_installable, install_create_shortcut_tabbed, " + "set_open_in_window_internal, launch_internal, assert_window_created", + "navigate_installable_site_a, assert_install_icon_shown, " + "install_omnibox_or_menu, assert_window_created, launch_internal_site_a, " + "close_pwa, assert_no_crash", +#if BUILDFLAG(IS_CHROMEOS_ASH) "navigate_installable,install_omnibox_or_menu,launch_internal," "uninstall_internal,navigate_browser_in_scope," "assert_install_icon_shown,assert_launch_icon_not_shown", - "navigate_installable, install_create_shortcut_tabbed, " - "set_open_in_window_internal, launch_internal, assert_window_created"}; #else - "navigate_installable,assert_install_icon_shown," - "assert_launch_icon_not_shown", - "navigate_not_installable,assert_install_icon_not_shown", - "navigate_installable,assert_installable,install_omnibox_or_menu," - "navigate_browser_in_scope,assert_launch_icon_shown," - "assert_install_icon_not_shown", "navigate_installable,install_omnibox_or_menu,launch_internal," "uninstall_from_menu,navigate_browser_in_scope," "assert_install_icon_shown,assert_launch_icon_not_shown", - "navigate_installable, install_create_shortcut_tabbed, " - "set_open_in_window_internal, launch_internal, assert_window_created"}; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +}; } // anonymous namespace @@ -120,7 +117,7 @@ } void ExecuteAction(const std::string& action_string) { - if (action_string == "navigate_installable") { + if (base::StartsWith(action_string, "navigate_installable")) { NavigateToSite(browser(), GetInstallableAppURL()); } else if (action_string == "navigate_browser_in_scope") { NavigateToSite(browser(), GetInScopeURL()); @@ -128,7 +125,7 @@ NavigateToSite(browser(), GetOutOfScopeURL()); } else if (action_string == "install_omnibox_or_menu") { ExecutePwaInstallIcon(); - } else if (action_string == "launch_internal") { + } else if (base::StartsWith(action_string, "launch_internal")) { LaunchInternal(); } else if (action_string == "uninstall_from_menu") { UninstallFromMenu(); @@ -138,6 +135,8 @@ InstallCreateShortcutTabbed(); } else if (action_string == "set_open_in_window_internal") { SetOpenInWindowInternal(); + } else if (action_string == "close_pwa") { + ClosePWA(); } else if (action_string == "assert_installable") { AssertInstallable(); } else if (action_string == "assert_install_icon_shown") { @@ -150,6 +149,7 @@ AssertLaunchIconNotShown(); } else if (action_string == "assert_window_created") { AssertWindowCreated(); + } else if (action_string == "assert_no_crash") { } else { FAIL() << "Unimplemented action: " << action_string; } @@ -204,6 +204,9 @@ chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false); app_id_ = app_id; + auto* browser_list = BrowserList::GetInstance(); + app_browser_ = browser_list->GetLastActive(); + DCHECK(AppBrowserController::IsWebApp(app_browser_)); return app_id; } @@ -274,6 +277,12 @@ app_id_, blink::mojom::DisplayMode::kStandalone, true); } + void ClosePWA() { + DCHECK(app_browser_); + app_browser_->window()->Close(); + ui_test_utils::WaitForBrowserToClose(app_browser_); + } + // Assert Actions void AssertInstallable() { EXPECT_TRUE(last_navigation_result_.installable); } void AssertInstallIconShown() { @@ -334,10 +343,19 @@ } IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest, LaunchInternal) { + auto* browser_list = BrowserList::GetInstance(); + EXPECT_EQ(1U, browser_list->size()); + EXPECT_FALSE(AppBrowserController::IsWebApp(browser_list->GetLastActive())); NavigateToSite(browser(), GetInstallableAppURL()); ExecutePwaInstallIcon(); - Browser* app_browser = LaunchInternal(); - DCHECK(app_browser); + EXPECT_EQ(2U, browser_list->size()); + EXPECT_TRUE(AppBrowserController::IsWebApp(browser_list->GetLastActive())); + ClosePWA(); + EXPECT_EQ(1U, browser_list->size()); + EXPECT_FALSE(AppBrowserController::IsWebApp(browser_list->GetLastActive())); + LaunchInternal(); + EXPECT_EQ(2U, browser_list->size()); + EXPECT_TRUE(AppBrowserController::IsWebApp(browser_list->GetLastActive())); } IN_PROC_BROWSER_TEST_P(WebAppIntegrationBrowserTest, Default) {
diff --git a/chrome/browser/ui/webui/OWNERS b/chrome/browser/ui/webui/OWNERS index 3997f24..c5159e35 100644 --- a/chrome/browser/ui/webui/OWNERS +++ b/chrome/browser/ui/webui/OWNERS
@@ -20,9 +20,4 @@ per-file signin_internals_ui*=achuith@chromium.org -per-file sync_internals*=file://components/sync/OWNERS - per-file invalidations_message_handler.*=file://components/invalidation/OWNERS - -per-file policy*=file://chromeos/policy/OWNERS -per-file policy*=file://chrome/browser/policy/OWNERS
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc index c44cb0e..d1d9053 100644 --- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc +++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
@@ -25,18 +25,11 @@ content::WebUIDataSource::Create(chrome::kChromeUIBluetoothInternalsHost); // Add required resources. - html_source->AddResourcePath("adapter.mojom-lite.js", - IDR_BLUETOOTH_INTERNALS_ADAPTER_MOJO_JS); - html_source->AddResourcePath("device.mojom-lite.js", - IDR_BLUETOOTH_INTERNALS_DEVICE_MOJO_JS); - html_source->AddResourcePath("bluetooth_internals.mojom-lite.js", - IDR_BLUETOOTH_INTERNALS_MOJO_JS); - html_source->AddResourcePath("uuid.mojom-lite.js", - IDR_BLUETOOTH_INTERNALS_UUID_MOJO_JS); webui::AddResourcePathsBulk( html_source, base::make_span(kBluetoothInternalsResources, kBluetoothInternalsResourcesSize)); - html_source->SetDefaultResource(IDR_BLUETOOTH_INTERNALS_HTML); + html_source->SetDefaultResource( + IDR_BLUETOOTH_INTERNALS_BLUETOOTH_INTERNALS_HTML); Profile* profile = Profile::FromWebUI(web_ui); content::WebUIDataSource::Add(profile, html_source);
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 6ca0bce..2b2f606 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -62,13 +62,13 @@ #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h" #include "chrome/browser/ui/webui/ntp_tiles_internals_ui.h" #include "chrome/browser/ui/webui/omnibox/omnibox_ui.h" -#include "chrome/browser/ui/webui/policy_ui.h" +#include "chrome/browser/ui/webui/policy/policy_ui.h" #include "chrome/browser/ui/webui/predictors/predictors_ui.h" #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h" #include "chrome/browser/ui/webui/settings/settings_ui.h" #include "chrome/browser/ui/webui/settings_utils.h" #include "chrome/browser/ui/webui/signin_internals_ui.h" -#include "chrome/browser/ui/webui/sync_internals_ui.h" +#include "chrome/browser/ui/webui/sync_internals/sync_internals_ui.h" #include "chrome/browser/ui/webui/translate_internals/translate_internals_ui.h" #include "chrome/browser/ui/webui/usb_internals/usb_internals_ui.h" #include "chrome/browser/ui/webui/user_actions/user_actions_ui.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 92490b12..1594246 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -80,6 +80,7 @@ #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" +#include "components/sync/driver/sync_driver_switches.h" #include "components/user_manager/known_user.h" #include "components/user_manager/user_manager.h" #include "components/version_info/version_info.h" @@ -107,6 +108,11 @@ const char kEndpointGen[] = "1.0"; +bool IsSyncTrustedVaultKeysEnabled() { + return base::FeatureList::IsEnabled( + ::switches::kSyncSupportTrustedVaultPassphraseRecovery); +} + // Must be kept consistent with ChromeOSSamlApiUsed in enums.xml // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused @@ -469,6 +475,8 @@ params.SetBoolean("extractSamlPasswordAttributes", login::ExtractSamlPasswordAttributesEnabled()); params.SetBoolean("enableGaiaActionButtons", true); + params.SetBoolean("enableSyncTrustedVaultKeys", + IsSyncTrustedVaultKeysEnabled()); if (public_saml_url_fetcher_) { params.SetBoolean("startsOnSamlPage", true); @@ -727,7 +735,8 @@ const std::string& password, bool using_saml, const ::login::StringList& services, - const base::DictionaryValue* password_attributes) { + const base::DictionaryValue* password_attributes, + const base::DictionaryValue* sync_trusted_vault_keys) { if (!LoginDisplayHost::default_host()) return; @@ -757,6 +766,8 @@ base::BindOnce(&LoginDisplayHost::CompleteLogin, base::Unretained(LoginDisplayHost::default_host()))); + // TODO(crbug.com/1081651): Propagate |sync_trusted_vault_keys| into + // UserContext. pending_user_context_ = std::make_unique<UserContext>(); std::string error_message; if (!login::BuildUserContextForGaiaSignIn(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index 0634adef..4c10268 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -194,7 +194,8 @@ const std::string& password, bool using_saml, const ::login::StringList& services, - const base::DictionaryValue* password_attributes); + const base::DictionaryValue* password_attributes, + const base::DictionaryValue* sync_trusted_vault_keys); void HandleCompleteLogin(const std::string& gaia_id, const std::string& typed_email, const std::string& password,
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy/policy_ui.cc similarity index 96% rename from chrome/browser/ui/webui/policy_ui.cc rename to chrome/browser/ui/webui/policy/policy_ui.cc index 13d0997..d487c6c 100644 --- a/chrome/browser/ui/webui/policy_ui.cc +++ b/chrome/browser/ui/webui/policy/policy_ui.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/policy_ui.h" +#include "chrome/browser/ui/webui/policy/policy_ui.h" #include <memory> #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/policy_ui_handler.h" +#include "chrome/browser/ui/webui/policy/policy_ui_handler.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/url_constants.h" #include "components/grit/dev_ui_components_resources.h"
diff --git a/chrome/browser/ui/webui/policy_ui.h b/chrome/browser/ui/webui/policy/policy_ui.h similarity index 77% rename from chrome/browser/ui/webui/policy_ui.h rename to chrome/browser/ui/webui/policy/policy_ui.h index d8b58392..a70da60 100644 --- a/chrome/browser/ui/webui/policy_ui.h +++ b/chrome/browser/ui/webui/policy/policy_ui.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_POLICY_UI_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_ #include <string> @@ -24,4 +24,4 @@ DISALLOW_COPY_AND_ASSIGN(PolicyUI); }; -#endif // CHROME_BROWSER_UI_WEBUI_POLICY_UI_H_ +#endif // CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_H_
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_ui_browsertest.cc similarity index 100% rename from chrome/browser/ui/webui/policy_ui_browsertest.cc rename to chrome/browser/ui/webui/policy/policy_ui_browsertest.cc
diff --git a/chrome/browser/ui/webui/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc similarity index 99% rename from chrome/browser/ui/webui/policy_ui_handler.cc rename to chrome/browser/ui/webui/policy/policy_ui_handler.cc index 037e2e9..e6f2bf5 100644 --- a/chrome/browser/ui/webui/policy_ui_handler.cc +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/policy_ui_handler.h" +#include "chrome/browser/ui/webui/policy/policy_ui_handler.h" #include <stddef.h>
diff --git a/chrome/browser/ui/webui/policy_ui_handler.h b/chrome/browser/ui/webui/policy/policy_ui_handler.h similarity index 96% rename from chrome/browser/ui/webui/policy_ui_handler.h rename to chrome/browser/ui/webui/policy/policy_ui_handler.h index 2b26a9a..5091f7ec 100644 --- a/chrome/browser/ui/webui/policy_ui_handler.h +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_UI_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_POLICY_UI_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_ #include <stddef.h> #include <string.h> @@ -142,4 +142,4 @@ DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler); }; -#endif // CHROME_BROWSER_UI_WEBUI_POLICY_UI_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_POLICY_POLICY_UI_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc index 1e50c8d..e400f05 100644 --- a/chrome/browser/ui/webui/settings/chromeos/internet_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/internet_section.cc
@@ -575,6 +575,7 @@ {"internetDeviceEnabling", IDS_SETTINGS_INTERNET_DEVICE_ENABLING}, {"internetDeviceDisabling", IDS_SETTINGS_INTERNET_DEVICE_DISABLING}, {"internetDeviceInitializing", IDS_SETTINGS_INTERNET_DEVICE_INITIALIZING}, + {"internetDeviceBusy", IDS_SETTINGS_INTERNET_DEVICE_BUSY}, {"internetJoinType", IDS_SETTINGS_INTERNET_JOIN_TYPE}, {"internetKnownNetworksPageTitle", IDS_SETTINGS_INTERNET_KNOWN_NETWORKS}, {"internetMobileSearching", IDS_SETTINGS_INTERNET_MOBILE_SEARCH},
diff --git a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc index 0b292d4..c78c1bc 100644 --- a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
@@ -204,6 +204,10 @@ IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_ALBUM_SELECTED}, {"ambientModeAlbumsSubpageAlbumUnselected", IDS_OS_SETTINGS_AMBIENT_MODE_ALBUMS_SUBPAGE_ALBUM_UNSELECTED}, + {"ambientModeLastArtAlbumMessage", + IDS_OS_SETTINGS_AMBIENT_MODE_LAST_ART_ALBUM_MESSAGE}, + {"ambientModeArtAlbumDialogCloseButtonLabel", + IDS_OS_SETTINGS_AMBIENT_MODE_ART_ALBUM_DIALOG_CLOSE_BUTTON_LABEL}, {"changePictureTitle", IDS_OS_SETTINGS_CHANGE_PICTURE_TITLE}, {"openWallpaperApp", IDS_OS_SETTINGS_OPEN_WALLPAPER_APP}, {"personalizationPageTitle", IDS_OS_SETTINGS_PERSONALIZATION},
diff --git a/chrome/browser/ui/webui/sync_internals/OWNERS b/chrome/browser/ui/webui/sync_internals/OWNERS new file mode 100644 index 0000000..261ab18 --- /dev/null +++ b/chrome/browser/ui/webui/sync_internals/OWNERS
@@ -0,0 +1 @@ +file://components/sync/OWNERS
diff --git a/chrome/browser/ui/webui/sync_internals_browsertest.js b/chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js similarity index 100% rename from chrome/browser/ui/webui/sync_internals_browsertest.js rename to chrome/browser/ui/webui/sync_internals/sync_internals_browsertest.js
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc similarity index 98% rename from chrome/browser/ui/webui/sync_internals_message_handler.cc rename to chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc index 214fa4c..b149bee7 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler.cc +++ b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/sync_internals_message_handler.h" +#include "chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h" #include <utility> #include <vector> @@ -368,8 +368,8 @@ void SyncInternalsMessageHandler::HandleJsEvent( const std::string& name, const syncer::JsEventDetails& details) { - DVLOG(1) << "Handling event: " << name - << " with details " << details.ToString(); + DVLOG(1) << "Handling event: " << name << " with details " + << details.ToString(); DispatchEvent(name, details.Get()); }
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.h b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h similarity index 95% rename from chrome/browser/ui/webui/sync_internals_message_handler.h rename to chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h index b28f34f..5b473f3 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler.h +++ b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_MESSAGE_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_MESSAGE_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_MESSAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_MESSAGE_HANDLER_H_ #include <memory> #include <string> @@ -143,4 +143,4 @@ DISALLOW_COPY_AND_ASSIGN(SyncInternalsMessageHandler); }; -#endif // CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_MESSAGE_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_MESSAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler_unittest.cc similarity index 99% rename from chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc rename to chrome/browser/ui/webui/sync_internals/sync_internals_message_handler_unittest.cc index d476a6be..cb01769a 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc +++ b/chrome/browser/ui/webui/sync_internals/sync_internals_message_handler_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/sync_internals_message_handler.h" +#include "chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h" #include <memory> #include <utility>
diff --git a/chrome/browser/ui/webui/sync_internals_ui.cc b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc similarity index 94% rename from chrome/browser/ui/webui/sync_internals_ui.cc rename to chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc index 14105ef..97d5d65c 100644 --- a/chrome/browser/ui/webui/sync_internals_ui.cc +++ b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/sync_internals_ui.h" +#include "chrome/browser/ui/webui/sync_internals/sync_internals_ui.h" #include <memory> #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/sync_internals_message_handler.h" +#include "chrome/browser/ui/webui/sync_internals/sync_internals_message_handler.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/url_constants.h" #include "components/grit/sync_driver_resources.h"
diff --git a/chrome/browser/ui/webui/sync_internals_ui.h b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h similarity index 72% rename from chrome/browser/ui/webui/sync_internals_ui.h rename to chrome/browser/ui/webui/sync_internals/sync_internals_ui.h index e1a773d53..8a0e174 100644 --- a/chrome/browser/ui/webui/sync_internals_ui.h +++ b/chrome/browser/ui/webui/sync_internals/sync_internals_ui.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_UI_H_ #include "base/compiler_specific.h" #include "base/macros.h" @@ -19,4 +19,4 @@ DISALLOW_COPY_AND_ASSIGN(SyncInternalsUI); }; -#endif // CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_UI_H_ +#endif // CHROME_BROWSER_UI_WEBUI_SYNC_INTERNALS_SYNC_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc index 4ca6c5a..c04b629 100644 --- a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc +++ b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc
@@ -106,8 +106,8 @@ base::CallbackListSubscription ChromeZoomLevelPrefs::RegisterDefaultZoomLevelCallback( - const base::Closure& callback) { - return default_zoom_changed_callbacks_.Add(callback); + base::RepeatingClosure callback) { + return default_zoom_changed_callbacks_.Add(std::move(callback)); } void ChromeZoomLevelPrefs::OnZoomLevelChanged(
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h index c901671..2ca1b25 100644 --- a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h +++ b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.h
@@ -51,7 +51,7 @@ void SetDefaultZoomLevelPref(double level); double GetDefaultZoomLevelPref() const; base::CallbackListSubscription RegisterDefaultZoomLevelCallback( - const base::Closure& callback); + base::RepeatingClosure callback); void ExtractPerHostZoomLevels( const base::DictionaryValue* host_zoom_dictionary,
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java index 789214b..d23093d 100644 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java +++ b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java
@@ -37,6 +37,17 @@ @Override public void getTutorial(int featureType, Callback<Tutorial> callback) { + if (featureType == FeatureType.SUMMARY) { + Tutorial summary = new Tutorial(FeatureType.SUMMARY, "Videos on how to use chrome", + "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.mp4", + "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", + "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif", + "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", + "caption url", "share url", 25); + callback.onResult(summary); + return; + } + for (Tutorial tutorial : mTutorials) { if (tutorial.featureType == featureType) callback.onResult(tutorial); }
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml index 259f719f..2c9347c 100644 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml +++ b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml
@@ -61,14 +61,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - style="@style/TextButton" - android:text="@string/video_tutorials_watch_next_video" /> + android:text="@string/video_tutorials_watch_next_video" + android:textAppearance="@style/TextAppearance.TextMediumThick.Primary.Light" + style="@style/TextButton" /> <TextView android:id="@+id/change_language" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" + android:textAppearance="@style/TextAppearance.TextMediumThick.Primary.Light" style="@style/TextButton" /> </LinearLayout>
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc index 497d405..04ae55f0 100644 --- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc +++ b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc
@@ -13,6 +13,20 @@ #include "components/prefs/pref_service.h" namespace video_tutorials { +namespace { + +std::vector<Tutorial> FilterTutorials(const std::vector<Tutorial>& tutorials) { + std::vector<Tutorial> tutorials_excluding_summary; + for (const auto& tutorial : tutorials) { + if (tutorial.feature == FeatureType::kSummary) + continue; + tutorials_excluding_summary.emplace_back(tutorial); + } + + return tutorials_excluding_summary; +} + +} // namespace TutorialManagerImpl::TutorialManagerImpl(std::unique_ptr<TutorialStore> store, PrefService* prefs) @@ -43,7 +57,7 @@ ? preferred_locale.value() : Config::GetDefaultPreferredLocale(); if (tutorial_group_.has_value() && tutorial_group_->language == locale) { - std::move(callback).Run(tutorial_group_->tutorials); + std::move(callback).Run(FilterTutorials(tutorial_group_->tutorials)); return; } @@ -117,7 +131,7 @@ // We are loading tutorials only for the preferred locale. DCHECK(loaded_groups->size() == 1u); tutorial_group_ = loaded_groups->front(); - std::move(callback).Run(tutorial_group_->tutorials); + std::move(callback).Run(FilterTutorials(tutorial_group_->tutorials)); } void TutorialManagerImpl::SaveGroups(
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc index 1c4bd9c..e731b89 100644 --- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc +++ b/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc
@@ -23,13 +23,17 @@ namespace { std::vector<TutorialGroup> CreateSampleGroups( - const std::vector<std::string>& locales) { + const std::vector<std::string>& locales, + const std::vector<FeatureType>& features) { std::vector<TutorialGroup> groups; for (const auto& locale : locales) { TutorialGroup group; group.language = locale; - group.tutorials.emplace_back(Tutorial()); - group.tutorials.emplace_back(Tutorial()); + for (FeatureType feature : features) { + group.tutorials.emplace_back( + Tutorial(feature, "", "", "", "", "", "", "", 10)); + } + groups.emplace_back(group); } @@ -37,9 +41,10 @@ } std::unique_ptr<std::vector<TutorialGroup>> CreateSampleFetchData( - const std::vector<std::string>& locales) { + const std::vector<std::string>& locales, + const std::vector<FeatureType>& features) { auto groups = std::make_unique<std::vector<TutorialGroup>>(); - for (const auto& group : CreateSampleGroups(locales)) { + for (const auto& group : CreateSampleGroups(locales, features)) { groups->emplace_back(group); } @@ -150,7 +155,24 @@ }; TEST_F(TutorialManagerTest, InitAndGetTutorials) { - auto groups = CreateSampleGroups({"hi", "kn"}); + std::vector<FeatureType> features( + {FeatureType::kDownload, FeatureType::kSearch}); + auto groups = CreateSampleGroups({"hi", "kn"}, features); + auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); + tutorial_store->InitStoreData("hi", groups); + CreateTutorialManager(std::move(tutorial_store)); + + auto languages = manager()->GetSupportedLanguages(); + EXPECT_EQ(languages.size(), 2u); + manager()->SetPreferredLocale("hi"); + GetTutorials(); + EXPECT_EQ(last_results().size(), 2u); +} + +TEST_F(TutorialManagerTest, InitAndGetTutorialsWithSummary) { + std::vector<FeatureType> features( + {FeatureType::kDownload, FeatureType::kSearch, FeatureType::kSummary}); + auto groups = CreateSampleGroups({"hi", "kn"}, features); auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); tutorial_store->InitStoreData("hi", groups); CreateTutorialManager(std::move(tutorial_store)); @@ -163,7 +185,9 @@ } TEST_F(TutorialManagerTest, SaveNewData) { - auto groups = CreateSampleGroups({"hi", "kn"}); + std::vector<FeatureType> features( + {FeatureType::kDownload, FeatureType::kSearch, FeatureType::kSummary}); + auto groups = CreateSampleGroups({"hi", "kn"}, features); auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); tutorial_store->InitStoreData("hi", groups); CreateTutorialManager(std::move(tutorial_store)); @@ -172,14 +196,28 @@ auto languages = manager()->GetSupportedLanguages(); EXPECT_EQ(languages.size(), 2u); GetTutorials(); - EXPECT_EQ(last_results().size(), groups[0].tutorials.size()); + EXPECT_EQ(last_results().size(), 2u); - auto new_groups = CreateSampleFetchData({"hi", "tl", "ar"}); + // New fetch data. + features = std::vector<FeatureType>( + {FeatureType::kChromeIntro, FeatureType::kDownload, FeatureType::kSearch, + FeatureType::kVoiceSearch}); + auto new_groups = CreateSampleFetchData({"hi", "tl", "ar"}, features); auto new_group = new_groups->at(0); SaveGroups(std::move(new_groups)); manager()->SetPreferredLocale("ar"); GetTutorials(); - EXPECT_EQ(last_results().size(), new_group.tutorials.size()); + EXPECT_EQ(last_results().size(), 4u); + + // New fetch data with summary. + features = std::vector<FeatureType>( + {FeatureType::kChromeIntro, FeatureType::kVoiceSearch, + FeatureType::kSearch, FeatureType::kSummary}); + new_groups = CreateSampleFetchData({"hi", "tl", "ar"}, features); + SaveGroups(std::move(new_groups)); + manager()->SetPreferredLocale("tl"); + GetTutorials(); + EXPECT_EQ(last_results().size(), 3u); } } // namespace
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 60231d96..a032df9 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -265,6 +265,7 @@ "web_app_audio_focus_browsertest.cc", "web_app_icon_manager_browsertest.cc", "web_app_migration_manager_browsertest.cc", + "web_app_mover_browsertest.cc", ] defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
diff --git a/chrome/browser/web_applications/web_app_mover.cc b/chrome/browser/web_applications/web_app_mover.cc index 3a937eb..7b6841f 100644 --- a/chrome/browser/web_applications/web_app_mover.cc +++ b/chrome/browser/web_applications/web_app_mover.cc
@@ -4,13 +4,22 @@ #include "chrome/browser/web_applications/web_app_mover.h" +#include "base/barrier_closure.h" +#include "base/callback_helpers.h" #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" #include "base/no_destructor.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/web_applications/components/app_registrar.h" +#include "chrome/browser/web_applications/components/app_registry_controller.h" +#include "chrome/browser/web_applications/components/install_finalizer.h" +#include "chrome/browser/web_applications/components/install_manager.h" #include "chrome/common/chrome_features.h" +#include "components/webapps/installable/installable_metrics.h" +#include "content/public/browser/web_contents.h" namespace { @@ -26,32 +35,36 @@ namespace web_app { -std::unique_ptr<WebAppMover> WebAppMover::CreateIfNeeded(Profile* profile) { +std::unique_ptr<WebAppMover> WebAppMover::CreateIfNeeded( + Profile* profile, + AppRegistrar* registrar, + InstallFinalizer* install_finalizer, + InstallManager* install_manager, + AppRegistryController* controller) { DCHECK(base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)); - if (g_disabled_for_testing) return nullptr; if (!base::FeatureList::IsEnabled(features::kMoveWebApp)) return nullptr; - std::string uninstall_url_prefix_str = + std::string uninstall_url_prefix = features::kMoveWebAppUninstallStartUrlPrefix.Get(); std::string install_url_str = features::kMoveWebAppInstallStartUrl.Get(); - if (uninstall_url_prefix_str.empty() || install_url_str.empty()) + if (uninstall_url_prefix.empty() || install_url_str.empty()) return nullptr; - GURL uninstall_url_prefix = GURL(uninstall_url_prefix_str); GURL install_url = GURL(install_url_str); // The URLs have to be valid, and the installation URL cannot be contained in // the uninstall prefix. - if (!uninstall_url_prefix.is_valid() || !install_url.is_valid() || - base::StartsWith(install_url.spec(), uninstall_url_prefix.spec())) { + if (!install_url.is_valid() || + base::StartsWith(install_url.spec(), uninstall_url_prefix)) { return nullptr; } - return std::make_unique<WebAppMover>(profile, uninstall_url_prefix, - install_url); + return std::make_unique<WebAppMover>(profile, registrar, install_finalizer, + install_manager, controller, + uninstall_url_prefix, install_url); } void WebAppMover::DisableForTesting() { @@ -67,9 +80,17 @@ } WebAppMover::WebAppMover(Profile* profile, - const GURL& uninstall_url_prefix, + AppRegistrar* registrar, + InstallFinalizer* install_finalizer, + InstallManager* install_manager, + AppRegistryController* controller, + const std::string& uninstall_url_prefix, const GURL& install_url) : profile_(profile), + registrar_(registrar), + install_finalizer_(install_finalizer), + install_manager_(install_manager), + controller_(controller), uninstall_url_prefix_(uninstall_url_prefix), install_url_(install_url) {} @@ -122,10 +143,124 @@ } void WebAppMover::OnFirstSyncCycleComplete() { - // TODO(dmurph): Implement migration here. + DCHECK(apps_to_uninstall_.empty()); - if (GetCompletedCallbackForTesting()) - std::move(GetCompletedCallbackForTesting()).Run(); + base::ScopedClosureRunner complete_callback_runner; + if (GetCompletedCallbackForTesting()) { + complete_callback_runner.ReplaceClosure( + std::move(GetCompletedCallbackForTesting())); + } + + for (const AppId& id : registrar_->GetAppIds()) { + // Stop if the destination app is already installed. + const GURL& start_url = registrar_->GetAppStartUrl(id); + if (start_url == install_url_) + return; + // To avoid edge cases only consider installed apps to uninstall. + if (!registrar_->IsInstalled(id)) + continue; + if (base::StartsWith(start_url.spec(), uninstall_url_prefix_)) { + apps_to_uninstall_.push_back(id); + new_app_open_as_window_ = + registrar_->GetAppUserDisplayMode(id) == DisplayMode::kStandalone; + } + } + + if (apps_to_uninstall_.empty()) + return; + + install_manager_->LoadWebAppAndCheckManifest( + install_url_, webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, + base::BindOnce(&WebAppMover::OnInstallManifestFetched, + weak_ptr_factory_.GetWeakPtr(), + std::move(complete_callback_runner))); +} + +void WebAppMover::OnInstallManifestFetched( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents, + InstallManager::InstallableCheckResult result, + base::Optional<AppId> app_id) { + switch (result) { + case InstallManager::InstallableCheckResult::kAlreadyInstalled: + LOG(WARNING) << "App already installed."; + return; + case InstallManager::InstallableCheckResult::kNotInstallable: + // If the app is not installable, then abort. + return; + case InstallManager::InstallableCheckResult::kInstallable: + break; + } + DCHECK(!apps_to_uninstall_.empty()); + + scoped_refptr<base::RefCountedData<bool>> success_accumulator = + base::MakeRefCounted<base::RefCountedData<bool>>(true); + + auto barrier = base::BarrierClosure( + apps_to_uninstall_.size(), + base::BindOnce(&WebAppMover::OnAllUninstalled, + weak_ptr_factory_.GetWeakPtr(), + std::move(complete_callback_runner), + std::move(web_contents), success_accumulator)); + for (const AppId& id : apps_to_uninstall_) { + install_finalizer_->UninstallExternalAppByUser( + id, + base::BindOnce( + [](base::OnceClosure done, + scoped_refptr<base::RefCountedData<bool>> success_accumulator, + bool success) { + if (!success) { + LOG(WARNING) + << "Uninstallation unsuccesful in app move operation."; + success_accumulator->data = false; + } + std::move(done).Run(); + }, + barrier, success_accumulator)); + } +} + +void WebAppMover::OnAllUninstalled( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents_for_install, + scoped_refptr<base::RefCountedData<bool>> success_accumulator) { + if (!success_accumulator->data) + return; + auto* web_contents = web_contents_for_install.get(); + install_manager_->InstallWebAppFromManifest( + web_contents, true, webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, + base::BindOnce([](content::WebContents* initiator_web_contents, + std::unique_ptr<WebApplicationInfo> web_app_info, + ForInstallableSite for_installable_site, + InstallManager::WebAppInstallationAcceptanceCallback + acceptance_callback) { + // Note: |open_as_window| is set to false here (which it should be by + // default), because if that is true the WebAppInstallTask will try to + // reparent the the web contents into an app browser. This is + // impossible, as this web contents is internal & not visible to the + // user (and we will segfault). Instead, set the user display mode after + // installation is complete. + DCHECK(web_app_info); + web_app_info->open_as_window = false; + std::move(acceptance_callback).Run(true, std::move(web_app_info)); + }), + base::BindOnce(&WebAppMover::OnInstallCompleted, + weak_ptr_factory_.GetWeakPtr(), + std::move(complete_callback_runner), + std::move(web_contents_for_install))); +} + +void WebAppMover::OnInstallCompleted( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents_for_install, + const AppId& id, + InstallResultCode code) { + if (code == InstallResultCode::kSuccessNewInstall) { + if (new_app_open_as_window_) + controller_->SetAppUserDisplayMode(id, DisplayMode::kStandalone, false); + } else { + LOG(WARNING) << "Installation in app move operation failed: " << code; + } } } // namespace web_app \ No newline at end of file
diff --git a/chrome/browser/web_applications/web_app_mover.h b/chrome/browser/web_applications/web_app_mover.h index 8a30f4c..04d8685 100644 --- a/chrome/browser/web_applications/web_app_mover.h +++ b/chrome/browser/web_applications/web_app_mover.h
@@ -8,29 +8,49 @@ #include <memory> #include "base/callback.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/scoped_observation.h" +#include "chrome/browser/web_applications/components/install_manager.h" +#include "chrome/browser/web_applications/components/web_app_id.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_service_observer.h" #include "url/gurl.h" class Profile; +namespace content { +class WebContents; +} namespace web_app { +class AppRegistrar; +class AppRegistryController; +class InstallFinalizer; + // WebAppMover is designed to facilitate a one-off migration for a webapp, from // one start_url to another. // TODO(dmurph): Finish implementing. class WebAppMover final : public syncer::SyncServiceObserver { public: - static std::unique_ptr<WebAppMover> CreateIfNeeded(Profile* profile); + static std::unique_ptr<WebAppMover> CreateIfNeeded( + Profile* profile, + AppRegistrar* registrar, + InstallFinalizer* install_finalizer, + InstallManager* install_manager, + AppRegistryController* controller); static void DisableForTesting(); static void SkipWaitForSyncForTesting(); static void SetCompletedCallbackForTesting(base::OnceClosure callback); WebAppMover(Profile* profile, - const GURL& uninstall_url_prefix, + AppRegistrar* registrar, + InstallFinalizer* install_finalizer, + InstallManager* install_manager, + AppRegistryController* controller, + const std::string& uninstall_url_prefix, const GURL& install_url); WebAppMover(const WebAppMover&) = delete; WebAppMover& operator=(const WebAppMover&) = delete; @@ -47,12 +67,38 @@ void WaitForFirstSyncCycle(base::OnceClosure callback); void OnFirstSyncCycleComplete(); + void OnInstallManifestFetched( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents, + InstallManager::InstallableCheckResult result, + base::Optional<AppId> app_id); + + void OnAllUninstalled( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents_for_install, + scoped_refptr<base::RefCountedData<bool>> success_accumulator); + + void OnInstallCompleted( + base::ScopedClosureRunner complete_callback_runner, + std::unique_ptr<content::WebContents> web_contents_for_install, + const AppId& id, + InstallResultCode code); + Profile* profile_; - GURL uninstall_url_prefix_; + AppRegistrar* registrar_; + InstallFinalizer* install_finalizer_; + InstallManager* install_manager_; + AppRegistryController* controller_; + + std::string uninstall_url_prefix_; GURL install_url_; + syncer::SyncService* sync_service_ = nullptr; base::OnceClosure sync_ready_callback_; + bool new_app_open_as_window_ = false; + std::vector<AppId> apps_to_uninstall_; + base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver> sync_observer_{this};
diff --git a/chrome/browser/web_applications/web_app_mover_browsertest.cc b/chrome/browser/web_applications/web_app_mover_browsertest.cc new file mode 100644 index 0000000..9a317d8 --- /dev/null +++ b/chrome/browser/web_applications/web_app_mover_browsertest.cc
@@ -0,0 +1,128 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/web_app_mover.h" + +#include "base/bind.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/web_applications/components/os_integration_manager.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/components/web_app_provider_base.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/common/chrome_features.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/webapps/installable/installable_metrics.h" +#include "content/public/test/browser_test.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_app { +namespace { +class WebAppMoverBrowsertest : public InProcessBrowserTest { + public: + WebAppMoverBrowsertest() { + suppress_hooks_ = OsIntegrationManager::ScopedSuppressOsHooksForTesting(); + https_server_.AddDefaultHandlers(GetChromeTestDataDir()); + // Since the port is a part of the start_url, this needs to stay consistent + // between the tests below. + CHECK(https_server_.Start(44221)); + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kMoveWebApp, + {{features::kMoveWebAppUninstallStartUrlPrefix.name, + GetMigratingFromUrlPrefix()}, + {features::kMoveWebAppInstallStartUrl.name, + GetMigratingToApp().spec()}}}}, + {}); + switch (GetTestPreCount()) { + case 1: + WebAppMover::DisableForTesting(); + break; + case 0: + WebAppMover::SetCompletedCallbackForTesting( + base::BindLambdaForTesting([this]() { + clean_up_completed_ = true; + if (completed_callback_) + std::move(completed_callback_).Run(); + })); + break; + } + } + ~WebAppMoverBrowsertest() override = default; + + // InProcessBrowserTest: + void SetUp() override { InProcessBrowserTest::SetUp(); } + + protected: + std::string GetMigratingFromUrlPrefix() { + return https_server_.GetURL("/web_apps/mover/migrate_from/").spec(); + } + + GURL GetMigratingFromAppA() { + return https_server_.GetURL("/web_apps/mover/migrate_from/a/index.html"); + } + + GURL GetMigratingFromAppB() { + return https_server_.GetURL("/web_apps/mover/migrate_from/b/index.html"); + } + + GURL GetMigratingToApp() { + return https_server_.GetURL("/web_apps/mover/migrate_to/index.html"); + } + + AppId InstallApp(GURL url) { + ui_test_utils::NavigateToURL(browser(), url); + + AppId app_id; + base::RunLoop run_loop; + GetProvider().install_manager().InstallWebAppFromManifestWithFallback( + browser()->tab_strip_model()->GetActiveWebContents(), + /*force_shortcut_app=*/false, + webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, + base::BindOnce(TestAcceptDialogCallback), + base::BindLambdaForTesting( + [&](const AppId& new_app_id, InstallResultCode code) { + EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall) << code; + app_id = new_app_id; + run_loop.Quit(); + })); + run_loop.Run(); + return app_id; + } + + WebAppProviderBase& GetProvider() { + return *WebAppProviderBase::GetProviderBase(browser()->profile()); + } + + bool clean_up_completed_ = false; + base::OnceClosure completed_callback_; + + private: + base::test::ScopedFeatureList scoped_feature_list_; + ScopedOsHooksSuppress suppress_hooks_; + net::EmbeddedTestServer https_server_; +}; + +IN_PROC_BROWSER_TEST_F(WebAppMoverBrowsertest, PRE_TestMigration) { + InstallApp(GetMigratingFromAppA()); + InstallApp(GetMigratingFromAppB()); +} + +IN_PROC_BROWSER_TEST_F(WebAppMoverBrowsertest, TestMigration) { + // Wait for clean up to complete (this will timeout if we don't run clean up). + if (!clean_up_completed_) { + base::RunLoop run_loop; + completed_callback_ = run_loop.QuitClosure(); + run_loop.Run(); + } + ASSERT_EQ(GetProvider().registrar().GetAppIds().size(), 1ul); + EXPECT_EQ(GetProvider().registrar().GetAppIds().front(), + GenerateAppIdFromURL(GetMigratingToApp())); +} + +} // namespace +} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_mover_unittest.cc b/chrome/browser/web_applications/web_app_mover_unittest.cc index f1e8550e..9bbd4b1f 100644 --- a/chrome/browser/web_applications/web_app_mover_unittest.cc +++ b/chrome/browser/web_applications/web_app_mover_unittest.cc
@@ -33,7 +33,8 @@ using WebAppMoverTestWithInvalidParams = WebAppMoverTestWithParams; TEST_P(WebAppMoverTestWithInvalidParams, VerifyInvalidParams) { - std::unique_ptr<WebAppMover> mover = WebAppMover::CreateIfNeeded(nullptr); + std::unique_ptr<WebAppMover> mover = + WebAppMover::CreateIfNeeded(nullptr, nullptr, nullptr, nullptr, nullptr); EXPECT_FALSE(mover); } @@ -52,7 +53,8 @@ using WebAppMoverTestWithValidParams = WebAppMoverTestWithParams; TEST_P(WebAppMoverTestWithValidParams, VerifyValidParams) { - std::unique_ptr<WebAppMover> mover = WebAppMover::CreateIfNeeded(nullptr); + std::unique_ptr<WebAppMover> mover = + WebAppMover::CreateIfNeeded(nullptr, nullptr, nullptr, nullptr, nullptr); EXPECT_TRUE(mover); }
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index 915aca0..97d5c40 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -238,7 +238,9 @@ migration_manager_ = std::make_unique<WebAppMigrationManager>( profile, database_factory_.get(), icon_manager.get(), os_integration_manager_.get()); - web_app_mover_ = WebAppMover::CreateIfNeeded(profile); + web_app_mover_ = WebAppMover::CreateIfNeeded( + profile, registrar.get(), install_finalizer_.get(), + install_manager_.get(), sync_bridge.get()); // Upcast to unified subsystem types: registrar_ = std::move(registrar);
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java index 1209e04f..68e13eb 100644 --- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java +++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/ProcessScopeDependencyProvider.java
@@ -80,4 +80,8 @@ default LibraryResolver getLibraryResolver() { return null; } + + default boolean isXsurfaceUsageAndCrashReportingEnabled() { + return false; + } }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index faa1be0..22bd1b9 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1608206305-4389a6a6a359fb8abf452a6f4bc1a98be145b6cd.profdata +chrome-linux-master-1608249589-9c170b057d7f5d331838398008b8ec38a41e02e3.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 9d1d645..fcef0766 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1608206305-43a406c5421ed694ad09e180106f1be95f3f52fa.profdata +chrome-mac-master-1608249589-e11ce53a2384150a68c372a42aa0334667012fbb.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 6991f7a..719b2d2 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1608195565-bd827a491b21adb0b88af96833fe918adc2826b3.profdata +chrome-win64-master-1608228003-e74739fcdefa7518b67623025a08d95b63f00b00.profdata
diff --git a/chrome/common/subresource_redirect_service.mojom b/chrome/common/subresource_redirect_service.mojom index 493b446e..bd242ef 100644 --- a/chrome/common/subresource_redirect_service.mojom +++ b/chrome/common/subresource_redirect_service.mojom
@@ -5,6 +5,7 @@ module subresource_redirect.mojom; import "mojo/public/mojom/base/time.mojom"; +import "url/mojom/origin.mojom"; // Image loading hints passed by the browser to renderers. Send at most once // per page load from browser to renderer. The hints are provided to the @@ -22,6 +23,12 @@ // after which subsequent image fetches should be initiated, otherwise // |retry_after| is zero. NotifyCompressedImageFetchFailed(mojo_base.mojom.TimeDelta retry_after); + + // Requests robots rules for the |origin|. The reply result + // |robots_rules_proto| will be empty when the rules fetch failed. The proto + // format will be subresource_redirect::proto::RobotsRules from + // robots_rules.proto + GetRobotsRules(url.mojom.Origin origin) => (string? robots_rules_proto); }; // Render process implemented interface that receives hints from the browser
diff --git a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc index db69d12..8e28e97 100644 --- a/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc +++ b/chrome/renderer/subresource_redirect/login_robots_decider_agent.cc
@@ -59,16 +59,6 @@ LoginRobotsDeciderAgent::~LoginRobotsDeciderAgent() = default; -void LoginRobotsDeciderAgent::UpdateRobotsRules( - const url::Origin& origin, - const base::Optional<std::string>& rules) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!origin.opaque()); - if (!render_frame()->IsMainFrame()) - return; - GetRobotsRulesParserCache().UpdateRobotsRules(origin, rules); -} - base::Optional<RedirectResult> LoginRobotsDeciderAgent::ShouldRedirectSubresource( const GURL& url, @@ -78,8 +68,21 @@ if (!render_frame()->IsMainFrame()) return RedirectResult::kIneligibleSubframeResource; + // Trigger the robots rules fetch if needed. + const auto origin = url::Origin::Create(url); + RobotsRulesParserCache& robots_rules_parser_cache = + GetRobotsRulesParserCache(); + if (!robots_rules_parser_cache.DoRobotsRulesExist(origin)) { + // base::Unretained can be used here since the |robots_rules_parser_cache| + // is never destructed. + GetSubresourceRedirectServiceRemote()->GetRobotsRules( + origin, + base::BindOnce(&RobotsRulesParserCache::UpdateRobotsRules, + base::Unretained(&robots_rules_parser_cache), origin)); + } + base::Optional<RobotsRulesParser::CheckResult> result = - GetRobotsRulesParserCache().CheckRobotsRules( + robots_rules_parser_cache.CheckRobotsRules( url, base::BindOnce(&SendRedirectResultToCallback, std::move(callback))); if (result) @@ -106,4 +109,10 @@ NOTREACHED(); } +void LoginRobotsDeciderAgent::UpdateRobotsRulesForTesting( + const url::Origin& origin, + const base::Optional<std::string>& rules) { + GetRobotsRulesParserCache().UpdateRobotsRules(origin, rules); +} + } // namespace subresource_redirect
diff --git a/chrome/renderer/subresource_redirect/login_robots_decider_agent.h b/chrome/renderer/subresource_redirect/login_robots_decider_agent.h index fcfcb50..72b0b8e 100644 --- a/chrome/renderer/subresource_redirect/login_robots_decider_agent.h +++ b/chrome/renderer/subresource_redirect/login_robots_decider_agent.h
@@ -30,14 +30,13 @@ LoginRobotsDeciderAgent(const LoginRobotsDeciderAgent&) = delete; LoginRobotsDeciderAgent& operator=(const LoginRobotsDeciderAgent&) = delete; - // Updates the robots rules for the origin. - void UpdateRobotsRules(const url::Origin& origin, - const base::Optional<std::string>& rules); - private: friend class SubresourceRedirectLoginRobotsDeciderAgentTest; friend class SubresourceRedirectLoginRobotsURLLoaderThrottleTest; + void UpdateRobotsRulesForTesting(const url::Origin& origin, + const base::Optional<std::string>& rules); + // mojom::SubresourceRedirectHintsReceiver: void SetCompressPublicImagesHints( mojom::CompressPublicImagesHintsPtr images_hints) override;
diff --git a/chrome/renderer/subresource_redirect/login_robots_decider_agent_browsertest.cc b/chrome/renderer/subresource_redirect/login_robots_decider_agent_browsertest.cc index 28cd460..ab6c89a 100644 --- a/chrome/renderer/subresource_redirect/login_robots_decider_agent_browsertest.cc +++ b/chrome/renderer/subresource_redirect/login_robots_decider_agent_browsertest.cc
@@ -54,7 +54,7 @@ public: void SetUpRobotsRules(const std::string& origin, const std::vector<Rule>& patterns) { - login_robots_decider_agent_->UpdateRobotsRules( + login_robots_decider_agent_->UpdateRobotsRulesForTesting( url::Origin::Create(GURL(origin)), GetRobotsRulesProtoString(patterns)); }
diff --git a/chrome/renderer/subresource_redirect/login_robots_url_loader_throttle_browsertest.cc b/chrome/renderer/subresource_redirect/login_robots_url_loader_throttle_browsertest.cc index f64a5b4..99f8fa6 100644 --- a/chrome/renderer/subresource_redirect/login_robots_url_loader_throttle_browsertest.cc +++ b/chrome/renderer/subresource_redirect/login_robots_url_loader_throttle_browsertest.cc
@@ -123,7 +123,7 @@ void SetUpRobotsRules(const std::string& origin, const std::vector<Rule>& patterns) { - login_robots_decider_agent_->UpdateRobotsRules( + login_robots_decider_agent_->UpdateRobotsRulesForTesting( url::Origin::Create(GURL(origin)), GetRobotsRulesProtoString(patterns)); }
diff --git a/chrome/services/sharing/nearby/platform/log_message.cc b/chrome/services/sharing/nearby/platform/log_message.cc index dfcd9559..6442bca6 100644 --- a/chrome/services/sharing/nearby/platform/log_message.cc +++ b/chrome/services/sharing/nearby/platform/log_message.cc
@@ -47,13 +47,14 @@ namespace api { +// static void LogMessage::SetMinLogSeverity(Severity severity) { chrome::g_min_log_severity = severity; } +// static bool LogMessage::ShouldCreateLogMessage(Severity severity) { - return severity >= chrome::g_min_log_severity && - logging::ShouldCreateLogMessage(chrome::ConvertSeverity(severity)); + return severity >= chrome::g_min_log_severity; } } // namespace api
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 7d80c529..9e9e526 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1018,6 +1018,7 @@ "../browser/data_saver/data_saver_webapis_browsertest.cc", "../browser/data_saver/lite_video_browsertest.cc", "../browser/data_saver/subresource_redirect_browsertest.cc", + "../browser/data_saver/subresource_redirect_login_robots_browsertest.cc", "../browser/data_use_measurement/chrome_data_use_measurement_browsertest.cc", "../browser/device_api/managed_configuration_api_browsertest.cc", "../browser/devtools/device/adb/adb_client_socket_browsertest.cc", @@ -1041,7 +1042,6 @@ "../browser/download/download_frame_policy_browsertest.cc", "../browser/download/download_started_animation_browsertest.cc", "../browser/download/save_page_browsertest.cc", - "../browser/enterprise/connectors/connectors_service_browsertest.cc", "../browser/enterprise/connectors/content_analysis_delegate_browsertest.cc", "../browser/enterprise/connectors/content_analysis_dialog_browsertest.cc", "../browser/enterprise/reporting/report_scheduler_browsertest.cc", @@ -1076,6 +1076,7 @@ "../browser/loader/signed_exchange_policy_browsertest.cc", "../browser/loadtimes_extension_bindings_browsertest.cc", "../browser/locale_tests_browsertest.cc", + "../browser/login_detection/login_detection_browsertest.cc", "../browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc", "../browser/media/autoplay_metrics_browsertest.cc", "../browser/media/cast_mirroring_performance_browsertest.cc", @@ -1540,7 +1541,7 @@ "../browser/ui/webui/net_internals/net_internals_ui_browsertest.h", "../browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc", "../browser/ui/webui/ntp/new_tab_ui_browsertest.cc", - "../browser/ui/webui/policy_ui_browsertest.cc", + "../browser/ui/webui/policy/policy_ui_browsertest.cc", "../browser/ui/webui/prefs_internals_browsertest.cc", "../browser/ui/webui/profile_helper_browsertest.cc", "../browser/ui/webui/settings/settings_clear_browsing_data_handler_browsertest.cc", @@ -1630,6 +1631,13 @@ ] } + if (is_linux || is_chromeos) { + sources += [ + "../browser/error_reporting/webui_js_error_reporting_browsertest.cc", + ] + deps += [ "//chrome/browser/error_reporting:test_support" ] + } + if (is_linux && !is_chromeos_lacros) { sources += [ "../browser/chrome_main_browsertest.cc", @@ -3490,7 +3498,6 @@ "../browser/engagement/site_engagement_helper_unittest.cc", "../browser/engagement/site_engagement_score_unittest.cc", "../browser/engagement/site_engagement_service_unittest.cc", - "../browser/enterprise/util/affiliation_unittest.cc", "../browser/enterprise/util/managed_browser_utils_unittest.cc", "../browser/external_protocol/external_protocol_handler_unittest.cc", "../browser/federated_learning/floc_id_provider_unittest.cc", @@ -3905,7 +3912,6 @@ "../browser/android/usage_stats/usage_stats_database_unittest.cc", "../browser/android/webapk/webapk_icon_hasher_unittest.cc", "../browser/android/webapk/webapk_installer_unittest.cc", - "../browser/android/webapk/webapk_web_manifest_checker_unittest.cc", "../browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc", "../browser/data_reduction_proxy/data_reduction_proxy_settings_unittest_android.cc", "../browser/download/android/available_offline_content_provider_unittest.cc", @@ -4710,7 +4716,7 @@ "../browser/ui/webui/settings/site_settings_helper_unittest.cc", "../browser/ui/webui/settings_utils_unittest.cc", "../browser/ui/webui/signin/login_ui_service_unittest.cc", - "../browser/ui/webui/sync_internals_message_handler_unittest.cc", + "../browser/ui/webui/sync_internals/sync_internals_message_handler_unittest.cc", "../browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc", "../browser/ui/webui/theme_source_unittest.cc", "../browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java index dba985d0..8a8903d 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
@@ -54,17 +54,29 @@ sActivity = mActivityTestRule.getActivity(); } else { mActivityTestRule.setActivity(sActivity); - if (mClearAllTabState) { - resetTabStateThorough(); - } else { + if (shouldPerformFastReset()) { resetTabStateFast(); + } else { + resetTabStateThorough(); } } - base.evaluate(); + try { + base.evaluate(); + } finally { + // If the activity was relaunched during the test, update the reference to use + // the most up to date Activity. + sActivity = mActivityTestRule.getActivity(); + } } }; } + private boolean shouldPerformFastReset() { + if (mClearAllTabState) return false; + return TestThreadUtils.runOnUiThreadBlockingNoException( + () -> { return sActivity.getTabModelSelector().getModel(false).getCount() > 0; }); + } + // Avoids closing the primary tab (and killing the renderer) in order to reset tab state // quickly, at the cost of thoroughness. This should be adequate for most tests. private void resetTabStateFast() {
diff --git a/chrome/test/data/load_image/image.html b/chrome/test/data/load_image/image.html index accf515..4fdd0bb 100644 --- a/chrome/test/data/load_image/image.html +++ b/chrome/test/data/load_image/image.html
@@ -1,17 +1,16 @@ <html> <head></head> <img alt="long_placeholder_text" src="image.png" /> +<script src="common.js"></script> <script> -function checkImage() { - sendValueToTest(document.images[0].complete); -} - -function imageSrc() { - sendValueToTest(document.images[0].src); -} - -function sendValueToTest(value) { - window.domAutomationController.send(value); +function loadNewImage(url) { + return new Promise((resolve, reject) => { + document.images[0].onload = () => { + console.log('new image loaded', url); + resolve(true); + }; + document.images[0].src = url; + }); } </script> </html>
diff --git a/chrome/test/data/web_apps/mover/index.html b/chrome/test/data/web_apps/mover/index.html new file mode 100644 index 0000000..2dbc1af5 --- /dev/null +++ b/chrome/test/data/web_apps/mover/index.html
@@ -0,0 +1,75 @@ +<!DOCTYPE html> + +<head> + <title id="title">App Migration Tester</title> + <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> + <meta content="utf-8" http-equiv="encoding"> +</head> + +<h1> + App Migration Tester +</h1> +<p> + This website can be used to test the web app mover code. +</p> + +<div> + To use this test site, launch Chromium with the following command line + arguments: + <pre>--enable-features=MoveWebApp:uninstallStartUrlPrefix/<span id="prefixUrl"></span>/installStartUrl/<span id="installUrl"></span></pre> + + (or customize the URL prefix and install URL here) + <div> + <label for="urlPrefixInput">URL Prefix</label> + <input type="text" id="urlPrefixInput" name="urlPrefixInput" size="100" /> + <label for="installUrlInput">Install URL</label> + <input type="text" id="installUrlInput" name="installUrlInput" size="100" /> + </div> +</div> + +<p> + This is just the root page, not a web app. +</p> + +<div style="border: solid 1px grey; margin: 5px; padding: 5px;"> + Directory: + <ul> + <li><a href="migrate_from/a/index.html">migrate_from/a/index.html</a></li> + <li><a href="migrate_from/b/index.html">migrate_from/b/index.html</a></li> + <li><a href="migrate_to/index.html">migrate_to/index.html</a></li> + <li><a href="index.html">index.html (here)</a></li> + </ul> +</div> + +<script> + function createFeatureParam(str) { + return str.replace(/[.%\/,:]/g, function(c) { + return "%" + c.charCodeAt(0).toString(16); + }); + } + function updateCommandLine(prefix, installUrl) { + document.getElementById("prefixUrl").innerHTML = createFeatureParam(prefix); + document.getElementById("installUrl").innerHTML = createFeatureParam( + installUrl + ); + } + function updateCommandLineFromForm() { + updateCommandLine(urlPrefixInput.value, installUrlInput.value); + } + var urlPrefixInput = document.getElementById("urlPrefixInput"); + var installUrlInput = document.getElementById("installUrlInput"); + + urlPrefixInput.addEventListener("change", updateCommandLineFromForm); + installUrlInput.addEventListener("change", updateCommandLineFromForm); + + var href_without_file = window.location.href; + href_without_file = + href_without_file.substring(0, href_without_file.lastIndexOf("/")) + "/"; + var prefixUrl = href_without_file + "migrate_from/"; + var installUrl = href_without_file + "migrate_to/index.html"; + + urlPrefixInput.value = prefixUrl; + installUrlInput.value = installUrl; + + updateCommandLineFromForm(); +</script>
diff --git a/chrome/test/data/web_apps/mover/migrate_from/a/icon144.png b/chrome/test/data/web_apps/mover/migrate_from/a/icon144.png new file mode 100644 index 0000000..103d75a --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/a/icon144.png Binary files differ
diff --git a/chrome/test/data/web_apps/mover/migrate_from/a/index.html b/chrome/test/data/web_apps/mover/migrate_from/a/index.html new file mode 100644 index 0000000..b88b2b8 --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/a/index.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> + +<head> + <title id="title">Migration has happened!</title> + <link rel="manifest" href="./manifest.webmanifest" /> + <meta id="themeColor" name="theme-color" content="#ec9740" /> + <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> + <meta content="utf-8" http-equiv="encoding"> + <link + rel="icon" + type="image/png" + href="icon144.png" + /> +</head> + +<style> + * { + font-family: monospace; + background-color: #ec9740; + } +</style> + +<h1> + App to migrate from! App A. +</h1> + +<div> + This is app we are trying from! +</div> + +<div style="border: solid 1px grey; margin: 5px; padding: 5px;"> + Directory: + <ul> + <li><a href="index.html">migrate_from/a/index.html (here)</a></li> + <li><a href="../b/index.html">migrate_from/b/index.html</a></li> + <li><a href="../../migrate_to/index.html">migrate_to/index.html</a></li> + <li><a href="../../index.html">index.html</a></li> + </ul> +</div> + +<script> +navigator.serviceWorker.register('./serviceworker.js') +</script>
diff --git a/chrome/test/data/web_apps/mover/migrate_from/a/manifest.webmanifest b/chrome/test/data/web_apps/mover/migrate_from/a/manifest.webmanifest new file mode 100644 index 0000000..d169acb --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/a/manifest.webmanifest
@@ -0,0 +1,13 @@ +{ + "name": "App Migration Tester", + "description": "This is the migration source! A", + "start_url": "/web_apps/mover/migrate_from/a/index.html", + "display": "standalone", + "theme_color": "#ec9740", + "scope": "/web_apps/mover/migrate_from/a/", + "icons": [{ + "src": "icon144.png", + "sizes": "144x144", + "type": "image/png" + }] +} \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_from/a/serviceworker.js b/chrome/test/data/web_apps/mover/migrate_from/a/serviceworker.js new file mode 100644 index 0000000..8194787e --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/a/serviceworker.js
@@ -0,0 +1,9 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +self.addEventListener('fetch', event => { + event.respondWith(fetch(event.request).catch(_ => { + return new Response('Offline app migrator.'); + })); +}); \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_from/b/icon144.png b/chrome/test/data/web_apps/mover/migrate_from/b/icon144.png new file mode 100644 index 0000000..103d75a --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/b/icon144.png Binary files differ
diff --git a/chrome/test/data/web_apps/mover/migrate_from/b/index.html b/chrome/test/data/web_apps/mover/migrate_from/b/index.html new file mode 100644 index 0000000..bb8be807 --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/b/index.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> + +<head> + <title id="title">Migration has happened!</title> + <link rel="manifest" href="manifest.webmanifest" /> + <meta id="themeColor" name="theme-color" content="#ec9780" /> + <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> + <meta content="utf-8" http-equiv="encoding"> + <link + rel="icon" + type="image/png" + href="icon144.png" + /> +</head> + +<style> + * { + font-family: monospace; + background-color: #ec9780; + } +</style> + +<h1> + App to migrate from! App B. +</h1> + +<div> + This is app we are trying from! +</div> + +<div style="border: solid 1px grey; margin: 5px; padding: 5px;"> + Directory: + <ul> + <li><a href="../a/index.html">migrate_from/a/index.html</a></li> + <li><a href="index.html">migrate_from/b/index.html (here)</a></li> + <li><a href="../../migrate_to/index.html">migrate_to/index.html</a></li> + <li><a href="../../index.html">index.html</a></li> + </ul> +</div> + +<script> +navigator.serviceWorker.register('./serviceworker.js') +</script> \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_from/b/manifest.webmanifest b/chrome/test/data/web_apps/mover/migrate_from/b/manifest.webmanifest new file mode 100644 index 0000000..8d90575 --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/b/manifest.webmanifest
@@ -0,0 +1,13 @@ +{ + "name": "App Migration Tester", + "description": "This is the migration source! B", + "start_url": "/web_apps/mover/migrate_from/b/index.html", + "display": "standalone", + "theme_color": "#ec9780", + "scope": "/web_apps/mover/migrate_from/b/", + "icons": [{ + "src": "icon144.png", + "sizes": "144x144", + "type": "image/png" + }] +} \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_from/b/serviceworker.js b/chrome/test/data/web_apps/mover/migrate_from/b/serviceworker.js new file mode 100644 index 0000000..8194787e --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_from/b/serviceworker.js
@@ -0,0 +1,9 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +self.addEventListener('fetch', event => { + event.respondWith(fetch(event.request).catch(_ => { + return new Response('Offline app migrator.'); + })); +}); \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_to/icon144.png b/chrome/test/data/web_apps/mover/migrate_to/icon144.png new file mode 100644 index 0000000..103d75a --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_to/icon144.png Binary files differ
diff --git a/chrome/test/data/web_apps/mover/migrate_to/index.html b/chrome/test/data/web_apps/mover/migrate_to/index.html new file mode 100644 index 0000000..dd395d3 --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_to/index.html
@@ -0,0 +1,42 @@ +<!DOCTYPE html> + +<head> + <title id="title">Migration has happened!</title> + <link rel="manifest" href="manifest.webmanifest" /> + <meta id="themeColor" name="theme-color" content="#b2ec40" /> + <link + rel="icon" + type="image/png" + href="icon144.png" + /> +</head> + +<style> + * { + font-family: monospace; + background-color: #b2ec40; + } +</style> + +<h1> + Migration success! (probably) +</h1> + +<div> + This is app we are trying to migrate to! +</div> + + +<div style="border: solid 1px grey; margin: 5px; padding: 5px;"> + Directory: + <ul> + <li><a href="../migrate_from/a/index.html">migrate_from/a/index.html</a></li> + <li><a href="../migrate_from/b/index.html">migrate_from/b/index.html</a></li> + <li><a href="index.html">migrate_to/index.html (here)</a></li> + <li><a href="../index.html">index.html</a></li> + </ul> +</div> + +<script> +navigator.serviceWorker.register('./serviceworker.js') +</script> \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_to/manifest.webmanifest b/chrome/test/data/web_apps/mover/migrate_to/manifest.webmanifest new file mode 100644 index 0000000..c2e112305 --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_to/manifest.webmanifest
@@ -0,0 +1,13 @@ +{ + "name": "App Migration Tester", + "description": "This is the migration goal!", + "start_url": "/web_apps/mover/migrate_to/index.html", + "display": "standalone", + "theme_color": "#b2ec40", + "scope": "/web_apps/mover/migrate_to/", + "icons": [{ + "src": "icon144.png", + "sizes": "144x144", + "type": "image/png" + }] +} \ No newline at end of file
diff --git a/chrome/test/data/web_apps/mover/migrate_to/serviceworker.js b/chrome/test/data/web_apps/mover/migrate_to/serviceworker.js new file mode 100644 index 0000000..8194787e --- /dev/null +++ b/chrome/test/data/web_apps/mover/migrate_to/serviceworker.js
@@ -0,0 +1,9 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +self.addEventListener('fetch', event => { + event.respondWith(fetch(event.request).catch(_ => { + return new Response('Offline app migrator.'); + })); +}); \ No newline at end of file
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 96e909ed..d2b1a2b 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -74,7 +74,7 @@ # action so need to be separated out. sources = [ "../../../browser/ui/webui/identity_internals_ui_browsertest.js", - "../../../browser/ui/webui/sync_internals_browsertest.js", + "../../../browser/ui/webui/sync_internals/sync_internals_browsertest.js", "about_invalidations_browsertest.js", "assertions.js", "async_gen.js",
diff --git a/chrome/test/data/webui/bookmarks/bookmarks_browsertest.js b/chrome/test/data/webui/bookmarks/bookmarks_browsertest.js index 771b01f..5a8a9ba 100644 --- a/chrome/test/data/webui/bookmarks/bookmarks_browsertest.js +++ b/chrome/test/data/webui/bookmarks/bookmarks_browsertest.js
@@ -17,11 +17,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get typedefCppFixture() { return 'BookmarksBrowserTest'; }
diff --git a/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js b/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js index 163bb37..c73c69c 100644 --- a/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js +++ b/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js
@@ -16,11 +16,6 @@ get browsePreload() { throw 'this is abstract and should be overriden by subclasses'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/chromeos/account_manager/account_manager_browsertest.js b/chrome/test/data/webui/chromeos/account_manager/account_manager_browsertest.js index 0a2e523..8931a62 100644 --- a/chrome/test/data/webui/chromeos/account_manager/account_manager_browsertest.js +++ b/chrome/test/data/webui/chromeos/account_manager/account_manager_browsertest.js
@@ -15,11 +15,6 @@ get browsePreload() { return 'chrome://account-migration-welcome/test_loader.html?module=chromeos/account_manager/account_migration_welcome_test.js'; } - - /** @override */ - get extraLibraries() { - return []; - } }; TEST_F('AccountMigrationWelcomeTest', 'CloseDialog', () => {
diff --git a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js index 59845b99..37b948e 100644 --- a/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js +++ b/chrome/test/data/webui/chromeos/diagnostics/diagnostics_browsertest.js
@@ -31,11 +31,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { return { enabled: [
diff --git a/chrome/test/data/webui/chromeos/edu_coexistence/edu_coexistence_browsertest.js b/chrome/test/data/webui/chromeos/edu_coexistence/edu_coexistence_browsertest.js index fc779140..349663b 100644 --- a/chrome/test/data/webui/chromeos/edu_coexistence/edu_coexistence_browsertest.js +++ b/chrome/test/data/webui/chromeos/edu_coexistence/edu_coexistence_browsertest.js
@@ -18,11 +18,6 @@ throw 'this is abstract and should be overridden by subclasses'; } - /** @override */ - get extraLibraries() { - return []; - } - /** @param {string} testName The name of the test to run. */ runMochaTest(testName) { runMochaTest(this.suiteName, testName);
diff --git a/chrome/test/data/webui/chromeos/edu_login/edu_login_browsertest.js b/chrome/test/data/webui/chromeos/edu_login/edu_login_browsertest.js index 62a55f4..a74e85d 100644 --- a/chrome/test/data/webui/chromeos/edu_login/edu_login_browsertest.js +++ b/chrome/test/data/webui/chromeos/edu_login/edu_login_browsertest.js
@@ -18,11 +18,6 @@ throw 'this is abstract and should be overridden by subclasses'; } - /** @override */ - get extraLibraries() { - return []; - } - /** @param {string} testName The name of the test to run. */ runMochaTest(testName) { runMochaTest(this.suiteName, testName);
diff --git a/chrome/test/data/webui/chromeos/gaia_action_buttons/gaia_action_buttons_browsertest.js b/chrome/test/data/webui/chromeos/gaia_action_buttons/gaia_action_buttons_browsertest.js index caee405..913a435 100644 --- a/chrome/test/data/webui/chromeos/gaia_action_buttons/gaia_action_buttons_browsertest.js +++ b/chrome/test/data/webui/chromeos/gaia_action_buttons/gaia_action_buttons_browsertest.js
@@ -22,11 +22,6 @@ return gaia_action_buttons_test.suiteName; } - /** @override */ - get extraLibraries() { - return []; - } - /** @param {string} testName The name of the test to run. */ runMochaTest(testName) { runMochaTest(this.suiteName, testName);
diff --git a/chrome/test/data/webui/commander/commander_browsertest.js b/chrome/test/data/webui/commander/commander_browsertest.js index 99e38d3e..3e48fa8 100644 --- a/chrome/test/data/webui/commander/commander_browsertest.js +++ b/chrome/test/data/webui/commander/commander_browsertest.js
@@ -12,10 +12,6 @@ get browsePreload() { return 'chrome://commander/test_loader.html?module=commander/commander_app_test.js'; } - /** @override */ - get extraLibraries() { - return []; - } }; TEST_F('CommanderWebUIBrowserTest', 'All', function() {
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js index c95c8b1..cfb5ea7 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js +++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_browsertest.js
@@ -97,7 +97,7 @@ function registerTest(componentName, webuiHost, testName, module, deps) { const className = `${componentName}${testName}Test`; - this[className] = class extends PolymerTest { + this[className] = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return `chrome://${webuiHost}/`;
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js index e1e564c..792472e 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js +++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
@@ -60,11 +60,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { return { enabled: [
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_browsertest.js index 7357f25..ce14f10 100644 --- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -17,7 +17,7 @@ function CrComponentsBrowserTest() {} CrComponentsBrowserTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, /** @override */ get browsePreload() {
diff --git a/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js index 9b93f98..ff4c7c4 100644 --- a/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js
@@ -16,11 +16,6 @@ get browsePreload() { throw 'this is abstract and should be overriden by subclasses'; } - - /** @override */ - get extraLibraries() { - return []; - } }; var CrComponentsCustomizeThemesTest =
diff --git a/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js index 85d54278..33e0f64 100644 --- a/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_v3_browsertest.js
@@ -20,11 +20,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get webuiHost() { return 'dummyurl'; }
diff --git a/chrome/test/data/webui/cr_components/customize_themes_test.js b/chrome/test/data/webui/cr_components/customize_themes_test.js index a4e6a97..a15c60e 100644 --- a/chrome/test/data/webui/cr_components/customize_themes_test.js +++ b/chrome/test/data/webui/cr_components/customize_themes_test.js
@@ -169,14 +169,19 @@ await flushTasks(); // Assert. + const tilesWrapper = customizeThemesElement.shadowRoot.querySelectorAll( + 'div.chrome-theme-wrapper'); + assertEquals(tilesWrapper.length, themes.length); + tilesWrapper.forEach(function(tileWrapper, i) { + assertEquals(tileWrapper.getAttribute('aria-label'), themes[i].label); + }); + const tiles = customizeThemesElement.shadowRoot.querySelectorAll('cr-theme-icon'); assertEquals(tiles.length, 4); - assertEquals(tiles[2].getAttribute('aria-label'), 'theme_0'); assertStyle(tiles[2], '--cr-theme-icon-frame-color', 'rgba(0, 0, 0, 1)'); assertStyle( tiles[2], '--cr-theme-icon-active-tab-color', 'rgba(0, 0, 255, 1)'); - assertEquals(tiles[3].getAttribute('aria-label'), 'theme_1'); assertStyle(tiles[3], '--cr-theme-icon-frame-color', 'rgba(255, 0, 0, 1)'); assertStyle( tiles[3], '--cr-theme-icon-active-tab-color', 'rgba(0, 255, 0, 1)'); @@ -307,7 +312,10 @@ const selectedIcons = customizeThemesElement.shadowRoot.querySelectorAll( 'cr-theme-icon[selected]'); assertEquals(selectedIcons.length, 1); - assertEquals(selectedIcons[0].getAttribute('aria-label'), 'foo'); + const selectedIconWrapper = customizeThemesElement.shadowRoot.querySelector( + 'div.chrome-theme-wrapper'); + assertTrue(!!selectedIconWrapper.querySelector('cr-theme-icon[selected]')); + assertEquals(selectedIconWrapper.getAttribute('aria-label'), 'foo'); }); test('setting third-party theme shows uninstall UI', async () => {
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js index c763b9dc..6286e85a 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -17,11 +17,11 @@ function CrElementsBrowserTest() {} CrElementsBrowserTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, /** @override */ extraLibraries: [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '//ui/webui/resources/js/assert.js', ],
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js index 8911b0d..a834535a 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -12,7 +12,7 @@ function CrElementsFocusTest() {} CrElementsFocusTest.prototype = { - __proto__: PolymerInteractiveUITest.prototype, + __proto__: Polymer2DeprecatedInteractiveUITest.prototype, }; function CrElementsActionMenuTest() {} @@ -231,7 +231,7 @@ /** @override */ get extraLibraries() { return [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '../test_util.js', 'cr_toolbar_focus_tests.js', ]; @@ -252,7 +252,7 @@ /** @override */ get extraLibraries() { return [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '../test_util.js', 'iron_list_focus_test.js', ];
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js index d201dbb..87dce99b 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
@@ -19,11 +19,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get webuiHost() { return 'dummyurl'; }
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js index 1c1bb89..ec77c4b 100644 --- a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js +++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js
@@ -17,11 +17,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get webuiHost() { return 'dummyurl'; }
diff --git a/chrome/test/data/webui/cr_focus_outline_manager_test.js b/chrome/test/data/webui/cr_focus_outline_manager_test.js index bef79e6d..05cabc2 100644 --- a/chrome/test/data/webui/cr_focus_outline_manager_test.js +++ b/chrome/test/data/webui/cr_focus_outline_manager_test.js
@@ -12,7 +12,8 @@ GEN('#include "content/public/test/browser_test.h"'); // eslint-disable-next-line no-var -var FocusOutlineManagerTest = class extends PolymerInteractiveUITest { +var FocusOutlineManagerTest = + class extends Polymer2DeprecatedInteractiveUITest { /** @override */ get browsePreload() { return 'chrome://resources/html/cr/ui/focus_outline_manager.html';
diff --git a/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js b/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js index dc72a25a..38b55eba 100644 --- a/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js +++ b/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js
@@ -15,14 +15,14 @@ function CrFocusRowBehaviorTest() {} CrFocusRowBehaviorTest.prototype = { - __proto__: PolymerInteractiveUITest.prototype, + __proto__: Polymer2DeprecatedInteractiveUITest.prototype, /** @override */ browsePreload: 'chrome://resources/html/cr/ui/focus_row_behavior.html', /** @override */ extraLibraries: [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '//ui/webui/resources/js/util.js', 'cr_focus_row_behavior_test.js', 'test_util.js',
diff --git a/chrome/test/data/webui/cr_focus_row_behavior_v3_interactive_test.js b/chrome/test/data/webui/cr_focus_row_behavior_v3_interactive_test.js index 01422f2..f0b8518 100644 --- a/chrome/test/data/webui/cr_focus_row_behavior_v3_interactive_test.js +++ b/chrome/test/data/webui/cr_focus_row_behavior_v3_interactive_test.js
@@ -22,11 +22,6 @@ get webuiHost() { return 'dummyurl'; } - - /** @override */ - get extraLibraries() { - return []; - } }; TEST_F('CrFocusRowBehaviorV3Test', 'FocusTest', function() {
diff --git a/chrome/test/data/webui/discards/discards_browsertest.js b/chrome/test/data/webui/discards/discards_browsertest.js index 3e6f12b..c37103d 100644 --- a/chrome/test/data/webui/discards/discards_browsertest.js +++ b/chrome/test/data/webui/discards/discards_browsertest.js
@@ -12,10 +12,6 @@ get browsePreload() { return 'chrome://discards/test_loader.html?module=discards/discards_test.js'; } - - get extraLibraries() { - return []; - } };
diff --git a/chrome/test/data/webui/downloads/downloads_browsertest.js b/chrome/test/data/webui/downloads/downloads_browsertest.js index a5f9dfb..85b1f50 100644 --- a/chrome/test/data/webui/downloads/downloads_browsertest.js +++ b/chrome/test/data/webui/downloads/downloads_browsertest.js
@@ -15,11 +15,6 @@ get browsePreload() { return 'chrome://downloads'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js index a8608e0..380968b8 100644 --- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js +++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -22,11 +22,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get typedefCppFixture() { return 'ExtensionSettingsUIBrowserTest'; }
diff --git a/chrome/test/data/webui/extensions/cr_extensions_interactive_ui_tests.js b/chrome/test/data/webui/extensions/cr_extensions_interactive_ui_tests.js index 1f41b059..1aa9067 100644 --- a/chrome/test/data/webui/extensions/cr_extensions_interactive_ui_tests.js +++ b/chrome/test/data/webui/extensions/cr_extensions_interactive_ui_tests.js
@@ -22,11 +22,6 @@ return 'chrome://extensions/'; } - /** @override */ - get extraLibraries() { - return []; - } - // The name of the mocha suite. Should be overridden by subclasses. get suiteName() { return null;
diff --git a/chrome/test/data/webui/history/history_browsertest.js b/chrome/test/data/webui/history/history_browsertest.js index 0078afb56..e1cccc7 100644 --- a/chrome/test/data/webui/history/history_browsertest.js +++ b/chrome/test/data/webui/history/history_browsertest.js
@@ -17,11 +17,6 @@ get browsePreload() { return 'chrome://history/'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/history/history_focus_test.js b/chrome/test/data/webui/history/history_focus_test.js index 91222ea..9849ea9 100644 --- a/chrome/test/data/webui/history/history_focus_test.js +++ b/chrome/test/data/webui/history/history_focus_test.js
@@ -16,11 +16,6 @@ get browsePreload() { return 'chrome://history/'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/inline_login/inline_login_browsertest.js b/chrome/test/data/webui/inline_login/inline_login_browsertest.js index 3de82af5..fb128c8 100644 --- a/chrome/test/data/webui/inline_login/inline_login_browsertest.js +++ b/chrome/test/data/webui/inline_login/inline_login_browsertest.js
@@ -27,11 +27,6 @@ return inline_login_test.suiteName; } - /** @override */ - get extraLibraries() { - return []; - } - /** @param {string} testName The name of the test to run. */ runMochaTest(testName) { runMochaTest(this.suiteName, testName);
diff --git a/chrome/test/data/webui/interventions_internals_browsertest.js b/chrome/test/data/webui/interventions_internals_browsertest.js index 62769a6e..280404a 100644 --- a/chrome/test/data/webui/interventions_internals_browsertest.js +++ b/chrome/test/data/webui/interventions_internals_browsertest.js
@@ -186,7 +186,7 @@ TEST_F('InterventionsInternalsUITest', 'LogNewMessage', function() { test('LogMessageIsPostedCorrectly', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let logs = [ { type: 'Type_a', @@ -225,7 +225,7 @@ // log table). expectEquals( - getTimeFormat(log.time), row.querySelector('.log-time').textContent); + window.getTimeFormat(log.time), row.querySelector('.log-time').textContent); expectEquals(log.type, row.querySelector('.log-type').textContent); expectEquals( log.description, row.querySelector('.log-description').textContent); @@ -239,7 +239,7 @@ TEST_F('InterventionsInternalsUITest', 'LogNewMessageWithLongUrl', function() { test('LogMessageIsPostedCorrectly', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let log = { type: 'Some type', url: {url: ''}, @@ -263,7 +263,7 @@ TEST_F('InterventionsInternalsUITest', 'LogNewMessageWithNoUrl', function() { test('LogMessageIsPostedCorrectly', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let log = { type: 'Some type', url: {url: ''}, @@ -285,7 +285,7 @@ TEST_F('InterventionsInternalsUITest', 'LogNewMessagePageIdZero', function() { test('LogMessageWithPageIdZero', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let logs = [ { type: 'Type_a', @@ -330,7 +330,7 @@ TEST_F('InterventionsInternalsUITest', 'LogNewMessageNewPageId', function() { test('LogMessageWithNewPageId', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let logs = [ { type: 'Type_a', @@ -375,7 +375,7 @@ TEST_F( 'InterventionsInternalsUITest', 'LogNewMessageExistedPageId', function() { test('LogMessageWithExistedPageId', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let logs = [ { type: 'Type_a', @@ -437,7 +437,7 @@ 'InterventionsInternalsUITest', 'LogNewMessageExistedPageIdGroupToTopOfTable', function() { test('NewMessagePushedToTopOfTable', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let logs = [ { type: 'Type_a', @@ -486,7 +486,7 @@ TEST_F('InterventionsInternalsUITest', 'AddNewBlocklistedHost', function() { test('AddNewBlocklistedHost', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let time = 758675653000; // Jan 15 1994 23:14:13 UTC let expectedHost = 'example.com'; pageImpl.onBlocklistedHost(expectedHost, time); @@ -507,7 +507,7 @@ TEST_F('InterventionsInternalsUITest', 'HostAlreadyBlocklisted', function() { test('HostAlreadyBlocklisted', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let time0 = 758675653000; // Jan 15 1994 23:14:13 UTC let time1 = 1507221689240; // Oct 05 2017 16:41:29 UTC let expectedHost = 'example.com'; @@ -536,7 +536,7 @@ TEST_F('InterventionsInternalsUITest', 'UpdateUserBlocklisted', function() { test('UpdateUserBlocklistedDisplayCorrectly', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let state = $('user-blocklisted-status-value'); pageImpl.onUserBlocklistedStatusChange(true /* blocklisted */); @@ -553,7 +553,7 @@ TEST_F('InterventionsInternalsUITest', 'OnBlocklistCleared', function() { test('OnBlocklistClearedRemovesAllBlocklistedHostInTable', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let state = $('user-blocklisted-status-value'); let time = 758675653000; // Jan 15 1994 23:14:13 UTC @@ -572,7 +572,7 @@ 'InterventionsInternalsUITest', 'ClearLogMessageOnBlocklistCleared', function() { test('ClearLogsTableOnBlocklistCleared', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let time = 758675653000; // Jan 15 1994 23:14:13 UTC let log = { type: 'Some type', @@ -598,7 +598,7 @@ TEST_F('InterventionsInternalsUITest', 'OnECTChanged', function() { test('UpdateETCOnChange', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); let ectTypes = ['type1', 'type2', 'type3']; ectTypes.forEach((type) => { pageImpl.updateEffectiveConnectionType(type, 'max'); @@ -612,7 +612,7 @@ TEST_F('InterventionsInternalsUITest', 'OnBlocklistIgnoreChange', function() { test('OnBlocklistIgnoreChangeDisable', () => { - let pageImpl = new InterventionsInternalPageImpl(null); + let pageImpl = new window.InterventionsInternalPageImpl(null); pageImpl.onIgnoreBlocklistDecisionStatusChanged(true /* ignored */); expectEquals('Enable Blocklist', $('ignore-blocklist-button').textContent); expectEquals(
diff --git a/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js index 66ad9106..65e259150 100644 --- a/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js +++ b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
@@ -17,12 +17,12 @@ function MultiDeviceSetupBrowserTest() {} MultiDeviceSetupBrowserTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, browsePreload: 'chrome://multidevice-setup/', extraLibraries: [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '../test_browser_proxy.js', '../fake_chrome_event.js', // Necessary for fake_quick_unlock_private.js '../settings/chromeos/fake_quick_unlock_private.js',
diff --git a/chrome/test/data/webui/nearby_share/nearby_browsertest.js b/chrome/test/data/webui/nearby_share/nearby_browsertest.js index 6df9cf3..d8b9495 100644 --- a/chrome/test/data/webui/nearby_share/nearby_browsertest.js +++ b/chrome/test/data/webui/nearby_share/nearby_browsertest.js
@@ -17,15 +17,6 @@ throw 'this is abstract and should be overridden by subclasses'; } - /** - * Override default |extraLibraries| since PolymerTest includes more than are - * needed in JS Module based tests. - * @override - */ - get extraLibraries() { - return []; - } - /** @override */ get webuiHost() { return 'nearby';
diff --git a/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js b/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js index ff9f729..45be795 100644 --- a/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js +++ b/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js
@@ -10,7 +10,7 @@ GEN('#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"'); GEN('#include "content/public/test/browser_test.h"'); -const NearbySharedBrowserTest = class extends PolymerTest { +const NearbySharedBrowserTest = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return 'chrome://os-settings/';
diff --git a/chrome/test/data/webui/nearby_share/shared/nearby_shared_v3_browsertest.js b/chrome/test/data/webui/nearby_share/shared/nearby_shared_v3_browsertest.js index a98f805..ab4cfd9 100644 --- a/chrome/test/data/webui/nearby_share/shared/nearby_shared_v3_browsertest.js +++ b/chrome/test/data/webui/nearby_share/shared/nearby_shared_v3_browsertest.js
@@ -12,15 +12,6 @@ /** Test fixture for Polymer Nearby Share Shared elements. */ const NearbySharedV3Test = class extends PolymerTest { - /** - * Override default |extraLibraries| since PolymerTest includes more than are - * needed in JS Module based tests. - * @override - */ - get extraLibraries() { - return []; - } - /** @override */ get webuiHost() { return 'nearby';
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js index 375f2f7a..e1fe4db 100644 --- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js +++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
@@ -13,11 +13,6 @@ get browsePreload() { throw 'this is abstract and should be overriden by subclasses'; } - - /** @override */ - get extraLibraries() { - return []; - } } // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js b/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js index 94ffd0d..1a85d227 100644 --- a/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js +++ b/chrome/test/data/webui/new_tab_page/new_tab_page_interactive_test.js
@@ -13,11 +13,6 @@ get browsePreload() { throw 'this is abstract and should be overriden by subclasses'; } - - /** @override */ - get extraLibraries() { - return []; - } } // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/polymer_browser_test_base.js b/chrome/test/data/webui/polymer_browser_test_base.js index 2a7ec70..5f218b20 100644 --- a/chrome/test/data/webui/polymer_browser_test_base.js +++ b/chrome/test/data/webui/polymer_browser_test_base.js
@@ -29,6 +29,19 @@ * @final */ isAsync: true, +}; + +/** + * Test fixture for Polymer2 elements testing (deprecated). + * TODO(crbug.com/965770): Delete once all remaining Polymer2 UIs have been + * migrated. + * @constructor + * @extends PolymerTest + */ +function Polymer2DeprecatedTest() {} + +Polymer2DeprecatedTest.prototype = { + __proto__: PolymerTest.prototype, /** * Files that need not be compiled.
diff --git a/chrome/test/data/webui/polymer_interactive_ui_test.js b/chrome/test/data/webui/polymer_interactive_ui_test.js index a754f38..c429501b 100644 --- a/chrome/test/data/webui/polymer_interactive_ui_test.js +++ b/chrome/test/data/webui/polymer_interactive_ui_test.js
@@ -20,3 +20,18 @@ GEN(' browser()->tab_strip_model()->GetActiveWebContents()->Focus();'); }, }; + +// TODO(crbug.com/965770): Delete once all remaining Polymer2 UIs have been +// migrated. +function Polymer2DeprecatedInteractiveUITest() {} + +Polymer2DeprecatedInteractiveUITest.prototype = { + __proto__: Polymer2DeprecatedTest.prototype, + + /** @override */ + testGenPreamble: function() { + // Must explicitly focus the web contents before running the test on Mac. + // See: https://crbug.com/642467. + GEN(' browser()->tab_strip_model()->GetActiveWebContents()->Focus();'); + }, +};
diff --git a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js index f395a166..c35bdfd 100644 --- a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js +++ b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
@@ -15,11 +15,6 @@ throw 'this is abstract and should be overriden by subclasses'; } - /** @override */ - get extraLibraries() { - return []; - } - // The name of the mocha suite. Should be overridden by subclasses. get suiteName() { return null;
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js index 66d6d40f..0a5a0fc 100644 --- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js +++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -15,11 +15,6 @@ return 'chrome://print/'; } - /** @override */ - get extraLibraries() { - return []; - } - // The name of the mocha suite. Should be overridden by subclasses. get suiteName() { return null;
diff --git a/chrome/test/data/webui/read_later/read_later_browsertest.js b/chrome/test/data/webui/read_later/read_later_browsertest.js index 215fdde..c38aa63 100644 --- a/chrome/test/data/webui/read_later/read_later_browsertest.js +++ b/chrome/test/data/webui/read_later/read_later_browsertest.js
@@ -14,10 +14,6 @@ throw 'this is abstract and should be overriden by subclasses'; } - get extraLibraries() { - return []; - } - /** @override */ get featureList() { return {enabled: ['reading_list::switches::kReadLater']};
diff --git a/chrome/test/data/webui/resources/webui_resources_browsertest.js b/chrome/test/data/webui/resources/webui_resources_browsertest.js index cf446a3..72ca0e7 100644 --- a/chrome/test/data/webui/resources/webui_resources_browsertest.js +++ b/chrome/test/data/webui/resources/webui_resources_browsertest.js
@@ -17,7 +17,7 @@ function WebUIResourcesBrowserTest() {} WebUIResourcesBrowserTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, /** @override */ get browsePreload() {
diff --git a/chrome/test/data/webui/resources/webui_resources_v3_browsertest.js b/chrome/test/data/webui/resources/webui_resources_v3_browsertest.js index e3c010a..64963c3d 100644 --- a/chrome/test/data/webui/resources/webui_resources_v3_browsertest.js +++ b/chrome/test/data/webui/resources/webui_resources_v3_browsertest.js
@@ -20,11 +20,6 @@ get webuiHost() { return 'dummyurl'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var
diff --git a/chrome/test/data/webui/set_time_dialog_browsertest.js b/chrome/test/data/webui/set_time_dialog_browsertest.js index 62fbdfb..a77ed2d 100644 --- a/chrome/test/data/webui/set_time_dialog_browsertest.js +++ b/chrome/test/data/webui/set_time_dialog_browsertest.js
@@ -13,11 +13,6 @@ get browsePreload() { return 'chrome://set-time/test_loader.html?module=set_time_dialog_test.js'; } - - /** @override */ - get extraLibraries() { - return []; - } }; TEST_F('SetTimeDialogBrowserTest', 'All', function() {
diff --git a/chrome/test/data/webui/settings/chromeos/a11y/crostini_accessibility_test.js b/chrome/test/data/webui/settings/chromeos/a11y/crostini_accessibility_test.js index 5eb7f1f..574b79e 100644 --- a/chrome/test/data/webui/settings/chromeos/a11y/crostini_accessibility_test.js +++ b/chrome/test/data/webui/settings/chromeos/a11y/crostini_accessibility_test.js
@@ -22,7 +22,7 @@ GEN('#include "components/prefs/pref_service.h"'); // eslint-disable-next-line no-var -var CrostiniAccessibilityTest = class extends PolymerTest { +var CrostiniAccessibilityTest = class extends Polymer2DeprecatedTest { /** @override */ get featureList() { return {enabled: ['features::kCrostini']};
diff --git a/chrome/test/data/webui/settings/chromeos/a11y/google_assistant_a11y_test.js b/chrome/test/data/webui/settings/chromeos/a11y/google_assistant_a11y_test.js index c6e4b7868..f10eddc 100644 --- a/chrome/test/data/webui/settings/chromeos/a11y/google_assistant_a11y_test.js +++ b/chrome/test/data/webui/settings/chromeos/a11y/google_assistant_a11y_test.js
@@ -16,7 +16,7 @@ GEN('#include "content/public/test/browser_test.h"'); // eslint-disable-next-line no-var -var GoogleAssistantA11yTest = class extends PolymerTest { +var GoogleAssistantA11yTest = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return 'chrome://os-settings/';
diff --git a/chrome/test/data/webui/settings/chromeos/a11y/os_settings_accessibility_test.js b/chrome/test/data/webui/settings/chromeos/a11y/os_settings_accessibility_test.js index b3092a8..32be451c 100644 --- a/chrome/test/data/webui/settings/chromeos/a11y/os_settings_accessibility_test.js +++ b/chrome/test/data/webui/settings/chromeos/a11y/os_settings_accessibility_test.js
@@ -13,7 +13,7 @@ /** * Test fixture for Accessibility of Chrome Settings. * @constructor - * @extends {PolymerTest} + * @extends {Polymer2DeprecatedTest} */ function OSSettingsAccessibilityTest() {} @@ -70,7 +70,7 @@ }; OSSettingsAccessibilityTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, /** @override */ browsePreload: 'chrome://os-settings/',
diff --git a/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js b/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js index 581a41323..3ef9f51f 100644 --- a/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/ambient_mode_photos_page_test.js
@@ -5,10 +5,11 @@ // clang-format off // #import 'chrome://os-settings/chromeos/os_settings.js'; -// #import {AmbientModeBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js'; +// #import {AmbientModeTopicSource, AmbientModeBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js'; // #import {TestBrowserProxy} from '../../test_browser_proxy.m.js'; // #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {waitAfterNextRender} from 'chrome://test/test_util.m.js'; // clang-format on /** @@ -260,6 +261,41 @@ assertEquals(4, selectedAlbumsChangedEventCalls); }); + test('notDeselectLastArtAlbum', async () => { + ambientModePhotosPage.albums = [ + {albumId: 'id0', checked: true, title: 'album0', url: 'url'}, + {albumId: 'id1', checked: true, title: 'album1', url: 'url'} + ]; + ambientModePhotosPage.topicSource = AmbientModeTopicSource.ART_GALLERY; + Polymer.dom.flush(); + + const albumList = ambientModePhotosPage.$$('album-list'); + const ironList = albumList.$$('iron-list'); + const albumItems = ironList.querySelectorAll('album-item:not([hidden])'); + assertEquals(2, albumItems.length); + + const album0 = albumItems[0]; + const album1 = albumItems[1]; + assertTrue(album0.checked); + assertTrue(album1.checked); + + // Click album item image will toggle the check. + const image0 = album0.$$('#image'); + image0.click(); + assertFalse(album0.checked); + + // Click the last art album item image will not toggle the check and will + // show a dialog. + const image1 = album1.$$('#image'); + image1.click(); + assertTrue(album1.checked); + Polymer.dom.flush(); + + const artAlbumDialog = ambientModePhotosPage.$$('art-album-dialog'); + await test_util.waitAfterNextRender(artAlbumDialog); + assertTrue(artAlbumDialog.$$('#dialog').open); + }); + test('showCheckIconOnSelectedAlbum', function() { ambientModePhotosPage.albums = [ {albumId: 'id0', checked: true, title: 'album0', url: 'url'},
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 f1fb6ae..038583b2 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -14,7 +14,7 @@ Power: 'power', Storage: 'storage', Stylus: 'stylus', - KeyboardArrangement: 'arrow key arrangement', + KeyboardArrangementDisabled: 'arrow key arrangement disabled', }; /** @@ -1339,7 +1339,82 @@ 'Display mirroring checkbox should be focused for settingId=428.'); }); - test('Keyboard display arrangement diasabled test', async () => { + test('Keyboard display arrangement', async () => { + addDisplay(1); + addDisplay(2); + fakeSystemDisplay.onDisplayChanged.callListeners(); + + return Promise + .all([ + fakeSystemDisplay.getInfoCalled.promise, + fakeSystemDisplay.getLayoutCalled.promise, + ]) + .then(() => { + return new Promise(resolve => { + Polymer.dom.flush(); + + assert(displayPage); + assertEquals(2, displayPage.displays.length); + assertTrue(displayPage.shouldShowArrangementSection_()); + + expectTrue(!!displayPage.$$('#arrangement-section')); + + expectTrue( + displayPage.showMirror_(false, displayPage.displays)); + expectFalse(displayPage.isMirrored_(displayPage.displays)); + + Polymer.dom.flush(); + + displayPage.async(resolve); + }); + }) + .then(() => { + const displayLayout = displayPage.$$('#displayLayout'); + const display = displayLayout.$$('#_fakeDisplayId2'); + const layout = + displayLayout.displayLayoutMap_.get('fakeDisplayId2'); + + expectEquals(layout.parentId, 'fakeDisplayId1'); + expectEquals(layout.position, 'right'); + + const offset = displayLayout.keyboardDragStepSize / + displayLayout.visualScale; + + display.focus(); + + display.dispatchEvent(new KeyboardEvent( + 'keydown', {key: 'ArrowDown', bubbles: true})); + display.dispatchEvent( + new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); + expectEquals(offset, layout.offset); + + display.dispatchEvent(new KeyboardEvent( + 'keydown', {key: 'ArrowDown', bubbles: true})); + display.dispatchEvent( + new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); + expectEquals(offset * 2, layout.offset); + + display.dispatchEvent(new KeyboardEvent( + 'keydown', {key: 'ArrowUp', bubbles: true})); + display.dispatchEvent( + new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); + expectEquals(offset, layout.offset); + }); + }); + }); + + suite(assert(TestNames.KeyboardArrangementDisabled), function() { + let displayPage; + let browserProxy; + + setup(async () => { + displayPage = + await showAndGetDeviceSubpage('display', settings.routes.DISPLAY); + browserProxy = settings.DevicePageBrowserProxyImpl.getInstance(); + await fakeSystemDisplay.getInfoCalled.promise; + }); + + test('Arrow key arrangement diasabled test', async () => { addDisplay(1); addDisplay(2); fakeSystemDisplay.onDisplayChanged.callListeners(); @@ -1408,80 +1483,6 @@ }); }); - suite(assert(TestNames.KeyboardArrangement), function() { - let displayPage; - let browserProxy; - - setup(async () => { - displayPage = - await showAndGetDeviceSubpage('display', settings.routes.DISPLAY); - browserProxy = settings.DevicePageBrowserProxyImpl.getInstance(); - await fakeSystemDisplay.getInfoCalled.promise; - }); - - test('Arrow key arrangement enabled test', async () => { - addDisplay(1); - addDisplay(2); - fakeSystemDisplay.onDisplayChanged.callListeners(); - - return Promise - .all([ - fakeSystemDisplay.getInfoCalled.promise, - fakeSystemDisplay.getLayoutCalled.promise, - ]) - .then(() => { - return new Promise(resolve => { - Polymer.dom.flush(); - - assert(displayPage); - assertEquals(2, displayPage.displays.length); - assertTrue(displayPage.shouldShowArrangementSection_()); - - expectTrue(!!displayPage.$$('#arrangement-section')); - - expectTrue( - displayPage.showMirror_(false, displayPage.displays)); - expectFalse(displayPage.isMirrored_(displayPage.displays)); - - Polymer.dom.flush(); - - displayPage.async(resolve); - }); - }) - .then(() => { - const displayLayout = displayPage.$$('#displayLayout'); - const display = displayLayout.$$('#_fakeDisplayId2'); - const layout = - displayLayout.displayLayoutMap_.get('fakeDisplayId2'); - - expectEquals(layout.parentId, 'fakeDisplayId1'); - expectEquals(layout.position, 'right'); - - const offset = displayLayout.keyboardDragStepSize / - displayLayout.visualScale; - - display.focus(); - display.dispatchEvent(new KeyboardEvent( - 'keydown', {key: 'ArrowDown', bubbles: true})); - display.dispatchEvent( - new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); - expectEquals(offset, layout.offset); - - display.dispatchEvent(new KeyboardEvent( - 'keydown', {key: 'ArrowDown', bubbles: true})); - display.dispatchEvent( - new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); - expectEquals(offset * 2, layout.offset); - - display.dispatchEvent(new KeyboardEvent( - 'keydown', {key: 'ArrowUp', bubbles: true})); - display.dispatchEvent( - new KeyboardEvent('keydown', {key: 'Enter', bubbles: true})); - expectEquals(offset, layout.offset); - }); - }); - }); - test(assert(TestNames.NightLight), async function() { // Set up a single display. const displayPage =
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js index d50d4126..5f1fdf4c 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -25,7 +25,7 @@ // Generic test fixture for CrOS Polymer Settings elements to be overridden by // individual element tests. -const OSSettingsBrowserTest = class extends PolymerTest { +const OSSettingsBrowserTest = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return 'chrome://os-settings/'; @@ -347,6 +347,7 @@ get extraLibraries() { return super.extraLibraries.concat([ BROWSER_SETTINGS_PATH + '../test_browser_proxy.js', + BROWSER_SETTINGS_PATH + '../test_util.js', 'ambient_mode_photos_page_test.js', ]); } @@ -748,8 +749,9 @@ return { enabled: [ 'ash::features::kDisplayIdentification', + 'ash::features::kKeyboardBasedDisplayArrangementInSettings', 'display::features::kListAllDisplayModes' - ] + ], }; } @@ -802,14 +804,14 @@ mocha.grep(assert(device_page_tests.TestNames.Stylus)).run(); }); -// Tests for the Device page with keyboard arrangement flag enabled. +// Tests for the Device page with keyboard arrangement flag disabled. // eslint-disable-next-line no-var -var OSSettingsDevicePageKeyboardArrangementTest = +var OSSettingsDevicePageKeyboardArrangementDisabledTest = class extends OSSettingsDevicePageTest { /** @override */ get featureList() { return { - enabled: [ + disabled: [ 'ash::features::kKeyboardBasedDisplayArrangementInSettings', ] }; @@ -817,9 +819,11 @@ }; TEST_F( - 'OSSettingsDevicePageKeyboardArrangementTest', 'KeyboardArrangement', - () => { - mocha.grep(assert(device_page_tests.TestNames.KeyboardArrangement)).run(); + 'OSSettingsDevicePageKeyboardArrangementDisabledTest', + 'KeyboardArrangement', () => { + mocha + .grep(assert(device_page_tests.TestNames.KeyboardArrangementDisabled)) + .run(); }); // Tests for the Fingerprint page.
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js index a6c167b..7cefab727 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js
@@ -26,7 +26,7 @@ // Test fixture for the top-level OS settings UI. // eslint-disable-next-line no-var -var OSSettingsUIBrowserTest = class extends PolymerTest { +var OSSettingsUIBrowserTest = class extends Polymer2DeprecatedTest { /** @override */ get browsePreload() { return 'chrome://os-settings/';
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js index 1f17824d..457415e 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -21,11 +21,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { return { enabled: [
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js index 391b2e3..ed5686b 100644 --- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -22,11 +22,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { if (!this.featureListInternal.enabled && !this.featureListInternal.disabled) {
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js index 05c3629c..58ce9c71 100644 --- a/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js +++ b/chrome/test/data/webui/settings/cr_settings_v3_interactive_ui_tests.js
@@ -16,11 +16,6 @@ get browsePreload() { return 'chrome://settings'; } - - /** @override */ - get extraLibraries() { - return []; - } }; // eslint-disable-next-line no-var @@ -124,4 +119,4 @@ TEST_F('CrSettingsMenuV3InteractiveTest', 'All', function() { mocha.run(); -}); \ No newline at end of file +});
diff --git a/chrome/test/data/webui/settings/privacy_sandbox_browsertest.js b/chrome/test/data/webui/settings/privacy_sandbox_browsertest.js index 981da47..fd44155 100644 --- a/chrome/test/data/webui/settings/privacy_sandbox_browsertest.js +++ b/chrome/test/data/webui/settings/privacy_sandbox_browsertest.js
@@ -18,11 +18,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { return {enabled: ['features::kPrivacySandboxSettings']}; }
diff --git a/chrome/test/data/webui/signin/local_profile_customization_interactive_ui_test.js b/chrome/test/data/webui/signin/local_profile_customization_interactive_ui_test.js index 8221a57..1f760efc 100644 --- a/chrome/test/data/webui/signin/local_profile_customization_interactive_ui_test.js +++ b/chrome/test/data/webui/signin/local_profile_customization_interactive_ui_test.js
@@ -18,11 +18,6 @@ } /** @override */ - get extraLibraries() { - return []; - } - - /** @override */ get featureList() { return { enabled: [
diff --git a/chrome/test/data/webui/signin/signin_browsertest.js b/chrome/test/data/webui/signin/signin_browsertest.js index ec6e5fdc..9f6d7e7 100644 --- a/chrome/test/data/webui/signin/signin_browsertest.js +++ b/chrome/test/data/webui/signin/signin_browsertest.js
@@ -17,14 +17,6 @@ get browsePreload() { throw 'this is abstract and should be overriden by subclasses'; } - - /** @override */ - get extraLibraries() { - return [ - '//third_party/mocha/mocha.js', - '//chrome/test/data/webui/mocha_adapter.js', - ]; - } } /**
diff --git a/chrome/test/data/webui/tab_search/tab_search_browsertest.js b/chrome/test/data/webui/tab_search/tab_search_browsertest.js index 6a9eca5..5831d58 100644 --- a/chrome/test/data/webui/tab_search/tab_search_browsertest.js +++ b/chrome/test/data/webui/tab_search/tab_search_browsertest.js
@@ -15,10 +15,6 @@ throw 'this is abstract and should be overriden by subclasses'; } - get extraLibraries() { - return []; - } - /** @override */ get featureList() { return {
diff --git a/chrome/test/data/webui/tab_search/tab_search_interactive_ui_tests.js b/chrome/test/data/webui/tab_search/tab_search_interactive_ui_tests.js index 3302245..afbd71781 100644 --- a/chrome/test/data/webui/tab_search/tab_search_interactive_ui_tests.js +++ b/chrome/test/data/webui/tab_search/tab_search_interactive_ui_tests.js
@@ -17,10 +17,6 @@ return 'chrome://tab-search/test_loader.html?module=tab_search/tab_search_app_focus_test.js'; } - get extraLibraries() { - return []; - } - /** @override */ get featureList() { return {
diff --git a/chrome/test/data/webui/tab_strip/tab_strip_browsertest.js b/chrome/test/data/webui/tab_strip/tab_strip_browsertest.js index 09dccce..b590ba71 100644 --- a/chrome/test/data/webui/tab_strip/tab_strip_browsertest.js +++ b/chrome/test/data/webui/tab_strip/tab_strip_browsertest.js
@@ -12,10 +12,6 @@ get webuiHost() { return 'tab-strip'; } - - get extraLibraries() { - return []; - } }; var TabStripTabListTest = class extends TabStripBrowserTest {
diff --git a/chrome/test/data/webui/usb_internals_browsertest.js b/chrome/test/data/webui/usb_internals_browsertest.js index 7ab52ac2..94d8956 100644 --- a/chrome/test/data/webui/usb_internals_browsertest.js +++ b/chrome/test/data/webui/usb_internals_browsertest.js
@@ -23,9 +23,6 @@ /** @override */ isAsync: true, - - /** @override */ - extraLibraries: [], }; TEST_F('UsbInternalsTest', 'WebUIValueRenderTest', function() {
diff --git a/chrome/test/data/webui/user_manager/user_manager_browsertest.js b/chrome/test/data/webui/user_manager/user_manager_browsertest.js index 7f75cb8..7d66bb71 100644 --- a/chrome/test/data/webui/user_manager/user_manager_browsertest.js +++ b/chrome/test/data/webui/user_manager/user_manager_browsertest.js
@@ -17,14 +17,14 @@ function UserManagerBrowserTest() {} UserManagerBrowserTest.prototype = { - __proto__: PolymerTest.prototype, + __proto__: Polymer2DeprecatedTest.prototype, /** @override */ browsePreload: 'chrome://md-user-manager/', /** @override */ extraLibraries: [ - ...PolymerTest.prototype.extraLibraries, + ...Polymer2DeprecatedTest.prototype.extraLibraries, '../test_browser_proxy.js', 'control_bar_tests.js', 'create_profile_tests.js',
diff --git a/chrome/test/data/webui/welcome/welcome_browsertest.js b/chrome/test/data/webui/welcome/welcome_browsertest.js index c493d3e6..9cb2303 100644 --- a/chrome/test/data/webui/welcome/welcome_browsertest.js +++ b/chrome/test/data/webui/welcome/welcome_browsertest.js
@@ -17,15 +17,6 @@ throw 'this is abstract and should be overridden by subclasses'; } - /** - * Override default |extraLibraries| since PolymerTest includes more than are - * needed in JS Module based tests. - * @override - */ - get extraLibraries() { - return []; - } - /** @override */ get webuiHost() { return 'welcome';
diff --git a/chrome/utility/safe_browsing/mac/hfs.cc b/chrome/utility/safe_browsing/mac/hfs.cc index 5adc60e..7c71a07 100644 --- a/chrome/utility/safe_browsing/mac/hfs.cc +++ b/chrome/utility/safe_browsing/mac/hfs.cc
@@ -23,7 +23,7 @@ namespace dmg { // UTF-16 character for file path seprator. -static const uint16_t kFilePathSeparator = '/'; +static const base::char16 kFilePathSeparator = '/'; static void ConvertBigEndian(HFSPlusForkData* fork) { ConvertBigEndian(&fork->logicalSize);
diff --git a/chromeos/components/scanning/resources/BUILD.gn b/chromeos/components/scanning/resources/BUILD.gn index d14228c..48bab69 100644 --- a/chromeos/components/scanning/resources/BUILD.gn +++ b/chromeos/components/scanning/resources/BUILD.gn
@@ -128,6 +128,7 @@ ":scanning_browser_proxy", ":source_select", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m", "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m", "//ui/webui/resources/js:i18n_behavior.m", ]
diff --git a/chromeos/components/scanning/resources/index.html b/chromeos/components/scanning/resources/index.html index da14e63..a0aa0ffc 100644 --- a/chromeos/components/scanning/resources/index.html +++ b/chromeos/components/scanning/resources/index.html
@@ -2,7 +2,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <!DOCTYPE html> -<html> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> <head> <meta charset="utf-8"> <title>$i18n{appTitle}</title>
diff --git a/chromeos/components/scanning/resources/scanning_app.html b/chromeos/components/scanning/resources/scanning_app.html index c83754b0..4192ea9 100644 --- a/chromeos/components/scanning/resources/scanning_app.html +++ b/chromeos/components/scanning/resources/scanning_app.html
@@ -76,13 +76,34 @@ margin-inline-start: var(--right-panel-margin-inline-start); padding-inline-end: var(--right-panel-padding-inline-end); padding-inline-start: var(--right-panel-padding-inline-start); - width: var(--right-panel-width); + width: 352px; + } + + /* Align with Print Preview and use lighter box-shadows compared to the + * default styling. */ + #cr-container-shadow-top, + #cr-container-shadow-bottom { + box-shadow: inset 0 5px 3px -3px rgba(0, 0, 0, .2); + margin-inline-end: 40px; + margin-inline-start: 32px; + } + + #settingsSection { + display: flex; + flex-direction: column; + height: calc(100vh - var(--panel-container-margin-top)); + } + + #container { + flex: 1; + max-height: 445px; + overflow: overlay; } .scan-button-container { display: flex; justify-content: flex-end; - margin-bottom: 0; + margin-bottom: 32px; margin-inline-end: 40px; margin-inline-start: 32px; margin-top: 32px; @@ -144,47 +165,51 @@ progress-percent="[[progressPercent_]]"></scan-preview> </div> <div class="right-panel"> - <template is="dom-if" if="[[!showDoneSection_]]"> + <div id="settingsSection" hidden="[[showDoneSection_]]"> <h1 id="appTitle">[[i18n('appTitle')]]</h1> - <scanner-select id="scannerSelect" scanners="[[scanners_]]" - loaded="[[scannersLoaded_]]" - disabled="[[settingsDisabled_]]" - selected-scanner-id="{{selectedScannerId}}"></scanner-select> - <source-select id="sourceSelect" sources="[[capabilities_.sources]]" - disabled="[[settingsDisabled_]]" - selected-source="{{selectedSource}}"></source-select> - <scan-to-select id="scanToSelect" - disabled="[[settingsDisabled_]]" - selected-file-path="{{selectedFilePath}}"> - </scan-to-select> - <file-type-select id="fileTypeSelect" - disabled="[[settingsDisabled_]]" - selected-file-type="{{selectedFileType}}"></file-type-select> - <div id="more-settings-line-separator"></div> - <cr-button id="moreSettingsButton" on-click="toggleClicked_" - aria-expanded$="[[opened]]" - disabled="[[settingsDisabled_]]"> - <span>[[i18n('moreSettings')]]</span> - <iron-icon icon="[[getArrowIcon_(opened)]]"> - </iron-icon> - </cr-button> - <iron-collapse id="collapse" opened="{{opened}}"> - <color-mode-select id="colorModeSelect" - color-modes="[[capabilities_.colorModes]]" - disabled="[[settingsDisabled_]]" - selected-color-mode="{{selectedColorMode}}"> - </color-mode-select> - <page-size-select id="pageSizeSelect" - page-sizes="[[selectedSourcePageSizes_]]" - disabled="[[settingsDisabled_]]" - selected-page-size="{{selectedPageSize}}"> - </page-size-select> - <resolution-select id="resolutionSelect" - resolutions="[[capabilities_.resolutions]]" - disabled="[[settingsDisabled_]]" - selected-resolution="{{selectedResolution}}"> - </resolution-select> - </iron-collapse> + <div id="container" show-bottom-shadow> + <template is="dom-if" if="[[!showDoneSection_]]"> + <scanner-select id="scannerSelect" scanners="[[scanners_]]" + loaded="[[scannersLoaded_]]" + disabled="[[settingsDisabled_]]" + selected-scanner-id="{{selectedScannerId}}"></scanner-select> + <source-select id="sourceSelect" sources="[[capabilities_.sources]]" + disabled="[[settingsDisabled_]]" + selected-source="{{selectedSource}}"></source-select> + <scan-to-select id="scanToSelect" + disabled="[[settingsDisabled_]]" + selected-file-path="{{selectedFilePath}}"> + </scan-to-select> + <file-type-select id="fileTypeSelect" + disabled="[[settingsDisabled_]]" + selected-file-type="{{selectedFileType}}"></file-type-select> + <div id="more-settings-line-separator"></div> + <cr-button id="moreSettingsButton" on-click="toggleClicked_" + aria-expanded$="[[opened]]" + disabled="[[settingsDisabled_]]"> + <span>[[i18n('moreSettings')]]</span> + <iron-icon icon="[[getArrowIcon_(opened)]]"> + </iron-icon> + </cr-button> + <iron-collapse id="collapse" opened="{{opened}}"> + <color-mode-select id="colorModeSelect" + color-modes="[[capabilities_.colorModes]]" + disabled="[[settingsDisabled_]]" + selected-color-mode="{{selectedColorMode}}"> + </color-mode-select> + <page-size-select id="pageSizeSelect" + page-sizes="[[selectedSourcePageSizes_]]" + disabled="[[settingsDisabled_]]" + selected-page-size="{{selectedPageSize}}"> + </page-size-select> + <resolution-select id="resolutionSelect" + resolutions="[[capabilities_.resolutions]]" + disabled="[[settingsDisabled_]]" + selected-resolution="{{selectedResolution}}"> + </resolution-select> + </iron-collapse> + </template> + </div> <div class="scan-button-container"> <cr-button id="scanButton" class="action-button" on-click="onScanClick_" disabled$="[[settingsDisabled_]]" @@ -197,7 +222,7 @@ [[i18n('cancelButtonText')]] </cr-button> </div> - </template> + </div> <template is="dom-if" if="[[showDoneSection_]]"> <scan-done-section page-number="[[pageNumber_]]" on-done-click="onDoneClick_" on-file-not-found="onFileNotFound_"
diff --git a/chromeos/components/scanning/resources/scanning_app.js b/chromeos/components/scanning/resources/scanning_app.js index 0dfb0b5..0438a4c 100644 --- a/chromeos/components/scanning/resources/scanning_app.js +++ b/chromeos/components/scanning/resources/scanning_app.js
@@ -25,6 +25,7 @@ import './scanning_shared_css.js'; import './source_select.js'; +import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js'; import {assert} from 'chrome://resources/js/assert.m.js'; import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -49,7 +50,7 @@ _template: html`{__html_template__}`, - behaviors: [I18nBehavior], + behaviors: [CrContainerShadowBehavior, I18nBehavior], /** * Receives scan job notifications.
diff --git a/chromeos/components/scanning/resources/scanning_shared_css.html b/chromeos/components/scanning/resources/scanning_shared_css.html index eb6bb58..22739cb 100644 --- a/chromeos/components/scanning/resources/scanning_shared_css.html +++ b/chromeos/components/scanning/resources/scanning_shared_css.html
@@ -23,6 +23,10 @@ padding-inline-start: 16px; } + :host-context([dir='rtl']) select.md-select { + background-position-x: 12px; + } + @media (min-width: 600px) { :host { --container-width: 600px; @@ -34,7 +38,6 @@ --right-panel-margin-inline-start: 0; --right-panel-padding-inline-end: 8px; --right-panel-padding-inline-start: 8px; - --right-panel-width: 370px; } } @@ -49,7 +52,6 @@ --right-panel-margin-inline-start: 0; --right-panel-padding-inline-end: 16px; --right-panel-padding-inline-start: 16px; - --right-panel-width: 384px; } } @@ -64,7 +66,6 @@ --right-panel-margin-inline-start: 48px; --right-panel-padding-inline-end: 16px; --right-panel-padding-inline-start: 16px; - --right-panel-width: 384px; } } @@ -79,7 +80,6 @@ --right-panel-margin-inline-start: 60px; --right-panel-padding-inline-end: 32px; --right-panel-padding-inline-start: 32px; - --right-panel-width: 416px; } } </style>
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 9badc71..6ebbe211 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -715,6 +715,11 @@ const base::Feature kCrostiniResetLxdDb{"CrostiniResetLxdDb", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether the camera privacy switch toasts and notification should be +// displayed. +const base::Feature kCameraPrivacySwitchNotifications{ + "CameraPrivacySwitchNotifications", base::FEATURE_ENABLED_BY_DEFAULT}; + //////////////////////////////////////////////////////////////////////////////// bool IsAccountManagementFlowsV2Enabled() {
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 2f2536b..fedbf41 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -321,6 +321,8 @@ extern const base::Feature kImeMozcProto; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kCrostiniResetLxdDb; +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) +extern const base::Feature kCameraPrivacySwitchNotifications; // Keep alphabetized.
diff --git a/chromeos/network/device_state.cc b/chromeos/network/device_state.cc index 1cfea50..7139fb4f 100644 --- a/chromeos/network/device_state.cc +++ b/chromeos/network/device_state.cc
@@ -107,6 +107,8 @@ return false; apn_list_ = base::ListValue(value.Clone().TakeList()); return true; + } else if (key == shill::kInhibitedProperty) { + return GetBooleanValue(key, value, &inhibited_); } else if (key == shill::kEapAuthenticationCompletedProperty) { return GetBooleanValue(key, value, &eap_authentication_completed_); } else if (key == shill::kIPConfigsProperty) {
diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h index 0853009..2efbc01 100644 --- a/chromeos/network/device_state.h +++ b/chromeos/network/device_state.h
@@ -54,6 +54,7 @@ const std::string& mdn() const { return mdn_; } const base::ListValue& apn_list() const { return apn_list_; } const CellularScanResults& scan_results() const { return scan_results_; } + bool inhibited() const { return inhibited_; } // |ip_configs_| is kept up to date by NetworkStateHandler. const base::DictionaryValue& ip_configs() const { return ip_configs_; } @@ -114,6 +115,7 @@ std::string iccid_; std::string mdn_; CellularScanResults scan_results_; + bool inhibited_ = false; // Ethernet specific properties bool eap_authentication_completed_ = false;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index d8bbe5fb..7c03ac1 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -24,7 +24,6 @@ #include "chromeos/constants/chromeos_switches.h" #include "chromeos/network/device_state.h" #include "chromeos/network/network_connection_handler.h" -#include "chromeos/network/network_device_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_handler_callbacks.h" #include "chromeos/network/network_state_handler_observer.h"
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt index ab83dd3..c41f2ce 100644 --- a/chromeos/profiles/orderfile.newest.txt +++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@ -chromeos-chrome-orderfile-field-89-4324.9-1606733211-benchmark-89.0.4343.0-r1.orderfile.xz +chromeos-chrome-orderfile-field-89-4342.0-1607345364-benchmark-89.0.4351.0-r1.orderfile.xz
diff --git a/chromeos/services/assistant/BUILD.gn b/chromeos/services/assistant/BUILD.gn index 7334fd360..680d850 100644 --- a/chromeos/services/assistant/BUILD.gn +++ b/chromeos/services/assistant/BUILD.gn
@@ -124,7 +124,6 @@ "//chromeos/resources", "//chromeos/services/assistant/proxy", "//chromeos/services/assistant/public/cpp/migration", - "//chromeos/services/assistant/public/cpp/migration", "//chromeos/services/libassistant", "//chromeos/services/network_config/public/mojom", "//chromeos/strings", @@ -235,6 +234,10 @@ "//testing/gmock", "//testing/gtest", ] + + if (enable_cros_libassistant) { + deps += [ "//chromeos/services/assistant/public/cpp/migration" ] + } } buildflag_header("buildflags") {
diff --git a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc index a95b9b3b..13d4b23d 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
@@ -196,6 +196,13 @@ } void Stop() override { service_->Unbind(); } + void SetInitializeCallback( + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)> + callback) override { + service_->service_controller().SetInitializeCallback(std::move(callback)); + } + private: FakeLibassistantService* service_; };
diff --git a/chromeos/services/assistant/libassistant_service_host_impl.cc b/chromeos/services/assistant/libassistant_service_host_impl.cc index 68a2d4d..3d443b9d 100644 --- a/chromeos/services/assistant/libassistant_service_host_impl.cc +++ b/chromeos/services/assistant/libassistant_service_host_impl.cc
@@ -32,5 +32,13 @@ libassistant_service_ = nullptr; } +void LibassistantServiceHostImpl::SetInitializeCallback( + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)> + callback) { + DCHECK_NE(libassistant_service_, nullptr); + libassistant_service_->SetInitializeCallback(std::move(callback)); +} + } // namespace assistant } // namespace chromeos
diff --git a/chromeos/services/assistant/libassistant_service_host_impl.h b/chromeos/services/assistant/libassistant_service_host_impl.h index eb115ff1..3d3e4a5 100644 --- a/chromeos/services/assistant/libassistant_service_host_impl.h +++ b/chromeos/services/assistant/libassistant_service_host_impl.h
@@ -14,6 +14,12 @@ } // namespace assistant_client namespace chromeos { +namespace libassistant { +class LibassistantService; +} // namespace libassistant +} // namespace chromeos + +namespace chromeos { namespace assistant { class AssistantManagerServiceDelegate; @@ -30,6 +36,10 @@ void Launch( mojo::PendingReceiver<LibassistantServiceMojom> receiver) override; void Stop() override; + void SetInitializeCallback( + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)>) + override; private: // Owned by |AssistantManagerServiceImpl| which also owns |this|. @@ -37,7 +47,8 @@ // Owned by |AssistantManagerServiceImpl| which also owns |this|. AssistantManagerServiceDelegate* const delegate_; - std::unique_ptr<LibassistantServiceMojom> libassistant_service_; + std::unique_ptr<chromeos::libassistant::LibassistantService> + libassistant_service_; }; } // namespace assistant
diff --git a/chromeos/services/assistant/proxy/assistant_proxy.cc b/chromeos/services/assistant/proxy/assistant_proxy.cc index a3feb582..6cee87f 100644 --- a/chromeos/services/assistant/proxy/assistant_proxy.cc +++ b/chromeos/services/assistant/proxy/assistant_proxy.cc
@@ -28,8 +28,8 @@ libassistant_service_host_ = host; LaunchLibassistantService(); - service_controller_proxy_ = std::make_unique<ServiceControllerProxy>( - background_task_runner(), BindServiceController()); + service_controller_proxy_ = + std::make_unique<ServiceControllerProxy>(host, BindServiceController()); } void AssistantProxy::LaunchLibassistantService() {
diff --git a/chromeos/services/assistant/proxy/libassistant_service_host.h b/chromeos/services/assistant/proxy/libassistant_service_host.h index 7097cff5..6191d37d 100644 --- a/chromeos/services/assistant/proxy/libassistant_service_host.h +++ b/chromeos/services/assistant/proxy/libassistant_service_host.h
@@ -9,6 +9,11 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" +namespace assistant_client { +class AssistantManager; +class AssistantManagerInternal; +} // namespace assistant_client + namespace chromeos { namespace libassistant { namespace mojom { @@ -36,9 +41,18 @@ // |Stop| is called. virtual void Launch( mojo::PendingReceiver<LibassistantServiceMojom> receiver) = 0; - // Stop the mojom service. + // Stop the mojom service. virtual void Stop() = 0; + + // Set a callback to initialize |AssistantManager| and + // |AssistantManagerInternal|. This callback will be invoked before + // AssistantManager::Start() is called. This is temporary until we've migrated + // all initialization code to the mojom service. + virtual void SetInitializeCallback( + base::OnceCallback< + void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)>) = 0; }; } // namespace assistant
diff --git a/chromeos/services/assistant/proxy/service_controller_proxy.cc b/chromeos/services/assistant/proxy/service_controller_proxy.cc index 0dc1660..8390fc7 100644 --- a/chromeos/services/assistant/proxy/service_controller_proxy.cc +++ b/chromeos/services/assistant/proxy/service_controller_proxy.cc
@@ -11,6 +11,7 @@ #include "chromeos/assistant/internal/cros_display_connection.h" #include "chromeos/assistant/internal/internal_util.h" #include "chromeos/constants/chromeos_features.h" +#include "chromeos/services/assistant/proxy/libassistant_service_host.h" #include "chromeos/services/assistant/public/cpp/features.h" #include "chromeos/services/assistant/public/cpp/migration/assistant_manager_service_delegate.h" #include "chromeos/services/assistant/public/cpp/migration/libassistant_v1_api.h" @@ -36,6 +37,25 @@ constexpr char kServersideOpenAppExperimentId[] = "39651593"; constexpr char kServersideResponseProcessingV2ExperimentId[] = "1793869"; +struct StartArguments { + StartArguments() = default; + StartArguments(StartArguments&&) = default; + StartArguments& operator=(StartArguments&&) = default; + ~StartArguments() = default; + + assistant_client::ActionModule* action_module; + assistant_client::FuchsiaApiDelegate* fuchsia_api_delegate; + assistant_client::AssistantManagerDelegate* assistant_manager_delegate; + assistant_client::ConversationStateListener* conversation_state_listener; + assistant_client::DeviceStateListener* device_state_listener; + CrosDisplayConnection* display_connection; + std::string libassistant_config; + std::string locale; + std::string locale_override; + bool spoken_feedback_enabled; + ServiceControllerProxy::AuthTokens auth_tokens; +}; + void FillServerExperimentIds(std::vector<std::string>* server_experiment_ids) { if (base::FeatureList::IsEnabled(kChromeOSAssistantDogfood)) { server_experiment_ids->emplace_back(kServersideDogfoodExperimentId); @@ -58,17 +78,59 @@ } } +void SetInternalOptions( + assistant_client::AssistantManagerInternal* assistant_manager_internal, + const std::string& locale, + bool spoken_feedback_enabled) { + auto* internal_options = + assistant_manager_internal->CreateDefaultInternalOptions(); + SetAssistantOptions(internal_options, locale, spoken_feedback_enabled); + + internal_options->SetClientControlEnabled( + assistant::features::IsRoutinesEnabled()); + + if (!features::IsVoiceMatchDisabled()) + internal_options->EnableRequireVoiceMatchVerification(); + + assistant_manager_internal->SetOptions(*internal_options, [](bool success) { + DVLOG(2) << "set options: " << success; + }); +} + +// TODO(b/171748795): This should all be migrated to the mojom service, which +// should be responsible for the complete creation of the Libassistant +// objects. +// Note: this method will be called from the mojom (background) thread. +void InitializeAssistantManager( + StartArguments arguments, + assistant_client::AssistantManager* assistant_manager, + assistant_client::AssistantManagerInternal* assistant_manager_internal) { + SetInternalOptions(assistant_manager_internal, arguments.locale, + arguments.spoken_feedback_enabled); + assistant_manager_internal->SetDisplayConnection( + arguments.display_connection); + assistant_manager_internal->SetLocaleOverride(arguments.locale_override); + assistant_manager_internal->RegisterActionModule(arguments.action_module); + assistant_manager_internal->SetAssistantManagerDelegate( + arguments.assistant_manager_delegate); + assistant_manager_internal->GetFuchsiaApiHelperOrDie()->SetFuchsiaApiDelegate( + arguments.fuchsia_api_delegate); + assistant_manager->AddConversationStateListener( + arguments.conversation_state_listener); + assistant_manager->AddDeviceStateListener(arguments.device_state_listener); + SetServerExperiments(assistant_manager_internal); + assistant_manager->SetAuthTokens(arguments.auth_tokens); +} + } // namespace ServiceControllerProxy::ServiceControllerProxy( - scoped_refptr<base::SingleThreadTaskRunner> background_task_runner, + LibassistantServiceHost* host, mojo::PendingRemote<chromeos::libassistant::mojom::ServiceController> client) - : background_task_runner_(std::move(background_task_runner)), + : host_(host), service_controller_remote_(std::move(client)), state_observer_receiver_(this) { - DCHECK(background_task_runner_); - service_controller_remote_->AddAndFireStateObserver( state_observer_receiver_.BindNewPipeAndPassRemote()); } @@ -92,24 +154,31 @@ DCHECK_EQ(state_, State::kStopped); state_ = State::kStarting; + pending_display_connection_ = std::make_unique<CrosDisplayConnection>( + event_observer, /*feedback_ui_enabled=*/true, + assistant::features::IsMediaSessionIntegrationEnabled()); + // The mojom service will create the |AssistantManager|. service_controller_remote_->Start(libassistant_config); - // We need to finalize (and start) the |AssistantManager| once it's created, - // so we have to store all the required arguments for that. + // We need to initialize the |AssistantManager| once it's created and before + // it's started, so we register a callback to do just that. StartArguments arguments; arguments.action_module = action_module; arguments.fuchsia_api_delegate = fuchsia_api_delegate; arguments.assistant_manager_delegate = assistant_manager_delegate; arguments.conversation_state_listener = conversation_state_listener; arguments.device_state_listener = device_state_listener; - arguments.event_observer = event_observer; + arguments.display_connection = pending_display_connection_.get(); arguments.locale = locale; arguments.locale_override = locale_override; arguments.spoken_feedback_enabled = spoken_feedback_enabled; arguments.auth_tokens = auth_tokens; - arguments.done_callback = std::move(done_callback); - pending_start_argument_ = std::move(arguments); + + host_->SetInitializeCallback( + base::BindOnce(InitializeAssistantManager, std::move(arguments))); + + on_start_done_callback_ = std::move(done_callback); } void ServiceControllerProxy::Stop() { @@ -126,21 +195,8 @@ void ServiceControllerProxy::UpdateInternalOptions( const std::string& locale, bool spoken_feedback_enabled) { - // NOTE: this method is called on multiple threads, it needs to be - // thread-safe. - auto* internal_options = - assistant_manager_internal()->CreateDefaultInternalOptions(); - SetAssistantOptions(internal_options, locale, spoken_feedback_enabled); - - internal_options->SetClientControlEnabled( - assistant::features::IsRoutinesEnabled()); - - if (!features::IsVoiceMatchDisabled()) - internal_options->EnableRequireVoiceMatchVerification(); - - assistant_manager_internal()->SetOptions(*internal_options, [](bool success) { - DVLOG(2) << "set options: " << success; - }); + SetInternalOptions(assistant_manager_internal(), locale, + spoken_feedback_enabled); } void ServiceControllerProxy::SetAuthTokens(const AuthTokens& tokens) { @@ -181,45 +237,13 @@ } void ServiceControllerProxy::FinishCreatingAssistant() { - // TODO(b/171748795): This should all be migrated to the mojom service, which - // should be responsible for the complete creation of the Libassistant - // objects. - DCHECK(pending_start_argument_.has_value()); - - auto arguments = std::move(pending_start_argument_.value()); - - display_connection_ = std::make_unique<CrosDisplayConnection>( - arguments.event_observer, /*feedback_ui_enabled=*/true, - assistant::features::IsMediaSessionIntegrationEnabled()); - - UpdateInternalOptions(arguments.locale, arguments.spoken_feedback_enabled); - - assistant_manager_internal()->SetDisplayConnection(display_connection()); - assistant_manager_internal()->SetLocaleOverride(arguments.locale_override); - assistant_manager_internal()->RegisterActionModule(arguments.action_module); - assistant_manager_internal()->SetAssistantManagerDelegate( - arguments.assistant_manager_delegate); - assistant_manager_internal() - ->GetFuchsiaApiHelperOrDie() - ->SetFuchsiaApiDelegate(arguments.fuchsia_api_delegate); - assistant_manager()->AddConversationStateListener( - arguments.conversation_state_listener); - assistant_manager()->AddDeviceStateListener(arguments.device_state_listener); - SetServerExperiments(assistant_manager_internal()); - SetAuthTokens(arguments.auth_tokens); - - assistant_manager()->Start(); + DCHECK(on_start_done_callback_.has_value()); + DCHECK_NE(pending_display_connection_, nullptr); state_ = State::kStarted; - std::move(arguments.done_callback).Run(); + display_connection_ = std::move(pending_display_connection_); + std::move(on_start_done_callback_.value()).Run(); } -ServiceControllerProxy::StartArguments::StartArguments() = default; -ServiceControllerProxy::StartArguments::StartArguments(StartArguments&&) = - default; -ServiceControllerProxy::StartArguments& -ServiceControllerProxy::StartArguments::operator=(StartArguments&&) = default; -ServiceControllerProxy::StartArguments::~StartArguments() = default; - } // namespace assistant } // namespace chromeos
diff --git a/chromeos/services/assistant/proxy/service_controller_proxy.h b/chromeos/services/assistant/proxy/service_controller_proxy.h index d98f1a1..83a1a2b 100644 --- a/chromeos/services/assistant/proxy/service_controller_proxy.h +++ b/chromeos/services/assistant/proxy/service_controller_proxy.h
@@ -11,9 +11,7 @@ #include <vector> #include "base/check.h" -#include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" #include "chromeos/services/libassistant/public/mojom/service_controller.mojom.h" #include "mojo/public/cpp/bindings/remote.h" @@ -34,6 +32,7 @@ class AssistantEventObserver; class CrosDisplayConnection; +class LibassistantServiceHost; // Component managing the lifecycle of Libassistant, // exposing methods to start/stop and configure Libassistant. @@ -43,7 +42,7 @@ using AuthTokens = std::vector<std::pair<std::string, std::string>>; ServiceControllerProxy( - scoped_refptr<base::SingleThreadTaskRunner> background_task_runner, + LibassistantServiceHost* host, mojo::PendingRemote<chromeos::libassistant::mojom::ServiceController> client); @@ -52,8 +51,6 @@ ~ServiceControllerProxy() override; // Can not be invoked before Start() has finished. - // Both LibAssistant and Chrome threads may access |display_connection|. - // |display_connection| is thread safe. CrosDisplayConnection* display_connection() { DCHECK(display_connection_); return display_connection_.get(); @@ -112,25 +109,6 @@ // Can not be invoked before Start() has finished. assistant_client::AssistantManagerInternal* assistant_manager_internal(); - struct StartArguments { - StartArguments(); - StartArguments(StartArguments&&); - StartArguments& operator=(StartArguments&&); - ~StartArguments(); - assistant_client::ActionModule* action_module; - assistant_client::FuchsiaApiDelegate* fuchsia_api_delegate; - assistant_client::AssistantManagerDelegate* assistant_manager_delegate; - assistant_client::ConversationStateListener* conversation_state_listener; - assistant_client::DeviceStateListener* device_state_listener; - AssistantEventObserver* event_observer; - std::string libassistant_config; - std::string locale; - std::string locale_override; - bool spoken_feedback_enabled; - AuthTokens auth_tokens; - base::OnceClosure done_callback; - }; - void FinishCreatingAssistant(); // libassistant::mojom::StateObserver implementation: @@ -141,20 +119,22 @@ // Used internally for consistency checks. State state_ = State::kStopped; - scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_; + // Owned by |AssistantManagerServiceImpl| which (indirectly) also owns us. + LibassistantServiceHost* const host_; mojo::Remote<chromeos::libassistant::mojom::ServiceController> service_controller_remote_; mojo::Receiver<chromeos::libassistant::mojom::StateObserver> state_observer_receiver_; - // Arguments passed to the last Start() call. - // Used to finish starting Libassistant after the Libassistant mojom service - // signals it has created the required objects. - // Unset once we've finished starting. - base::Optional<StartArguments> pending_start_argument_; + // Callback passed to Start(). Will be invoked once the Libassistant service + // has started. + base::Optional<base::OnceClosure> on_start_done_callback_; std::unique_ptr<CrosDisplayConnection> display_connection_; + // Populated when we're starting but not started yet, so after Start() has + // been called but before the mojom service signalled it has started. + std::unique_ptr<CrosDisplayConnection> pending_display_connection_; base::WeakPtrFactory<ServiceControllerProxy> weak_factory_{this}; };
diff --git a/chromeos/services/assistant/test_support/fake_service_controller.cc b/chromeos/services/assistant/test_support/fake_service_controller.cc index 6feaaff..235d54ba 100644 --- a/chromeos/services/assistant/test_support/fake_service_controller.cc +++ b/chromeos/services/assistant/test_support/fake_service_controller.cc
@@ -4,6 +4,7 @@ #include "chromeos/services/assistant/test_support/fake_service_controller.h" +#include "chromeos/services/assistant/public/cpp/migration/libassistant_v1_api.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { @@ -35,6 +36,10 @@ state_observers_.Clear(); } +void FakeServiceController::SetInitializeCallback(InitializeCallback callback) { + initialize_callback_ = std::move(callback); +} + void FakeServiceController::BlockStartCalls() { // This lock will be release in |UnblockStartCalls|. start_mutex_.lock(); @@ -50,6 +55,12 @@ // Will block if |BlockStartCalls| was invoked. std::lock_guard<std::mutex> lock(start_mutex_); + if (initialize_callback_) { + std::move(initialize_callback_) + .Run(LibassistantV1Api::Get()->assistant_manager(), + LibassistantV1Api::Get()->assistant_manager_internal()); + } + SetState(State::kStarted); }
diff --git a/chromeos/services/assistant/test_support/fake_service_controller.h b/chromeos/services/assistant/test_support/fake_service_controller.h index 59f2bae..9dc561a 100644 --- a/chromeos/services/assistant/test_support/fake_service_controller.h +++ b/chromeos/services/assistant/test_support/fake_service_controller.h
@@ -12,6 +12,11 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote_set.h" +namespace assistant_client { +class AssistantManager; +class AssistantManagerInternal; +} // namespace assistant_client + namespace chromeos { namespace assistant { @@ -21,6 +26,9 @@ class FakeServiceController : public libassistant::mojom::ServiceController { public: using State = libassistant::mojom::ServiceState; + using InitializeCallback = + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)>; FakeServiceController(); FakeServiceController(FakeServiceController&) = delete; @@ -39,6 +47,8 @@ pending_receiver); void Unbind(); + void SetInitializeCallback(InitializeCallback callback); + // Call this to block any call to |Start|. The observers will not be invoked // as long as the start call is blocked. Unblock these calls using // |UnblockStartCalls|. This is not enabled by default, so unless you call @@ -61,6 +71,8 @@ // Config passed to LibAssistant when it was started. std::string libassistant_config_; + InitializeCallback initialize_callback_; + State state_ = State::kStopped; mojo::Receiver<libassistant::mojom::ServiceController> receiver_; mojo::RemoteSet<libassistant::mojom::StateObserver> state_observers_;
diff --git a/chromeos/services/libassistant/libassistant_service.cc b/chromeos/services/libassistant/libassistant_service.cc index 6bf0ea1..481fb6d 100644 --- a/chromeos/services/libassistant/libassistant_service.cc +++ b/chromeos/services/libassistant/libassistant_service.cc
@@ -29,5 +29,9 @@ service_controller_->Bind(std::move(receiver)); } +void LibassistantService::SetInitializeCallback(InitializeCallback callback) { + service_controller().SetInitializeCallback(std::move(callback)); +} + } // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/libassistant/libassistant_service.h b/chromeos/services/libassistant/libassistant_service.h index fed2dfa..38c5c05 100644 --- a/chromeos/services/libassistant/libassistant_service.h +++ b/chromeos/services/libassistant/libassistant_service.h
@@ -12,6 +12,8 @@ #include "mojo/public/cpp/bindings/receiver.h" namespace assistant_client { +class AssistantManager; +class AssistantManagerInternal; class PlatformApi; } // namespace assistant_client @@ -29,6 +31,10 @@ class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) LibassistantService : public mojom::LibassistantService { public: + using InitializeCallback = + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)>; + explicit LibassistantService( mojo::PendingReceiver<mojom::LibassistantService> receiver, assistant_client::PlatformApi* platform_api, @@ -37,7 +43,11 @@ LibassistantService& operator=(LibassistantService&) = delete; ~LibassistantService() override; + void SetInitializeCallback(InitializeCallback callback); + private: + ServiceController& service_controller() { return *service_controller_; } + // mojom::LibassistantService implementation: void BindServiceController( mojo::PendingReceiver<mojom::ServiceController> receiver) override;
diff --git a/chromeos/services/libassistant/service_controller.cc b/chromeos/services/libassistant/service_controller.cc index 68ceb36..24a235e 100644 --- a/chromeos/services/libassistant/service_controller.cc +++ b/chromeos/services/libassistant/service_controller.cc
@@ -32,6 +32,10 @@ receiver_.Bind(std::move(receiver)); } +void ServiceController::SetInitializeCallback(InitializeCallback callback) { + initialize_callback_ = std::move(callback); +} + void ServiceController::Start(const std::string& libassistant_config) { if (state_ != ServiceState::kStopped) return; @@ -43,6 +47,13 @@ libassistant_v1_api_ = std::make_unique<assistant::LibassistantV1Api>( assistant_manager_.get(), assistant_manager_internal_); + if (initialize_callback_) { + std::move(initialize_callback_) + .Run(assistant_manager(), assistant_manager_internal()); + } + + assistant_manager()->Start(); + SetStateAndInformObservers(ServiceState::kStarted); for (auto& observer : assistant_manager_observers_) {
diff --git a/chromeos/services/libassistant/service_controller.h b/chromeos/services/libassistant/service_controller.h index 26ffd61..c93bfba 100644 --- a/chromeos/services/libassistant/service_controller.h +++ b/chromeos/services/libassistant/service_controller.h
@@ -43,6 +43,10 @@ class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) ServiceController : public mojom::ServiceController { public: + using InitializeCallback = + base::OnceCallback<void(assistant_client::AssistantManager*, + assistant_client::AssistantManagerInternal*)>; + ServiceController(assistant::AssistantManagerServiceDelegate* delegate, assistant_client::PlatformApi* platform_api); ServiceController(ServiceController&) = delete; @@ -51,6 +55,12 @@ void Bind(mojo::PendingReceiver<mojom::ServiceController> receiver); + // Set a callback to initialize |AssistantManager| and + // |AssistantManagerInternal|. This callback will be invoked before + // AssistantManager::Start() is called. This is temporary until we've migrated + // all initialization code to this class. + void SetInitializeCallback(InitializeCallback callback); + // mojom::ServiceController implementation: void Start(const std::string& libassistant_config) override; void Stop() override; @@ -77,6 +87,9 @@ // Owned by |AssistantManagerServiceImpl| which indirectly owns us. assistant_client::PlatformApi* const platform_api_; + // Callback called to initialize |AssistantManager| before it's started. + InitializeCallback initialize_callback_; + std::unique_ptr<assistant_client::AssistantManager> assistant_manager_; assistant_client::AssistantManagerInternal* assistant_manager_internal_ = nullptr;
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc index f19d83da..dc4704a 100644 --- a/chromeos/services/network_config/cros_network_config.cc +++ b/chromeos/services/network_config/cros_network_config.cc
@@ -1848,6 +1848,10 @@ NET_LOG(ERROR) << "Device state unavailable: " << device->name(); continue; } + if (technology_state == mojom::DeviceStateType::kEnabled && + device->inhibited()) { + technology_state = mojom::DeviceStateType::kInhibited; + } mojom::DeviceStatePropertiesPtr mojo_device = DeviceStateToMojo(device, technology_state); if (mojo_device)
diff --git a/chromeos/services/network_config/public/mojom/network_types.mojom b/chromeos/services/network_config/public/mojom/network_types.mojom index 7932153..be869a6 100644 --- a/chromeos/services/network_config/public/mojom/network_types.mojom +++ b/chromeos/services/network_config/public/mojom/network_types.mojom
@@ -23,6 +23,8 @@ kEnabling, kEnabled, kProhibited, + // Cellular devices may have Inhibited set, preventing active scans. + kInhibited, // Not used in DeviceStateProperties, but useful when querying by type. kUnavailable, };
diff --git a/components/autofill/android/BUILD.gn b/components/autofill/android/BUILD.gn index 9f15164..856af4d 100644 --- a/components/autofill/android/BUILD.gn +++ b/components/autofill/android/BUILD.gn
@@ -36,9 +36,10 @@ ] } -android_library("autofill_java") { +android_library("full_autofill_java") { deps = [ ":autofill_java_resources", + ":payments_autofill_java", "//base:base_java", "//content/public/android:content_java", "//third_party/android_deps:androidx_annotation_annotation_java", @@ -52,9 +53,24 @@ "java/src/org/chromium/components/autofill/AutofillDropdownFooter.java", "java/src/org/chromium/components/autofill/AutofillPopup.java", "java/src/org/chromium/components/autofill/AutofillSuggestion.java", - "java/src/org/chromium/components/autofill/Completable.java", - "java/src/org/chromium/components/autofill/EditableOption.java", ] srcjar_deps = [ ":autofill_core_browser_java_enums" ] resources_package = "org.chromium.components.autofill" } + +# A library containing the minimal deps for payments, so that ui_java_resources +# doesn't have to be pulled in. +android_library("payments_autofill_java") { + sources = [ + "java/src/org/chromium/components/autofill/Completable.java", + "java/src/org/chromium/components/autofill/EditableOption.java", + ] + deps = [ "//third_party/android_deps:androidx_annotation_annotation_java" ] +} + +java_group("autofill_java") { + deps = [ + ":full_autofill_java", + ":payments_autofill_java", + ] +}
diff --git a/components/cast_channel/cast_message_util.cc b/components/cast_channel/cast_message_util.cc index afc0d9e3..8b4649e 100644 --- a/components/cast_channel/cast_message_util.cc +++ b/components/cast_channel/cast_message_util.cc
@@ -28,72 +28,81 @@ using cast_channel::GetAppAvailabilityResult; template <> -const EnumTable<CastMessageType> EnumTable<CastMessageType>::instance( - { - {CastMessageType::kPing, "PING"}, - {CastMessageType::kPong, "PONG"}, - {CastMessageType::kRpc, "RPC"}, - {CastMessageType::kGetAppAvailability, "GET_APP_AVAILABILITY"}, - {CastMessageType::kGetStatus, "GET_STATUS"}, - {CastMessageType::kConnect, "CONNECT"}, - {CastMessageType::kCloseConnection, "CLOSE"}, - {CastMessageType::kBroadcast, "APPLICATION_BROADCAST"}, - {CastMessageType::kLaunch, "LAUNCH"}, - {CastMessageType::kStop, "STOP"}, - {CastMessageType::kReceiverStatus, "RECEIVER_STATUS"}, - {CastMessageType::kMediaStatus, "MEDIA_STATUS"}, - {CastMessageType::kLaunchError, "LAUNCH_ERROR"}, - {CastMessageType::kOffer, "OFFER"}, - {CastMessageType::kAnswer, "ANSWER"}, - {CastMessageType::kCapabilitiesResponse, "CAPABILITIES_RESPONSE"}, - {CastMessageType::kStatusResponse, "STATUS_RESPONSE"}, - {CastMessageType::kMultizoneStatus, "MULTIZONE_STATUS"}, - {CastMessageType::kInvalidPlayerState, "INVALID_PLAYER_STATE"}, - {CastMessageType::kLoadFailed, "LOAD_FAILED"}, - {CastMessageType::kLoadCancelled, "LOAD_CANCELLED"}, - {CastMessageType::kInvalidRequest, "INVALID_REQUEST"}, - {CastMessageType::kPresentation, "PRESENTATION"}, - {CastMessageType::kGetCapabilities, "GET_CAPABILITIES"}, - {CastMessageType::kOther}, - }, - CastMessageType::kMaxValue); +const EnumTable<CastMessageType>& EnumTable<CastMessageType>::GetInstance() { + static const EnumTable<CastMessageType> kInstance( + { + {CastMessageType::kPing, "PING"}, + {CastMessageType::kPong, "PONG"}, + {CastMessageType::kRpc, "RPC"}, + {CastMessageType::kGetAppAvailability, "GET_APP_AVAILABILITY"}, + {CastMessageType::kGetStatus, "GET_STATUS"}, + {CastMessageType::kConnect, "CONNECT"}, + {CastMessageType::kCloseConnection, "CLOSE"}, + {CastMessageType::kBroadcast, "APPLICATION_BROADCAST"}, + {CastMessageType::kLaunch, "LAUNCH"}, + {CastMessageType::kStop, "STOP"}, + {CastMessageType::kReceiverStatus, "RECEIVER_STATUS"}, + {CastMessageType::kMediaStatus, "MEDIA_STATUS"}, + {CastMessageType::kLaunchError, "LAUNCH_ERROR"}, + {CastMessageType::kOffer, "OFFER"}, + {CastMessageType::kAnswer, "ANSWER"}, + {CastMessageType::kCapabilitiesResponse, "CAPABILITIES_RESPONSE"}, + {CastMessageType::kStatusResponse, "STATUS_RESPONSE"}, + {CastMessageType::kMultizoneStatus, "MULTIZONE_STATUS"}, + {CastMessageType::kInvalidPlayerState, "INVALID_PLAYER_STATE"}, + {CastMessageType::kLoadFailed, "LOAD_FAILED"}, + {CastMessageType::kLoadCancelled, "LOAD_CANCELLED"}, + {CastMessageType::kInvalidRequest, "INVALID_REQUEST"}, + {CastMessageType::kPresentation, "PRESENTATION"}, + {CastMessageType::kGetCapabilities, "GET_CAPABILITIES"}, + {CastMessageType::kOther}, + }, + CastMessageType::kMaxValue); + return kInstance; +} template <> -const EnumTable<cast_channel::V2MessageType> - EnumTable<cast_channel::V2MessageType>::instance( - { - {cast_channel::V2MessageType::kEditTracksInfo, "EDIT_TRACKS_INFO"}, - {cast_channel::V2MessageType::kGetStatus, "GET_STATUS"}, - {cast_channel::V2MessageType::kLoad, "LOAD"}, - {cast_channel::V2MessageType::kMediaGetStatus, "MEDIA_GET_STATUS"}, - {cast_channel::V2MessageType::kMediaSetVolume, "MEDIA_SET_VOLUME"}, - {cast_channel::V2MessageType::kPause, "PAUSE"}, - {cast_channel::V2MessageType::kPlay, "PLAY"}, - {cast_channel::V2MessageType::kPrecache, "PRECACHE"}, - {cast_channel::V2MessageType::kQueueInsert, "QUEUE_INSERT"}, - {cast_channel::V2MessageType::kQueueLoad, "QUEUE_LOAD"}, - {cast_channel::V2MessageType::kQueueRemove, "QUEUE_REMOVE"}, - {cast_channel::V2MessageType::kQueueReorder, "QUEUE_REORDER"}, - {cast_channel::V2MessageType::kQueueUpdate, "QUEUE_UPDATE"}, - {cast_channel::V2MessageType::kQueueNext, "QUEUE_NEXT"}, - {cast_channel::V2MessageType::kQueuePrev, "QUEUE_PREV"}, - {cast_channel::V2MessageType::kSeek, "SEEK"}, - {cast_channel::V2MessageType::kSetVolume, "SET_VOLUME"}, - {cast_channel::V2MessageType::kStop, "STOP"}, - {cast_channel::V2MessageType::kStopMedia, "STOP_MEDIA"}, - {cast_channel::V2MessageType::kOther}, - }, - cast_channel::V2MessageType::kMaxValue); +const EnumTable<cast_channel::V2MessageType>& +EnumTable<cast_channel::V2MessageType>::GetInstance() { + static const EnumTable<cast_channel::V2MessageType> kInstance( + { + {cast_channel::V2MessageType::kEditTracksInfo, "EDIT_TRACKS_INFO"}, + {cast_channel::V2MessageType::kGetStatus, "GET_STATUS"}, + {cast_channel::V2MessageType::kLoad, "LOAD"}, + {cast_channel::V2MessageType::kMediaGetStatus, "MEDIA_GET_STATUS"}, + {cast_channel::V2MessageType::kMediaSetVolume, "MEDIA_SET_VOLUME"}, + {cast_channel::V2MessageType::kPause, "PAUSE"}, + {cast_channel::V2MessageType::kPlay, "PLAY"}, + {cast_channel::V2MessageType::kPrecache, "PRECACHE"}, + {cast_channel::V2MessageType::kQueueInsert, "QUEUE_INSERT"}, + {cast_channel::V2MessageType::kQueueLoad, "QUEUE_LOAD"}, + {cast_channel::V2MessageType::kQueueRemove, "QUEUE_REMOVE"}, + {cast_channel::V2MessageType::kQueueReorder, "QUEUE_REORDER"}, + {cast_channel::V2MessageType::kQueueUpdate, "QUEUE_UPDATE"}, + {cast_channel::V2MessageType::kQueueNext, "QUEUE_NEXT"}, + {cast_channel::V2MessageType::kQueuePrev, "QUEUE_PREV"}, + {cast_channel::V2MessageType::kSeek, "SEEK"}, + {cast_channel::V2MessageType::kSetVolume, "SET_VOLUME"}, + {cast_channel::V2MessageType::kStop, "STOP"}, + {cast_channel::V2MessageType::kStopMedia, "STOP_MEDIA"}, + {cast_channel::V2MessageType::kOther}, + }, + cast_channel::V2MessageType::kMaxValue); + return kInstance; +} template <> -const EnumTable<GetAppAvailabilityResult> - EnumTable<GetAppAvailabilityResult>::instance( - { - {GetAppAvailabilityResult::kAvailable, "APP_AVAILABLE"}, - {GetAppAvailabilityResult::kUnavailable, "APP_UNAVAILABLE"}, - {GetAppAvailabilityResult::kUnknown}, - }, - GetAppAvailabilityResult::kMaxValue); +const EnumTable<GetAppAvailabilityResult>& +EnumTable<GetAppAvailabilityResult>::GetInstance() { + static const EnumTable<GetAppAvailabilityResult> kInstance( + { + {GetAppAvailabilityResult::kAvailable, "APP_AVAILABLE"}, + {GetAppAvailabilityResult::kUnavailable, "APP_UNAVAILABLE"}, + {GetAppAvailabilityResult::kUnknown}, + }, + GetAppAvailabilityResult::kMaxValue); + return kInstance; +} } // namespace cast_util
diff --git a/components/cast_channel/enum_table.h b/components/cast_channel/enum_table.h index 85539057d..e3130c7 100644 --- a/components/cast_channel/enum_table.h +++ b/components/cast_channel/enum_table.h
@@ -351,7 +351,7 @@ // instance of this class for a given enum type. Users of this class are // responsible for providing a suitable definition for each enum type if the // EnumToString() or StringToEnum() functions are used. - static const EnumTable<E> instance; + static const EnumTable& GetInstance(); private: #ifdef ARCH_CPU_64_BITS @@ -403,30 +403,31 @@ // (EnumTable<E>::instance) for the given enum type. template <typename E> inline base::Optional<base::StringPiece> EnumToString(E value) { - return EnumTable<E>::instance.GetString(value); + return EnumTable<E>::GetInstance().GetString(value); } // Converts a literal enum value to a string at compile time using the default -// table (EnumTable<E>::instance) for the given enum type. +// table (EnumTable<E>::GetInstance()) for the given enum type. // // TODO(jrw): Once C++17 features are allowed, change this function to have only // one template parameter: // // template <auto Value> // inline base::StringPiece EnumToString() { -// return EnumTable<decltype(Value)>::instance.template GetString<Value>(); +// return EnumTable<decltype(Value) +// >::GetInstance().template GetString<Value>(); // } // template <typename E, E Value> inline base::StringPiece EnumToString() { - return EnumTable<E>::instance.template GetString<Value>(); + return EnumTable<E>::GetInstance().template GetString<Value>(); } // Converts a string to an enum value using the default table // (EnumTable<E>::instance) for the given enum type. template <typename E> inline base::Optional<E> StringToEnum(base::StringPiece str) { - return EnumTable<E>::instance.GetEnum(str); + return EnumTable<E>::GetInstance().GetEnum(str); } } // namespace cast_util
diff --git a/components/cast_channel/enum_table_unittest.cc b/components/cast_channel/enum_table_unittest.cc index 7772625..5ba3fc8 100644 --- a/components/cast_channel/enum_table_unittest.cc +++ b/components/cast_channel/enum_table_unittest.cc
@@ -37,11 +37,13 @@ } // namespace template <> -const EnumTable<MyEnum> EnumTable<MyEnum>::instance( - {{MyEnum::kZero, "ZERO_DEFAULT"}, - {MyEnum::kOne, "ONE_DEFAULT"}, - {MyEnum::kTwo, "TWO_DEFAULT"}}, - MyEnum::kMaxValue); +const EnumTable<MyEnum>& EnumTable<MyEnum>::GetInstance() { + static const EnumTable<MyEnum> kInstance({{MyEnum::kZero, "ZERO_DEFAULT"}, + {MyEnum::kOne, "ONE_DEFAULT"}, + {MyEnum::kTwo, "TWO_DEFAULT"}}, + MyEnum::kMaxValue); + return kInstance; +} namespace {
diff --git a/components/crash/content/browser/error_reporting/mock_crash_endpoint.h b/components/crash/content/browser/error_reporting/mock_crash_endpoint.h index e53732ec..7d0fb98 100644 --- a/components/crash/content/browser/error_reporting/mock_crash_endpoint.h +++ b/components/crash/content/browser/error_reporting/mock_crash_endpoint.h
@@ -40,6 +40,10 @@ // Returns the last report received, if any. const base::Optional<Report>& last_report() const { return last_report_; } + // Clears last report so that WaitForReport will wait for another report. + // Does not clear report_count() + void clear_last_report() { last_report_.reset(); } + // Get the number of reports received since this object was created. int report_count() const { return report_count_; }
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index 619de8a..bc537245 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -917,9 +917,11 @@ startup_id_ ? *startup_id_ : std::string(), /*for_creation=*/true, params.init_properties_container); + SetShellApplicationId(¶ms.init_properties_container, application_id_); + SetShellMainSurface(¶ms.init_properties_container, root_surface()); + SetShellStartupId(¶ms.init_properties_container, startup_id_); + bool activatable = activatable_; - if (container_ == ash::kShellWindowId_SystemModalContainer) - activatable &= HasHitTestRegion(); // ShellSurfaces in system modal container are only activatable if input // region is non-empty. See OnCommitSurface() for more details. @@ -942,9 +944,6 @@ window->SetEventTargetingPolicy( aura::EventTargetingPolicy::kTargetAndDescendants); InstallCustomWindowTargeter(); - SetShellApplicationId(window, application_id_); - SetShellStartupId(window, startup_id_); - SetShellMainSurface(window, root_surface()); // Start tracking changes to window bounds and window state. window->AddObserver(this);
diff --git a/components/exo/shell_surface_util.cc b/components/exo/shell_surface_util.cc index e66fdf8..e3124ce 100644 --- a/components/exo/shell_surface_util.cc +++ b/components/exo/shell_surface_util.cc
@@ -78,28 +78,28 @@ } // namespace -void SetShellApplicationId(aura::Window* window, +void SetShellApplicationId(ui::PropertyHandler* property_handler, const base::Optional<std::string>& id) { TRACE_EVENT1("exo", "SetApplicationId", "application_id", id ? *id : "null"); if (id) - window->SetProperty(kApplicationIdKey, *id); + property_handler->SetProperty(kApplicationIdKey, *id); else - window->ClearProperty(kApplicationIdKey); + property_handler->ClearProperty(kApplicationIdKey); } -const std::string* GetShellApplicationId(const aura::Window* window) { - return window->GetProperty(kApplicationIdKey); +const std::string* GetShellApplicationId(const aura::Window* property_handler) { + return property_handler->GetProperty(kApplicationIdKey); } -void SetShellStartupId(aura::Window* window, +void SetShellStartupId(ui::PropertyHandler* property_handler, const base::Optional<std::string>& id) { TRACE_EVENT1("exo", "SetStartupId", "startup_id", id ? *id : "null"); if (id) - window->SetProperty(kStartupIdKey, *id); + property_handler->SetProperty(kStartupIdKey, *id); else - window->ClearProperty(kStartupIdKey); + property_handler->ClearProperty(kStartupIdKey); } const std::string* GetShellStartupId(aura::Window* window) { @@ -140,8 +140,9 @@ return kMainSurfaceKey == key; } -void SetShellMainSurface(aura::Window* window, Surface* surface) { - window->SetProperty(kMainSurfaceKey, surface); +void SetShellMainSurface(ui::PropertyHandler* property_handler, + Surface* surface) { + property_handler->SetProperty(kMainSurfaceKey, surface); } Surface* GetShellMainSurface(const aura::Window* window) {
diff --git a/components/exo/shell_surface_util.h b/components/exo/shell_surface_util.h index bd73fff..d3e9dd6 100644 --- a/components/exo/shell_surface_util.h +++ b/components/exo/shell_surface_util.h
@@ -10,6 +10,10 @@ #include "base/optional.h" +namespace ui { +class PropertyHandler; +} + namespace aura { class Window; } @@ -29,21 +33,15 @@ class Surface; class ShellSurfaceBase; -// Sets the application ID for the window. The application ID identifies the -// general class of applications to which the window belongs. -void SetShellApplicationId(aura::Window* window, +// Sets the application ID to the property_handler. The application ID +// identifies the general class of applications to which the window belongs. +void SetShellApplicationId(ui::PropertyHandler* property_handler, const base::Optional<std::string>& id); const std::string* GetShellApplicationId(const aura::Window* window); -// Sets ARC app type for the provided |window|. -void SetArcAppType(aura::Window* window); - -// Sets Lacros app type for the provided |window|. -void SetLacrosAppType(aura::Window* window); - -// Sets the startup ID for the window. The startup ID identifies the +// Sets the startup ID to the property handler. The startup ID identifies the // application using startup notification protocol. -void SetShellStartupId(aura::Window* window, +void SetShellStartupId(ui::PropertyHandler* property_handler, const base::Optional<std::string>& id); const std::string* GetShellStartupId(aura::Window* window); @@ -62,8 +60,9 @@ // Returns true if the given key is the shell main surface key bool IsShellMainSurfaceKey(const void* key); -// Sets the main surface for the window. -void SetShellMainSurface(aura::Window* window, Surface* surface); +// Sets the main surface to the property handler. +void SetShellMainSurface(ui::PropertyHandler* property_handler, + Surface* surface); // Returns the main Surface instance or nullptr if it is not set. // |window| must not be nullptr.
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc index d535500d..841252e 100644 --- a/components/feed/feed_feature_list.cc +++ b/components/feed/feed_feature_list.cc
@@ -47,6 +47,8 @@ "InterestFeedSpinnerAlwaysAnimate", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kWebFeed{"WebFeed", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kXsurfaceMetricsReporting{ + "XsurfaceMetricsReporting", base::FEATURE_DISABLED_BY_DEFAULT}; const char kDefaultReferrerUrl[] = "https://www.googleapis.com/auth/chrome-content-suggestions";
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h index d7f0a16b..fa5d9222 100644 --- a/components/feed/feed_feature_list.h +++ b/components/feed/feed_feature_list.h
@@ -45,6 +45,10 @@ // Feature that allows users to keep up with and consume web content. extern const base::Feature kWebFeed; +// Feature that enables xsurface to provide the metrics reporting state to an +// xsurface feed. +extern const base::Feature kXsurfaceMetricsReporting; + std::string GetFeedReferrerUrl(); } // namespace feed
diff --git a/components/full_restore/BUILD.gn b/components/full_restore/BUILD.gn index 7f18380fc..6ba09a7 100644 --- a/components/full_restore/BUILD.gn +++ b/components/full_restore/BUILD.gn
@@ -11,6 +11,8 @@ "app_restore_data.h", "full_restore_file_handler.cc", "full_restore_file_handler.h", + "full_restore_info.cc", + "full_restore_info.h", "full_restore_read_handler.cc", "full_restore_read_handler.h", "full_restore_save_handler.cc", @@ -28,6 +30,7 @@ public_deps = [ "//ash/public/cpp", "//base", + "//components/account_id:account_id", "//components/services/app_service/public/cpp:intents", "//components/services/app_service/public/mojom", "//ui/aura", @@ -37,7 +40,10 @@ source_set("unit_tests") { testonly = true - sources = [ "restore_data_unittest.cc" ] + sources = [ + "full_restore_info_unittest.cc", + "restore_data_unittest.cc", + ] deps = [ ":full_restore",
diff --git a/components/full_restore/DEPS b/components/full_restore/DEPS index 70f5410..1953382 100644 --- a/components/full_restore/DEPS +++ b/components/full_restore/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+ash/public", + "+components/account_id/account_id.h", "+components/services/app_service/public", "+ui", ]
diff --git a/components/full_restore/full_restore_info.cc b/components/full_restore/full_restore_info.cc new file mode 100644 index 0000000..3d439f64 --- /dev/null +++ b/components/full_restore/full_restore_info.cc
@@ -0,0 +1,47 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/full_restore/full_restore_info.h" + +#include "base/no_destructor.h" +#include "components/account_id/account_id.h" + +namespace full_restore { + +FullRestoreInfo* FullRestoreInfo::GetInstance() { + static base::NoDestructor<FullRestoreInfo> full_restore_info; + return full_restore_info.get(); +} + +FullRestoreInfo::FullRestoreInfo() = default; + +FullRestoreInfo::~FullRestoreInfo() = default; + +void FullRestoreInfo::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void FullRestoreInfo::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +bool FullRestoreInfo::ShouldRestore(const AccountId& account_id) { + return restore_flags_.find(account_id) != restore_flags_.end(); +} + +void FullRestoreInfo::SetRestoreFlag(const AccountId& account_id, + bool should_restore) { + if (should_restore == ShouldRestore(account_id)) + return; + + if (should_restore) + restore_flags_.insert(account_id); + else + restore_flags_.erase(account_id); + + for (auto& observer : observers_) + observer.OnRestoreFlagChanged(account_id, should_restore); +} + +} // namespace full_restore
diff --git a/components/full_restore/full_restore_info.h b/components/full_restore/full_restore_info.h new file mode 100644 index 0000000..8dbe414d --- /dev/null +++ b/components/full_restore/full_restore_info.h
@@ -0,0 +1,76 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_FULL_RESTORE_FULL_RESTORE_INFO_H_ +#define COMPONENTS_FULL_RESTORE_FULL_RESTORE_INFO_H_ + +#include <set> + +#include "base/component_export.h" +#include "base/observer_list.h" +#include "base/observer_list_types.h" + +class AccountId; + +namespace aura { +class Window; +} + +namespace full_restore { + +// FullRestoreInfo is responsible for providing the information for +// FullRestoreInfo::Observer, including: +// 1. Whether we should restore apps and browser windows for |account_id|. +// 2. Notifies when |window| is ready to be restored, after we have the app +// launch information, e.g. a task id for an ARC app +// +// TODO(crbug.com/1146900): Get the app launch information, and notify +// observers. +class COMPONENT_EXPORT(FULL_RESTORE) FullRestoreInfo { + public: + class Observer : public base::CheckedObserver { + public: + // Notifies when |restore_flags_| is changed. + virtual void OnRestoreFlagChanged(const AccountId& account_id, + bool should_restore) {} + + // Notifies when |window| is ready to be restored, after we have the app + // launch information, e.g. a task id for an ARC app. + virtual void OnAppLaunched(aura::Window* window) {} + + protected: + ~Observer() override = default; + }; + + static FullRestoreInfo* GetInstance(); + + FullRestoreInfo(); + FullRestoreInfo(const FullRestoreInfo&) = delete; + FullRestoreInfo& operator=(const FullRestoreInfo&) = delete; + ~FullRestoreInfo(); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Returns true if we should restore apps and pages based on the restore + // setting and the user's choice from the notification for |account_id|. + // Otherwise, returns false. + bool ShouldRestore(const AccountId& account_id); + + // Sets whether we should restore apps and pages, based on the restore setting + // and the user's choice from the notification for |account_id|. + void SetRestoreFlag(const AccountId& account_id, bool should_restore); + + private: + base::ObserverList<Observer> observers_; + + // Records whether restore or not for the account id. If the account id is + // added, that means we should restore apps and pages for the account id. + // Otherwise, we should not restore for the account id. + std::set<AccountId> restore_flags_; +}; + +} // namespace full_restore + +#endif // COMPONENTS_FULL_RESTORE_FULL_RESTORE_INFO_H_
diff --git a/components/full_restore/full_restore_info_unittest.cc b/components/full_restore/full_restore_info_unittest.cc new file mode 100644 index 0000000..84c0597 --- /dev/null +++ b/components/full_restore/full_restore_info_unittest.cc
@@ -0,0 +1,72 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/full_restore/full_restore_info.h" + +#include <map> +#include <set> + +#include "components/account_id/account_id.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace full_restore { + +class FakeFullRestoreInfoObserver : public FullRestoreInfo::Observer { + public: + void OnRestoreFlagChanged(const AccountId& account_id, + bool should_restore) override { + if (should_restore) + restore_flags_.insert(account_id); + else + restore_flags_.erase(account_id); + + invoked_count_[account_id]++; + } + + bool ShouldRestore(const AccountId& account_id) { + return restore_flags_.find(account_id) != restore_flags_.end(); + } + + int InvokedCount(const AccountId& account_id) { + auto it = invoked_count_.find(account_id); + return it != invoked_count_.end() ? it->second : 0; + } + + private: + std::set<AccountId> restore_flags_; + std::map<AccountId, int> invoked_count_; +}; + +using FullRestoreInfoTest = testing::Test; + +// Test the RestoreFlagChanged callback when the restore flag is reset. +TEST_F(FullRestoreInfoTest, RestoreFlag) { + AccountId account_id1 = AccountId::FromUserEmail("aaa@gmail.com"); + AccountId account_id2 = AccountId::FromUserEmail("bbb@gmail.com"); + + FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id1, true); + + FakeFullRestoreInfoObserver observer; + FullRestoreInfo::GetInstance()->AddObserver(&observer); + + // Not change the restore flag + FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id1, true); + FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id2, false); + EXPECT_EQ(0, observer.InvokedCount(account_id1)); + EXPECT_EQ(0, observer.InvokedCount(account_id2)); + EXPECT_TRUE(FullRestoreInfo::GetInstance()->ShouldRestore(account_id1)); + EXPECT_FALSE(FullRestoreInfo::GetInstance()->ShouldRestore(account_id2)); + + // Change the restore flag + FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id1, false); + FullRestoreInfo::GetInstance()->SetRestoreFlag(account_id2, true); + EXPECT_EQ(1, observer.InvokedCount(account_id1)); + EXPECT_EQ(1, observer.InvokedCount(account_id2)); + EXPECT_FALSE(observer.ShouldRestore(account_id1)); + EXPECT_TRUE(observer.ShouldRestore(account_id2)); + EXPECT_FALSE(FullRestoreInfo::GetInstance()->ShouldRestore(account_id1)); + EXPECT_TRUE(FullRestoreInfo::GetInstance()->ShouldRestore(account_id2)); +} + +} // namespace full_restore
diff --git a/components/full_restore/full_restore_utils.cc b/components/full_restore/full_restore_utils.cc index 41b002a..05febd5 100644 --- a/components/full_restore/full_restore_utils.cc +++ b/components/full_restore/full_restore_utils.cc
@@ -6,18 +6,12 @@ #include "ash/public/cpp/ash_features.h" #include "base/files/file_path.h" +#include "components/account_id/account_id.h" #include "components/full_restore/app_launch_info.h" +#include "components/full_restore/full_restore_info.h" #include "components/full_restore/full_restore_save_handler.h" #include "components/full_restore/window_info.h" -namespace { - -// Set the default restore flag as false, and it can be reset based on the -// restore setting and the user's choice from notifications. -bool g_restore = false; - -} // namespace - namespace full_restore { void SaveAppLaunchInfo(const base::FilePath& profile_dir, @@ -48,12 +42,8 @@ return window_info; } -bool ShouldRestore() { - return g_restore; -} - -void SetRestoreFlag(bool should_restore) { - g_restore = should_restore; +bool ShouldRestore(const AccountId& account_id) { + return FullRestoreInfo::GetInstance()->ShouldRestore(account_id); } } // namespace full_restore
diff --git a/components/full_restore/full_restore_utils.h b/components/full_restore/full_restore_utils.h index 2e70e81..8bcdafe7 100644 --- a/components/full_restore/full_restore_utils.h +++ b/components/full_restore/full_restore_utils.h
@@ -9,6 +9,8 @@ #include "base/component_export.h" +class AccountId; + namespace aura { class Window; } @@ -37,11 +39,7 @@ // Returns true if we should restore apps and pages based on the restore setting // and the user's choice from the notification. Otherwise, returns false. -COMPONENT_EXPORT(FULL_RESTORE) bool ShouldRestore(); - -// Sets whether we should restore apps and pages, based on the restore setting -// and the user's choice from the notification. -COMPONENT_EXPORT(FULL_RESTORE) void SetRestoreFlag(bool should_restore); +COMPONENT_EXPORT(FULL_RESTORE) bool ShouldRestore(const AccountId& account_id); } // namespace full_restore
diff --git a/components/history_strings.grdp b/components/history_strings.grdp index 48d5f1e..321292b 100644 --- a/components/history_strings.grdp +++ b/components/history_strings.grdp
@@ -33,7 +33,7 @@ Bookmarked </message> <message name="IDS_HISTORY_ENTRY_SUMMARY" desc="Summary of all the fields in a history entry (time, whether the entry is bookmarked, title, and domain)."> - <ph name="TIME"><ex>3:14</ex>$1</ph> <ph name="BOOKMARKED"><ex>bookmarked</ex>$2</ph> <ph name="TITLE"><ex>PI: The Magical Number</ex>$3</ph> <ph name="DOMAIN"><ex>pi.com</ex>$4</ph> + <ph name="CARD_TITLE"><ex>Found 11 search results for Pi</ex>$1</ph> <ph name="TIME"><ex>3:14</ex>$2</ph> <ph name="BOOKMARKED"><ex>bookmarked</ex>$3</ph> <ph name="TITLE"><ex>PI: The Magical Number</ex>$4</ph> <ph name="DOMAIN"><ex>pi.com</ex>$5</ph> </message> <message name="IDS_HISTORY_FOUND_SEARCH_RESULTS" desc="Message shown when zero or multiple search results are found."> Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'
diff --git a/components/history_strings_grdp/IDS_HISTORY_ENTRY_SUMMARY.png.sha1 b/components/history_strings_grdp/IDS_HISTORY_ENTRY_SUMMARY.png.sha1 new file mode 100644 index 0000000..acb8705 --- /dev/null +++ b/components/history_strings_grdp/IDS_HISTORY_ENTRY_SUMMARY.png.sha1
@@ -0,0 +1 @@ +785909476d8e236d45e20086c8c58d652b948a51 \ No newline at end of file
diff --git a/components/media_router/common/providers/cast/cast_media_source.cc b/components/media_router/common/providers/cast/cast_media_source.cc index 89cb2f4..acc24584 100644 --- a/components/media_router/common/providers/cast/cast_media_source.cc +++ b/components/media_router/common/providers/cast/cast_media_source.cc
@@ -30,43 +30,57 @@ using media_router::DefaultActionPolicy; template <> -const EnumTable<AutoJoinPolicy> EnumTable<AutoJoinPolicy>::instance( - { - {AutoJoinPolicy::kPageScoped, "page_scoped"}, - {AutoJoinPolicy::kTabAndOriginScoped, "tab_and_origin_scoped"}, - {AutoJoinPolicy::kOriginScoped, "origin_scoped"}, - }, - AutoJoinPolicy::kMaxValue); +const EnumTable<AutoJoinPolicy>& EnumTable<AutoJoinPolicy>::GetInstance() { + static const EnumTable<AutoJoinPolicy> kInstance( + { + {AutoJoinPolicy::kPageScoped, "page_scoped"}, + {AutoJoinPolicy::kTabAndOriginScoped, "tab_and_origin_scoped"}, + {AutoJoinPolicy::kOriginScoped, "origin_scoped"}, + }, + AutoJoinPolicy::kMaxValue); + return kInstance; +} template <> -const EnumTable<DefaultActionPolicy> EnumTable<DefaultActionPolicy>::instance( - { - {DefaultActionPolicy::kCreateSession, "create_session"}, - {DefaultActionPolicy::kCastThisTab, "cast_this_tab"}, - }, - DefaultActionPolicy::kMaxValue); +const EnumTable<DefaultActionPolicy>& +EnumTable<DefaultActionPolicy>::GetInstance() { + static const EnumTable<DefaultActionPolicy> kInstance( + { + {DefaultActionPolicy::kCreateSession, "create_session"}, + {DefaultActionPolicy::kCastThisTab, "cast_this_tab"}, + }, + DefaultActionPolicy::kMaxValue); + return kInstance; +} template <> -const EnumTable<CastDeviceCapability> EnumTable<CastDeviceCapability>::instance( - { - {CastDeviceCapability::MULTIZONE_GROUP, "multizone_group"}, - {CastDeviceCapability::DEV_MODE, "dev_mode"}, - {CastDeviceCapability::AUDIO_IN, "audio_in"}, - {CastDeviceCapability::AUDIO_OUT, "audio_out"}, - {CastDeviceCapability::VIDEO_IN, "video_in"}, - {CastDeviceCapability::VIDEO_OUT, "video_out"}, - // NONE deliberately omitted - }, - NonConsecutiveEnumTable); +const EnumTable<CastDeviceCapability>& +EnumTable<CastDeviceCapability>::GetInstance() { + static const EnumTable<CastDeviceCapability> kInstance( + { + {CastDeviceCapability::MULTIZONE_GROUP, "multizone_group"}, + {CastDeviceCapability::DEV_MODE, "dev_mode"}, + {CastDeviceCapability::AUDIO_IN, "audio_in"}, + {CastDeviceCapability::AUDIO_OUT, "audio_out"}, + {CastDeviceCapability::VIDEO_IN, "video_in"}, + {CastDeviceCapability::VIDEO_OUT, "video_out"}, + // NONE deliberately omitted + }, + NonConsecutiveEnumTable); + return kInstance; +} template <> -const EnumTable<ReceiverAppType> EnumTable<ReceiverAppType>::instance( - { - {ReceiverAppType::kOther, "OTHER"}, - {ReceiverAppType::kWeb, "WEB"}, - {ReceiverAppType::kAndroidTv, "ANDROID_TV"}, - }, - ReceiverAppType::kMaxValue); +const EnumTable<ReceiverAppType>& EnumTable<ReceiverAppType>::GetInstance() { + static const EnumTable<ReceiverAppType> kInstance( + { + {ReceiverAppType::kOther, "OTHER"}, + {ReceiverAppType::kWeb, "WEB"}, + {ReceiverAppType::kAndroidTv, "ANDROID_TV"}, + }, + ReceiverAppType::kMaxValue); + return kInstance; +} } // namespace cast_util
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index 890f8e93..a6363ba3 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -231,6 +231,32 @@ match.type == AutocompleteMatchType::SEARCH_SUGGEST_PROFILE; } +// Returns if rich autocompletion had (or would have had for counterfactual +// variations) an impact; i.e. whether the top scoring rich autocompleted +// suggestion outscores the top scoring default suggestion. +bool TopMatchWouldHaveBeenRichAutocompletion(const AutocompleteResult& result) { + // Trigger rich autocompletion logging if the highest scoring match has + // |rich_autocompletion_triggered| set to true indicating it is, or could have + // been, rich autocompleted. It's not sufficient to check the default match + // since counterfactual variations will not allow rich autocompleted matches + // to be the default match. + if (result.empty()) + return false; + + auto get_sort_key = [](const AutocompleteMatch& match) { + return std::make_tuple(match.allowed_to_be_default_match || + match.rich_autocompletion_triggered, + match.relevance); + }; + + auto top_match = std::max_element( + result.begin(), result.end(), + [&](const AutocompleteMatch& match1, const AutocompleteMatch& match2) { + return get_sort_key(match1) < get_sort_key(match2); + }); + return top_match->rich_autocompletion_triggered; +} + } // namespace AutocompleteController::AutocompleteController( @@ -761,9 +787,7 @@ if (notify_default_match) last_time_default_match_changed_ = base::TimeTicks::Now(); - if (default_is_valid && - (result_.default_match()->swapped_fill_into_edit || - !result_.default_match()->prefix_autocompletion.empty())) { + if (TopMatchWouldHaveBeenRichAutocompletion(result_)) { provider_client_->GetOmniboxTriggeredFeatureService()->TriggerFeature( OmniboxTriggeredFeatureService::Feature::kRichAutocompletion); }
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc index 5764e1b..6922d9b 100644 --- a/components/omnibox/browser/autocomplete_match.cc +++ b/components/omnibox/browser/autocomplete_match.cc
@@ -153,6 +153,7 @@ fill_into_edit_additional_text(match.fill_into_edit_additional_text), swapped_fill_into_edit(match.swapped_fill_into_edit), inline_autocompletion(match.inline_autocompletion), + rich_autocompletion_triggered(match.rich_autocompletion_triggered), prefix_autocompletion(match.prefix_autocompletion), split_autocompletion(match.split_autocompletion), allowed_to_be_default_match(match.allowed_to_be_default_match), @@ -213,6 +214,7 @@ fill_into_edit_additional_text = match.fill_into_edit_additional_text; swapped_fill_into_edit = match.swapped_fill_into_edit; inline_autocompletion = match.inline_autocompletion; + rich_autocompletion_triggered = match.rich_autocompletion_triggered; prefix_autocompletion = match.prefix_autocompletion; split_autocompletion = match.split_autocompletion; allowed_to_be_default_match = match.allowed_to_be_default_match; @@ -1176,6 +1178,13 @@ pedal = duplicate_match.pedal; duplicate_match.pedal = nullptr; } + + // Copy |rich_autocompletion_triggered| for counterfactual logging. Only copy + // true values since a rich autocompleted would have + // |allowed_to_be_default_match| true and would be preferred to a non rich + // autocompleted duplicate in non-counterfactual variations. + if (duplicate_match.rich_autocompletion_triggered) + rich_autocompletion_triggered = true; } bool AutocompleteMatch::TryRichAutocompletion( @@ -1186,11 +1195,13 @@ if (!OmniboxFieldTrial::IsRichAutocompletionEnabled()) return false; + bool counterfactual = OmniboxFieldTrial::RichAutocompletionCounterfactual(); + // If the appropriate param is enabled, titles should be shown in the omnibox // regardless of whether the suggestion can be the default. By default, // secondary text should be displayed unless we autocomplete the secondary // text, in which case |fill_into_edit_additional_text| will be overridden. - if (OmniboxFieldTrial::RichAutocompletionShowTitles()) + if (OmniboxFieldTrial::RichAutocompletionShowTitles() && !counterfactual) fill_into_edit_additional_text = secondary_text; if (input.prevent_inline_autocomplete()) @@ -1205,6 +1216,11 @@ if (base::StartsWith(primary_text_lower, input_text_lower, base::CompareCase::SENSITIVE)) { // |fill_into_edit| should already be set to |primary_text|. + if (counterfactual) + return false; + // This case intentionally doesn't set |rich_autocompletion_triggered| to + // true since presumably non-rich autocompletion should also be able to + // handle this case. inline_autocompletion = primary_text.substr(input_text_lower.length()); allowed_to_be_default_match = true; RecordAdditionalInfo("autocompletion", "primary & prefix"); @@ -1220,6 +1236,9 @@ if (can_autocomplete_titles && base::StartsWith(secondary_text_lower, input_text_lower, base::CompareCase::SENSITIVE)) { + rich_autocompletion_triggered = true; + if (counterfactual) + return false; fill_into_edit = secondary_text; fill_into_edit_additional_text = primary_text; swapped_fill_into_edit = true; @@ -1248,6 +1267,9 @@ if (can_autocomplete_non_prefix && (find_index = FindAtWordbreak(primary_text_lower, input_text_lower)) != base::string16::npos) { + rich_autocompletion_triggered = true; + if (counterfactual) + return false; // |fill_into_edit| should already be set to |primary_text|. inline_autocompletion = primary_text.substr(find_index + input_text_lower.length()); @@ -1261,6 +1283,9 @@ if (can_autocomplete_non_prefix && can_autocomplete_titles && (find_index = FindAtWordbreak(secondary_text_lower, input_text_lower)) != base::string16::npos) { + rich_autocompletion_triggered = true; + if (counterfactual) + return false; fill_into_edit = secondary_text; fill_into_edit_additional_text = primary_text; swapped_fill_into_edit = true; @@ -1284,6 +1309,9 @@ !(input_words = FindWordsSequentiallyAtWordbreak(primary_text_lower, input_text_lower)) .empty()) { + rich_autocompletion_triggered = true; + if (counterfactual) + return false; // |fill_into_edit| should already be set to |primary_text|. split_autocompletion = SplitAutocompletion( primary_text_lower, @@ -1304,6 +1332,9 @@ !(input_words = FindWordsSequentiallyAtWordbreak(secondary_text_lower, input_text_lower)) .empty()) { + rich_autocompletion_triggered = true; + if (counterfactual) + return false; fill_into_edit = secondary_text; fill_into_edit_additional_text = primary_text; swapped_fill_into_edit = true;
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index 3a5cf0f..4e72c1b0 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -544,6 +544,16 @@ // The inline autocompletion to display after the user's input in the // omnibox, if this match becomes the default match. It may be empty. base::string16 inline_autocompletion; + // Whether rich autocompletion triggered; i.e. this suggestion *is or could + // have been* rich autocompleted. This is usually redundant and checking + // whether either of |prefix_autocompletion| or |split_autocompletion| are + // non-empty should be used instead to determine if this suggestion *is* rich + // autocompelted. But for counterfactual variations, the latter 2 aren't + // copied when deduping matches to avoid showing rich autocompletion and so + // can't be used to trigger logging. + // TODO(manukh): remove |rich_autocompletion_triggered| when counterfactual + // experiments end. + bool rich_autocompletion_triggered = false; // The inline autocompletion to display before the user's input in the // omnibox, if this match becomes the default match. Always empty if // non-prefix autocompletion is disabled.
diff --git a/components/omnibox/browser/autocomplete_match_unittest.cc b/components/omnibox/browser/autocomplete_match_unittest.cc index 1d1933a..7fdf8e01 100644 --- a/components/omnibox/browser/autocomplete_match_unittest.cc +++ b/components/omnibox/browser/autocomplete_match_unittest.cc
@@ -502,6 +502,7 @@ bool input_prevent_inline_autocomplete, const std::string primary_text, const std::string secondary_text, bool expected_return, + bool expected_rich_autocompletion_triggered, const std::string expected_inline_autocompletion, const std::string expected_prefix_autocompletion, const std::string expected_fill_into_edit_second_line, @@ -518,6 +519,9 @@ base::UTF8ToUTF16(secondary_text), input), expected_return); + EXPECT_EQ(match.rich_autocompletion_triggered, + expected_rich_autocompletion_triggered); + EXPECT_EQ(base::UTF16ToUTF8(match.inline_autocompletion).c_str(), expected_inline_autocompletion); EXPECT_EQ(base::UTF16ToUTF8(match.prefix_autocompletion).c_str(), @@ -545,31 +549,32 @@ {"RichAutocompletionSplitUrlCompletion", "true"}, }); - // Prefer autocompleting primary text prefix. + // Prefer autocompleting primary text prefix. Should not set + // |rich_autocompletion_triggered|. { SCOPED_TRACE("primary prefix"); - test("x", false, "x_mixd_x_primary", "x_mixd_x_secondary", true, + test("x", false, "x_mixd_x_primary", "x_mixd_x_secondary", true, false, "_mixd_x_primary", "", "x_mixd_x_secondary", false, true); } // Otherwise, prefer secondary text prefix. { SCOPED_TRACE("secondary prefix"); - test("x", false, "y_mixd_x_primary", "x_mixd_x_secondary", true, + test("x", false, "y_mixd_x_primary", "x_mixd_x_secondary", true, true, "_mixd_x_secondary", "", "y_mixd_x_primary", true, true); } // Otherwise, prefer primary text non-prefix (wordbreak). { SCOPED_TRACE("primary non-prefix"); - test("x", false, "y_mixd_x_primary", "y_mixd_x_secondary", true, + test("x", false, "y_mixd_x_primary", "y_mixd_x_secondary", true, true, "_primary", "y_mixd_", "y_mixd_x_secondary", false, true); } // Otherwise, prefer secondary text non-prefix (wordbreak). { SCOPED_TRACE("secondary non-prefix"); - test("x", false, "y_mid_y_primary", "y_mixd_x_secondary", true, + test("x", false, "y_mid_y_primary", "y_mixd_x_secondary", true, true, "_secondary", "y_mixd_", "y_mid_y_primary", true, true); } @@ -583,15 +588,15 @@ // Otherwise, don't autocomplete but still set |fill_into_edit_second_line| { SCOPED_TRACE("no autocompletion applicable"); - test("x", false, "y_mid_y_primary", "y_mid_y_secondary", false, "", "", - "y_mid_y_secondary", false, false); + test("x", false, "y_mid_y_primary", "y_mid_y_secondary", false, false, "", + "", "y_mid_y_secondary", false, false); } // Don't autocomplete if |prevent_inline_autocomplete| is true. { SCOPED_TRACE("prevent inline autocomplete"); - test("x", true, "x_mixd_x_primary", "x_mixd_x_secondary", false, "", "", - "x_mixd_x_secondary", false, false); + test("x", true, "x_mixd_x_primary", "x_mixd_x_secondary", false, false, + "", "", "x_mixd_x_secondary", false, false); } } @@ -604,24 +609,80 @@ {"RichAutocompletionTwoLineOmnibox", "true"}, {"RichAutocompletionShowTitles", "true"}, {"RichAutocompletionAutocompleteNonPrefixAll", "true"}, - {"RichAutocompletionAutocompleteTitlesMinChar", "2"}, + {"RichAutocompletionAutocompleteTitlesMinChar", "3"}, {"RichAutocompletionAutocompleteNonPrefixMinChar", "2"}, {"RichAutocompletionSplitCompletionMinChar", "2"}, }); + // Do autocomplete title if input is greater than limits. + { + SCOPED_TRACE("min char shorter than input"); + test("x_prim", false, "y_mixd_x_primary", "x_mixd_x_secondary", true, + true, "ary", "y_mixd_", "x_mixd_x_secondary", false, true); + } + + // Usually, title autocompletion is preferred to non-prefix. Autocomplete + // non-prefix if title autocompletion has a limit larger than the input. + { + SCOPED_TRACE( + "title min char longer & non-prefix min char shorter than input"); + test("x_", false, "y_mixd_x_primary", "x_mixd_x_secondary", true, true, + "primary", "y_mixd_", "x_mixd_x_secondary", false, true); + } + // Don't autocomplete title and non-prefix if input is less than limits. { - SCOPED_TRACE("min char"); - test("x", false, "y_mixd_x_primary", "x_mixd_x_secondary", false, "", "", - "x_mixd_x_secondary", false, false); + SCOPED_TRACE("min char longer than input"); + test("x", false, "y_mixd_x_primary", "x_mixd_x_secondary", false, false, + "", "", "x_mixd_x_secondary", false, false); } } // Don't autocomplete if IsRichAutocompletionEnabled is disabled { SCOPED_TRACE("feature disabled"); - test("x", false, "x_mixd_x_primary", "x_mixd_x_secondary", false, "", "", - "", false, false); + test("x", false, "x_mixd_x_primary", "x_mixd_x_secondary", false, false, "", + "", "", false, false); + } + + // Don't autocomplete if RichAutocompletionCounterfactual param is enabled; + // do set rich_autocompletion_triggered if it would have autocompleted. + { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeatureWithParameters( + omnibox::kRichAutocompletion, + { + {"RichAutocompletionAutocompleteTitles", "true"}, + {"RichAutocompletionTwoLineOmnibox", "true"}, + {"RichAutocompletionShowTitles", "true"}, + {"RichAutocompletionAutocompleteNonPrefixAll", "true"}, + {"RichAutocompletionAutocompleteTitlesMinChar", "3"}, + {"RichAutocompletionAutocompleteNonPrefixMinChar", "2"}, + {"RichAutocompletionSplitCompletionMinChar", "2"}, + {"RichAutocompletionCounterfactual", "true"}, + }); + + // Do trigger if input is greater than limits. + { + SCOPED_TRACE("min char shorter than input, counterfactual"); + test("x_prim", false, "y_mixd_x_primary", "x_mixd_x_secondary", false, + true, "", "", "", false, false); + } + + { + SCOPED_TRACE( + "title min char longer & non-prefix min char shorter than input, " + "counterfactual"); + test("x_", false, "y_mixd_x_primary", "x_mixd_x_secondary", false, true, + "", "", "", false, false); + } + + // Don't trigger if input is less than limits. + { + SCOPED_TRACE("min char longer than input, counterfactual"); + test("x", false, "y_mixd_x_primary", "x_mixd_x_secondary", false, false, + "", "", "", false, false); + } } }
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc index e95e1c0..9f67deeb 100644 --- a/components/omnibox/browser/autocomplete_result.cc +++ b/components/omnibox/browser/autocomplete_result.cc
@@ -620,7 +620,7 @@ if (top_match->type != ACMatchType::SEARCH_SUGGEST_ENTITY) return; - // Search the duplicates for a equivalent non-entity search suggestion. + // Search the duplicates for an equivalent non-entity search suggestion. for (auto it = top_match->duplicate_matches.begin(); it != top_match->duplicate_matches.end(); ++it) { // Reject any ineligible duplicates.
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 7b064c1..661fa95 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -736,6 +736,12 @@ kRichAutocompletionSplitCompletionMinCharParam, 0); } +bool OmniboxFieldTrial::RichAutocompletionCounterfactual() { + return base::GetFieldTrialParamByFeatureAsBool( + omnibox::kRichAutocompletion, kRichAutocompletionCounterfactualParam, + false); +} + bool OmniboxFieldTrial::IsOnDeviceHeadSuggestEnabledForIncognito() { return base::FeatureList::IsEnabled(omnibox::kOnDeviceHeadProviderIncognito); } @@ -959,6 +965,8 @@ "RichAutocompletionSplitUrlCompletion"; const char OmniboxFieldTrial::kRichAutocompletionSplitCompletionMinCharParam[] = "RichAutocompletionSplitCompletionMinChar"; +const char OmniboxFieldTrial::kRichAutocompletionCounterfactualParam[] = + "RichAutocompletionCounterfactual"; const char OmniboxFieldTrial::kOmniboxUIUnelideURLOnHoverThresholdMsParam[] = "OmniboxUIUnelideURLOnHoverThresholdMsdMs";
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 593a75d3..82a701d 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -410,6 +410,7 @@ bool RichAutocompletionSplitTitleCompletion(); bool RichAutocompletionSplitUrlCompletion(); size_t RichAutocompletionSplitCompletionMinChar(); +bool RichAutocompletionCounterfactual(); // On Device Head Suggestions feature and its helper functions. bool IsOnDeviceHeadSuggestEnabledForIncognito(); @@ -548,6 +549,7 @@ extern const char kRichAutocompletionSplitTitleCompletionParam[]; extern const char kRichAutocompletionSplitUrlCompletionParam[]; extern const char kRichAutocompletionSplitCompletionMinCharParam[]; +extern const char kRichAutocompletionCounterfactualParam[]; // Parameter names used by omnibox experiments that hide the path (and // optionally subdomains) in the steady state.
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn index 5c1584d..454066a 100644 --- a/components/payments/content/BUILD.gn +++ b/components/payments/content/BUILD.gn
@@ -38,6 +38,8 @@ "payment_request_converter.h", "payment_request_spec.cc", "payment_request_spec.h", + "payments_userdata_key.cc", + "payments_userdata_key.h", "secure_payment_confirmation_app.cc", "secure_payment_confirmation_app.h", "secure_payment_confirmation_app_factory.cc",
diff --git a/components/payments/content/android/BUILD.gn b/components/payments/content/android/BUILD.gn index 330ba2ae..fa36bb8 100644 --- a/components/payments/content/android/BUILD.gn +++ b/components/payments/content/android/BUILD.gn
@@ -72,9 +72,18 @@ ] } +android_resources("minimal_java_resources") { + sources = [ + "//components/payments/content/android/google_pay_res/drawable/google_pay.xml", + "//components/payments/content/android/google_pay_res/values-night/colors.xml", + "//components/payments/content/android/google_pay_res/values/colors.xml", + ] +} + android_resources("java_resources") { sources = payments_java_resources deps = [ + ":minimal_java_resources", "//components/browser_ui/strings/android:browser_ui_strings_grd", "//components/browser_ui/styles/android:java_resources", "//components/strings:components_strings_grd", @@ -110,7 +119,7 @@ ] } -android_library("java") { +android_library("full_java") { annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] sources = [ "java/src/org/chromium/components/payments/AndroidPaymentApp.java", @@ -123,23 +132,14 @@ "java/src/org/chromium/components/payments/JniPaymentApp.java", "java/src/org/chromium/components/payments/JourneyLogger.java", "java/src/org/chromium/components/payments/MojoPaymentRequestGateKeeper.java", - "java/src/org/chromium/components/payments/MojoStructCollection.java", "java/src/org/chromium/components/payments/OriginSecurityChecker.java", - "java/src/org/chromium/components/payments/PaymentApp.java", - "java/src/org/chromium/components/payments/PaymentAppFactoryDelegate.java", - "java/src/org/chromium/components/payments/PaymentAppFactoryInterface.java", - "java/src/org/chromium/components/payments/PaymentAppFactoryParams.java", - "java/src/org/chromium/components/payments/PaymentAppService.java", "java/src/org/chromium/components/payments/PaymentDetailsConverter.java", - "java/src/org/chromium/components/payments/PaymentHandlerHost.java", "java/src/org/chromium/components/payments/PaymentManifestDownloader.java", "java/src/org/chromium/components/payments/PaymentManifestParser.java", "java/src/org/chromium/components/payments/PaymentNotShownError.java", "java/src/org/chromium/components/payments/PaymentOptionsUtils.java", - "java/src/org/chromium/components/payments/PaymentRequestParams.java", "java/src/org/chromium/components/payments/PaymentRequestService.java", "java/src/org/chromium/components/payments/PaymentRequestServiceUtil.java", - "java/src/org/chromium/components/payments/PaymentRequestSpec.java", "java/src/org/chromium/components/payments/PaymentResponseHelper.java", "java/src/org/chromium/components/payments/PaymentResponseHelperInterface.java", "java/src/org/chromium/components/payments/PaymentUiServiceTestInterface.java", @@ -155,6 +155,7 @@ resources_package = "org.chromium.components.payments" deps = [ ":java_resources", + ":minimal_java", ":service_java", "//base:base_java", "//base:jni_java", @@ -177,14 +178,53 @@ "//url:origin_java", ] srcjar_deps = [ - ":method_strings_generated_srcjar", - ":payment_app_type_generated_enum", ":payments_journey_logger_enum_javagen", ":prefs_strings_generated_srcjar", ] resources_package = "org.chromium.components.payments" } +# Minimal target that only includes what downstream code depends on. +android_library("minimal_java") { + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + sources = [ + "java/src/org/chromium/components/payments/MojoStructCollection.java", + "java/src/org/chromium/components/payments/PaymentApp.java", + "java/src/org/chromium/components/payments/PaymentAppFactoryDelegate.java", + "java/src/org/chromium/components/payments/PaymentAppFactoryInterface.java", + "java/src/org/chromium/components/payments/PaymentAppFactoryParams.java", + "java/src/org/chromium/components/payments/PaymentAppService.java", + "java/src/org/chromium/components/payments/PaymentHandlerHost.java", + "java/src/org/chromium/components/payments/PaymentRequestParams.java", + "java/src/org/chromium/components/payments/PaymentRequestSpec.java", + ] + deps = [ + ":service_java", + "//base:base_java", + "//base:jni_java", + "//components/autofill/android:payments_autofill_java", + "//components/payments/mojom:mojom_java", + "//content/public/android:content_java", + "//mojo/public/java:bindings_java", + "//third_party/android_deps:androidx_annotation_annotation_java", + "//third_party/android_deps:androidx_collection_collection_java", + "//third_party/blink/public/mojom:android_mojo_bindings_java", + "//url:origin_java", + ] + srcjar_deps = [ + ":method_strings_generated_srcjar", + ":payment_app_type_generated_enum", + ] + resources_package = "org.chromium.components.payments" +} + +java_group("java") { + deps = [ + ":full_java", + ":minimal_java", + ] +} + android_aidl("payment_details_update_service_aidl") { interface_file = "java/src/org/chromium/components/payments/payment_details_update_service.aidl" sources = [
diff --git a/components/payments/content/android/java/res/drawable/google_pay.xml b/components/payments/content/android/google_pay_res/drawable/google_pay.xml similarity index 100% rename from components/payments/content/android/java/res/drawable/google_pay.xml rename to components/payments/content/android/google_pay_res/drawable/google_pay.xml
diff --git a/components/payments/content/android/java/res/values-night/colors.xml b/components/payments/content/android/google_pay_res/values-night/colors.xml similarity index 100% rename from components/payments/content/android/java/res/values-night/colors.xml rename to components/payments/content/android/google_pay_res/values-night/colors.xml
diff --git a/components/payments/content/android/google_pay_res/values/colors.xml b/components/payments/content/android/google_pay_res/values/colors.xml new file mode 100644 index 0000000..e529bd4 --- /dev/null +++ b/components/payments/content/android/google_pay_res/values/colors.xml
@@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2020 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<resources xmlns:tools="http://schemas.android.com/tools"> + <!-- Payments UI colors --> + <color name="google_pay_icon_color">@color/modern_grey_700</color> +</resources>
diff --git a/components/payments/content/android/java/res/values/colors.xml b/components/payments/content/android/java/res/values/colors.xml index ef86bcb..8cee1e6 100644 --- a/components/payments/content/android/java/res/values/colors.xml +++ b/components/payments/content/android/java/res/values/colors.xml
@@ -8,5 +8,4 @@ <color name="payment_request_bg">@color/sheet_bg_color</color> <color name="payments_section_edit_background">@color/default_bg_color_secondary</color> <color name="payments_section_chevron">@color/black_alpha_30</color> - <color name="google_pay_icon_color">@color/modern_grey_700</color> </resources>
diff --git a/components/payments/content/android/payments_java_resources.gni b/components/payments/content/android/payments_java_resources.gni index e488f1d..4d9a4a6 100644 --- a/components/payments/content/android/payments_java_resources.gni +++ b/components/payments/content/android/payments_java_resources.gni
@@ -3,7 +3,6 @@ # found in the LICENSE file. payments_java_resources = [ - "//components/payments/content/android/java/res/drawable/google_pay.xml", "//components/payments/content/android/java/res/layout/payment_handler_content.xml", "//components/payments/content/android/java/res/layout/payment_minimal_ui_content.xml", "//components/payments/content/android/java/res/layout/payment_minimal_ui_toolbar.xml", @@ -17,7 +16,6 @@ "//components/payments/content/android/java/res/layout/payment_request_header.xml", "//components/payments/content/android/java/res/layout/payment_request_spinny.xml", "//components/payments/content/android/java/res/layout/payments_request_editor_textview.xml", - "//components/payments/content/android/java/res/values-night/colors.xml", "//components/payments/content/android/java/res/values-sw600dp/dimens.xml", "//components/payments/content/android/java/res/values/colors.xml", "//components/payments/content/android/java/res/values/dimens.xml",
diff --git a/components/payments/content/payment_handler_host.h b/components/payments/content/payment_handler_host.h index 53ef2ff4..6f40bdd 100644 --- a/components/payments/content/payment_handler_host.h +++ b/components/payments/content/payment_handler_host.h
@@ -54,6 +54,8 @@ mojom::PaymentAddressPtr shipping_address) = 0; }; + static const char kWebContentsUserDataKey[]; + // The |delegate| cannot be null and must outlive this object. Typically this // is accomplished by the |delegate| owning this object. The |web_contents| is // used for developer tools logging and should be from the same browser
diff --git a/components/payments/content/payments_userdata_key.cc b/components/payments/content/payments_userdata_key.cc new file mode 100644 index 0000000..9c05d72 --- /dev/null +++ b/components/payments/content/payments_userdata_key.cc
@@ -0,0 +1,12 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/payments/content/payments_userdata_key.h" + +namespace payments { + +const char kPaymentHandlerWebContentsUserDataKey[] = + "payment_handler_web_contents_user_data"; + +} // namespace payments
diff --git a/components/payments/content/payments_userdata_key.h b/components/payments/content/payments_userdata_key.h new file mode 100644 index 0000000..916345c --- /dev/null +++ b/components/payments/content/payments_userdata_key.h
@@ -0,0 +1,15 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_USERDATA_KEY_H_ +#define COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_USERDATA_KEY_H_ + +namespace payments { + +// This is used as the user data key for the payment handler web-contents. +extern const char kPaymentHandlerWebContentsUserDataKey[]; + +} // namespace payments + +#endif // COMPONENTS_PAYMENTS_CONTENT_PAYMENTS_USERDATA_KEY_H_
diff --git a/components/pdf/browser/pdf_web_contents_helper.cc b/components/pdf/browser/pdf_web_contents_helper.cc index cfac16c..51bb84e 100644 --- a/components/pdf/browser/pdf_web_contents_helper.cc +++ b/components/pdf/browser/pdf_web_contents_helper.cc
@@ -159,7 +159,9 @@ void PDFWebContentsHelper::OnSelectionEvent(ui::SelectionEventType event) {} -void PDFWebContentsHelper::OnDragUpdate(const gfx::PointF& position) {} +void PDFWebContentsHelper::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) {} std::unique_ptr<ui::TouchHandleDrawable> PDFWebContentsHelper::CreateDrawable() {
diff --git a/components/pdf/browser/pdf_web_contents_helper.h b/components/pdf/browser/pdf_web_contents_helper.h index 3cb2550..fda469f 100644 --- a/components/pdf/browser/pdf_web_contents_helper.h +++ b/components/pdf/browser/pdf_web_contents_helper.h
@@ -51,7 +51,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; void OnSelectionEvent(ui::SelectionEventType event) override; - void OnDragUpdate(const gfx::PointF& position) override; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; void DidScroll() override;
diff --git a/components/safe_browsing/content/password_protection/password_protection_request.cc b/components/safe_browsing/content/password_protection/password_protection_request.cc index 6c3fd3a..9cc13012 100644 --- a/components/safe_browsing/content/password_protection/password_protection_request.cc +++ b/components/safe_browsing/content/password_protection/password_protection_request.cc
@@ -280,6 +280,11 @@ #if defined(OS_ANDROID) LoginReputationClientRequest::ReferringAppInfo referring_app_info = password_protection_service_->GetReferringAppInfo(web_contents_); + UMA_HISTOGRAM_ENUMERATION( + "PasswordProtection.RequestReferringAppSource", + referring_app_info.referring_app_source(), + LoginReputationClientRequest::ReferringAppInfo::ReferringAppSource_MAX + + 1); *request_proto_->mutable_referring_app_info() = std::move(referring_app_info); #endif // defined(OS_ANDROID)
diff --git a/components/search_engines/android/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc index 1c9bc5b..e9cc1d42 100644 --- a/components/search_engines/android/template_url_service_android.cc +++ b/components/search_engines/android/template_url_service_android.cc
@@ -289,8 +289,19 @@ auto existing_play_api_turl = std::find_if( template_urls.cbegin(), template_urls.cend(), [](const TemplateURL* turl) { return turl->created_from_play_api(); }); - if (existing_play_api_turl != template_urls.cend()) + if (existing_play_api_turl != template_urls.cend()) { + // Migrate old Play API database entries that were incorrectly marked as + // safe_for_autoreplace() before M89. + // TODO(tommycli): Delete this once the below metric approaches zero. + TemplateURL* turl = *existing_play_api_turl; + if (turl->safe_for_autoreplace()) { + TemplateURLService::LogSearchTemplateURLEvent( + TemplateURLService::MIGRATE_SAFE_FOR_AUTOREPLACE_PLAY_API_ENGINE); + template_url_service_->ResetTemplateURL(turl, turl->short_name(), + turl->keyword(), turl->url()); + } return false; + } base::string16 keyword = base::android::ConvertJavaStringToUTF16(env, jkeyword); @@ -305,12 +316,14 @@ favicon_url = base::android::ConvertJavaStringToUTF8(jfavicon_url); } - TemplateURL* t_url = - template_url_service_->CreateOrUpdateTemplateURLFromPlayAPIData( - name, keyword, search_url, suggest_url, favicon_url); + TemplateURL* t_url = template_url_service_->CreatePlayAPISearchEngine( + name, keyword, search_url, suggest_url, favicon_url); - if (set_as_default && template_url_service_->CanMakeDefault(t_url)) + // CanMakeDefault() will prevent us from taking over a policy or extension + // defined default search engine. + if (set_as_default && template_url_service_->CanMakeDefault(t_url)) { template_url_service_->SetUserSelectedDefaultSearchProvider(t_url); + } return true; }
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc index 8c5c3f1d..c683c02 100644 --- a/components/search_engines/template_url.cc +++ b/components/search_engines/template_url.cc
@@ -1363,6 +1363,8 @@ : base::Time(), // Prefer engines that CANNOT be auto-replaced. !engine->safe_for_autoreplace(), + // Prefer engines created by Play API. + engine->created_from_play_api(), // More recently modified engines or created engines win. engine->last_modified(), engine->date_created(), // TODO(tommycli): This should be a tie-breaker than provides a total
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc index c2fa54e..c3e599be 100644 --- a/components/search_engines/template_url_service.cc +++ b/components/search_engines/template_url_service.cc
@@ -59,23 +59,6 @@ DELETE_ENGINE_MAX, }; -const char kSearchTemplateURLEventsHistogramName[] = - "Search.TemplateURL.Events"; - -// Values for an enumerated histogram used to track TemplateURL edge cases. -// These are persisted. Do not re-number. -enum SearchTemplateURLEvent { - SYNC_DELETE_SUCCESS = 0, - SYNC_DELETE_FAIL_NONEXISTENT_ENGINE = 1, - SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER = 2, - SYNC_ADD_SUCCESS = 3, - SYNC_ADD_CONVERTED_TO_UPDATE = 4, - SYNC_ADD_FAIL_OTHER_ERROR = 5, - SYNC_UPDATE_SUCCESS = 6, - SYNC_UPDATE_CONVERTED_TO_ADD = 7, - SEARCH_TEMPLATE_URL_EVENT_MAX, -}; - // Returns true iff the change in |change_list| at index |i| should not be sent // up to the server based on its GUIDs presence in |sync_data| or when compared // to changes after it in |change_list|. @@ -324,6 +307,13 @@ } // static +void TemplateURLService::LogSearchTemplateURLEvent( + SearchTemplateURLEvent event) { + UMA_HISTOGRAM_ENUMERATION("Search.TemplateURL.Events", event, + SEARCH_TEMPLATE_URL_EVENT_MAX); +} + +// static void TemplateURLService::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { #if defined(OS_IOS) || defined(OS_ANDROID) @@ -360,9 +350,12 @@ if (template_url_to_replace) *template_url_to_replace = existing_url; if (existing_url) { - // We already have a TemplateURL for this keyword. Only allow it to be - // replaced if the TemplateURL can be replaced. - return CanReplace(existing_url); + // TODO(tommycli): Currently, this code goes one step beyond + // safe_for_autoreplace() and also forbids automatically modifying + // prepopulated engines. That's debatable, as we already update prepopulated + // provider favicons as the user browses. See UpdateProviderFavicons(). + return existing_url->safe_for_autoreplace() && + existing_url->prepopulate_id() == 0; } // We don't have a TemplateURL with keyword. We still may not allow this @@ -556,14 +549,13 @@ Scoper scoper(this); for (size_t i = 0; i < template_urls_.size();) { - if (template_urls_[i]->date_created() >= created_after && - (created_before.is_null() || - template_urls_[i]->date_created() < created_before) && - CanReplace(template_urls_[i].get()) && + TemplateURL* turl = template_urls_[i].get(); + if (turl->date_created() >= created_after && + (created_before.is_null() || turl->date_created() < created_before) && + turl->safe_for_autoreplace() && turl->prepopulate_id() == 0 && (url_filter.is_null() || - url_filter.Run( - template_urls_[i]->GenerateSearchURL(search_terms_data())))) { - Remove(template_urls_[i].get()); + url_filter.Run(turl->GenerateSearchURL(search_terms_data())))) { + Remove(turl); } else { ++i; } @@ -631,30 +623,36 @@ Update(url, TemplateURL(data)); } -TemplateURL* TemplateURLService::CreateOrUpdateTemplateURLFromPlayAPIData( +TemplateURL* TemplateURLService::CreatePlayAPISearchEngine( const base::string16& title, const base::string16& keyword, const std::string& search_url, const std::string& suggestions_url, const std::string& favicon_url) { - TemplateURL* existing_turl = FindNonExtensionTemplateURLForKeyword(keyword); + // It's the caller's responsibility to check that there are no existing + // Play API for engine, but still CHECK this to avoid polluting the database. + // Currently, we never update Play API engine data. If we ever want to do + // that, we need to change how this method behaves. + const auto match_range = keyword_to_turl_and_length_.equal_range(keyword); + for (auto it = match_range.first; it != match_range.second; ++it) { + CHECK(!it->second.first->created_from_play_api()); + } + TemplateURLData data; - if (existing_turl) - data = existing_turl->data(); data.SetShortName(title); data.SetKeyword(keyword); data.SetURL(search_url); data.suggestions_url = suggestions_url; data.favicon_url = GURL(favicon_url); - data.safe_for_autoreplace = true; data.created_from_play_api = true; - if (existing_turl) { - Update(existing_turl, TemplateURL(data)); - } else { - existing_turl = Add(std::make_unique<TemplateURL>(data)); - DCHECK(existing_turl); - } - return existing_turl; + // Play API engines are created by explicit user gesture, and should not be + // auto-replaceable by an auto-generated engine as the user browses. + data.safe_for_autoreplace = false; + + // The Play API search engine is not guaranteed to be the best engine for + // |keyword|, if there are user-defined, extension, or policy engines. + // In practice on Android, this rarely happens, as there is only policy. + return Add(std::make_unique<TemplateURL>(data)); } void TemplateURLService::UpdateProviderFavicons( @@ -1015,9 +1013,7 @@ if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) { if (!existing_turl) { // Can't DELETE a non-existent engine, although we log it. - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_DELETE_FAIL_NONEXISTENT_ENGINE, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_DELETE_FAIL_NONEXISTENT_ENGINE); error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg); continue; } @@ -1035,13 +1031,9 @@ // likely a source of duplicate search engine entries. crbug.com/1022775 if (existing_turl != GetDefaultSearchProvider()) { Remove(existing_turl); - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_DELETE_SUCCESS, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_DELETE_SUCCESS); } else { - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER); } continue; } @@ -1057,9 +1049,7 @@ if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE) { // This can happen if we have silently deleted a replaceable engine due // to keyword conflict, and Sync server sends us an UPDATE to it. - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_UPDATE_CONVERTED_TO_ADD, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_UPDATE_CONVERTED_TO_ADD); } base::AutoReset<DefaultSearchChangeOrigin> change_origin( @@ -1072,25 +1062,19 @@ if (added) { MaybeUpdateDSEViaPrefs(added); - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_ADD_SUCCESS, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_ADD_SUCCESS); } else { // Currently, in practice, this means that we tried to add a replaceable // duplicate that was worse than our existing entry, but the API doesn't // promise that, so we just log a generic SYNC_ADD_FAIL_OTHER_ERROR. - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_ADD_FAIL_OTHER_ERROR, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_ADD_FAIL_OTHER_ERROR); } } else { if (iter->change_type() == syncer::SyncChange::ACTION_ADD) { // This can happen if we have ignored a DELETE request in the past to // avoid deleting the default search provider, and later on, Sync tries // to re-ADD something it thinks it has deleted. - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_ADD_CONVERTED_TO_UPDATE, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_ADD_CONVERTED_TO_UPDATE); } // Since we've already found |existing_turl| by GUID, this Update() should @@ -1100,9 +1084,7 @@ DCHECK(update_success); MaybeUpdateDSEViaPrefs(existing_turl); - UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName, - SYNC_UPDATE_SUCCESS, - SEARCH_TEMPLATE_URL_EVENT_MAX); + LogSearchTemplateURLEvent(SYNC_UPDATE_SUCCESS); } } @@ -1583,25 +1565,6 @@ }); } -bool TemplateURLService::CanReplace(const TemplateURL* t_url) const { - return !ShowInDefaultList(t_url) && t_url->safe_for_autoreplace(); -} - -TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword( - const base::string16& keyword) { - TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword); - if (!keyword_turl || (keyword_turl->type() == TemplateURL::NORMAL)) - return keyword_turl; - // The extension keyword in the model may be hiding a replaceable - // non-extension keyword. Look for it. - for (const auto& turl : template_urls_) { - if ((turl->type() == TemplateURL::NORMAL) && - (turl->keyword() == keyword)) - return turl.get(); - } - return nullptr; -} - bool TemplateURLService::Update(TemplateURL* existing_turl, const TemplateURL& new_values) { DCHECK(existing_turl); @@ -1944,6 +1907,7 @@ if (new_data.sync_guid.empty()) new_data.GenerateSyncGUID(); new_data.created_by_policy = true; + new_data.safe_for_autoreplace = false; std::unique_ptr<TemplateURL> new_dse_ptr = std::make_unique<TemplateURL>(new_data); TemplateURL* new_dse = new_dse_ptr.get(); @@ -2192,46 +2156,37 @@ return false; } - // Partition into two separate lists, non-replaceable vs replaceable. We don't - // do it in-place, as we later call Remove(), which invalidates iterators. - std::vector<TemplateURL*> non_replaceable_turls; + // Gather the replaceable TemplateURLs to be removed. We don't do it in-place, + // because Remove() invalidates iterators. std::vector<TemplateURL*> replaceable_turls; for (auto it = match_range.first; it != match_range.second; ++it) { TemplateURL* turl = it->second.first; DCHECK_NE(turl, candidate) << "This algorithm runs BEFORE |candidate| is " "added to the keyword map."; - if (CanReplace(turl)) { + if (turl->safe_for_autoreplace()) { replaceable_turls.push_back(turl); - } else { - non_replaceable_turls.push_back(turl); } } - // Add the new candidate to the proper list at the end. Because ties are - // broken via Sync GUID, we specifically do not promise "last one wins". - const bool candidate_is_replaceable = CanReplace(candidate); - if (candidate_is_replaceable) { - replaceable_turls.push_back(candidate); - } else { - non_replaceable_turls.push_back(candidate); + + // Find the BEST engine for |keyword| factoring in the new |candidate|. + TemplateURL* best = GetTemplateURLForKeyword(keyword); + if (!best || candidate->IsBetterThanEngineWithConflictingKeyword(best)) { + best = candidate; } - // Now we remove all but the BEST replaceable engine. - // But if there are ANY non-replaceable engines, we should remove ALL the - // replaceable engines, and we do that by considering best == nullptr. - TemplateURL* best = nullptr; - if (non_replaceable_turls.empty()) { - best = *base::ranges::min_element( - replaceable_turls, [&](const auto& a, const auto& b) { - return a->IsBetterThanEngineWithConflictingKeyword(b); - }); - } + // Remove all the replaceable TemplateURLs that are not the best. for (TemplateURL* turl : replaceable_turls) { - if (turl != best && turl != candidate) { + DCHECK_NE(turl, candidate); + + // Never actually remove the DSE during this phase. This handling defers + // deleting the DSE until it's no longer set as the DSE, analagous to how + // we handle ACTION_DELETE of the DSE in ProcessSyncChanges(). + if (turl != best && turl != default_search_provider_) { Remove(turl); } } // Caller needs to know if |candidate| would have been deleted. - return candidate_is_replaceable && candidate != best; + return candidate != best && candidate->safe_for_autoreplace(); }
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h index ff33ce6..2f9cda4e 100644 --- a/components/search_engines/template_url_service.h +++ b/components/search_engines/template_url_service.h
@@ -102,6 +102,21 @@ bool is_keyword_transition; }; + // Values for an enumerated histogram used to track TemplateURL edge cases. + // These are persisted. Do not re-number. + enum SearchTemplateURLEvent { + SYNC_DELETE_SUCCESS = 0, + SYNC_DELETE_FAIL_NONEXISTENT_ENGINE = 1, + SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER = 2, + SYNC_ADD_SUCCESS = 3, + SYNC_ADD_CONVERTED_TO_UPDATE = 4, + SYNC_ADD_FAIL_OTHER_ERROR = 5, + SYNC_UPDATE_SUCCESS = 6, + SYNC_UPDATE_CONVERTED_TO_ADD = 7, + MIGRATE_SAFE_FOR_AUTOREPLACE_PLAY_API_ENGINE = 8, + SEARCH_TEMPLATE_URL_EVENT_MAX, + }; + TemplateURLService( PrefService* prefs, std::unique_ptr<SearchTermsData> search_terms_data, @@ -112,6 +127,9 @@ TemplateURLService(const Initializer* initializers, const int count); ~TemplateURLService() override; + // Log a SearchTemplateURLEvent. + static void LogSearchTemplateURLEvent(SearchTemplateURLEvent event); + // Register Profile preferences in |registry|. static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); @@ -238,15 +256,17 @@ const base::string16& keyword, const std::string& search_url); - // Creates TemplateURL, populating it with data from Play API. If TemplateURL - // with matching keyword already exists then merges Play API data into it. - // Sets |created_from_play_api| flag. - TemplateURL* CreateOrUpdateTemplateURLFromPlayAPIData( - const base::string16& title, - const base::string16& keyword, - const std::string& search_url, - const std::string& suggestions_url, - const std::string& favicon_url); + // Creates a TemplateURL for |keyword| marked with created_from_play_api(). + // Returns the newly created engine. + // + // This method must NOT be called multiple times for the same |keyword|, + // because that would create duplicate engines. Caller is responsible for + // verifying there are no existing |keyword| created_from_play_api() engines. + TemplateURL* CreatePlayAPISearchEngine(const base::string16& title, + const base::string16& keyword, + const std::string& search_url, + const std::string& suggestions_url, + const std::string& favicon_url); // Updates any search providers matching |potential_search_url| with the new // favicon location |favicon_url|. @@ -539,16 +559,6 @@ // specified host and that TemplateURL has been manually modified. bool CanAddAutogeneratedKeywordForHost(const std::string& host) const; - // Returns true if the TemplateURL is replaceable. This doesn't look at the - // uniqueness of the keyword or host and is intended to be called after those - // checks have been done. This returns true if the TemplateURL doesn't appear - // in the default list and is marked as safe_for_autoreplace. - bool CanReplace(const TemplateURL* t_url) const; - - // Like GetTemplateURLForKeyword(), but ignores extension-provided keywords. - TemplateURL* FindNonExtensionTemplateURLForKeyword( - const base::string16& keyword); - // Updates the information in |existing_turl| using the information from // |new_values|, but the ID for |existing_turl| is retained. Returns whether // |existing_turl| was found in |template_urls_| and thus could be updated.
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc index 7ee2862..211d685 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -321,16 +321,11 @@ } } else if (ShouldInheritParentActivation(navigation_handle)) { // Throttles are only constructed for navigations handled by the network - // stack and we only release filters for committed navigations. - - // These redundant DCHECKs are temporarily added to investigate a crash. - // TODO(crbug.com/1155870): Remove extra DCHECKs after the crash's cause is - // determined. - DCHECK(!filter || navigation_handle->HasCommitted()); - DCHECK(!filter || ShouldInheritActivation( - navigation_handle->GetRedirectChain().front())); - DCHECK(!filter || (navigation_handle->GetRedirectChain().size() == 1)); - DCHECK(!filter); + // stack and we only release filters for committed navigations. When a + // navigation redirects from a URL handled by the network stack to + // about:blank, a filter can already exist here. We replace it to match + // behavior for other about:blank frames. + DCHECK(!filter || navigation_handle->GetRedirectChain().size() != 1); activation_to_inherit = GetFrameActivationState(navigation_handle->GetParentFrame()); }
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm index 156bc47..88cd62c 100644 --- a/components/translate/ios/browser/language_detection_controller.mm +++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -137,7 +137,7 @@ const base::Value* text_content) { std::string model_detected_language; bool is_model_reliable; - base::string16 text = text_content->is_string() + base::string16 text = text_content && text_content->is_string() ? base::UTF8ToUTF16(text_content->GetString()) : base::string16(); std::string language = translate::DeterminePageLanguage(
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn index 9eb282e..1200e64f 100644 --- a/components/vector_icons/BUILD.gn +++ b/components/vector_icons/BUILD.gn
@@ -82,6 +82,7 @@ "sync.icon", "usb.icon", "videocam.icon", + "videocam_off.icon", "videogame_asset.icon", "volume_up.icon", "vr_headset.icon",
diff --git a/components/vector_icons/videocam_off.icon b/components/vector_icons/videocam_off.icon new file mode 100644 index 0000000..b8c6253 --- /dev/null +++ b/components/vector_icons/videocam_off.icon
@@ -0,0 +1,35 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 2.23f, 2.31f, +LINE_TO, 1, 3.55f, +R_LINE_TO, 1.56f, 1.56f, +R_ARC_TO, 1, 1, 0, 0, 0, -0.56f, 0.89f, +R_V_LINE_TO, 8.01f, +R_CUBIC_TO, 0, 0.55f, 0.45f, 1, 1, 1, +R_H_LINE_TO, 9.45f, +R_LINE_TO, 3.14f, 3.14f, +R_LINE_TO, 1.24f, -1.24f, +LINE_TO, 2.23f, 2.31f, +CLOSE, +MOVE_TO, 10.45f, 13, +R_LINE_TO, -6, -6, +H_LINE_TO, 4, +R_V_LINE_TO, 6, +R_H_LINE_TO, 6.45f, +CLOSE, +MOVE_TO, 12, 10, +R_LINE_TO, 2, 2, +LINE_TO, 18, 14.5f, +R_V_LINE_TO, -9, +R_LINE_TO, -4, 3, +V_LINE_TO, 6, +CUBIC_TO, 14, 5.45f, 13.55f, 5, 13, 5, +H_LINE_TO, 7, +R_LINE_TO, 2, 2, +H_LINE_TO, 12, +V_LINE_TO, 10, +CLOSE +
diff --git a/components/viz/common/switches.h b/components/viz/common/switches.h index bf50453..3c3dc763b 100644 --- a/components/viz/common/switches.h +++ b/components/viz/common/switches.h
@@ -31,6 +31,11 @@ VIZ_COMMON_EXPORT extern const char kRunAllCompositorStagesBeforeDraw[]; VIZ_COMMON_EXPORT extern const char kShowAggregatedDamage[]; +// kShowDCLayerDebugBorders shows the debug borders of the overlays and the +// damage rect after using overlays on Windows. Do not use +// kShowDCLayerDebugBorders and kShowAggregatedDamage together because +// kShowAggregatedDamage sets the entire frame as damaged and this causes +// incorrect damage rect borders after using overlays. VIZ_COMMON_EXPORT extern const char kShowDCLayerDebugBorders[]; VIZ_COMMON_EXPORT base::Optional<uint32_t> GetDeadlineToSynchronizeSurfaces();
diff --git a/components/viz/service/display/copy_output_scaling_pixeltest.cc b/components/viz/service/display/copy_output_scaling_pixeltest.cc index 351e28d..34286284 100644 --- a/components/viz/service/display/copy_output_scaling_pixeltest.cc +++ b/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -178,7 +178,7 @@ SurfaceDamageRectList surface_damage_rect_list; renderer()->DrawFrame(&list, 1.0f, viewport_size, gfx::DisplayColorSpaces(), - &surface_damage_rect_list); + std::move(surface_damage_rect_list)); // Call SwapBuffersSkipped(), so the renderer can release related // resources. renderer()->SwapBuffersSkipped();
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc index 64e7b2e..36c3aa11 100644 --- a/components/viz/service/display/dc_layer_overlay.cc +++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -296,23 +296,23 @@ gfx::Rect CalculateOccludingDamageRect( const SharedQuadState* shared_quad_state, - SurfaceDamageRectList* surface_damage_rect_list, + const SurfaceDamageRectList& surface_damage_rect_list, const gfx::Rect& quad_rect_in_root_target_space) { if (!shared_quad_state->overlay_damage_index.has_value()) return quad_rect_in_root_target_space; size_t overlay_damage_index = shared_quad_state->overlay_damage_index.value(); - if (overlay_damage_index >= surface_damage_rect_list->size()) { + if (overlay_damage_index >= surface_damage_rect_list.size()) { DCHECK(false); } // Damage rects in surface_damage_rect_list are arranged from top to bottom. - // (*surface_damage_rect_list)[0] is the one on the very top. - // (*surface_damage_rect_list)[overlay_damage_index] is the damage rect of + // surface_damage_rect_list[0] is the one on the very top. + // surface_damage_rect_list[overlay_damage_index] is the damage rect of // this overlay surface. gfx::Rect occluding_damage_rect; for (size_t i = 0; i < overlay_damage_index; ++i) { - occluding_damage_rect.Union((*surface_damage_rect_list)[i]); + occluding_damage_rect.Union(surface_damage_rect_list[i]); } occluding_damage_rect.Intersect(quad_rect_in_root_target_space); @@ -446,10 +446,10 @@ if (it->shared_quad_state->overlay_damage_index.has_value()) { size_t overlay_damage_index = it->shared_quad_state->overlay_damage_index.value(); - if (overlay_damage_index >= surface_damage_rect_list_->size()) + if (overlay_damage_index >= surface_damage_rect_list_.size()) DCHECK(false); else - (*surface_damage_rect_list_)[overlay_damage_index] = gfx::Rect(); + surface_damage_rect_list_[overlay_damage_index] = gfx::Rect(); } } else { // This is done by subtract the overlay rect fromt the root damage rect. @@ -494,7 +494,7 @@ // |surface_damage_rect_list_|. The union is the result of non-overlay // rects. gfx::Rect root_damage_rect; - for (const auto& damage_rect : *surface_damage_rect_list_) + for (const auto& damage_rect : surface_damage_rect_list_) root_damage_rect.Union(damage_rect); *damage_rect = root_damage_rect; @@ -523,7 +523,20 @@ const gfx::RectF& display_rect, gfx::Rect* damage_rect) { auto* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); + auto& quad_list = render_pass->quad_list; + // Add debug borders for the root damage rect after overlay promotion. + SkColor border_color = SK_ColorGREEN; + auto it = quad_list.InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>( + quad_list.begin(), 1u); + auto* debug_quad = static_cast<DebugBorderDrawQuad*>(*it); + + gfx::Rect rect = *damage_rect; + rect.Inset(kDCLayerDebugBorderInsets); + debug_quad->SetNew(shared_quad_state, rect, rect, border_color, + kDCLayerDebugBorderWidth); + + // Add debug borders for overlays/underlays for (const auto& dc_layer : *dc_layer_overlays) { gfx::RectF overlay_rect(dc_layer.quad_rect); dc_layer.transform.TransformRect(&overlay_rect); @@ -532,13 +545,11 @@ // Overlay:red, Underlay:blue. SkColor border_color = dc_layer.z_order > 0 ? SK_ColorRED : SK_ColorBLUE; - - auto& quad_list = render_pass->quad_list; auto it = quad_list.InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>( quad_list.begin(), 1u); - auto* debug_quad = static_cast<DebugBorderDrawQuad*>(*it); + gfx::Rect rect = gfx::ToEnclosingRect(overlay_rect); rect.Inset(kDCLayerDebugBorderInsets); debug_quad->SetNew(shared_quad_state, rect, rect, border_color, @@ -580,12 +591,12 @@ const FilterOperationsMap& render_pass_backdrop_filters, AggregatedRenderPassList* render_pass_list, gfx::Rect* damage_rect, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, DCLayerOverlayList* dc_layer_overlays) { gfx::Rect this_frame_underlay_rect; bool this_frame_has_occluding_damage_rect = false; processed_yuv_overlay_count_ = 0; - surface_damage_rect_list_ = surface_damage_rect_list; + surface_damage_rect_list_ = std::move(surface_damage_rect_list); // Output rects of child render passes that have backdrop filters in target // space. These rects are used to determine if the overlay rect could be read @@ -718,7 +729,7 @@ gfx::Rect occluding_damage_rect; if (!is_overlay) { occluding_damage_rect = CalculateOccludingDamageRect( - it->shared_quad_state, surface_damage_rect_list, + it->shared_quad_state, surface_damage_rect_list_, quad_rectangle_in_target_space); // Used by a histogram. @@ -760,8 +771,7 @@ this_frame_has_occluding_damage_rect, damage_rect); } - if (debug_settings_->show_dc_layer_debug_borders && - dc_layer_overlays->size() > 0) { + if (debug_settings_->show_dc_layer_debug_borders) { InsertDebugBorderDrawQuad(dc_layer_overlays, root_render_pass, display_rect, damage_rect); } @@ -918,7 +928,7 @@ } else { // Entire replacement quad must be redrawn. damage_rect->Union(quad_rectangle); - surface_damage_rect_list_->push_back(quad_rectangle); + surface_damage_rect_list_.push_back(quad_rectangle); } // We only compare current frame's first underlay with the previous frame's
diff --git a/components/viz/service/display/dc_layer_overlay.h b/components/viz/service/display/dc_layer_overlay.h index 47588a6..56e5145 100644 --- a/components/viz/service/display/dc_layer_overlay.h +++ b/components/viz/service/display/dc_layer_overlay.h
@@ -100,7 +100,7 @@ const FilterOperationsMap& render_pass_backdrop_filters, AggregatedRenderPassList* render_passes, gfx::Rect* damage_rect, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, DCLayerOverlayList* dc_layer_overlays); void ClearOverlayState(); // This is the damage contribution due to previous frame's overlays which can @@ -185,7 +185,7 @@ }; std::vector<OverlayRect> previous_frame_overlay_rects_; std::vector<OverlayRect> current_frame_overlay_rects_; - SurfaceDamageRectList* surface_damage_rect_list_; + SurfaceDamageRectList surface_damage_rect_list_; scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index 4bcc35a..e4196d75 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -209,7 +209,7 @@ float device_scale_factor, const gfx::Size& device_viewport_size, const gfx::DisplayColorSpaces& display_color_spaces, - SurfaceDamageRectList* surface_damage_rect_list) { + SurfaceDamageRectList surface_damage_rect_list) { DCHECK(visible_); TRACE_EVENT0("viz,benchmark", "DirectRenderer::DrawFrame"); UMA_HISTOGRAM_COUNTS_1M( @@ -326,8 +326,9 @@ overlay_processor_->ProcessForOverlays( resource_provider_, render_passes_in_draw_order, output_surface_->color_matrix(), render_pass_filters_, - render_pass_backdrop_filters_, surface_damage_rect_list, primary_plane, - ¤t_frame()->overlay_list, ¤t_frame()->root_damage_rect, + render_pass_backdrop_filters_, std::move(surface_damage_rect_list), + primary_plane, ¤t_frame()->overlay_list, + ¤t_frame()->root_damage_rect, ¤t_frame()->root_content_bounds); // If we promote any quad to an underlay then the main plane must support
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 6288953f..0bc00c4b 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -74,7 +74,7 @@ float device_scale_factor, const gfx::Size& device_viewport_size, const gfx::DisplayColorSpaces& display_color_spaces, - SurfaceDamageRectList* surface_damage_rect_list); + SurfaceDamageRectList surface_damage_rect_list); // Public interface implemented by subclasses. struct SwapFrameData {
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index f464541..9332039 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -766,7 +766,7 @@ overlay_processor_->SetFrameSequenceNumber(frame_sequence_number_); renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_, current_surface_size, display_color_spaces_, - &frame.surface_damage_rect_list_); + std::move(frame.surface_damage_rect_list_)); switch (output_surface_->type()) { case OutputSurface::Type::kSoftware: UMA_HISTOGRAM_COUNTS_1M(
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc index e0235468..372bb83b 100644 --- a/components/viz/service/display/gl_renderer_unittest.cc +++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -102,7 +102,8 @@ gfx::DisplayColorSpaces()) { SurfaceDamageRectList surface_damage_rect_list; renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size, - display_color_spaces, &surface_damage_rect_list); + display_color_spaces, + std::move(surface_damage_rect_list)); } static const Program* current_program(GLRenderer* renderer) { @@ -2576,7 +2577,7 @@ SurfaceDamageRectList surface_damage_rect_list; renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor, viewport_size, gfx::DisplayColorSpaces(), - &surface_damage_rect_list); + std::move(surface_damage_rect_list)); } RendererSettings settings_; @@ -2615,7 +2616,7 @@ const FilterOperationsMap& render_pass_backdrop_filters, AggregatedRenderPassList* render_passes, gfx::Rect* damage_rect, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, DCLayerOverlayList* dc_layer_overlays)); protected:
diff --git a/components/viz/service/display/overlay_ca_unittest.cc b/components/viz/service/display/overlay_ca_unittest.cc index 3bcc0d3..537f8f6 100644 --- a/components/viz/service/display/overlay_ca_unittest.cc +++ b/components/viz/service/display/overlay_ca_unittest.cc
@@ -272,8 +272,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(1U, ca_layer_list.size()); gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage(); @@ -299,8 +299,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, ca_layer_list.size()); gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage(); EXPECT_EQ(kRenderPassOutputRect, overlay_damage); @@ -330,8 +330,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(1U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -356,8 +356,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(1U, ca_layer_list.size()); EXPECT_TRUE(ca_layer_list.back().shared_state->is_clipped); @@ -384,8 +384,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -409,8 +409,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &ca_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &ca_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -430,8 +430,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(), render_pass_filters_, render_pass_backdrop_filters_, - &surface_damage_rect_list_, nullptr, &ca_layer_list_, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list_), nullptr, &ca_layer_list_, + &damage_rect_, &content_bounds_); } AggregatedRenderPassList pass_list_; AggregatedRenderPass* pass_;
diff --git a/components/viz/service/display/overlay_dc_unittest.cc b/components/viz/service/display/overlay_dc_unittest.cc index 209c350..f392032 100644 --- a/components/viz/service/display/overlay_dc_unittest.cc +++ b/components/viz/service/display/overlay_dc_unittest.cc
@@ -313,8 +313,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(2U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -364,8 +364,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(2U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -426,8 +426,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); EXPECT_EQ(-1, dc_layer_list.back().z_order); @@ -470,8 +470,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); EXPECT_EQ(-1, dc_layer_list.back().z_order); @@ -500,8 +500,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); EXPECT_EQ(1, dc_layer_list.back().z_order); @@ -550,8 +550,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); // Because of clip rects the overlay isn't occluded and shouldn't be an // underlay. @@ -589,8 +589,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(1, dc_layer_list.back().z_order); // Quad isn't opaque, so underlying damage must remain the same. @@ -630,8 +630,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); EXPECT_EQ(-1, dc_layer_list.back().z_order); @@ -682,8 +682,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); // Skip overlays. EXPECT_EQ(0U, dc_layer_list.size()); @@ -731,8 +731,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -776,8 +776,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0u, dc_layer_list.size()); EXPECT_EQ(0u, output_surface_->bind_framebuffer_count()); @@ -848,8 +848,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, dc_layer_list.size()); // Make sure the video is in an underlay mode if the overlay quad intersects @@ -920,8 +920,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &dc_layer_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &dc_layer_list, + &damage_rect_, &content_bounds_); // Make sure the video is not promoted if the overlay quad intersects // with the backdrop filter rpdq->rect.
diff --git a/components/viz/service/display/overlay_processor_interface.h b/components/viz/service/display/overlay_processor_interface.h index 5e98081a..3fa06a6 100644 --- a/components/viz/service/display/overlay_processor_interface.h +++ b/components/viz/service/display/overlay_processor_interface.h
@@ -124,7 +124,7 @@ const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* overlay_candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_processor_mac.cc b/components/viz/service/display/overlay_processor_mac.cc index ba05208b..710cfbac 100644 --- a/components/viz/service/display/overlay_processor_mac.cc +++ b/components/viz/service/display/overlay_processor_mac.cc
@@ -48,7 +48,7 @@ const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters, const OverlayProcessorInterface::FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_processor_mac.h b/components/viz/service/display/overlay_processor_mac.h index 8773b87..dfcd8a5 100644 --- a/components/viz/service/display/overlay_processor_mac.h +++ b/components/viz/service/display/overlay_processor_mac.h
@@ -51,7 +51,7 @@ const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* overlay_candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_processor_stub.h b/components/viz/service/display/overlay_processor_stub.h index 1c3f593..cc5de1f 100644 --- a/components/viz/service/display/overlay_processor_stub.h +++ b/components/viz/service/display/overlay_processor_stub.h
@@ -28,7 +28,7 @@ const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* overlay_candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc index 928b6c5..6f12bf7c 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.cc +++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -4,6 +4,7 @@ #include "components/viz/service/display/overlay_processor_using_strategy.h" +#include <utility> #include <vector> #include "base/feature_list.h" @@ -74,7 +75,7 @@ const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters, const OverlayProcessorInterface::FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* candidates, gfx::Rect* damage_rect, @@ -91,19 +92,19 @@ if (features::IsOverlayPrioritizationEnabled()) { success = AttemptWithStrategiesPrioritized( output_color_matrix, render_pass_backdrop_filters, resource_provider, - render_passes, surface_damage_rect_list, output_surface_plane, + render_passes, &surface_damage_rect_list, output_surface_plane, candidates, content_bounds, damage_rect); } else { success = AttemptWithStrategies( output_color_matrix, render_pass_backdrop_filters, resource_provider, - render_passes, surface_damage_rect_list, output_surface_plane, + render_passes, &surface_damage_rect_list, output_surface_plane, candidates, content_bounds); } } DCHECK(candidates->empty() || success); - UpdateDamageRect(candidates, surface_damage_rect_list, + UpdateDamageRect(candidates, &surface_damage_rect_list, &render_pass->quad_list, damage_rect); NotifyOverlayPromotion(resource_provider, *candidates,
diff --git a/components/viz/service/display/overlay_processor_using_strategy.h b/components/viz/service/display/overlay_processor_using_strategy.h index c2c6655..85e0696 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.h +++ b/components/viz/service/display/overlay_processor_using_strategy.h
@@ -134,7 +134,7 @@ const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* overlay_candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_processor_win.cc b/components/viz/service/display/overlay_processor_win.cc index ab271bc5..abb668cc 100644 --- a/components/viz/service/display/overlay_processor_win.cc +++ b/components/viz/service/display/overlay_processor_win.cc
@@ -48,7 +48,7 @@ const OverlayProcessorInterface::FilterOperationsMap& render_pass_filters, const OverlayProcessorInterface::FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* candidates, gfx::Rect* damage_rect, @@ -83,7 +83,7 @@ dc_layer_overlay_processor_->Process( resource_provider, gfx::RectF(root_render_pass->output_rect), render_pass_filters, render_pass_backdrop_filters, render_passes, - damage_rect, surface_damage_rect_list, candidates); + damage_rect, std::move(surface_damage_rect_list), candidates); bool was_using_dc_layers = using_dc_layers_; if (!candidates->empty()) {
diff --git a/components/viz/service/display/overlay_processor_win.h b/components/viz/service/display/overlay_processor_win.h index bcd64e5..81212d8 100644 --- a/components/viz/service/display/overlay_processor_win.h +++ b/components/viz/service/display/overlay_processor_win.h
@@ -53,7 +53,7 @@ const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_backdrop_filters, - SurfaceDamageRectList* surface_damage_rect_list, + SurfaceDamageRectList surface_damage_rect_list, OutputSurfaceOverlayPlane* output_surface_plane, CandidateList* overlay_candidates, gfx::Rect* damage_rect,
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index 5025863..6dff1b2 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -642,8 +642,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); @@ -682,8 +682,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetNonIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(0U, candidate_list.size()); // Check that the 2 quads are not gone. @@ -709,8 +709,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); // Check that all the quads are gone. EXPECT_EQ(1U, main_pass->quad_list.size()); @@ -737,8 +737,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); // Check that the quad is gone. @@ -769,8 +769,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(0U, candidate_list.size()); // Check that the 2 quads are not gone. @@ -798,8 +798,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(0U, candidate_list.size()); // Check that the quad is not gone. @@ -833,8 +833,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); // Check that the fullscreen quad is gone. @@ -868,8 +868,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); // Check that the quad is gone. @@ -922,8 +922,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); // Check that one quad is gone. @@ -968,8 +968,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_TRUE(damage_rect_.IsEmpty()); } @@ -994,8 +994,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); // There should be nothing new here. CompareRenderPassLists(pass_list, original_pass_list); @@ -1026,8 +1026,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); // There should be nothing new here. CompareRenderPassLists(pass_list, original_pass_list); @@ -1057,8 +1057,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1080,8 +1080,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); EXPECT_FALSE(damage_rect_.IsEmpty()); gfx::Rect overlay_damage_rect = @@ -1106,8 +1106,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1128,8 +1128,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1151,8 +1151,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1173,8 +1173,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1195,8 +1195,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1218,8 +1218,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1241,8 +1241,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1264,8 +1264,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1289,8 +1289,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, candidate_list.back().transform); @@ -1317,8 +1317,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, candidate_list.back().transform); @@ -1343,8 +1343,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1368,8 +1368,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); } @@ -1393,8 +1393,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform); } @@ -1419,8 +1419,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform); } @@ -1445,8 +1445,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform); } @@ -1469,8 +1469,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); } @@ -1491,8 +1491,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(0U, candidate_list.size()); } @@ -1528,8 +1528,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(0U, candidate_list.size()); } @@ -1571,8 +1571,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); } @@ -1594,8 +1594,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); } @@ -1616,8 +1616,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); } @@ -1643,8 +1643,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1672,8 +1672,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1699,8 +1699,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); } @@ -1726,8 +1726,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1751,8 +1751,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, candidate_list.size()); } @@ -1817,8 +1817,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); frame_counter++; if (i <= kFramesSkippedBeforeNotPromoting) { EXPECT_EQ(1U, candidate_list.size()); @@ -1906,8 +1906,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(3u, main_pass->quad_list.size()); @@ -1943,8 +1943,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(-1, candidate_list[0].plane_z_order); EXPECT_EQ(2U, main_pass->quad_list.size()); @@ -1977,8 +1977,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(-1, candidate_list[0].plane_z_order); // The overlay quad should have changed to a SOLID_COLOR quad. @@ -2036,8 +2036,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(candidate_list.size(), 1U); @@ -2082,8 +2082,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(kOverlayRect, damage_rect_); } @@ -2126,8 +2126,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); if (i == 0) { // A promoted underlay needs to damage the primary plane on the first @@ -2178,8 +2178,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); // This is a union as the demoted underlay display rect is added as damage // as well as the newly promoted underlay display rect (updating the primary @@ -2228,8 +2228,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); if (i == 0) { EXPECT_FALSE(damage_rect_.IsEmpty()); } else { @@ -2277,8 +2277,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); // The damage rect should not be excluded if the underlay has been promoted // this frame. @@ -2334,8 +2334,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); } EXPECT_EQ(damage_rect_, kOverlayTopLeftRect); @@ -2370,8 +2370,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, primary_plane, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), primary_plane, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, candidate_list.size()); ASSERT_EQ(true, output_surface_plane.enable_blending); @@ -2405,8 +2405,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); } EXPECT_EQ(kOverlayRect, damage_rect_); @@ -2608,8 +2608,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_background_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect, &content_bounds_); EXPECT_EQ(expected_damages[i], damage_rect); ASSERT_EQ(expected_candidate_size[i], candidate_list.size()); @@ -2660,8 +2660,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); if (i == 0 || i == 1) { EXPECT_EQ(candidate_list[0].overlay_damage_index, @@ -2694,8 +2694,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(0U, content_bounds_.size()); } @@ -2714,8 +2714,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_TRUE(content_bounds_[0].IsEmpty()); @@ -2747,8 +2747,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_TRUE(content_bounds_[0].IsEmpty()); @@ -2772,8 +2772,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_EQ(kOverlayTopLeftRect, content_bounds_[0]); @@ -2800,8 +2800,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_EQ(kOverlayRect, content_bounds_[0]); @@ -2833,8 +2833,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_EQ(gfx::Rect(0, 0, 11, 11), content_bounds_[0]); @@ -2867,8 +2867,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); EXPECT_EQ(1U, content_bounds_.size()); EXPECT_EQ(kOverlayRect, content_bounds_[0]); @@ -2891,8 +2891,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, nullptr, &candidate_list, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list), nullptr, &candidate_list, + &damage_rect_, &content_bounds_); ASSERT_TRUE(candidate_list.empty()); EXPECT_TRUE(content_bounds_.empty()); @@ -2919,8 +2919,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_backdrop_filters, - &surface_damage_rect_list, &output_surface_plane, &candidate_list, - &damage_rect_, &content_bounds_); + std::move(surface_damage_rect_list), &output_surface_plane, + &candidate_list, &damage_rect_, &content_bounds_); ASSERT_EQ(true, output_surface_plane.enable_blending); EXPECT_EQ(0U, content_bounds_.size()); @@ -3036,7 +3036,8 @@ SurfaceDamageRectList surface_damage_rect_list = SurfaceDamageRectList()) { renderer_->DrawFrame(pass_list, 1.f, viewport_size, - gfx::DisplayColorSpaces(), &surface_damage_rect_list); + gfx::DisplayColorSpaces(), + std::move(surface_damage_rect_list)); } void SwapBuffers() { renderer_->SwapBuffers({}); @@ -3239,7 +3240,7 @@ EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); - DrawFrame(&pass_list, kDisplaySize, surface_damage_rect_list); + DrawFrame(&pass_list, kDisplaySize, std::move(surface_damage_rect_list)); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); SwapBuffers(); Mock::VerifyAndClearExpectations(renderer_.get()); @@ -3284,7 +3285,7 @@ output_surface_->set_is_displayed_as_overlay_plane(true); EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); - DrawFrame(&pass_list, kDisplaySize, surface_damage_rect_list); + DrawFrame(&pass_list, kDisplaySize, std::move(surface_damage_rect_list)); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); SwapBuffers(); Mock::VerifyAndClearExpectations(renderer_.get()); @@ -3615,8 +3616,8 @@ overlay_processor_->ProcessForOverlays( resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(), render_pass_filters_, render_pass_backdrop_filters_, - &surface_damage_rect_list_, nullity, &ca_layer_list_, &damage_rect_, - &content_bounds_); + std::move(surface_damage_rect_list_), nullity, &ca_layer_list_, + &damage_rect_, &content_bounds_); } AggregatedRenderPassList pass_list_; AggregatedRenderPass* pass_;
diff --git a/components/viz/service/display/skia_readback_pixeltest.cc b/components/viz/service/display/skia_readback_pixeltest.cc index 64d15de..0cbab16 100644 --- a/components/viz/service/display/skia_readback_pixeltest.cc +++ b/components/viz/service/display/skia_readback_pixeltest.cc
@@ -199,7 +199,7 @@ renderer_->DecideRenderPassAllocationsForFrame(pass_list); renderer_->DrawFrame(&pass_list, 1.0f, kSourceSize, gfx::DisplayColorSpaces(), - &surface_damage_rect_list); + std::move(surface_damage_rect_list)); // Call SwapBuffersSkipped(), so the renderer can have a chance to release // resources. renderer_->SwapBuffersSkipped();
diff --git a/components/viz/service/display/software_renderer_unittest.cc b/components/viz/service/display/software_renderer_unittest.cc index 91e223e0..17966bc 100644 --- a/components/viz/service/display/software_renderer_unittest.cc +++ b/components/viz/service/display/software_renderer_unittest.cc
@@ -111,7 +111,8 @@ SurfaceDamageRectList surface_damage_rect_list; renderer()->DrawFrame(list, device_scale_factor, viewport_size, - gfx::DisplayColorSpaces(), &surface_damage_rect_list); + gfx::DisplayColorSpaces(), + std::move(surface_damage_rect_list)); loop.Run(); return bitmap_result; } @@ -542,7 +543,8 @@ renderer()->DecideRenderPassAllocationsForFrame(list); renderer()->DrawFrame(&list, device_scale_factor, viewport_size, - gfx::DisplayColorSpaces(), &surface_damage_rect_list); + gfx::DisplayColorSpaces(), + std::move(surface_damage_rect_list)); } { AggregatedRenderPassList list; @@ -559,7 +561,8 @@ renderer()->DecideRenderPassAllocationsForFrame(list); renderer()->DrawFrame(&list, device_scale_factor, viewport_size, - gfx::DisplayColorSpaces(), &surface_damage_rect_list); + gfx::DisplayColorSpaces(), + std::move(surface_damage_rect_list)); // The damage rect should be reported to the SoftwareOutputDevice. EXPECT_EQ(gfx::Rect(2, 2, 3, 3), device->damage_rect_at_start());
diff --git a/components/webapps/android/BUILD.gn b/components/webapps/android/BUILD.gn index a14451d..2adab71 100644 --- a/components/webapps/android/BUILD.gn +++ b/components/webapps/android/BUILD.gn
@@ -52,12 +52,16 @@ source_set("unit_tests") { testonly = true - sources = [ "shortcut_info_unittest.cc" ] + sources = [ + "shortcut_info_unittest.cc", + "webapps_utils_unittest.cc", + ] deps = [ "//base", "//components/webapps", "//testing/gtest", "//third_party/blink/public/common:common", + "//third_party/blink/public/mojom:mojom_platform", "//url", ] }
diff --git a/components/webapps/android/webapps_utils.cc b/components/webapps/android/webapps_utils.cc index 7acbd4b..c3d15f3e 100644 --- a/components/webapps/android/webapps_utils.cc +++ b/components/webapps/android/webapps_utils.cc
@@ -9,10 +9,23 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "components/webapps/android/webapps_jni_headers/WebappsUtils_jni.h" +#include "third_party/blink/public/common/manifest/manifest.h" #include "url/gurl.h" namespace webapps { +namespace { + +// Returns whether a URL in the Web Manifest is WebAPK compatible. +bool IsUrlWebApkCompatible(const GURL& url) { + // WebAPK web manifests are stored on the Chrome WebAPK server. Do not + // generate WebAPKs for Web Manifests with URLs with a user name or password + // in order to avoid storing user names and passwords on the WebAPK server. + return !url.has_username() && !url.has_password(); +} + +} // namespace + // static bool WebappsUtils::IsWebApkInstalled(content::BrowserContext* browser_context, const GURL& url) { @@ -30,4 +43,18 @@ return !webapk_package_name.empty(); } +// static +bool WebappsUtils::AreWebManifestUrlsWebApkCompatible( + const blink::Manifest& manifest) { + for (const auto& icon : manifest.icons) { + if (!IsUrlWebApkCompatible(icon.src)) + return false; + } + + // Do not check "related_applications" URLs because they are not used by + // WebAPKs. + return IsUrlWebApkCompatible(manifest.start_url) && + IsUrlWebApkCompatible(manifest.scope); +} + } // namespace webapps
diff --git a/components/webapps/android/webapps_utils.h b/components/webapps/android/webapps_utils.h index a8609609..955d5c8d 100644 --- a/components/webapps/android/webapps_utils.h +++ b/components/webapps/android/webapps_utils.h
@@ -7,6 +7,10 @@ class GURL; +namespace blink { +struct Manifest; +} + namespace content { class BrowserContext; } @@ -22,6 +26,11 @@ // Returns true if there is an installed WebAPK which can handle |url|. static bool IsWebApkInstalled(content::BrowserContext* browser_context, const GURL& url); + + // Returns whether the format of the URLs in the Web Manifest is WebAPK + // compatible. + static bool AreWebManifestUrlsWebApkCompatible( + const blink::Manifest& manifest); }; } // namespace webapps
diff --git a/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc b/components/webapps/android/webapps_utils_unittest.cc similarity index 71% rename from chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc rename to components/webapps/android/webapps_utils_unittest.cc index e3015e60..d74f764c0 100644 --- a/chrome/browser/android/webapk/webapk_web_manifest_checker_unittest.cc +++ b/components/webapps/android/webapps_utils_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/android/webapk/webapk_web_manifest_checker.h" +#include "components/webapps/android/webapps_utils.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" @@ -10,6 +10,8 @@ #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" #include "url/gurl.h" +namespace webapps { + namespace { blink::Manifest GetValidManifest() { @@ -29,23 +31,25 @@ } // anonymous namespace -TEST(WebApkWebManifestCheckerTest, Compatible) { +TEST(WebappsUtilsTest, Compatible) { blink::Manifest manifest = GetValidManifest(); - EXPECT_TRUE(AreWebManifestUrlsWebApkCompatible(manifest)); + EXPECT_TRUE(WebappsUtils::AreWebManifestUrlsWebApkCompatible(manifest)); } -TEST(WebApkWebManifestCheckerTest, CompatibleURLHasNoPassword) { +TEST(WebappsUtilsTest, CompatibleURLHasNoPassword) { const GURL kUrlWithPassword("http://answer:42@life/universe/and/everything"); blink::Manifest manifest = GetValidManifest(); manifest.start_url = kUrlWithPassword; - EXPECT_FALSE(AreWebManifestUrlsWebApkCompatible(manifest)); + EXPECT_FALSE(WebappsUtils::AreWebManifestUrlsWebApkCompatible(manifest)); manifest = GetValidManifest(); manifest.scope = kUrlWithPassword; - EXPECT_FALSE(AreWebManifestUrlsWebApkCompatible(manifest)); + EXPECT_FALSE(WebappsUtils::AreWebManifestUrlsWebApkCompatible(manifest)); manifest = GetValidManifest(); manifest.icons[0].src = kUrlWithPassword; - EXPECT_FALSE(AreWebManifestUrlsWebApkCompatible(manifest)); + EXPECT_FALSE(WebappsUtils::AreWebManifestUrlsWebApkCompatible(manifest)); } + +} // namespace webapps
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc index 3df1515..837d6dd 100644 --- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc +++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -25,6 +25,9 @@ namespace content { +#define ASSERT_UIA_ELEMENTNOTAVAILABLE(expr) \ + ASSERT_EQ(static_cast<HRESULT>(UIA_E_ELEMENTNOTAVAILABLE), (expr)) + #define EXPECT_UIA_DOUBLE_SAFEARRAY_EQ(safearray, expected_property_values) \ { \ EXPECT_EQ(sizeof(V_R8(LPVARIANT(NULL))), \ @@ -2659,7 +2662,7 @@ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Before frame"); } - // 1. Test when |start_| is not in the iframe but |end_| is. + // 2. Test when |start_| is not in the iframe but |end_| is. { ComPtr<ITextRangeProvider> text_range_provider; GetTextRangeProviderFromTextNode(*before_frame_node, &text_range_provider); @@ -2688,7 +2691,7 @@ EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Before frame\nText "); } - // 1. Test when |start_| is in the iframe but |end_| is not. + // 3. Test when |start_| is in the iframe but |end_| is not. { ComPtr<ITextRangeProvider> text_range_provider; auto* after_frame_node = @@ -2720,6 +2723,85 @@ } } +// Test that a page reload removes the AXTreeObserver from the AXTree's +// observers list. If it doesn't, this test will crash. +IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest, + ReloadTreeShouldRemoveObserverFromTree) { + LoadInitialAccessibilityTreeFromHtmlFilePath( + "/accessibility/html/simple_spans.html"); + auto* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); + WaitForAccessibilityTreeToContainNodeWithName(web_contents, "Some text"); + + // 1. Reload the page and trigger a tree update - this should update the tree + // id without modifying the observers from the tree. + { + auto* node = FindNode(ax::mojom::Role::kStaticText, "Some text"); + ASSERT_NE(nullptr, node); + + ComPtr<ITextRangeProvider> text_range_provider; + GetTextRangeProviderFromTextNode(*node, &text_range_provider); + ASSERT_NE(nullptr, text_range_provider.Get()); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Some text"); + AXTreeID old_tree_id = GetManager()->GetTreeID(); + + // Reloading changes the tree id, triggering an AXTreeManager replacement. + shell()->Reload(); + + AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete, + ax::mojom::Event::kChildrenChanged); + + // We do a style change here only to trigger an AXTree update - apparently, + // a shell reload doesn't update the tree by itself. + EXPECT_TRUE(ExecuteScript( + web_contents, + "document.getElementById('s1').style.outline = '1px solid black';")); + + waiter.WaitForNotification(); + ASSERT_NE(old_tree_id, GetManager()->GetTreeID()); + + // |text_range_provider| should now be invalid since it is using nodes + // pointing to the previous tree id. If the tree id has not been updated + // from the page reload, this should fail. + base::win::ScopedSafearray children; + ASSERT_UIA_ELEMENTNOTAVAILABLE( + text_range_provider->GetChildren(children.Receive())); + } + + // 2. Validate that the observer for the previous range has been removed. Also + // test that the new observer has been added correctly. + { + auto* node = FindNode(ax::mojom::Role::kStaticText, "Some text"); + ASSERT_NE(nullptr, node); + + ComPtr<ITextRangeProvider> text_range_provider; + GetTextRangeProviderFromTextNode(*node, &text_range_provider); + ASSERT_NE(nullptr, text_range_provider.Get()); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Some text"); + + // Make the range span the entire document. + EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( + text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Paragraph, + /*count*/ 1, + /*expected_text*/ L"Some text 3.14159", + /*expected_count*/ 1); + + AccessibilityNotificationWaiter waiter(web_contents, ui::kAXModeComplete, + ax::mojom::Event::kChildrenChanged); + + // We do a style change here only to trigger an AXTree update. + EXPECT_TRUE(ExecuteScript( + web_contents, + "document.getElementById('s2').style.outline = '1px solid black';")); + + waiter.WaitForNotification(); + + // If the previous observer was not removed correctly, this will cause a + // crash. If it was removed correctly and this EXPECT fails, it's likely + // because the new observer has not been added as expected. + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"Some text 3.14159"); + } +} + IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest, GetAttributeValueNormalizesClonedRange) { LoadInitialAccessibilityTreeFromHtml(
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index a049c25..79d65de 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1513,6 +1513,13 @@ return nullptr; } +void BrowserAccessibilityManager::WillBeRemovedFromMap() { + if (!ax_tree()) + return; + + ax_tree()->NotifyTreeManagerWillBeRemoved(ax_tree_id_); +} + BrowserAccessibilityManager* BrowserAccessibilityManager::GetRootManager() const { BrowserAccessibility* parent = GetParentNodeFromParentTree();
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index d0969c9df..5d2d8e6 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -469,6 +469,7 @@ AXTreeID GetParentTreeID() const override; ui::AXNode* GetRootAsAXNode() const override; ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override; + void WillBeRemovedFromMap() override; BrowserAccessibilityDelegate* delegate() const { return delegate_; }
diff --git a/content/browser/android/selection/selection_popup_controller.cc b/content/browser/android/selection/selection_popup_controller.cc index d5ea917d..414dbcfc 100644 --- a/content/browser/android/selection/selection_popup_controller.cc +++ b/content/browser/android/selection/selection_popup_controller.cc
@@ -133,14 +133,16 @@ selection_rect.right(), selection_rect.bottom()); } -void SelectionPopupController::OnDragUpdate(const gfx::PointF& position) { +void SelectionPopupController::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_obj_.get(env); if (obj.is_null()) return; - Java_SelectionPopupControllerImpl_onDragUpdate(env, obj, position.x(), - position.y()); + Java_SelectionPopupControllerImpl_onDragUpdate( + env, obj, static_cast<int>(type), position.x(), position.y()); } void SelectionPopupController::OnSelectionChanged(const std::string& text) {
diff --git a/content/browser/android/selection/selection_popup_controller.h b/content/browser/android/selection/selection_popup_controller.h index 151a407..2eff17e0 100644 --- a/content/browser/android/selection/selection_popup_controller.h +++ b/content/browser/android/selection/selection_popup_controller.h
@@ -40,7 +40,8 @@ // Called from native -> java void OnSelectionEvent(ui::SelectionEventType event, const gfx::RectF& selection_rect); - void OnDragUpdate(const gfx::PointF& position); + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position); void OnSelectionChanged(const std::string& text); bool ShowSelectionMenu(const ContextMenuParams& params, int handle_height); void OnSelectWordAroundCaretAck(bool did_select,
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index ab3170d..5c5036f8 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -2032,6 +2032,22 @@ return origins; } +bool ChildProcessSecurityPolicyImpl::IsIsolatedSiteFromSource( + const url::Origin& origin, + IsolatedOriginSource source) { + base::AutoLock isolated_origins_lock(isolated_origins_lock_); + GURL site_url = SiteInstanceImpl::GetSiteForOrigin(origin); + auto it = isolated_origins_.find(site_url); + if (it == isolated_origins_.end()) + return false; + url::Origin site_origin = url::Origin::Create(site_url); + for (const auto& entry : it->second) { + if (entry.source() == source && entry.origin() == site_origin) + return true; + } + return false; +} + bool ChildProcessSecurityPolicyImpl::GetMatchingIsolatedOrigin( const IsolationContext& isolation_context, const url::Origin& origin,
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h index 648b189..784ff5c 100644 --- a/content/browser/child_process_security_policy_impl.h +++ b/content/browser/child_process_security_policy_impl.h
@@ -306,6 +306,8 @@ std::vector<url::Origin> GetIsolatedOrigins( base::Optional<IsolatedOriginSource> source = base::nullopt, BrowserContext* browser_context = nullptr) override; + bool IsIsolatedSiteFromSource(const url::Origin& origin, + IsolatedOriginSource source) override; void ClearIsolatedOriginsForTesting() override; // Identical to the above method, but takes url::Origin as input.
diff --git a/content/browser/conversions/conversion_manager_impl.cc b/content/browser/conversions/conversion_manager_impl.cc index ffb832e5..d3e3fbb0 100644 --- a/content/browser/conversions/conversion_manager_impl.cc +++ b/content/browser/conversions/conversion_manager_impl.cc
@@ -22,6 +22,25 @@ namespace content { +namespace { + +bool IsOriginSessionOnly( + scoped_refptr<storage::SpecialStoragePolicy> storage_policy, + const url::Origin& origin) { + // TODO(johnidel): This conversion is unfortunate but necessary. Storage + // partition clear data logic uses Origin keyed deletion, while the storage + // policy uses GURLs. Ideally these would be coalesced. + const GURL& url = origin.GetURL(); + if (storage_policy->IsStorageProtected(url)) + return false; + + if (storage_policy->IsStorageSessionOnly(url)) + return true; + return false; +} + +} // namespace + const constexpr base::TimeDelta kConversionManagerQueueReportsInterval = base::TimeDelta::FromMinutes(30); @@ -43,14 +62,17 @@ std::unique_ptr<ConversionReporter> reporter, std::unique_ptr<ConversionPolicy> policy, const base::Clock* clock, - const base::FilePath& user_data_directory) { + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) { return base::WrapUnique<ConversionManagerImpl>(new ConversionManagerImpl( - std::move(reporter), std::move(policy), clock, user_data_directory)); + std::move(reporter), std::move(policy), clock, user_data_directory, + std::move(special_storage_policy))); } ConversionManagerImpl::ConversionManagerImpl( StoragePartition* storage_partition, - const base::FilePath& user_data_directory) + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) : ConversionManagerImpl( std::make_unique<ConversionReporterImpl>( storage_partition, @@ -59,13 +81,15 @@ base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kConversionsDebugMode)), base::DefaultClock::GetInstance(), - user_data_directory) {} + user_data_directory, + std::move(special_storage_policy)) {} ConversionManagerImpl::ConversionManagerImpl( std::unique_ptr<ConversionReporter> reporter, std::unique_ptr<ConversionPolicy> policy, const base::Clock* clock, - const base::FilePath& user_data_directory) + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) : debug_mode_(base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kConversionsDebugMode)), clock_(clock), @@ -76,6 +100,7 @@ std::make_unique<ConversionStorageDelegateImpl>(debug_mode_), clock_)), conversion_policy_(std::move(policy)), + special_storage_policy_(std::move(special_storage_policy)), weak_factory_(this) { // Once the database is loaded, get all reports that may have expired while // Chrome was not running and handle these specially. It is safe to post tasks @@ -92,7 +117,22 @@ &ConversionManagerImpl::GetAndQueueReportsForNextInterval); } -ConversionManagerImpl::~ConversionManagerImpl() = default; +ConversionManagerImpl::~ConversionManagerImpl() { + // Browser contexts are not required to have a special storage policy. + if (!special_storage_policy_ || + !special_storage_policy_->HasSessionOnlyOrigins()) { + return; + } + + // Delete stored data for all session only origins given by + // |special_storage_policy|. + base::RepeatingCallback<bool(const url::Origin&)> + session_only_origin_predicate = base::BindRepeating( + &IsOriginSessionOnly, std::move(special_storage_policy_)); + conversion_storage_context_->ClearData(base::Time::Min(), base::Time::Max(), + session_only_origin_predicate, + base::DoNothing()); +} void ConversionManagerImpl::HandleImpression( const StorableImpression& impression) {
diff --git a/content/browser/conversions/conversion_manager_impl.h b/content/browser/conversions/conversion_manager_impl.h index ad865ad..4602cab 100644 --- a/content/browser/conversions/conversion_manager_impl.h +++ b/content/browser/conversions/conversion_manager_impl.h
@@ -18,6 +18,7 @@ #include "content/browser/conversions/conversion_manager.h" #include "content/browser/conversions/conversion_policy.h" #include "content/browser/conversions/conversion_storage_context.h" +#include "storage/browser/quota/special_storage_policy.h" namespace base { @@ -75,10 +76,13 @@ std::unique_ptr<ConversionReporter> reporter, std::unique_ptr<ConversionPolicy> policy, const base::Clock* clock, - const base::FilePath& user_data_directory); + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy); - ConversionManagerImpl(StoragePartition* storage_partition, - const base::FilePath& user_data_directory); + ConversionManagerImpl( + StoragePartition* storage_partition, + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy); ConversionManagerImpl(const ConversionManagerImpl& other) = delete; ConversionManagerImpl& operator=(const ConversionManagerImpl& other) = delete; ~ConversionManagerImpl() override; @@ -100,10 +104,12 @@ base::OnceClosure done) override; private: - ConversionManagerImpl(std::unique_ptr<ConversionReporter> reporter, - std::unique_ptr<ConversionPolicy> policy, - const base::Clock* clock, - const base::FilePath& user_data_directory); + ConversionManagerImpl( + std::unique_ptr<ConversionReporter> reporter, + std::unique_ptr<ConversionPolicy> policy, + const base::Clock* clock, + const base::FilePath& user_data_directory, + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy); // Retrieves reports from storage whose |report_time| <= |max_report_time|, // and calls |handler_function| on them. @@ -162,6 +168,9 @@ // attribution models. Unique ptr so it can be overridden for testing. std::unique_ptr<ConversionPolicy> conversion_policy_; + // Storage policy for the browser context |this| is in. May be nullptr. + scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; + base::WeakPtrFactory<ConversionManagerImpl> weak_factory_; };
diff --git a/content/browser/conversions/conversion_manager_impl_unittest.cc b/content/browser/conversions/conversion_manager_impl_unittest.cc index f17b6f5..a6c734e0 100644 --- a/content/browser/conversions/conversion_manager_impl_unittest.cc +++ b/content/browser/conversions/conversion_manager_impl_unittest.cc
@@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/callback_forward.h" #include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/sequenced_task_runner.h" #include "base/test/bind.h" @@ -24,6 +25,7 @@ #include "content/browser/conversions/storable_conversion.h" #include "content/browser/conversions/storable_impression.h" #include "content/public/test/browser_task_environment.h" +#include "storage/browser/test/mock_special_storage_policy.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { @@ -110,7 +112,9 @@ class ConversionManagerImplTest : public testing::Test { public: ConversionManagerImplTest() - : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME), + mock_storage_policy_( + base::MakeRefCounted<storage::MockSpecialStoragePolicy>()) { EXPECT_TRUE(dir_.CreateUniqueTempDir()); CreateManager(); } @@ -120,7 +124,32 @@ test_reporter_ = reporter.get(); conversion_manager_ = ConversionManagerImpl::CreateForTesting( std::move(reporter), std::make_unique<ConstantStartupDelayPolicy>(), - task_environment_.GetMockClock(), dir_.GetPath()); + task_environment_.GetMockClock(), dir_.GetPath(), mock_storage_policy_); + } + + void ExpectNumStoredImpressions(size_t expected_num_impressions) { + // There should be one impression and one conversion. + base::RunLoop impression_loop; + auto get_impressions_callback = base::BindLambdaForTesting( + [&](std::vector<StorableImpression> impressions) { + EXPECT_EQ(expected_num_impressions, impressions.size()); + impression_loop.Quit(); + }); + conversion_manager_->GetActiveImpressionsForWebUI( + std::move(get_impressions_callback)); + impression_loop.Run(); + } + + void ExpectNumStoredReports(size_t expected_num_reports) { + base::RunLoop report_loop; + auto reports_callback = + base::BindLambdaForTesting([&](std::vector<ConversionReport> reports) { + EXPECT_EQ(expected_num_reports, reports.size()); + report_loop.Quit(); + }); + conversion_manager_->GetReportsForWebUI(std::move(reports_callback), + base::Time::Max()); + report_loop.Run(); } const base::Clock& clock() { return *task_environment_.GetMockClock(); } @@ -130,6 +159,7 @@ BrowserTaskEnvironment task_environment_; std::unique_ptr<ConversionManagerImpl> conversion_manager_; TestConversionReporter* test_reporter_ = nullptr; + scoped_refptr<storage::MockSpecialStoragePolicy> mock_storage_policy_; }; TEST_F(ConversionManagerImplTest, ImpressionRegistered_ReturnedToWebUI) { @@ -371,4 +401,63 @@ test_reporter_->last_report_time()); } +TEST_F(ConversionManagerImplTest, SessionOnlyOrigins_DataDeletedAtShutdown) { + GURL session_only_origin("https://sessiononly.example"); + auto impression = + ImpressionBuilder(clock().Now()) + .SetImpressionOrigin(url::Origin::Create(session_only_origin)) + .Build(); + + mock_storage_policy_->AddSessionOnly(session_only_origin); + + conversion_manager_->HandleImpression(impression); + conversion_manager_->HandleConversion(DefaultConversion()); + + ExpectNumStoredImpressions(1u); + ExpectNumStoredReports(1u); + + // Reset the manager to simulate shutdown. + conversion_manager_.reset(); + CreateManager(); + + ExpectNumStoredImpressions(0u); + ExpectNumStoredReports(0u); +} + +TEST_F(ConversionManagerImplTest, + SessionOnlyOrigins_DeletedIfAnyOriginMatches) { + url::Origin session_only_origin = + url::Origin::Create(GURL("https://sessiononly.example")); + // Create impressions which each have the session only origin as one of + // impression/conversion/reporting origin. + auto impression1 = ImpressionBuilder(clock().Now()) + .SetImpressionOrigin(session_only_origin) + .Build(); + auto impression2 = ImpressionBuilder(clock().Now()) + .SetReportingOrigin(session_only_origin) + .Build(); + auto impression3 = ImpressionBuilder(clock().Now()) + .SetConversionOrigin(session_only_origin) + .Build(); + + // Create one impression which is not session only. + auto impression4 = ImpressionBuilder(clock().Now()).Build(); + + mock_storage_policy_->AddSessionOnly(session_only_origin.GetURL()); + + conversion_manager_->HandleImpression(impression1); + conversion_manager_->HandleImpression(impression2); + conversion_manager_->HandleImpression(impression3); + conversion_manager_->HandleImpression(impression4); + + ExpectNumStoredImpressions(4u); + + // Reset the manager to simulate shutdown. + conversion_manager_.reset(); + CreateManager(); + + // All session-only impressions should be deleted. + ExpectNumStoredImpressions(1u); +} + } // namespace content
diff --git a/content/browser/conversions/conversion_storage_context.cc b/content/browser/conversions/conversion_storage_context.cc index 911bb43..8497f159 100644 --- a/content/browser/conversions/conversion_storage_context.cc +++ b/content/browser/conversions/conversion_storage_context.cc
@@ -15,10 +15,14 @@ // The shared-task runner for all conversion storage operations. Note that // different ConversionStorageContext perform operations on the same task // runner. This prevents any potential races when a given context is destroyed -// and recreated for the same backing storage. +// and recreated for the same backing storage. This uses +// BLOCK_SHUTDOWN as some data deletion operations may be running when the +// browser is closed, and we want to ensure all data is deleted correctly. base::LazyThreadPoolSequencedTaskRunner g_storage_task_runner = LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER( - base::TaskTraits(base::TaskPriority::BEST_EFFORT, base::MayBlock())); + base::TaskTraits(base::TaskPriority::BEST_EFFORT, + base::MayBlock(), + base::TaskShutdownBehavior::BLOCK_SHUTDOWN)); } // namespace
diff --git a/content/browser/conversions/conversion_storage_sql.cc b/content/browser/conversions/conversion_storage_sql.cc index 1b76dea..cfae07d 100644 --- a/content/browser/conversions/conversion_storage_sql.cc +++ b/content/browser/conversions/conversion_storage_sql.cc
@@ -12,6 +12,7 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/optional.h" #include "base/time/default_clock.h" @@ -434,6 +435,10 @@ return; } + // Measure the time it takes to perform a clear with a filter separately from + // the above histogram. + SCOPED_UMA_HISTOGRAM_TIMER("Conversions.Storage.ClearDataWithFilterDuration"); + // TODO(csharrison, johnidel): This query can be split up and optimized by // adding indexes on the impression_time and conversion_time columns. // See this comment for more information:
diff --git a/content/browser/file_system_access/native_file_system_file_handle_impl.cc b/content/browser/file_system_access/native_file_system_file_handle_impl.cc index 1f6243a0..94c8e0c 100644 --- a/content/browser/file_system_access/native_file_system_file_handle_impl.cc +++ b/content/browser/file_system_access/native_file_system_file_handle_impl.cc
@@ -76,12 +76,14 @@ void NativeFileSystemFileHandleImpl::CreateFileWriter( bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); RunWithWritePermission( base::BindOnce(&NativeFileSystemFileHandleImpl::CreateFileWriterImpl, - weak_factory_.GetWeakPtr(), keep_existing_data), + weak_factory_.GetWeakPtr(), keep_existing_data, + auto_close), base::BindOnce([](blink::mojom::NativeFileSystemErrorPtr result, CreateFileWriterCallback callback) { std::move(callback).Run(std::move(result), mojo::NullRemote()); @@ -221,6 +223,7 @@ void NativeFileSystemFileHandleImpl::CreateFileWriterImpl( bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(GetWritePermissionStatus(), @@ -233,12 +236,13 @@ // creation of the file ensures that this File Writer creation request owns // the file and eliminates possible race conditions. CreateSwapFile( - /*count=*/0, keep_existing_data, std::move(callback)); + /*count=*/0, keep_existing_data, auto_close, std::move(callback)); } void NativeFileSystemFileHandleImpl::CreateSwapFile( int count, bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(count >= 0); @@ -301,7 +305,8 @@ FROM_HERE, &FileSystemOperationRunner::CreateFile, base::BindOnce(&NativeFileSystemFileHandleImpl::DidCreateSwapFile, weak_factory_.GetWeakPtr(), count, swap_url, - swap_file_system, keep_existing_data, std::move(callback)), + swap_file_system, keep_existing_data, auto_close, + std::move(callback)), swap_url, /*exclusive=*/true); } @@ -311,12 +316,14 @@ const storage::FileSystemURL& swap_url, storage::IsolatedContext::ScopedFSHandle swap_file_system, bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback, base::File::Error result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (result == base::File::FILE_ERROR_EXISTS) { // Creation attempt failed. We need to find an unused filename. - CreateSwapFile(count + 1, keep_existing_data, std::move(callback)); + CreateSwapFile(count + 1, keep_existing_data, auto_close, + std::move(callback)); return; } @@ -337,7 +344,8 @@ context(), url(), swap_url, NativeFileSystemManagerImpl::SharedHandleState( handle_state().read_grant, handle_state().write_grant, - swap_file_system))); + swap_file_system), + auto_close)); return; } @@ -345,7 +353,7 @@ FROM_HERE, &FileSystemOperationRunner::Copy, base::BindOnce(&NativeFileSystemFileHandleImpl::DidCopySwapFile, weak_factory_.GetWeakPtr(), swap_url, swap_file_system, - std::move(callback)), + auto_close, std::move(callback)), url(), swap_url, storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT, @@ -355,6 +363,7 @@ void NativeFileSystemFileHandleImpl::DidCopySwapFile( const storage::FileSystemURL& swap_url, storage::IsolatedContext::ScopedFSHandle swap_file_system, + bool auto_close, CreateFileWriterCallback callback, base::File::Error result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -367,13 +376,13 @@ mojo::NullRemote()); return; } - std::move(callback).Run( - native_file_system_error::Ok(), - manager()->CreateFileWriter( - context(), url(), swap_url, - NativeFileSystemManagerImpl::SharedHandleState( - handle_state().read_grant, handle_state().write_grant, - swap_file_system))); + std::move(callback).Run(native_file_system_error::Ok(), + manager()->CreateFileWriter( + context(), url(), swap_url, + NativeFileSystemManagerImpl::SharedHandleState( + handle_state().read_grant, + handle_state().write_grant, swap_file_system), + auto_close)); } base::WeakPtr<NativeFileSystemHandleBase>
diff --git a/content/browser/file_system_access/native_file_system_file_handle_impl.h b/content/browser/file_system_access/native_file_system_file_handle_impl.h index a343752..e7f5471 100644 --- a/content/browser/file_system_access/native_file_system_file_handle_impl.h +++ b/content/browser/file_system_access/native_file_system_file_handle_impl.h
@@ -40,6 +40,7 @@ RequestPermissionCallback callback) override; void AsBlob(AsBlobCallback callback) override; void CreateFileWriter(bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback) override; void IsSameEntry( mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token, @@ -56,9 +57,11 @@ const base::File::Info& info); void CreateFileWriterImpl(bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback); void CreateSwapFile(int count, bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback); // |swap_file_system| is set to the isolated file system the swap url was // created in (if any) as that file system might be different than the file @@ -68,11 +71,13 @@ const storage::FileSystemURL& swap_url, storage::IsolatedContext::ScopedFSHandle swap_file_system, bool keep_existing_data, + bool auto_close, CreateFileWriterCallback callback, base::File::Error result); void DidCopySwapFile( const storage::FileSystemURL& swap_url, storage::IsolatedContext::ScopedFSHandle swap_file_system, + bool auto_close, CreateFileWriterCallback callback, base::File::Error result);
diff --git a/content/browser/file_system_access/native_file_system_file_handle_impl_unittest.cc b/content/browser/file_system_access/native_file_system_file_handle_impl_unittest.cc index 43eb0c9c..e94f4c6 100644 --- a/content/browser/file_system_access/native_file_system_file_handle_impl_unittest.cc +++ b/content/browser/file_system_access/native_file_system_file_handle_impl_unittest.cc
@@ -136,7 +136,8 @@ base::RunLoop loop; handle_->CreateFileWriter( - /*keepExistingData=*/false, + /*keep_existing_data=*/false, + /*auto_close=*/false, base::BindLambdaForTesting( [&](blink::mojom::NativeFileSystemErrorPtr result, mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter> @@ -152,7 +153,8 @@ base::RunLoop loop; handle_->CreateFileWriter( - /*keepExistingData=*/false, + /*keep_existing_data=*/false, + /*auto_close=*/false, base::BindLambdaForTesting( [&](blink::mojom::NativeFileSystemErrorPtr result, mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter>
diff --git a/content/browser/file_system_access/native_file_system_file_writer_impl.cc b/content/browser/file_system_access/native_file_system_file_writer_impl.cc index 52f4af9..daedaa6 100644 --- a/content/browser/file_system_access/native_file_system_file_writer_impl.cc +++ b/content/browser/file_system_access/native_file_system_file_writer_impl.cc
@@ -4,6 +4,7 @@ #include "content/browser/file_system_access/native_file_system_file_writer_impl.h" +#include "base/bind.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/task/post_task.h" @@ -144,13 +145,15 @@ const SharedHandleState& handle_state, mojo::PendingReceiver<blink::mojom::NativeFileSystemFileWriter> receiver, bool has_transient_user_activation, + bool auto_close, download::QuarantineConnectionCallback quarantine_connection_callback) : NativeFileSystemHandleBase(manager, context, url, handle_state), receiver_(this, std::move(receiver)), swap_url_(swap_url), quarantine_connection_callback_( std::move(quarantine_connection_callback)), - has_transient_user_activation_(has_transient_user_activation) { + has_transient_user_activation_(has_transient_user_activation), + auto_close_(auto_close) { DCHECK_EQ(swap_url.type(), url.type()); receiver_.set_disconnect_handler(base::BindOnce( &NativeFileSystemFileWriterImpl::OnDisconnect, base::Unretained(this))); @@ -235,6 +238,19 @@ std::move(callback)); } +void NativeFileSystemFileWriterImpl::Abort(AbortCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + RunWithWritePermission( + base::BindOnce(&NativeFileSystemFileWriterImpl::AbortImpl, + weak_factory_.GetWeakPtr()), + base::BindOnce([](blink::mojom::NativeFileSystemErrorPtr result, + AbortCallback callback) { + std::move(callback).Run(std::move(result)); + }), + std::move(callback)); +} + namespace { // Writing a blob to a file consists of three operations: @@ -350,11 +366,21 @@ } void NativeFileSystemFileWriterImpl::OnDisconnect() { - // TODO(https://crbug.com/1135687): Auto-close file on disconnect if flag is - // specified. + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); receiver_.reset(); if (!close_callback_) { + if (!is_closed() && auto_close_) { + // Close the Writer. |this| is deleted via + // CallCloseCallbackAndMaybeDeleteThis when Close finishes. + Close(base::BindOnce([](blink::mojom::NativeFileSystemErrorPtr result) { + if (result->status != blink::mojom::NativeFileSystemStatus::kOk) { + DLOG(ERROR) << "AutoClose failed with result:" + << base::File::ErrorToString(result->file_error); + } + })); + return; + } // |this| is deleted after this call. manager()->RemoveFileWriter(this); } @@ -498,6 +524,22 @@ weak_factory_.GetWeakPtr())); } +void NativeFileSystemFileWriterImpl::AbortImpl(AbortCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (is_closed()) { + std::move(callback).Run(native_file_system_error::FromStatus( + NativeFileSystemStatus::kInvalidState, + "An attempt was made to abort an already closed writer.")); + return; + } + + state_ = State::kClosed; + auto_close_ = false; + + std::move(callback).Run(native_file_system_error::Ok()); +} + +// static void NativeFileSystemFileWriterImpl::DoAfterWriteCheck( base::File::Error hash_result, const std::string& hash,
diff --git a/content/browser/file_system_access/native_file_system_file_writer_impl.h b/content/browser/file_system_access/native_file_system_file_writer_impl.h index 98825c5..181d3b5b 100644 --- a/content/browser/file_system_access/native_file_system_file_writer_impl.h +++ b/content/browser/file_system_access/native_file_system_file_writer_impl.h
@@ -49,6 +49,7 @@ const SharedHandleState& handle_state, mojo::PendingReceiver<blink::mojom::NativeFileSystemFileWriter> receiver, bool has_transient_user_activation, + bool auto_close, download::QuarantineConnectionCallback quarantine_connection_callback); ~NativeFileSystemFileWriterImpl() override; @@ -63,6 +64,7 @@ void Truncate(uint64_t length, TruncateCallback callback) override; void Close(CloseCallback callback) override; + void Abort(AbortCallback callback) override; using HashCallback = base::OnceCallback< void(base::File::Error error, const std::string& hash, int64_t size)>; @@ -95,6 +97,7 @@ bool complete); void TruncateImpl(uint64_t length, TruncateCallback callback); void CloseImpl(CloseCallback callback); + void AbortImpl(AbortCallback callback); void DoAfterWriteCheck(base::File::Error hash_result, const std::string& hash, int64_t size); @@ -165,6 +168,10 @@ // checks. bool has_transient_user_activation_ = false; + // Changes will be written to the target file even if the stream isn't + // explicitly closed. + bool auto_close_ = false; + base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() override; base::WeakPtrFactory<NativeFileSystemFileWriterImpl> weak_factory_{this};
diff --git a/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc b/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc index 04d5018..2d10d529 100644 --- a/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc +++ b/content/browser/file_system_access/native_file_system_file_writer_impl_unittest.cc
@@ -170,7 +170,8 @@ NativeFileSystemManagerImpl::SharedHandleState( permission_grant_, permission_grant_, std::move(fs)), remote_.InitWithNewPipeAndPassReceiver(), - /*has_transient_user_activation=*/false, quarantine_callback_); + /*has_transient_user_activation=*/false, + /*auto_close=*/false, quarantine_callback_); } void TearDown() override { @@ -299,6 +300,18 @@ return result_out; } + NativeFileSystemStatus AbortSync() { + base::RunLoop loop; + NativeFileSystemStatus result_out; + handle_->Abort(base::BindLambdaForTesting( + [&](blink::mojom::NativeFileSystemErrorPtr result) { + result_out = result->status; + loop.Quit(); + })); + loop.Run(); + return result_out; + } + virtual bool WriteUsingBlobs() { return true; } NativeFileSystemStatus WriteSync(uint64_t position, @@ -574,6 +587,67 @@ EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState); } +TEST_F(NativeFileSystemFileWriterImplTest, AbortAfterCloseNotOK) { + uint64_t bytes_written; + NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ(bytes_written, 3u); + + result = CloseSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + result = AbortSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState); +} + +TEST_F(NativeFileSystemFileWriterImplTest, AbortOK) { + uint64_t bytes_written; + NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ(bytes_written, 3u); + + result = AbortSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ("", ReadFile(test_file_url_)); +} + +TEST_F(NativeFileSystemFileWriterImplTest, TruncateAfterAbortNotOK) { + uint64_t bytes_written; + NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ(bytes_written, 3u); + + result = AbortSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + + result = TruncateSync(0); + EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState); +} + +TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteAfterAbortNotOK) { + uint64_t bytes_written; + NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ(bytes_written, 3u); + + result = AbortSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + + result = WriteSync(0, "bcd", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState); +} + +TEST_F(NativeFileSystemFileWriterImplTest, CloseAfterAbortNotOK) { + uint64_t bytes_written; + NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + EXPECT_EQ(bytes_written, 3u); + + result = AbortSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kOk); + result = CloseSync(); + EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState); +} + // TODO(mek): More tests, particularly for error conditions. class NativeFileSystemFileWriterAfterWriteChecksTest @@ -752,14 +826,15 @@ test_swap_url_)); mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter> remote; - handle_ = manager_->CreateFileWriter( - NativeFileSystemManagerImpl::BindingContext(kTestOrigin, kTestURL, - kFrameId), - test_file_url_, test_swap_url_, - NativeFileSystemManagerImpl::SharedHandleState(permission_grant_, - permission_grant_, {}), - remote.InitWithNewPipeAndPassReceiver(), - /*has_transient_user_activation=*/false, quarantine_callback_); + handle_ = + manager_->CreateFileWriter(NativeFileSystemManagerImpl::BindingContext( + kTestOrigin, kTestURL, kFrameId), + test_file_url_, test_swap_url_, + NativeFileSystemManagerImpl::SharedHandleState( + permission_grant_, permission_grant_, {}), + remote.InitWithNewPipeAndPassReceiver(), + /*has_transient_user_activation=*/false, + /*auto_close=*/false, quarantine_callback_); uint64_t bytes_written; NativeFileSystemStatus result = WriteSync(0, "foo", &bytes_written);
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.cc b/content/browser/file_system_access/native_file_system_manager_impl.cc index 242350e..bcf674c 100644 --- a/content/browser/file_system_access/native_file_system_manager_impl.cc +++ b/content/browser/file_system_access/native_file_system_manager_impl.cc
@@ -769,7 +769,8 @@ const BindingContext& binding_context, const storage::FileSystemURL& url, const storage::FileSystemURL& swap_url, - const SharedHandleState& handle_state) { + const SharedHandleState& handle_state, + bool auto_close) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); mojo::PendingRemote<blink::mojom::NativeFileSystemFileWriter> result; @@ -779,6 +780,7 @@ CreateFileWriter( binding_context, url, swap_url, handle_state, result.InitWithNewPipeAndPassReceiver(), has_transient_user_activation, + auto_close, GetContentClient()->browser()->GetQuarantineConnectionCallback()); return result; } @@ -790,12 +792,13 @@ const SharedHandleState& handle_state, mojo::PendingReceiver<blink::mojom::NativeFileSystemFileWriter> receiver, bool has_transient_user_activation, + bool auto_close, download::QuarantineConnectionCallback quarantine_connection_callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto writer = std::make_unique<NativeFileSystemFileWriterImpl>( this, PassKey(), binding_context, url, swap_url, handle_state, - std::move(receiver), has_transient_user_activation, + std::move(receiver), has_transient_user_activation, auto_close, quarantine_connection_callback); NativeFileSystemFileWriterImpl* writer_ptr = writer.get();
diff --git a/content/browser/file_system_access/native_file_system_manager_impl.h b/content/browser/file_system_access/native_file_system_manager_impl.h index 6085cbf..64bf949 100644 --- a/content/browser/file_system_access/native_file_system_manager_impl.h +++ b/content/browser/file_system_access/native_file_system_manager_impl.h
@@ -161,7 +161,8 @@ CreateFileWriter(const BindingContext& binding_context, const storage::FileSystemURL& url, const storage::FileSystemURL& swap_url, - const SharedHandleState& handle_state); + const SharedHandleState& handle_state, + bool auto_close); // Returns a raw pointer to a newly created NativeFileSystemFileWriterImpl. // Useful for tests NativeFileSystemFileWriterImpl* CreateFileWriter( @@ -171,6 +172,7 @@ const SharedHandleState& handle_state, mojo::PendingReceiver<blink::mojom::NativeFileSystemFileWriter> receiver, bool has_transient_user_activation, + bool auto_close, download::QuarantineConnectionCallback quarantine_connection_callback); // Create a transfer token for a specific file or directory.
diff --git a/content/browser/file_system_access/native_file_system_manager_impl_unittest.cc b/content/browser/file_system_access/native_file_system_manager_impl_unittest.cc index d7714e0..4a4729a 100644 --- a/content/browser/file_system_access/native_file_system_manager_impl_unittest.cc +++ b/content/browser/file_system_access/native_file_system_manager_impl_unittest.cc
@@ -501,7 +501,8 @@ mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote( manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url, NativeFileSystemManagerImpl::SharedHandleState( - allow_grant_, allow_grant_, {}))); + allow_grant_, allow_grant_, {}), + /*auto_close=*/false)); ASSERT_TRUE(writer_remote.is_bound()); ASSERT_TRUE(storage::AsyncFileTestHelper::FileExists( @@ -533,7 +534,8 @@ mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote( manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url, NativeFileSystemManagerImpl::SharedHandleState( - allow_grant_, allow_grant_, {}))); + allow_grant_, allow_grant_, {}), + /*auto_close=*/false)); ASSERT_TRUE(writer_remote.is_bound()); ASSERT_FALSE(storage::AsyncFileTestHelper::FileExists( @@ -576,7 +578,8 @@ mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote( manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url, NativeFileSystemManagerImpl::SharedHandleState( - allow_grant_, allow_grant_, {}))); + allow_grant_, allow_grant_, {}), + /*auto_close=*/false)); // Severs the mojo pipe. The writer should be destroyed. writer_remote.reset(); @@ -591,6 +594,50 @@ storage::AsyncFileTestHelper::kDontCheckSize)); } +TEST_F(NativeFileSystemManagerImplTest, + FileWriterAutoCloseIfConnectionLostBeforeClose) { + auto test_file_url = file_system_context_->CreateCrackedFileSystemURL( + kTestOrigin, storage::kFileSystemTypeTest, + base::FilePath::FromUTF8Unsafe("test")); + + auto test_swap_url = file_system_context_->CreateCrackedFileSystemURL( + kTestOrigin, storage::kFileSystemTypeTest, + base::FilePath::FromUTF8Unsafe("test.crswap")); + + ASSERT_EQ(base::File::FILE_OK, + storage::AsyncFileTestHelper::CreateFileWithData( + file_system_context_.get(), test_swap_url, "foo", 3)); + + mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote( + manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url, + NativeFileSystemManagerImpl::SharedHandleState( + allow_grant_, allow_grant_, {}), + /*auto_close=*/true)); + + ASSERT_TRUE(writer_remote.is_bound()); + ASSERT_FALSE(storage::AsyncFileTestHelper::FileExists( + file_system_context_.get(), test_file_url, + storage::AsyncFileTestHelper::kDontCheckSize)); + + EXPECT_CALL(permission_context_, + PerformAfterWriteChecks_(testing::_, kFrameId, testing::_)) + .WillOnce(base::test::RunOnceCallback<2>( + NativeFileSystemPermissionContext::AfterWriteCheckResult::kAllow)); + + // Severs the mojo pipe. Since autoClose was specified, the Writer will not be + // destroyed until the file is written out. + writer_remote.reset(); + base::RunLoop().RunUntilIdle(); + + // Since the close should complete, the swap file should have been destroyed + // and the write should be reflected in the target file. + EXPECT_FALSE(storage::AsyncFileTestHelper::FileExists( + file_system_context_.get(), test_swap_url, + storage::AsyncFileTestHelper::kDontCheckSize)); + ASSERT_TRUE(storage::AsyncFileTestHelper::FileExists( + file_system_context_.get(), test_file_url, 3)); +} + TEST_F(NativeFileSystemManagerImplTest, SerializeHandle_SandboxedFile) { auto test_file_url = file_system_context_->CreateCrackedFileSystemURL( kTestOrigin, storage::kFileSystemTypeTemporary,
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index 089194245..8dd0326 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -109,7 +109,7 @@ // static void IndexedDBContextImpl::ReleaseOnIDBSequence( - scoped_refptr<IndexedDBContextImpl> context) { + scoped_refptr<IndexedDBContextImpl>&& context) { if (!context->idb_task_runner_->RunsTasksInCurrentSequence()) { IndexedDBContextImpl* context_ptr = context.get(); context_ptr->IDBTaskRunner()->ReleaseSoon(FROM_HERE, std::move(context));
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h index 9b52926e..88a5f31 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.h +++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -57,7 +57,8 @@ static const base::FilePath::CharType kIndexedDBDirectory[]; // Release |context| on the IDBTaskRunner. - static void ReleaseOnIDBSequence(scoped_refptr<IndexedDBContextImpl> context); + static void ReleaseOnIDBSequence( + scoped_refptr<IndexedDBContextImpl>&& context); // If |data_path| is empty, nothing will be saved to disk. // |task_runner| is optional, and only set during testing.
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index f6add29f..71d657e 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -1067,6 +1067,50 @@ } } +// Ensure that renderer initiated navigations which have the opener suppressed +// work. +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, + RendererInitiatedNewWindowNoOpenerNavigation) { + GURL url(embedded_test_server()->GetURL("/simple_links.html")); + EXPECT_TRUE(NavigateToURL(shell(), url)); + + RenderFrameHost* initial_rfh = current_frame_host(); + url::Origin initial_origin = initial_rfh->GetLastCommittedOrigin(); + base::UnguessableToken initiator_frame_token = initial_rfh->GetFrameToken(); + + // Simulate clicking on a cross-site link which has rel="noopener". + { + const char kReplacePortNumber[] = + "window.domAutomationController.send(setPortNumber(%d));"; + uint16_t port_number = embedded_test_server()->port(); + GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); + bool success = false; + EXPECT_TRUE(ExecuteScriptAndExtractBool( + shell(), base::StringPrintf(kReplacePortNumber, port_number), + &success)); + success = false; + + ShellAddedObserver new_shell_observer; + EXPECT_TRUE( + ExecuteScriptAndExtractBool(shell(), + "window.domAutomationController.send(" + "clickCrossSiteNewWindowNoOpenerLink());", + &success)); + EXPECT_TRUE(success); + + TestNavigationObserver observer( + new_shell_observer.GetShell()->web_contents()); + observer.Wait(); + + EXPECT_EQ(url, observer.last_navigation_url()); + EXPECT_TRUE(observer.last_navigation_succeeded()); + EXPECT_EQ(initial_origin, observer.last_initiator_origin().value()); + EXPECT_TRUE(observer.last_initiator_frame_token().has_value()); + EXPECT_EQ(initiator_frame_token, + observer.last_initiator_frame_token().value()); + } +} + IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, RendererInitiatedWithSubframeInitator) { GURL url(embedded_test_server()->GetURL(
diff --git a/content/browser/navigation_mhtml_browsertest.cc b/content/browser/navigation_mhtml_browsertest.cc index ceef2a5..6c79073 100644 --- a/content/browser/navigation_mhtml_browsertest.cc +++ b/content/browser/navigation_mhtml_browsertest.cc
@@ -208,7 +208,7 @@ sub_document->GetLastCommittedURL()); EXPECT_TRUE(main_document->is_mhtml_document()); - EXPECT_FALSE(sub_document->is_mhtml_document()); // Served from data-url. + EXPECT_TRUE(sub_document->is_mhtml_document()); // Check the iframe is properly loaded. EvalJs("document.body.innerHTML") // can't be used, because javascript is disabled. Instead, check it was able @@ -237,7 +237,7 @@ sub_document->GetLastCommittedURL()); EXPECT_TRUE(main_document->is_mhtml_document()); - EXPECT_FALSE(sub_document->is_mhtml_document()); // Served from data-url. + EXPECT_TRUE(sub_document->is_mhtml_document()); // Check the iframe is properly loaded. EvalJs("document.body.innerHTML") // can't be used, because javascript is disabled. Instead, check it was able @@ -676,4 +676,29 @@ EXPECT_EQ(strict_sandbox, rfh_sandboxed->active_sandbox_flags()); } +// Regression test for https://crbug.com/1155862. +IN_PROC_BROWSER_TEST_F(NavigationMhtmlBrowserTest, DataIframe) { + MhtmlArchive mhtml_archive; + mhtml_archive.AddHtmlDocument( + GURL("http://127.0.0.1/starte.html"), "", + R"( <iframe src="http://8.8.8.8/test.html"></iframe> + <iframe src="data:text/html,blah1"></iframe> + <iframe src="about:blank?foo=123"></iframe> )"); + mhtml_archive.AddHtmlDocument(GURL("http://8.8.8.8/test.html"), "", R"( + <iframe src="data:text/html,blah2"></iframe> + <iframe src="about:blank?foo=123"></iframe> )"); + mhtml_archive.AddHtmlDocument(GURL("about:blank?foo=123"), "", "foo"); + GURL mhtml_url = mhtml_archive.Write("index.mhtml"); + + // The main test verification is that the navigation below succeeds (without + // crashing in NavigationRequest::GetOriginForURLLoaderFactory). + EXPECT_TRUE(NavigateToURL(shell(), mhtml_url)); + + // All MHTML frames should have an opaque origin. + for (RenderFrameHost* frame : shell()->web_contents()->GetAllFrames()) { + EXPECT_TRUE(frame->GetLastCommittedOrigin().opaque()) + << "frame->GetLastCommittedURL() = " << frame->GetLastCommittedURL(); + } +} + } // namespace content
diff --git a/content/browser/net/trust_token_browsertest.cc b/content/browser/net/trust_token_browsertest.cc index 4f4eca7f..7e66faf4 100644 --- a/content/browser/net/trust_token_browsertest.cc +++ b/content/browser/net/trust_token_browsertest.cc
@@ -12,8 +12,10 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" +#include "build/build_config.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/network_service_instance.h" +#include "content/public/common/trust_tokens.mojom.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -43,6 +45,11 @@ #include "url/origin.h" #include "url/url_canon_stdstring.h" +#if defined(OS_ANDROID) +#include "content/public/browser/android/java_interfaces.h" +#include "services/service_manager/public/cpp/interface_provider.h" +#endif // defined(OS_ANDROID) + namespace content { namespace { @@ -1638,4 +1645,236 @@ Optional(ReflectsSigningFailure())); } +class TrustTokenBrowsertestWithPlatformIssuance : public TrustTokenBrowsertest { + public: + TrustTokenBrowsertestWithPlatformIssuance() { + // This assertion helps guard against the brittleness of deserializing + // "true", in case we refactor the parameter's type. + static_assert( + std::is_same<decltype( + network::features::kPlatformProvidedTrustTokenIssuance + .default_value), + const bool>::value, + "Need to update this initialization logic if the type of the param " + "changes."); + features_.InitAndEnableFeatureWithParameters( + network::features::kTrustTokens, + {{network::features::kPlatformProvidedTrustTokenIssuance.name, + "true"}}); + } + + private: + base::test::ScopedFeatureList features_; +}; + +#if defined(OS_ANDROID) +IN_PROC_BROWSER_TEST_F(TrustTokenBrowsertestWithPlatformIssuance, + EndToEndAndroidPlatformIssuance) { + TrustTokenRequestHandler::Options options; + options.specify_platform_issuance_on = { + network::mojom::TrustTokenKeyCommitmentResult::Os::kAndroid}; + request_handler_.UpdateOptions(std::move(options)); + + class HandlerWrappingLocalTrustTokenFulfiller + : public content::mojom::LocalTrustTokenFulfiller { + public: + HandlerWrappingLocalTrustTokenFulfiller(TrustTokenRequestHandler& handler) + : handler_(handler) {} + void FulfillTrustTokenIssuance( + network::mojom::FulfillTrustTokenIssuanceRequestPtr request, + FulfillTrustTokenIssuanceCallback callback) override { + base::Optional<std::string> maybe_result = + handler_.Issue(std::move(request->request)); + if (maybe_result) { + std::move(callback).Run( + network::mojom::FulfillTrustTokenIssuanceAnswer::New( + network::mojom::FulfillTrustTokenIssuanceAnswer::Status::kOk, + std::move(*maybe_result))); + return; + } + std::move(callback).Run( + network::mojom::FulfillTrustTokenIssuanceAnswer::New( + network::mojom::FulfillTrustTokenIssuanceAnswer::Status:: + kUnknownError, + "")); + } + + void Bind(mojo::ScopedMessagePipeHandle handle) { + receiver_.Bind( + mojo::PendingReceiver<content::mojom::LocalTrustTokenFulfiller>( + std::move(handle))); + } + + private: + TrustTokenRequestHandler& handler_; + mojo::Receiver<content::mojom::LocalTrustTokenFulfiller> receiver_{this}; + }; + + service_manager::InterfaceProvider::TestApi interface_overrider( + content::GetGlobalJavaInterfaces()); + + HandlerWrappingLocalTrustTokenFulfiller fulfiller(request_handler_); + interface_overrider.SetBinderForName( + mojom::LocalTrustTokenFulfiller::Name_, + base::BindRepeating(&HandlerWrappingLocalTrustTokenFulfiller::Bind, + base::Unretained(&fulfiller))); + + ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"}); + + GURL start_url = server_.GetURL("a.test", "/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), start_url)); + + // Issuance operations successfully answered locally result in + // NoModificationAllowedError. + std::string command = R"( + (async () => { + try { + await fetch("/issue", {trustToken: {type: 'token-request'}}); + return "Unexpected success"; + } catch (e) { + if (e.name !== "NoModificationAllowedError") { + return "Unexpected exception"; + } + const hasToken = await document.hasTrustToken($1); + if (!hasToken) + return "Unexpectedly absent token"; + return "Success"; + }})(); )"; + + // We use EvalJs here, not ExecJs, because EvalJs waits for promises to + // resolve. + EXPECT_EQ( + "Success", + EvalJs(shell(), JsReplace(command, IssuanceOriginFromHost("a.test")))); +} + +IN_PROC_BROWSER_TEST_F(TrustTokenBrowsertestWithPlatformIssuance, + PlatformIssuanceWithoutEmbedderSupport) { + TrustTokenRequestHandler::Options options; + options.specify_platform_issuance_on = { + network::mojom::TrustTokenKeyCommitmentResult::Os::kAndroid}; + options.unavailable_local_operation_fallback = + network::mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kReturnWithError; + request_handler_.UpdateOptions(std::move(options)); + + service_manager::InterfaceProvider::TestApi interface_overrider( + content::GetGlobalJavaInterfaces()); + // Instead of using interface_overrider.ClearBinder(name), it's necessary to + // provide a callback that explicitly closes the pipe, since + // InterfaceProvider's contract requires that it either bind or close pipes + // it's given (see its comments in interface_provider.mojom). + interface_overrider.SetBinderForName( + mojom::LocalTrustTokenFulfiller::Name_, + base::BindRepeating([](mojo::ScopedMessagePipeHandle handle) { + mojo::Close(std::move(handle)); + })); + + ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"}); + + GURL start_url = server_.GetURL("a.test", "/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), start_url)); + + // Issuance operations diverted locally without embedder support, with + // "return_with_error" specified in the issuer's key commitments, should + // result in OperationError. + std::string command = R"( + (async () => { + try { + await fetch("/issue", {trustToken: {type: 'token-request'}}); + return "Unexpected success"; + } catch (e) { + return e.name; + }})(); )"; + + // We use EvalJs here, not ExecJs, because EvalJs waits for promises to + // resolve. + EXPECT_EQ("OperationError", EvalJs(shell(), command)); +} +#endif // defined(OS_ANDROID) +#if !defined(OS_ANDROID) +IN_PROC_BROWSER_TEST_F( + TrustTokenBrowsertestWithPlatformIssuance, + IssuanceOnOsNotSpecifiedInKeyCommitmentsReturnsErrorIfConfiguredToDoSo) { + TrustTokenRequestHandler::Options options; + options.specify_platform_issuance_on = { + network::mojom::TrustTokenKeyCommitmentResult::Os::kAndroid}; + // Since we're not on Android, if the issuer + // 1) configures that, on Android, we should attempt platform-provided token + // issuance, + // 2) specifies "return_with_error" as the fallback behavior for other OSes, + // issuance against the host configured for platform-provided issuance should + // fail. + options.unavailable_local_operation_fallback = + network::mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kReturnWithError; + request_handler_.UpdateOptions(std::move(options)); + + ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"}); + + GURL start_url = server_.GetURL("a.test", "/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), start_url)); + + // Issuance operations attempted on OSes other than those specified in + // the key commitment's "request_issuance_locally_on" field should result in + // OperationError returns if the issuer specified "return_with_error" as the + // fallback behavior. + std::string command = R"( + (async () => { + try { + await fetch("/issue", {trustToken: {type: 'token-request'}}); + return "Unexpected success"; + } catch (e) { + return e.name; + }})(); )"; + + // We use EvalJs here, not ExecJs, because EvalJs waits for promises to + // resolve. + EXPECT_EQ("OperationError", EvalJs(shell(), command)); +} + +IN_PROC_BROWSER_TEST_F( + TrustTokenBrowsertestWithPlatformIssuance, + IssuanceOnOsNotSpecifiedInKeyCommitmentsFallsBackToWebIssuanceIfSpecified) { + TrustTokenRequestHandler::Options options; + options.specify_platform_issuance_on = { + network::mojom::TrustTokenKeyCommitmentResult::Os::kAndroid}; + // Since we're not on Android, if the issuer + // 1) configures that, on Android, we should attempt platform-provided token + // issuance, + // 2) specifies "web_issuance" as fallback behavior for other OSes, + // we should see issuance succeed. + options.unavailable_local_operation_fallback = + network::mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kWebIssuance; + request_handler_.UpdateOptions(std::move(options)); + + ProvideRequestHandlerKeyCommitmentsToNetworkService({"a.test"}); + + GURL start_url = server_.GetURL("a.test", "/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), start_url)); + + // Issuance operations attempted on OSes other than those specified in + // the key commitment's "request_issuance_locally_on" field should result in + // OperationError returns if the issuer specified "return_with_error" as the + // fallback behavior. + std::string command = R"( + (async () => { + try { + await fetch("/issue", {trustToken: {type: 'token-request'}}); + if (await document.hasTrustToken($1)) + return "Success"; + return "Issuance failed unexpectedly"; + } catch (e) { + return e.name; + }})(); )"; + + // We use EvalJs here, not ExecJs, because EvalJs waits for promises to + // resolve. + EXPECT_EQ( + "Success", + EvalJs(shell(), JsReplace(command, IssuanceOriginFromHost("a.test")))); +} +#endif // !defined(OS_ANDROID) + } // namespace content
diff --git a/content/browser/renderer_host/cross_process_frame_connector.cc b/content/browser/renderer_host/cross_process_frame_connector.cc index 0d19335..047e61a 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.cc +++ b/content/browser/renderer_host/cross_process_frame_connector.cc
@@ -509,11 +509,14 @@ void CrossProcessFrameConnector::UpdateRenderThrottlingStatus( bool is_throttled, - bool subtree_throttled) { + bool subtree_throttled, + bool display_locked) { if (is_throttled != is_throttled_ || - subtree_throttled != subtree_throttled_) { + subtree_throttled != subtree_throttled_ || + display_locked != display_locked_) { is_throttled_ = is_throttled; subtree_throttled_ = subtree_throttled; + display_locked_ = display_locked; if (view_) view_->UpdateRenderThrottlingStatus(); } @@ -527,6 +530,10 @@ return subtree_throttled_; } +bool CrossProcessFrameConnector::IsDisplayLocked() const { + return display_locked_; +} + bool CrossProcessFrameConnector::MaybeLogCrash(CrashVisibility visibility) { if (!has_crashed_) return false;
diff --git a/content/browser/renderer_host/cross_process_frame_connector.h b/content/browser/renderer_host/cross_process_frame_connector.h index de83df5..adeb65a 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.h +++ b/content/browser/renderer_host/cross_process_frame_connector.h
@@ -233,10 +233,17 @@ // RenderWidgetHostView::Hide() is called on the current view. bool IsHidden() const; - // Determines whether the child frame should be render throttled, which - // happens when the entire rect is offscreen. + // IsThrottled() indicates that the frame is outside of it's parent frame's + // visible viewport, and should be render throttled. bool IsThrottled() const; + // IsSubtreeThrottled() indicates that IsThrottled() is true for one of this + // frame's ancestors, which means this frame must also be throttled. bool IsSubtreeThrottled() const; + // IsDisplayLocked() indicates that a DOM ancestor of this frame's owning + // <iframe> element in the parent frame is currently display locked; or that + // IsDisplayLocked() is true for one of this frame's ancestors; which means + // this frame should be render throttled. + bool IsDisplayLocked() const; // Called by RenderWidgetHostViewChildFrame when the child frame has updated // its visual properties and its viz::LocalSurfaceId has changed. @@ -272,7 +279,9 @@ return GetRootRenderWidgetHostView(); } - void UpdateRenderThrottlingStatus(bool is_throttled, bool subtree_throttled); + void UpdateRenderThrottlingStatus(bool is_throttled, + bool subtree_throttled, + bool display_locked); void UpdateViewportIntersection( const blink::mojom::ViewportIntersectionState& intersection_state); @@ -379,6 +388,7 @@ bool is_throttled_ = false; bool subtree_throttled_ = false; + bool display_locked_ = false; // Visibility state of the corresponding frame owner element in parent process // which is set through CSS or scrolling.
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc index a62ff93..29ff7c0 100644 --- a/content/browser/renderer_host/input/fling_browsertest.cc +++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -121,6 +121,16 @@ deleted_observer.WaitUntilDeleted(); } + // TODO(szager): This is a speculative fix for test flakiness caused by + // changes to render throttling (crbug.com/1158644). The hypothesis is that + // the test code might be initiating a scroll gesture before + // LocalFrameView::BeginLifecycleUpdates() is called in the child frame. By + // the time EvalJsAfterLifecycleUpdate() returns, BeginLifecycleUpdates() is + // guaranteed to have run. + ASSERT_TRUE( + EvalJsAfterLifecycleUpdate(iframe_node->current_frame_host(), "", "") + .error.empty()); + WaitForHitTestData(iframe_node->current_frame_host()); ASSERT_EQ( " Site A ------------ proxies for B\n"
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc index bf4d52f8..afb65cc 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc +++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
@@ -398,9 +398,11 @@ } void TouchSelectionControllerClientAura::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, const gfx::PointF& position) {} void TouchSelectionControllerClientAura::InternalClient::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, const gfx::PointF& position) { NOTREACHED(); }
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.h b/content/browser/renderer_host/input/touch_selection_controller_client_aura.h index 59da384..80ff5cd 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_aura.h +++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.h
@@ -85,7 +85,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; void OnSelectionEvent(ui::SelectionEventType event) override; - void OnDragUpdate(const gfx::PointF& position) override; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; void DidScroll() override; @@ -111,7 +112,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) final; void OnSelectionEvent(ui::SelectionEventType event) final; - void OnDragUpdate(const gfx::PointF& position) final; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) final; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() final; void DidScroll() override;
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc index 9902656..822b3817 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc +++ b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.cc
@@ -143,6 +143,7 @@ } void TouchSelectionControllerClientChildFrame::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, const gfx::PointF& position) { NOTREACHED(); }
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.h b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.h index 1d320f01..cb1cc12b 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.h +++ b/content/browser/renderer_host/input/touch_selection_controller_client_child_frame.h
@@ -50,7 +50,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; void OnSelectionEvent(ui::SelectionEventType event) override; - void OnDragUpdate(const gfx::PointF& position) override; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; void DidScroll() override;
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.cc b/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.cc index 5d0ba34..52572f3c 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.cc +++ b/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.cc
@@ -133,8 +133,9 @@ } void TouchSelectionControllerClientManagerAndroid::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, const gfx::PointF& position) { - rwhv_->OnDragUpdate(position); + rwhv_->OnDragUpdate(type, position); } std::unique_ptr<ui::TouchHandleDrawable>
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h b/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h index 79c431a..df312425 100644 --- a/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h +++ b/content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h
@@ -55,7 +55,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; void OnSelectionEvent(ui::SelectionEventType event) override; - void OnDragUpdate(const gfx::PointF& position) override; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; void DidScroll() override; void ShowTouchSelectionContextMenu(const gfx::Point& location) override;
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm index 9590497..3bcf245 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm +++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -309,8 +309,9 @@ if ([text_str length] < blink::WebKeyboardEvent::kTextLengthCap && [unmodified_str length] < blink::WebKeyboardEvent::kTextLengthCap) { - [text_str getCharacters:&result.text[0]]; - [unmodified_str getCharacters:&result.unmodified_text[0]]; + [text_str getCharacters:reinterpret_cast<UniChar*>(&result.text[0])]; + [unmodified_str + getCharacters:reinterpret_cast<UniChar*>(&result.unmodified_text[0])]; } else NOTIMPLEMENTED();
diff --git a/content/browser/renderer_host/native_web_keyboard_event_mac.mm b/content/browser/renderer_host/native_web_keyboard_event_mac.mm index 3cb3ad6..abe389e 100644 --- a/content/browser/renderer_host/native_web_keyboard_event_mac.mm +++ b/content/browser/renderer_host/native_web_keyboard_event_mac.mm
@@ -69,11 +69,12 @@ if (unmod_text_length == 0) type = NSFlagsChanged; - NSString* text = - [[[NSString alloc] initWithCharacters:web_event.text length:text_length] - autorelease]; + NSString* text = [[[NSString alloc] + initWithCharacters:reinterpret_cast<const UniChar*>(web_event.text) + length:text_length] autorelease]; NSString* unmodified_text = - [[[NSString alloc] initWithCharacters:web_event.unmodified_text + [[[NSString alloc] initWithCharacters:reinterpret_cast<const UniChar*>( + web_event.unmodified_text) length:unmod_text_length] autorelease]; os_event = [[NSEvent keyEventWithType:type
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc index f7f15e53..a96a0103 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3492,7 +3492,7 @@ auto navigation_request = NavigationRequest::CreateBrowserInitiated( node, std::move(common_params), std::move(commit_params), - !params.is_renderer_initiated, + !params.is_renderer_initiated, params.was_opener_suppressed, params.initiator_frame_token.has_value() ? &(params.initiator_frame_token.value()) : nullptr, @@ -3613,7 +3613,8 @@ return NavigationRequest::CreateBrowserInitiated( frame_tree_node, std::move(common_params), std::move(commit_params), - !entry->is_renderer_initiated(), nullptr /* initiator_frame_token */, + !entry->is_renderer_initiated(), false /* was_opener_suppressed */, + nullptr /* initiator_frame_token */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, entry->extra_headers(), frame_entry, entry, request_body, nullptr /* navigation_ui_data */, base::nullopt /* impression */); @@ -3714,7 +3715,8 @@ std::unique_ptr<NavigationRequest> navigation_request = NavigationRequest::CreateBrowserInitiated( node, std::move(common_params), std::move(commit_params), - true /* browser_initiated */, nullptr /* initiator_frame_token */, + true /* browser_initiated */, false /* was_opener_suppressed */, + nullptr /* initiator_frame_token */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, "" /* extra_headers */, nullptr /* frame_entry */, nullptr /* entry */, nullptr /* post_body */,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 29394a1..5ccaece 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -708,6 +708,7 @@ mojom::CommonNavigationParamsPtr common_params, mojom::CommitNavigationParamsPtr commit_params, bool browser_initiated, + bool was_opener_suppressed, const base::UnguessableToken* initiator_frame_token, int initiator_process_id, const std::string& extra_headers, @@ -763,7 +764,7 @@ false /* from_begin_navigation */, false /* is_for_commit */, frame_entry, entry, std::move(navigation_ui_data), mojo::NullAssociatedRemote(), mojo::NullRemote(), rfh_restored_from_back_forward_cache, - initiator_process_id)); + initiator_process_id, was_opener_suppressed)); if (frame_entry) { navigation_request->blob_url_loader_factory_ = @@ -870,6 +871,8 @@ int initiator_process_id = frame_tree_node->current_frame_host()->GetProcess()->GetID(); + // `was_opener_suppressed` can be true for renderer initiated navigations, but + // only in cases which get routed through `CreateBrowserInitiated()` instead. std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest( frame_tree_node, std::move(common_params), std::move(begin_params), std::move(commit_params), @@ -880,7 +883,8 @@ nullptr, // navigation_ui_data std::move(navigation_client), std::move(navigation_initiator), nullptr, // rfh_restored_from_back_forward_cache - initiator_process_id)); + initiator_process_id, + /*was_opener_suppressed=*/false)); navigation_request->blob_url_loader_factory_ = std::move(blob_url_loader_factory); navigation_request->prefetched_signed_exchange_cache_ = @@ -977,7 +981,8 @@ nullptr /* frame_navigation_entry */, nullptr /* navigation_entry */, nullptr /* navigation_ui_data */, mojo::NullAssociatedRemote(), mojo::NullRemote(), nullptr /* rfh_restored_from_back_forward_cache */, - ChildProcessHost::kInvalidUniqueID /* initiator_process_id */)); + ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, + false /* was_opener_suppressed */)); navigation_request->web_bundle_navigation_info_ = std::move(web_bundle_navigation_info); @@ -1009,7 +1014,8 @@ mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client, mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator, RenderFrameHostImpl* rfh_restored_from_back_forward_cache, - int initiator_process_id) + int initiator_process_id, + bool was_opener_suppressed) : frame_tree_node_(frame_tree_node), is_for_commit_(is_for_commit), common_params_(std::move(common_params)), @@ -1039,6 +1045,7 @@ frame_tree_node->current_frame_host()->GetRoutingID())), initiator_frame_token_(begin_params_->initiator_frame_token), initiator_process_id_(initiator_process_id), + was_opener_suppressed_(was_opener_suppressed), coop_status_(frame_tree_node, common_params_->initiator_origin), previous_page_ukm_source_id_( frame_tree_node_->current_frame_host()->GetPageUkmSourceId()) { @@ -1435,6 +1442,9 @@ return; } + if (IsForMhtmlSubframe()) + is_mhtml_or_subframe_ = true; + if (!NeedsUrlLoader()) { // The types of pages that don't need a URL Loader should never get served // from the BackForwardCache. @@ -1444,7 +1454,6 @@ // it immediately. EnterChildTraceEvent("ResponseStarted", this); - is_loaded_from_mhtml_archive_ = IsForMhtmlSubframe(); ComputeSandboxFlagsToCommit(/*response_head=*/nullptr); // Same-document navigations occur in the currently loaded document. See @@ -1468,8 +1477,9 @@ frame_host_choice_reason); SCOPED_CRASH_KEY_BOOL("nav_request", "has_source_instance", !!GetSourceSiteInstance()); - // Crash keys capturing values affecting |was_opener_suppressed| in - // RequiresInitiatorBasedSourceSiteInstance: + // Crash keys capturing values for/related to |was_opener_suppressed_|. + SCOPED_CRASH_KEY_BOOL("nav_request", "was_opener_suppressed", + was_opener_suppressed_); SCOPED_CRASH_KEY_BOOL("nav_request", "is_main_frame", IsInMainFrame()); SCOPED_CRASH_KEY_BOOL("nav_request", "got_initiator_routing_id", GetInitiatorFrameToken() != base::nullopt); @@ -2229,8 +2239,8 @@ bool is_mhtml_archive = response_head_->mime_type == "multipart/related" || response_head_->mime_type == "message/rfc822"; - - is_loaded_from_mhtml_archive_ = is_mhtml_archive || IsForMhtmlSubframe(); + if (is_mhtml_archive) + is_mhtml_or_subframe_ = true; ComputeSandboxFlagsToCommit(response_head_.get()); @@ -3211,7 +3221,7 @@ } } - is_loaded_from_mhtml_archive_ = false; + is_mhtml_or_subframe_ = false; sandbox_flags_to_commit_.reset(); // TODO(https://crbug.com/1158370): Apparently, error pages inherit sandbox // flags from their parent/opener. Document loaded from the network @@ -4084,21 +4094,18 @@ return throttle_runner_->GetDeferringThrottle() != nullptr; } -bool NavigationRequest::IsLoadedFromMhtmlArchive() { +bool NavigationRequest::IsMhtmlOrSubframe() { DCHECK(state_ >= WILL_PROCESS_RESPONSE || state_ == WILL_START_REQUEST && !NeedsUrlLoader()); - return is_loaded_from_mhtml_archive_; + + return is_mhtml_or_subframe_; } bool NavigationRequest::IsForMhtmlSubframe() const { - return frame_tree_node_->parent() && - frame_tree_node_->frame_tree() - ->root() - ->current_frame_host() - ->is_mhtml_document() && - // Unlike every other MHTML subframe URLs, data-url are loaded via the - // URL, not from the MHTML archive. See https://crbug.com/969696. - !common_params_->url.SchemeIs(url::kDataScheme); + return frame_tree_node_->parent() && frame_tree_node_->frame_tree() + ->root() + ->current_frame_host() + ->is_mhtml_document(); } void NavigationRequest::CancelDeferredNavigationInternal( @@ -4406,8 +4413,14 @@ } bool NavigationRequest::NeedsUrlLoader() { + bool is_mhtml_subframe_loaded_from_achive = + IsForMhtmlSubframe() && + // Unlike all other MHTML subframe URLs, data-url are loaded via the + // URL, not from the MHTML archive. See https://crbug.com/969696. + !common_params_->url.SchemeIs(url::kDataScheme); + return IsURLHandledByNetworkStack(common_params_->url) && !IsSameDocument() && - !IsForMhtmlSubframe(); + !is_mhtml_subframe_loaded_from_achive; } bool NavigationRequest::IsWebSecureContext() const { @@ -4580,7 +4593,7 @@ // MHTML documents should commit as an opaque origin. They should not be able // to make network request on behalf of the real origin. - DCHECK(!IsLoadedFromMhtmlArchive() || use_opaque_origin); + DCHECK(!IsMhtmlOrSubframe() || use_opaque_origin); // https://crbug.com/1041376) of the origin that will be committed because of // |this| NavigationRequest. @@ -4601,7 +4614,7 @@ // policy of the process being used. This is because the content is loaded // from the MHTML archive within the process. There are no data loaded from // the network. - if (IsLoadedFromMhtmlArchive() && !IsInMainFrame()) + if (IsForMhtmlSubframe()) return origin; int process_id = target_frame->GetProcess()->GetID(); @@ -5152,17 +5165,7 @@ common_params_->initiator_origin->GetTupleOrPrecursorTupleIfOpaque() .IsValid(); - // If renderer-initiated navigation of a main frame |has_valid_initiator| but - // has no |initiator_frame_token_|, then it means that the opener was - // suppressed (and therefore that a source SiteInstance is not needed). Note - // that |initiator_frame_token_| is always base::nullopt during - // browser-initiated navigations (including session restore or history - // navigations). - const bool was_opener_suppressed = - has_valid_initiator && frame_tree_node()->IsMainFrame() && - !initiator_frame_token_.has_value() && !browser_initiated_; - - return is_data_or_about && has_valid_initiator && !was_opener_suppressed && + return is_data_or_about && has_valid_initiator && !was_opener_suppressed_ && !dest_site_instance_; } @@ -5314,7 +5317,7 @@ // potentially dangerous. For this reason we force the document to be // sandboxed, providing exceptions only for creating new windows. This // includes disallowing javascript and using an opaque origin. - if (IsLoadedFromMhtmlArchive()) { + if (IsMhtmlOrSubframe()) { *sandbox_flags_to_commit_ |= ~network::mojom::WebSandboxFlags::kPopups & ~network::mojom::WebSandboxFlags:: kPropagatesToAuxiliaryBrowsingContexts;
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index dd495343e..a1647b73 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h
@@ -170,6 +170,7 @@ mojom::CommonNavigationParamsPtr common_params, mojom::CommitNavigationParamsPtr commit_params, bool browser_initiated, + bool was_opener_suppressed, const base::UnguessableToken* initiator_frame_token, int initiator_process_id, const std::string& extra_headers, @@ -573,14 +574,13 @@ void SetNavigationClient( mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client); - // Whether the new document loaded will be loaded from an MHTML archive. - // Contrary to IsForMhtmlSubframe(), this isn't scoped to subframe, but can't - // be called prior to receiving the final response. - bool IsLoadedFromMhtmlArchive(); + // Whether the navigation loads an MHTML document or a subframe of an MHTML + // document. The navigation might or might not be fullfilled from the MHTML + // archive (see `is_mhtml_subframe_loaded_from_achive` in the NeedsUrlLoader + // method). The navigation will commit in the main frame process. + bool IsMhtmlOrSubframe(); - // Whether the new document created by this navigation will be loaded from a - // MHTML document. In this case, the navigation will commit in the main frame - // process without needing any network requests. + // Whether this navigation navigates a subframe of an MHTML document. bool IsForMhtmlSubframe() const; std::unique_ptr<AppCacheNavigationHandle> TakeAppCacheHandle(); @@ -801,7 +801,8 @@ mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator, RenderFrameHostImpl* rfh_restored_from_back_forward_cache, - int initiator_process_id); + int initiator_process_id, + bool was_opener_suppressed); // Checks if the response requests an isolated origin (using either origin // policy or the Origin-Isolation header), and if so opts in the origin to be @@ -1462,6 +1463,11 @@ // only valid in conjunction with it. int initiator_process_id_ = ChildProcessHost::kInvalidUniqueID; + // Whether a navigation in a new window had the opener suppressed. False if + // the navigation is not in a new window. Can only be true for renderer + // initiated navigations which use `CreateBrowserInitiated()`. + bool was_opener_suppressed_; + // This tracks a connection between the current pending entry and this // request, such that the pending entry can be discarded if no requests are // left referencing it. @@ -1523,8 +1529,11 @@ // net::ERR_BLOCKED_BY_CLIENT. bool silently_ignore_blocked_by_client_ = false; - // Whether the new document will be loaded from an MHTML archive. - bool is_loaded_from_mhtml_archive_ = false; + // Whether the navigation loads an MHTML document or a subframe of an MHTML + // document. The navigation might or might not be fullfilled from the MHTML + // archive (see `is_mhtml_subframe_loaded_from_achive` in the NeedsUrlLoader + // method). + bool is_mhtml_or_subframe_ = false; // Observers listening to cookie access notifications for the network requests // made by this navigation.
diff --git a/content/browser/renderer_host/navigation_request_unittest.cc b/content/browser/renderer_host/navigation_request_unittest.cc index ae69926..07616a2 100644 --- a/content/browser/renderer_host/navigation_request_unittest.cc +++ b/content/browser/renderer_host/navigation_request_unittest.cc
@@ -200,7 +200,7 @@ request_ = NavigationRequest::CreateBrowserInitiated( main_test_rfh()->frame_tree_node(), std::move(common_params), std::move(commit_params), false /* browser-initiated */, - nullptr /* initiator_frame_token */, + false /* was_opener_suppressed */, nullptr /* initiator_frame_token */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, std::string() /* extra_headers */, nullptr /* frame_entry */, nullptr /* entry */, nullptr /* post_body */,
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 6c0bb3d6..ebbc97d 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6239,28 +6239,28 @@ bool is_same_document = NavigationTypeUtils::IsSameDocument(common_params->navigation_type); - bool is_mhtml_iframe = navigation_request->IsForMhtmlSubframe(); + bool is_mhtml_subframe = navigation_request->IsForMhtmlSubframe(); // A |response| and a |url_loader_client_endpoints| must always be provided, // except for edge cases, where another way to load the document exist. DCHECK((response_head && url_loader_client_endpoints) || common_params->url.SchemeIs(url::kDataScheme) || is_same_document || - !IsURLHandledByNetworkStack(common_params->url) || is_mhtml_iframe); + !IsURLHandledByNetworkStack(common_params->url) || is_mhtml_subframe); // All children of MHTML documents must be MHTML documents. // As a defensive measure, crash the browser if something went wrong. if (!frame_tree_node()->IsMainFrame()) { RenderFrameHostImpl* root = GetMainFrame(); - if (root->is_mhtml_document_ && - !common_params->url.SchemeIs(url::kDataScheme)) { + if (root->is_mhtml_document_) { bool loaded_from_outside_the_archive = response_head || url_loader_client_endpoints; - CHECK(!loaded_from_outside_the_archive); - CHECK(is_mhtml_iframe); + CHECK(!loaded_from_outside_the_archive || + common_params->url.SchemeIs(url::kDataScheme)); + CHECK(navigation_request->IsForMhtmlSubframe()); CHECK_EQ(GetSiteInstance(), root->GetSiteInstance()); CHECK_EQ(GetProcess(), root->GetProcess()); } else { - DCHECK(!is_mhtml_iframe); + DCHECK(!navigation_request->IsForMhtmlSubframe()); } } @@ -6288,7 +6288,7 @@ common_params->url.IsStandard() && !policy->CanAccessDataForOrigin(GetProcess()->GetID(), common_params->url) && - !is_mhtml_iframe) { + !is_mhtml_subframe) { base::debug::SetCrashKeyString( base::debug::AllocateCrashKeyString("lock_url", base::debug::CrashKeySize::Size64), @@ -8913,7 +8913,7 @@ // documents. Do not trust renderer data when determining that, rather use // the |navigation_request|, which was generated and stays browser side. is_mhtml_document_ = navigation_request->IsWaitingToCommit() && - navigation_request->IsLoadedFromMhtmlArchive(); + navigation_request->IsMhtmlOrSubframe(); is_overriding_user_agent_ = navigation_request->IsOverridingUserAgent() && frame_tree_node_->IsMainFrame();
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc index bbbae29..df5bc69 100644 --- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc +++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -414,7 +414,7 @@ std::unique_ptr<NavigationRequest> navigation_request = NavigationRequest::CreateBrowserInitiated( frame_tree_node, std::move(common_params), std::move(commit_params), - !entry->is_renderer_initiated(), + !entry->is_renderer_initiated(), false /* was_opener_suppressed */, nullptr /* initiator_frame_token */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, entry->extra_headers(), frame_entry, entry, request_body, @@ -2854,7 +2854,8 @@ std::unique_ptr<NavigationRequest> navigation_request = NavigationRequest::CreateBrowserInitiated( frame_tree_node, std::move(common_params), std::move(commit_params), - !entry.is_renderer_initiated(), nullptr /* initiator_frame_token */, + !entry.is_renderer_initiated(), false /* was_opener_suppressed */, + nullptr /* initiator_frame_token */, ChildProcessHost::kInvalidUniqueID /* initiator_process_id */, entry.extra_headers(), frame_entry, &entry, nullptr /* request_body */, nullptr /* navigation_ui_data */,
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc index dd4b004..9d562c24 100644 --- a/content/browser/renderer_host/render_frame_proxy_host.cc +++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -373,11 +373,11 @@ touch_action); } -void RenderFrameProxyHost::UpdateRenderThrottlingStatus( - bool is_throttled, - bool subtree_throttled) { +void RenderFrameProxyHost::UpdateRenderThrottlingStatus(bool is_throttled, + bool subtree_throttled, + bool display_locked) { cross_process_frame_connector_->UpdateRenderThrottlingStatus( - is_throttled, subtree_throttled); + is_throttled, subtree_throttled, display_locked); } void RenderFrameProxyHost::VisibilityChanged(
diff --git a/content/browser/renderer_host/render_frame_proxy_host.h b/content/browser/renderer_host/render_frame_proxy_host.h index 5e215e4..eab125ad 100644 --- a/content/browser/renderer_host/render_frame_proxy_host.h +++ b/content/browser/renderer_host/render_frame_proxy_host.h
@@ -162,7 +162,8 @@ // blink::mojom::RemoteFrameHost void SetInheritedEffectiveTouchAction(cc::TouchAction touch_action) override; void UpdateRenderThrottlingStatus(bool is_throttled, - bool subtree_throttled) override; + bool subtree_throttled, + bool display_locked) override; void VisibilityChanged(blink::mojom::FrameVisibility visibility) override; void DidFocusFrame() override; void CheckCompleted() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 272f475..5e2fa4b 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1227,10 +1227,12 @@ event, GetSelectionRect(*touch_selection_controller_)); } -void RenderWidgetHostViewAndroid::OnDragUpdate(const gfx::PointF& position) { +void RenderWidgetHostViewAndroid::OnDragUpdate( + const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) { if (!selection_popup_controller_) return; - selection_popup_controller_->OnDragUpdate(position); + selection_popup_controller_->OnDragUpdate(type, position); } ui::TouchSelectionControllerClient* @@ -2458,6 +2460,7 @@ // 0x0. if (rect.width() != 0.f || rect.height() != 0.f) { selection_popup_controller_->OnDragUpdate( + ui::TouchSelectionDraggable::Type::kNone, gfx::PointF(event.PositionInWidget().x(), rect.right_center().y())); } break;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 9e11697..bd3a6ac 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -219,7 +219,8 @@ void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; void OnSelectionEvent(ui::SelectionEventType event) override; - void OnDragUpdate(const gfx::PointF& position) override; + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override; std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; void DidScroll() override; void ShowTouchSelectionContextMenu(const gfx::Point& location) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index bbb381a6..ce37e22 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -463,8 +463,8 @@ // Do not send throttling status to main frames. if (host() && frame_connector_ && !host()->owner_delegate()) { host_->GetAssociatedFrameWidget()->UpdateRenderThrottlingStatusForSubFrame( - frame_connector_->IsThrottled(), - frame_connector_->IsSubtreeThrottled()); + frame_connector_->IsThrottled(), frame_connector_->IsSubtreeThrottled(), + frame_connector_->IsDisplayLocked()); } }
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index cc1ed9f..dd9d2660 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -11154,7 +11154,8 @@ void DidScroll() override {} - void OnDragUpdate(const gfx::PointF& position) override {} + void OnDragUpdate(const ui::TouchSelectionDraggable::Type type, + const gfx::PointF& position) override {} ui::SelectionEventType expected_event_; std::unique_ptr<base::RunLoop> run_loop_; @@ -13663,6 +13664,52 @@ filter->GetIntersectionState()->main_frame_intersection.IsEmpty()); } +IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, DisplayLockThrottlesOOPIF) { + GURL url_a(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + FrameTreeNode* a_frame = web_contents()->GetFrameTree()->root(); + FrameTreeNode* b_frame = a_frame->child_at(0); + + // Force a lifecycle update in both frames to get to steady state. + ASSERT_TRUE(EvalJsAfterLifecycleUpdate(a_frame->current_frame_host(), "", "") + .error.empty()); + ASSERT_TRUE(EvalJsAfterLifecycleUpdate(b_frame->current_frame_host(), "", "") + .error.empty()); + + // Display lock an ancestor of the <iframe> element in a_frame. The display + // lock status will be propagated to the OOPIF during lifecycle update. + ASSERT_TRUE(EvalJsAfterLifecycleUpdate( + a_frame->current_frame_host(), + "document.body.style = 'content-visibility: hidden'", "") + .error.empty()); + + // At this point, a_frame should have already sent an IPC to b_frame causing + // b_frame to become throttled. Create an IntersectionObserver and observe a + // visible element in b_frame. The display lock status should cause the + // visible element to be reported as "not intersecting". + static const char kObserverScript[] = R"( + new Promise((resolve, reject) => { + new IntersectionObserver((entries, observer) => { + observer.unobserve(entries[0].target); + resolve(String(entries[0].isIntersecting)) + }).observe(document.getElementById('siteNameHeading')) + }) + )"; + EvalJsResult result1 = EvalJs(b_frame->current_frame_host(), kObserverScript); + ASSERT_TRUE(result1.error.empty()); + EXPECT_EQ(result1.ExtractString(), "false"); + + // Unlock the element in a_frame, run through the same steps, and look for an + // "is intersecting" notification. + ASSERT_TRUE(EvalJsAfterLifecycleUpdate(a_frame->current_frame_host(), + "document.body.style = ''", "") + .error.empty()); + EvalJsResult result2 = EvalJs(b_frame->current_frame_host(), kObserverScript); + ASSERT_EQ(result2.error, ""); + EXPECT_EQ(result2.ExtractString(), "true"); +} + namespace { // Helper class to intercept DidCommitProvisionalLoad messages and inject a
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 9743e6c..4b0ce60 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -903,6 +903,9 @@ rwhv_root->OnScrollEvent(&scroll_event); ack_observer.Wait(); + // Wait until renderer's main thread is synced. + observer.Wait(); + // Verify the div scrolled. double div_scroll_top = div_scroll_top_start; EXPECT_TRUE(ExecuteScriptAndExtractDouble(
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index d28f626..92225b5 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -1303,7 +1303,8 @@ // The Conversion Measurement API is not available in Incognito mode. if (!is_in_memory_ && base::FeatureList::IsEnabled(features::kConversionMeasurement)) { - conversion_manager_ = std::make_unique<ConversionManagerImpl>(this, path); + conversion_manager_ = std::make_unique<ConversionManagerImpl>( + this, path, special_storage_policy_); } GeneratedCodeCacheSettings settings =
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 8056f3b..0488afe 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3660,6 +3660,7 @@ std::make_unique<NavigationController::LoadURLParams>( params.target_url); load_params->initiator_origin = opener->GetLastCommittedOrigin(); + load_params->initiator_frame_token = opener->GetFrameToken(); // Avoiding setting |load_params->source_site_instance| when // |opener_suppressed| is true, because in that case we do not want to use // the old SiteInstance and/or BrowsingInstance. See also the test here: @@ -3667,7 +3668,9 @@ load_params->referrer = params.referrer.To<Referrer>(); load_params->transition_type = ui::PAGE_TRANSITION_LINK; load_params->is_renderer_initiated = true; + load_params->was_opener_suppressed = true; load_params->has_user_gesture = has_user_gesture; + load_params->impression = params.impression; if (delegate_ && !is_guest && !delegate_->ShouldResumeRequestsForCreatedWindow()) {
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc index b77005280..2fab662 100644 --- a/content/browser/webui/web_ui_impl.cc +++ b/content/browser/webui/web_ui_impl.cc
@@ -128,8 +128,8 @@ return; frame_host_->GetFrameBindingsControl()->BindWebUI( - remote_.BindNewPipeAndPassReceiver(), - receiver_.BindNewPipeAndPassRemote()); + remote_.BindNewEndpointAndPassReceiver(), + receiver_.BindNewEndpointAndPassRemote()); } void WebUIImpl::InvalidateMojoConnection() {
diff --git a/content/browser/webui/web_ui_impl.h b/content/browser/webui/web_ui_impl.h index 2fcd9dc..d1336ce 100644 --- a/content/browser/webui/web_ui_impl.h +++ b/content/browser/webui/web_ui_impl.h
@@ -16,9 +16,8 @@ #include "base/memory/weak_ptr.h" #include "content/common/web_ui.mojom.h" #include "content/public/browser/web_ui.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" namespace content { class RenderFrameHost; @@ -94,7 +93,9 @@ std::vector<std::unique_ptr<WebUIMessageHandler>>* GetHandlersForTesting() override; - const mojo::Remote<mojom::WebUI>& GetRemoteForTest() const { return remote_; } + const mojo::AssociatedRemote<mojom::WebUI>& GetRemoteForTest() const { + return remote_; + } WebUIMainFrameObserver* GetWebUIMainFrameObserverForTest() const { return web_contents_observer_.get(); } @@ -139,8 +140,8 @@ std::unique_ptr<WebUIController> controller_; - mojo::Remote<mojom::WebUI> remote_; - mojo::Receiver<mojom::WebUIHost> receiver_{this}; + mojo::AssociatedRemote<mojom::WebUI> remote_; + mojo::AssociatedReceiver<mojom::WebUIHost> receiver_{this}; DISALLOW_COPY_AND_ASSIGN(WebUIImpl); };
diff --git a/content/browser/webui/web_ui_main_frame_observer.cc b/content/browser/webui/web_ui_main_frame_observer.cc index 3a50bba..aa698086 100644 --- a/content/browser/webui/web_ui_main_frame_observer.cc +++ b/content/browser/webui/web_ui_main_frame_observer.cc
@@ -19,6 +19,7 @@ #include "components/crash/content/browser/error_reporting/javascript_error_report.h" #include "components/crash/content/browser/error_reporting/js_error_report_processor.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_controller.h" #include "content/public/common/content_features.h" @@ -55,19 +56,19 @@ const base::string16& source_id, const base::Optional<base::string16>& untrusted_stack_trace) { // TODO(iby) Change all VLOGs to DVLOGs once tast tests are stable. - VLOG(3) << "OnDidAddMessageToConsole called for " << message; + DVLOG(3) << "OnDidAddMessageToConsole called for " << message; if (untrusted_stack_trace) { - VLOG(3) << "stack is " << *untrusted_stack_trace; + DVLOG(3) << "stack is " << *untrusted_stack_trace; } if (!error_reporting_enabled_) { - VLOG(3) << "Message not reported, error reporting disabled for this page " - "or experiment is off"; + DVLOG(3) << "Message not reported, error reporting disabled for this page " + "or experiment is off"; return; } if (log_level != blink::mojom::ConsoleMessageLevel::kError) { - VLOG(3) << "Message not reported, not an error"; + DVLOG(3) << "Message not reported, not an error"; return; } @@ -75,7 +76,7 @@ // WebUIMainFrameObservers will get a callback when either page gets an error. // To avoid duplicates, only report on errors from this page's frame. if (source_frame != web_ui_->frame_host()) { - VLOG(3) << "Message not reported, different frame"; + DVLOG(3) << "Message not reported, different frame"; return; } @@ -84,7 +85,7 @@ if (!processor) { // This usually means we are not on an official Google build, FYI. - VLOG(3) << "Message not reported, no processor"; + DVLOG(3) << "Message not reported, no processor"; return; } @@ -92,7 +93,7 @@ // TODO(https://crbug.com/1121816) Improve redaction. GURL url(source_id); if (!url.is_valid()) { - VLOG(3) << "Message not reported, invalid URL"; + DVLOG(3) << "Message not reported, invalid URL"; return; } @@ -102,7 +103,7 @@ // content because Chrome cannot control what information is being included in // the reports. if (!url.SchemeIs(kChromeUIScheme)) { - VLOG(3) << "Message not reported, not a chrome:// URL"; + DVLOG(3) << "Message not reported, not a chrome:// URL"; return; } @@ -124,19 +125,22 @@ report.send_to_production_servers = features::kWebUIJavaScriptErrorReportsSendToProductionParam.Get(); - VLOG(3) << "Error being sent to Google"; + DVLOG(3) << "Error being sent to Google"; processor->SendErrorReport(std::move(report), base::DoNothing(), web_contents()->GetBrowserContext()); } -void WebUIMainFrameObserver::RenderFrameCreated( - RenderFrameHost* render_frame_host) { +void WebUIMainFrameObserver::ReadyToCommitNavigation( + NavigationHandle* navigation_handle) { + DVLOG(3) << "WebUIMainFrameObserver::ReadyToCommitNavigation()"; if (!base::FeatureList::IsEnabled( features::kSendWebUIJavaScriptErrorReports)) { + DVLOG(3) << "Experiment is off"; return; } - if (render_frame_host != web_ui_->frame_host()) { + if (navigation_handle->GetRenderFrameHost() != web_ui_->frame_host()) { + DVLOG(3) << "Wrong frame"; return; } @@ -149,7 +153,10 @@ // frame is created, or it will lock up the communications channel. (See // https://crbug.com/1154866). if (error_reporting_enabled_) { + DVLOG(3) << "Enabled"; web_ui_->frame_host()->SetWantErrorMessageStackTrace(); + } else { + DVLOG(3) << "Error reporting disabled for this page"; } }
diff --git a/content/browser/webui/web_ui_main_frame_observer.h b/content/browser/webui/web_ui_main_frame_observer.h index 6d7d754..b66eccd3 100644 --- a/content/browser/webui/web_ui_main_frame_observer.h +++ b/content/browser/webui/web_ui_main_frame_observer.h
@@ -7,7 +7,6 @@ #include <stdint.h> -#include "base/gtest_prod_util.h" // FRIEND_TEST_ALL_PREFIXES #include "base/strings/string16.h" #include "build/build_config.h" #include "content/common/content_export.h" @@ -54,7 +53,7 @@ int32_t line_no, const base::string16& source_id, const base::Optional<base::string16>& untrusted_stack_trace) override; - void RenderFrameCreated(RenderFrameHost* render_frame_host) override; + void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override; #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) private:
diff --git a/content/browser/webui/web_ui_main_frame_observer_unittest.cc b/content/browser/webui/web_ui_main_frame_observer_unittest.cc index ad0b09d3..6678ef01 100644 --- a/content/browser/webui/web_ui_main_frame_observer_unittest.cc +++ b/content/browser/webui/web_ui_main_frame_observer_unittest.cc
@@ -17,6 +17,7 @@ #include "content/public/browser/web_ui_controller.h" #include "content/public/common/content_features.h" #include "content/public/test/browser_task_environment.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h" #include "content/test/test_web_contents.h" @@ -135,11 +136,12 @@ RenderViewHostTestHarness::TearDown(); } - // Simulate the remote renderer becoming alive. - void CreateRenderFrame() { - static_cast<TestWebContents*>(web_contents()) - ->GetRenderViewHost() - ->CreateRenderView(base::nullopt, 0, false); + // Simulate navigating to the WebUI page. Basically so that + // WebUIMainFrameObserver::ReadyToCommitNavigation() gets called, since that + // initializes the error handling. + void NavigateToPage() { + NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), + GURL(kSourceURL8)); } // Calls the observer's OnDidAddMessageToConsole with the given arguments. @@ -178,7 +180,7 @@ constexpr char WebUIMainFrameObserverTest::kStackTrace8[]; TEST_F(WebUIMainFrameObserverTest, ErrorReported) { - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, kMessage16, 5, kSourceId16, kStackTrace16); @@ -198,7 +200,7 @@ } TEST_F(WebUIMainFrameObserverTest, NoStackTrace) { - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, kMessage16, 5, kSourceId16, base::nullopt); @@ -208,7 +210,7 @@ } TEST_F(WebUIMainFrameObserverTest, NonErrorsIgnored) { - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kWarning, kMessage16, 5, kSourceId16, kStackTrace16); @@ -223,7 +225,7 @@ } TEST_F(WebUIMainFrameObserverTest, NoProcessorDoesntCrash) { - CreateRenderFrame(); + NavigateToPage(); FakeJsErrorReportProcessor::SetDefault(nullptr); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, @@ -235,7 +237,7 @@ scoped_feature_list_.Reset(); scoped_feature_list_.InitAndDisableFeature( features::kSendWebUIJavaScriptErrorReports); - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, kMessage16, 5, kSourceId16, kStackTrace16); @@ -244,7 +246,7 @@ } TEST_F(WebUIMainFrameObserverTest, NotSentIfInvalidURL) { - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole( web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, kMessage16, 5, base::UTF8ToUTF16("invalid URL"), kStackTrace16); @@ -255,7 +257,7 @@ TEST_F(WebUIMainFrameObserverTest, NotSentIfDisabledForPage) { static_cast<MockWebUIController*>(web_ui_->GetController()) ->enable_javascript_error_reporting(false); - CreateRenderFrame(); + NavigateToPage(); CallOnDidAddMessageToConsole(web_ui_->frame_host(), blink::mojom::ConsoleMessageLevel::kError, kMessage16, 5, kSourceId16, kStackTrace16); @@ -264,7 +266,7 @@ } TEST_F(WebUIMainFrameObserverTest, URLPathIsPreservedOtherPartsRemoved) { - CreateRenderFrame(); + NavigateToPage(); struct URLTest { const char* const input; const char* const expected; @@ -307,7 +309,7 @@ } TEST_F(WebUIMainFrameObserverTest, ErrorsNotReportedInOtherFrames) { - CreateRenderFrame(); + NavigateToPage(); auto another_contents = TestWebContents::Create(browser_context(), site_instance_); CHECK(another_contents->GetMainFrame()); @@ -319,7 +321,7 @@ } TEST_F(WebUIMainFrameObserverTest, ErrorsNotReportedForNonChromeURLs) { - CreateRenderFrame(); + NavigateToPage(); const char* const kNonChromeSourceURLs[] = { "chrome-untrusted://media-app", "chrome-error://chromewebdata/",
diff --git a/content/browser/xr/service/browser_xr_runtime_impl.cc b/content/browser/xr/service/browser_xr_runtime_impl.cc index cb0d692..680398d 100644 --- a/content/browser/xr/service/browser_xr_runtime_impl.cc +++ b/content/browser/xr/service/browser_xr_runtime_impl.cc
@@ -156,6 +156,7 @@ device::mojom::XRSessionFeature::REF_SPACE_LOCAL_FLOOR, device::mojom::XRSessionFeature::REF_SPACE_BOUNDED_FLOOR, device::mojom::XRSessionFeature::REF_SPACE_UNBOUNDED, + device::mojom::XRSessionFeature::ANCHORS, }; #endif } // anonymous namespace
diff --git a/content/common/frame.mojom b/content/common/frame.mojom index 68fcf36..559d2ee 100644 --- a/content/common/frame.mojom +++ b/content/common/frame.mojom
@@ -233,8 +233,8 @@ EnableMojoJsBindings(); // Used to bind WebUI and WebUIHost mojo connections. - BindWebUI(pending_receiver<content.mojom.WebUI> receiver, - pending_remote<content.mojom.WebUIHost> remote); + BindWebUI(pending_associated_receiver<content.mojom.WebUI> receiver, + pending_associated_remote<content.mojom.WebUIHost> remote); }; // Implemented by a service that provides implementations of the Frame @@ -280,6 +280,10 @@ // The window features to use for the new window. blink.mojom.WindowFeatures features; + + // The impression associated with the navigation in the new window, if + // one is specified. + Impression? impression; }; // Operation result when the renderer asks the browser to create a new window.
diff --git a/content/public/android/java/src/org/chromium/content/app/ZygotePreload.java b/content/public/android/java/src/org/chromium/content/app/ZygotePreload.java index 114725a..3a27008 100644 --- a/content/public/android/java/src/org/chromium/content/app/ZygotePreload.java +++ b/content/public/android/java/src/org/chromium/content/app/ZygotePreload.java
@@ -8,10 +8,13 @@ import android.annotation.TargetApi; import android.content.pm.ApplicationInfo; import android.os.Build; +import android.os.Process; +import android.os.SystemClock; import org.chromium.base.JNIUtils; import org.chromium.base.Log; import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.process_launcher.ChildProcessService; /** * Class used in android:zygotePreloadName attribute of manifest. @@ -28,6 +31,12 @@ @Override public void doPreload(ApplicationInfo appInfo) { try { + // The current thread time is the best approximation we have of the zygote start time + // since Process.getStartUptimeMillis() is not reliable in the zygote process. This will + // be the total CPU time the current thread has been running, and is reset on fork so + // should give an accurate measurement of zygote process startup time. + ChildProcessService.setZygoteInfo( + Process.myPid(), SystemClock.currentThreadTimeMillis()); JNIUtils.enableSelectiveJniRegistration(); LibraryLoader.getInstance().loadNowInZygote(appInfo); } catch (Throwable e) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java index 94eb9f4f..eeafef5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -38,6 +38,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import org.chromium.base.BuildInfo; import org.chromium.base.Log; import org.chromium.base.PackageManagerUtils; import org.chromium.base.UserData; @@ -68,6 +69,7 @@ import org.chromium.ui.base.ViewAndroidDelegate.ContainerViewObserver; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.touch_selection.SelectionEventType; +import org.chromium.ui.touch_selection.TouchSelectionDraggableType; import java.util.List; @@ -1419,7 +1421,12 @@ @VisibleForTesting @CalledByNative - /* package */ void onDragUpdate(float x, float y) { + /* package */ void onDragUpdate(@TouchSelectionDraggableType int type, float x, float y) { + // If this is for longpress drag selector, we can only have mangifier on S and above. + if (type == TouchSelectionDraggableType.LONGPRESS && !BuildInfo.isAtLeastS()) { + return; + } + if (mHandleObserver != null) { final float deviceScale = getDeviceScaleFactor(); x *= deviceScale;
diff --git a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java index c9b9309..26ebc23 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
@@ -59,6 +59,7 @@ import org.chromium.ui.base.ViewAndroidDelegate; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.touch_selection.SelectionEventType; +import org.chromium.ui.touch_selection.TouchSelectionDraggableType; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -493,11 +494,11 @@ mController.onSelectionEvent(SelectionEventType.SELECTION_HANDLES_SHOWN, 0, 0, 1, 1); // Selection handles drag started. - mController.onDragUpdate(0.f, 0.f); + mController.onDragUpdate(TouchSelectionDraggableType.TOUCH_HANDLE, 0.f, 0.f); order.verify(handleObserver).handleDragStartedOrMoved(0.f, 0.f); // Moving. - mController.onDragUpdate(5.f, 5.f); + mController.onDragUpdate(TouchSelectionDraggableType.TOUCH_HANDLE, 5.f, 5.f); order.verify(handleObserver).handleDragStartedOrMoved(5.f, 5.f); // Selection handle drag stopped. @@ -517,11 +518,11 @@ mController.onSelectionEvent(SelectionEventType.INSERTION_HANDLE_SHOWN, 0, 0, 1, 1); // Insertion handle drag started. - mController.onDragUpdate(0.f, 0.f); + mController.onDragUpdate(TouchSelectionDraggableType.TOUCH_HANDLE, 0.f, 0.f); order.verify(handleObserver).handleDragStartedOrMoved(0.f, 0.f); // Moving. - mController.onDragUpdate(5.f, 5.f); + mController.onDragUpdate(TouchSelectionDraggableType.TOUCH_HANDLE, 5.f, 5.f); order.verify(handleObserver).handleDragStartedOrMoved(5.f, 5.f); // Insertion handle drag stopped.
diff --git a/content/public/browser/child_process_security_policy.h b/content/public/browser/child_process_security_policy.h index 650a8d9..d73f2e2 100644 --- a/content/public/browser/child_process_security_policy.h +++ b/content/public/browser/child_process_security_policy.h
@@ -328,6 +328,11 @@ base::Optional<IsolatedOriginSource> source = base::nullopt, BrowserContext* browser_context = nullptr) = 0; + // Returns whether the site of |origin| is isolated and was added by the + // |source| to be isolated. + virtual bool IsIsolatedSiteFromSource(const url::Origin& origin, + IsolatedOriginSource source) = 0; + // Clears all isolated origins. This is unsafe to use outside of testing. virtual void ClearIsolatedOriginsForTesting() = 0; };
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h index 6017ae6..e744c444 100644 --- a/content/public/browser/navigation_controller.h +++ b/content/public/browser/navigation_controller.h
@@ -183,6 +183,11 @@ // important for tracking whether to display pending URLs. bool is_renderer_initiated; + // Whether a navigation in a new window has the opener suppressed. False if + // the navigation is not in a new window. Can only be true when + // |is_renderer_initiated| is true. + bool was_opener_suppressed; + // User agent override for this load. See comments in // UserAgentOverrideOption definition. UserAgentOverrideOption override_user_agent = UA_OVERRIDE_INHERIT;
diff --git a/content/public/test/fake_frame_widget.h b/content/public/test/fake_frame_widget.h index f751641..13e4cad 100644 --- a/content/public/test/fake_frame_widget.h +++ b/content/public/test/fake_frame_widget.h
@@ -63,9 +63,9 @@ void SetActive(bool active) override; void SetInheritedEffectiveTouchActionForSubFrame( const cc::TouchAction touch_action) override {} - void UpdateRenderThrottlingStatusForSubFrame( - bool is_throttled, - bool subtree_throttled) override {} + void UpdateRenderThrottlingStatusForSubFrame(bool is_throttled, + bool subtree_throttled, + bool display_locked) override {} void SetIsInertForSubFrame(bool inert) override {} #if defined(OS_MAC) void GetStringAtPoint(const gfx::Point& point_in_local_root,
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc index 3af525c..f65e230 100644 --- a/content/renderer/accessibility/render_accessibility_impl.cc +++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -334,12 +334,9 @@ // If there are any events in flight, |HandleAXEvent| will refuse to process // our new event. - pending_events_.clear(); - auto root_object = WebAXObject::FromWebDocument(document, false); - ax::mojom::Event event = root_object.IsLoaded() - ? ax::mojom::Event::kLoadComplete - : ax::mojom::Event::kLayoutComplete; - HandleAXEvent(ui::AXEvent(root_object.AxID(), event)); + needs_initial_ax_tree_root_ = true; + event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately; + ScheduleSendPendingAccessibilityEvents(); } } @@ -543,11 +540,11 @@ if (!document.IsNull()) { // Tree-only mode gets used by the automation extension API which requires a // load complete event to invoke listener callbacks. - auto root_object = WebAXObject::FromWebDocument(document, false); - ax::mojom::Event event = root_object.IsLoaded() - ? ax::mojom::Event::kLoadComplete - : ax::mojom::Event::kLayoutComplete; - HandleAXEvent(ui::AXEvent(root_object.AxID(), event)); + // SendPendingAccessibilityEvents() will fire the load complete event + // if the page is loaded. + needs_initial_ax_tree_root_ = true; + event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately; + ScheduleSendPendingAccessibilityEvents(); } } @@ -864,10 +861,18 @@ // complete for the entire document, in order to initialize the browser's // cached accessibility tree. needs_initial_ax_tree_root_ = false; - auto obj = WebAXObject::FromWebDocument(document); + auto root_obj = WebAXObject::FromWebDocument(document); + // Always fire layout complete for a new root object. pending_events_.insert( pending_events_.begin(), - ui::AXEvent(obj.AxID(), ax::mojom::Event::kLayoutComplete)); + ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLayoutComplete)); + + // If loaded, insert load complete at the top. + if (root_obj.IsLoaded()) { + pending_events_.insert( + pending_events_.begin(), + ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLoadComplete)); + } } if (pending_events_.empty() && dirty_objects_.empty()) { @@ -901,8 +906,8 @@ // location changes. bool need_to_send_location_changes = false; - // If there's a load complete message, we need to change the event schedule - // mode. + // Keep track of load complete messages. When a load completes, it's a good + // time to inject a stylesheet for image annotation debugging. bool had_load_complete_messages = false; ScopedFreezeBlinkAXTreeSource freeze(tree_source_.get());
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc index ef740c64..763e04f 100644 --- a/content/renderer/loader/web_url_loader_impl.cc +++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -896,6 +896,11 @@ ? blink::WebString::FromUTF8(head.cache_storage_cache_name) : blink::WebString()); + blink::WebVector<blink::WebString> dns_aliases(head.dns_aliases.size()); + std::transform( + head.dns_aliases.begin(), head.dns_aliases.end(), dns_aliases.begin(), + [](const std::string& h) { return blink::WebString::FromASCII(h); }); + response->SetDnsAliases(dns_aliases); response->SetRemoteIPEndpoint(head.remote_endpoint); // This computation can only be done once SetUrlListViaServiceWorker() has // been called on |response|, so that ResponseUrl() returns the correct
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 5ee447f..8119819 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -2916,8 +2916,9 @@ enable_mojo_js_bindings_ = true; } -void RenderFrameImpl::BindWebUI(mojo::PendingReceiver<mojom::WebUI> receiver, - mojo::PendingRemote<mojom::WebUIHost> remote) { +void RenderFrameImpl::BindWebUI( + mojo::PendingAssociatedReceiver<mojom::WebUI> receiver, + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote) { DCHECK(enabled_bindings_ & BINDINGS_POLICY_WEB_UI); WebUIExtensionData::Create(this, std::move(receiver), std::move(remote)); }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index ade3e66..82e8465d5 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -450,8 +450,9 @@ // mojom::FrameBindingsControl implementation: void AllowBindings(int32_t enabled_bindings_flags) override; void EnableMojoJsBindings() override; - void BindWebUI(mojo::PendingReceiver<mojom::WebUI> Receiver, - mojo::PendingRemote<mojom::WebUIHost> remote) override; + void BindWebUI( + mojo::PendingAssociatedReceiver<mojom::WebUI> Receiver, + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote) override; // These mirror mojom::NavigationClient, called by NavigationClient. void CommitNavigation(
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index c53f732..35de7c7 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/location.h" +#include "base/optional.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" @@ -1077,7 +1078,8 @@ GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo", blink::kWebNavigationPolicyNewForegroundTab, network::mojom::WebSandboxFlags::kNone, - blink::AllocateSessionStorageNamespaceId(), consumed_user_gesture); + blink::AllocateSessionStorageNamespaceId(), consumed_user_gesture, + base::nullopt); auto popup_navigation_info = std::make_unique<blink::WebNavigationInfo>(); popup_navigation_info->url_request = std::move(popup_request); popup_navigation_info->frame_type =
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 95450cc..3128b21 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -22,6 +22,7 @@ #include "content/public/renderer/render_view_visitor.h" #include "content/public/renderer/window_features_converter.h" #include "content/renderer/agent_scheduling_group.h" +#include "content/renderer/impression_conversions.h" #include "content/renderer/render_frame_proxy.h" #include "content/renderer/render_thread_impl.h" #include "third_party/blink/public/common/features.h" @@ -345,7 +346,8 @@ WebNavigationPolicy policy, network::mojom::WebSandboxFlags sandbox_flags, const blink::SessionStorageNamespaceId& session_storage_namespace_id, - bool& consumed_user_gesture) { + bool& consumed_user_gesture, + const base::Optional<blink::WebImpression>& impression) { consumed_user_gesture = false; RenderFrameImpl* creator_frame = RenderFrameImpl::FromWebFrame(creator); mojom::CreateNewWindowParamsPtr params = mojom::CreateNewWindowParams::New(); @@ -380,6 +382,10 @@ } params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features); + if (impression) { + params->impression = ConvertWebImpressionToImpression(*impression); + } + // We preserve this information before sending the message since |params| is // moved on send. bool is_background_tab =
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 5ec763b..c860de18 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -170,7 +170,8 @@ blink::WebNavigationPolicy policy, network::mojom::WebSandboxFlags sandbox_flags, const blink::SessionStorageNamespaceId& session_storage_namespace_id, - bool& consumed_user_gesture) override; + bool& consumed_user_gesture, + const base::Optional<blink::WebImpression>& impression) override; blink::WebPagePopup* CreatePopup(blink::WebLocalFrame* creator) override; base::StringPiece GetSessionStorageNamespaceId() override; void PrintPage(blink::WebLocalFrame* frame) override;
diff --git a/content/renderer/web_ui_extension_data.cc b/content/renderer/web_ui_extension_data.cc index 0dccd54..5372e6a 100644 --- a/content/renderer/web_ui_extension_data.cc +++ b/content/renderer/web_ui_extension_data.cc
@@ -6,22 +6,23 @@ #include "content/common/frame_messages.h" #include "content/public/renderer/render_frame.h" -#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" namespace content { -void WebUIExtensionData::Create(RenderFrame* render_frame, - mojo::PendingReceiver<mojom::WebUI> receiver, - mojo::PendingRemote<mojom::WebUIHost> remote) { - mojo::MakeSelfOwnedReceiver( +void WebUIExtensionData::Create( + RenderFrame* render_frame, + mojo::PendingAssociatedReceiver<mojom::WebUI> receiver, + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote) { + mojo::MakeSelfOwnedAssociatedReceiver( std::make_unique<WebUIExtensionData>(render_frame, std::move(remote)), std::move(receiver)); } WebUIExtensionData::WebUIExtensionData( RenderFrame* render_frame, - mojo::PendingRemote<mojom::WebUIHost> remote) + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote) : RenderFrameObserver(render_frame), RenderFrameObserverTracker<WebUIExtensionData>(render_frame), remote_(std::move(remote)) {}
diff --git a/content/renderer/web_ui_extension_data.h b/content/renderer/web_ui_extension_data.h index cf07d81..dce80fc31 100644 --- a/content/renderer/web_ui_extension_data.h +++ b/content/renderer/web_ui_extension_data.h
@@ -12,9 +12,9 @@ #include "content/common/web_ui.mojom.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer_tracker.h" -#include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_associated_remote.h" namespace content { @@ -24,10 +24,12 @@ public mojom::WebUI { public: static void Create(RenderFrame* render_frame, - mojo::PendingReceiver<mojom::WebUI> receiver, - mojo::PendingRemote<mojom::WebUIHost> remote); - explicit WebUIExtensionData(RenderFrame* render_frame, - mojo::PendingRemote<mojom::WebUIHost> remote); + mojo::PendingAssociatedReceiver<mojom::WebUI> receiver, + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote); + // TODO(dcheng): Why is this ctor public? + explicit WebUIExtensionData( + RenderFrame* render_frame, + mojo::PendingAssociatedRemote<mojom::WebUIHost> remote); ~WebUIExtensionData() override; // Returns value for a given |key|. Will return an empty string if no such key @@ -46,7 +48,7 @@ std::map<std::string, std::string> variable_map_; - mojo::Remote<mojom::WebUIHost> remote_; + mojo::AssociatedRemote<mojom::WebUIHost> remote_; DISALLOW_IMPLICIT_CONSTRUCTORS(WebUIExtensionData); };
diff --git a/content/services/isolated_xr_device/xr_device_service.cc b/content/services/isolated_xr_device/xr_device_service.cc index 5309b1e..8d160c8 100644 --- a/content/services/isolated_xr_device/xr_device_service.cc +++ b/content/services/isolated_xr_device/xr_device_service.cc
@@ -30,11 +30,10 @@ void XrDeviceService::BindRuntimeProvider( mojo::PendingReceiver<mojom::IsolatedXRRuntimeProvider> receiver, mojo::PendingRemote<mojom::XRDeviceServiceHost> device_service_host) { - mojo::MakeSelfOwnedReceiver(std::make_unique<IsolatedXRRuntimeProvider>( - mojo::Remote<mojom::XRDeviceServiceHost>( - std::move(device_service_host)), - io_task_runner_), - std::move(receiver)); + mojo::MakeSelfOwnedReceiver( + std::make_unique<IsolatedXRRuntimeProvider>( + std::move(device_service_host), io_task_runner_), + std::move(receiver)); } void XrDeviceService::BindTestHook(
diff --git a/content/services/isolated_xr_device/xr_runtime_provider.cc b/content/services/isolated_xr_device/xr_runtime_provider.cc index b651166..d5b0153 100644 --- a/content/services/isolated_xr_device/xr_runtime_provider.cc +++ b/content/services/isolated_xr_device/xr_runtime_provider.cc
@@ -207,7 +207,7 @@ #endif // BUILDFLAG(ENABLE_OPENXR) IsolatedXRRuntimeProvider::IsolatedXRRuntimeProvider( - mojo::Remote<device::mojom::XRDeviceServiceHost> device_service_host, + mojo::PendingRemote<device::mojom::XRDeviceServiceHost> device_service_host, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) : device_service_host_(std::move(device_service_host)), io_task_runner_(std::move(io_task_runner)) {}
diff --git a/content/services/isolated_xr_device/xr_runtime_provider.h b/content/services/isolated_xr_device/xr_runtime_provider.h index e58765a..3810e07 100644 --- a/content/services/isolated_xr_device/xr_runtime_provider.h +++ b/content/services/isolated_xr_device/xr_runtime_provider.h
@@ -31,7 +31,8 @@ : public device::mojom::IsolatedXRRuntimeProvider { public: explicit IsolatedXRRuntimeProvider( - mojo::Remote<device::mojom::XRDeviceServiceHost> device_service_host, + mojo::PendingRemote<device::mojom::XRDeviceServiceHost> + device_service_host, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); ~IsolatedXRRuntimeProvider() final;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 8b831b6..c2efa9d1 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -407,6 +407,7 @@ "//content/public/browser:proto", "//content/public/child", "//content/public/common", + "//content/public/common:trust_tokens_mojo_bindings", "//content/public/renderer", "//content/public/utility", "//content/renderer:for_content_tests",
diff --git a/content/test/data/accessibility/html/simple_spans.html b/content/test/data/accessibility/html/simple_spans.html new file mode 100644 index 0000000..8d3459d --- /dev/null +++ b/content/test/data/accessibility/html/simple_spans.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> + +<body> + <span id="s1">Some text</span> + <span id="s2">3.14159</span> +</body> + +</html> \ No newline at end of file
diff --git a/content/test/data/conversions/register_impression.js b/content/test/data/conversions/register_impression.js index 70eba0f..c7d7d212 100644 --- a/content/test/data/conversions/register_impression.js +++ b/content/test/data/conversions/register_impression.js
@@ -46,9 +46,6 @@ function createImpressionTagWithTarget(id, url, data, destination, target) { let anchor = document.createElement("a"); anchor.href = url; - if (target === "_blank") { - anchor.rel = "opener"; - } anchor.setAttribute("impressiondata", data); anchor.setAttribute("conversiondestination", destination); anchor.setAttribute("target", target);
diff --git a/content/test/data/simple_links.html b/content/test/data/simple_links.html index 4cbfd6f9..381ed5e 100644 --- a/content/test/data/simple_links.html +++ b/content/test/data/simple_links.html
@@ -17,6 +17,9 @@ link = document.getElementById("cross_site_new_window_link"); link.setAttribute("href", "http://foo.com:" + portNumber + "/title2.html"); + + link = document.getElementById("cross_site_new_window_no_opener_link"); + link.setAttribute("href", "http://foo.com:" + portNumber + "/title2.html"); return true; } @@ -36,6 +39,10 @@ return simulateClick(document.getElementById("cross_site_new_window_link")); } + function clickCrossSiteNewWindowNoOpenerLink() { + return simulateClick(document.getElementById("cross_site_new_window_no_opener_link")); + } + function clickViewSourceLink() { return simulateClick(document.getElementById("view_source_link")); } @@ -55,6 +62,7 @@ <a href="view-source:about:blank" id="view_source_link">view-source:</a><br> <a href="title2.html" id="same_site_new_window_link" rel="opener" target="_blank">same-site new window</a> <a href="http://foo.com/title2.html" id="cross_site_new_window_link" rel="opener" target="_blank">cross-site new window</a> +<a href="http://foo.com/title2.html" id="cross_site_new_window_no_opener_link" rel="noopener" target="_blank">cross-site new window no opener</a> <a href="" id="linkToSelf" rel="opener" target="_blank">self new window</a> <script> document.getElementById("linkToSelf").href = window.location.toString();
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index 97ea658..b2ec123c 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -56,10 +56,6 @@ # results: [ Failure RetryOnFailure Skip ] # END TAG HEADER - # TODO(kbr): flakily timing out on this configuration. -crbug.com/648369 [ linux debug intel ] TraceTest_* [ RetryOnFailure ] -crbug.com/978516 [ win10 nvidia-0x1cb3 ] TraceTest_* [ RetryOnFailure ] - # Require page actions - which are only supported in pixel tests. crbug.com/1048892 TraceTest_OffscreenCanvasIBRCWebGLMain [ Skip ] crbug.com/1048892 TraceTest_OffscreenCanvasIBRCWebGLWorker [ Skip ] @@ -110,9 +106,7 @@ # TODO(crbug.com/1079393): Compress down to just "intel" instead of specific # GPUs once UHD 630 failures are fixed. -crbug.com/969117 [ win10 intel-0xa2e ] OverlayModeTraceTest_DirectComposition_Video_MP4_FourColors_Aspect_4x3 [ RetryOnFailure ] crbug.com/969117 [ win10 intel-0x5912 ] OverlayModeTraceTest_DirectComposition_Video_MP4_FourColors_Aspect_4x3 [ RetryOnFailure ] -crbug.com/969117 [ win10 intel-0xd26 ] OverlayModeTraceTest_DirectComposition_Video_MP4_FourColors_Aspect_4x3 [ RetryOnFailure ] crbug.com/978181 [ win10 nvidia ] OverlayModeTraceTest_DirectComposition_Underlay [ RetryOnFailure ] # Incorrectly reporting SCALING instead of DIRECT on Windows 10 UHD 630 GPUs. @@ -136,19 +130,8 @@ crbug.com/1136971 [ win10 intel-0x3e92 ] OverlayModeTraceTest_DirectComposition_Video_VP9_VP_SCALING [ Skip ] # Zero copy also needs scaling to work. -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Underlay [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Underlay_DXVA [ Failure ] crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Underlay_Fullsize [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4 [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4_DXVA [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4_FourColors_Aspect_4x3 [ Failure ] crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4_Fullsize [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4_NV12 [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_MP4_VP_SCALING [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_VP9 [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_VP9_DXVA [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_VP9_NV12 [ Failure ] -crbug.com/1079393 [ win10 intel-0x3e92 ] VideoPathTraceTest_DirectComposition_Video_VP9_VP_SCALING [ Failure ] # Using YUY2 instead of NV12 on Windows 10 HD 630 GPUs due to NV12 support # showing up as SOFTWARE which causes zero copy to fail.
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 26a133c..5b5948e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -665,8 +665,8 @@ crbug.com/angleproject/5223 [ mac passthrough ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ] # Mac Passthrough / AMD -crbug.com/anglerpoject/5224 [ mac passthrough amd ] conformance2/rendering/instanced-arrays.html [ Failure ] -crbug.com/anglerpoject/5225 [ mac passthrough amd ] conformance2/rendering/vertex-id.html [ Failure ] +crbug.com/angleproject/5224 [ mac passthrough amd ] conformance2/rendering/instanced-arrays.html [ Failure ] +crbug.com/angleproject/5225 [ mac passthrough amd ] conformance2/rendering/vertex-id.html [ Failure ] crbug.com/982294 [ mac passthrough amd ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_lines.html [ Failure ] crbug.com/982294 [ mac passthrough amd ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_points.html [ Failure ] crbug.com/982294 [ mac passthrough amd ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_triangles.html [ Failure ] @@ -681,31 +681,31 @@ # Mac Passthrough / Intel crbug.com/982294 [ mac passthrough intel ] conformance/textures/misc/gl-teximage.html [ Failure ] -crbug.com/anglerpoject/5222 [ mac passthrough intel ] conformance2/textures/misc/tex-unpack-params.html [ Failure ] +crbug.com/angleproject/5222 [ mac passthrough intel ] conformance2/textures/misc/tex-unpack-params.html [ Failure ] crbug.com/982294 [ mac passthrough intel ] deqp/functional/gles3/fbocolorbuffer/tex2d_00.html [ Failure ] crbug.com/982294 [ mac passthrough intel ] deqp/functional/gles3/fboinvalidate/format_00.html [ Failure ] crbug.com/982294 [ mac passthrough intel ] deqp/functional/gles3/fboinvalidate/format_02.html [ Failure ] crbug.com/982294 [ mac passthrough intel ] deqp/functional/gles3/framebufferblit/default_framebuffer_05.html [ Failure ] -crbug.com/anglerpoject/5226 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/basic_copyteximage2d.html [ Failure ] -crbug.com/anglerpoject/5222 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/teximage3d_pbo_params.html [ Failure ] -crbug.com/anglerpoject/5222 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/texsubimage3d_pbo_params.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_lines.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_points.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_triangles.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_lines.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_points.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_triangles.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_centroid.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_flat.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_smooth.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/point_size.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/position.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_lines.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_points.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_triangles.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_lines.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ] -crbug.com/anglerpoject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_triangles.html [ Failure ] +crbug.com/angleproject/5226 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/basic_copyteximage2d.html [ Failure ] +crbug.com/angleproject/5222 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/teximage3d_pbo_params.html [ Failure ] +crbug.com/angleproject/5222 [ mac passthrough intel ] deqp/functional/gles3/texturespecification/texsubimage3d_pbo_params.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_lines.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_points.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_triangles.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_lines.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_points.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/basic_types_separate_triangles.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_centroid.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_flat.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/interpolation_smooth.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/point_size.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/position.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_lines.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_points.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_interleaved_triangles.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_lines.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ] +crbug.com/angleproject/5221 [ mac passthrough intel ] deqp/functional/gles3/transformfeedback/random_separate_triangles.html [ Failure ] crbug.com/1092734 [ mac passthrough intel ] conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_byte.html [ Failure ] crbug.com/1092734 [ mac passthrough intel ] conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ] crbug.com/1092734 [ mac passthrough intel ] conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations_unittest.py b/content/test/gpu/gpu_tests/test_expectations_unittest.py index 86d82d78..51caac2c 100644 --- a/content/test/gpu/gpu_tests/test_expectations_unittest.py +++ b/content/test/gpu/gpu_tests/test_expectations_unittest.py
@@ -7,6 +7,7 @@ import itertools import mock import os +import re import unittest from gpu_tests import gpu_helper @@ -57,6 +58,13 @@ ] GENERIC_CONDITIONS = OS_CONDITIONS + GPU_CONDITIONS +VALID_BUG_REGEXES = [ + re.compile(r'crbug\.com\/\d+'), + re.compile(r'crbug\.com\/angleproject\/\d+'), + re.compile(r'crbug\.com\/swiftshader\/\d+'), + re.compile(r'skbug\.com\/\d+'), +] + _map_specific_to_generic = {sos: 'win' for sos in WIN_CONDITIONS} _map_specific_to_generic.update({sos: 'mac' for sos in MAC_CONDITIONS}) _map_specific_to_generic.update({sos: 'android' for sos in ANDROID_CONDITIONS}) @@ -344,6 +352,22 @@ and test_case.ExpectationsFiles()): CheckTestExpectationsAreForExistingTests(self, test_case, options) + def testExpectationBugValidity(self): + expectation_dir = os.path.join(os.path.dirname(__file__), + 'test_expectations') + for expectation_file in os.listdir(expectation_dir): + with open(os.path.join(expectation_dir, expectation_file)) as f: + content = f.read() + list_parser = expectations_parser.TaggedTestListParser(content) + for expectation in list_parser.expectations: + reason = expectation.reason + if not reason: + continue + if not any(r.match(reason) for r in VALID_BUG_REGEXES): + self.fail('Bug string "%s" in expectation file %s is either not in a ' + 'recognized format or references an unknown project.' % + (reason, expectation_file)) + def testWebglTestExpectationsForDriverTags(self): webgl_conformance_test_class = ( webgl_conformance_integration_test.WebGLConformanceIntegrationTest)
diff --git a/content/test/gpu/unexpected_pass_finder.py b/content/test/gpu/unexpected_pass_finder.py index ee929249..ba55ad3 100755 --- a/content/test/gpu/unexpected_pass_finder.py +++ b/content/test/gpu/unexpected_pass_finder.py
@@ -195,10 +195,11 @@ for _, expectation_map in stale.iteritems(): stale_expectations.extend(expectation_map.keys()) stale_expectations.extend(unused_expectations) - expectations.RemoveExpectationsFromFile(stale_expectations, - args.expectation_file) + removed_urls = expectations.RemoveExpectationsFromFile( + stale_expectations, args.expectation_file) print('Stale expectations removed from %s. Stale comments, etc. may still ' 'need to be removed.' % args.expectation_file) + result_output.OutputRemovedUrls(removed_urls) if __name__ == '__main__':
diff --git a/content/test/gpu/unexpected_passes/expectations.py b/content/test/gpu/unexpected_passes/expectations.py index 684aa32..5297e23c 100644 --- a/content/test/gpu/unexpected_passes/expectations.py +++ b/content/test/gpu/unexpected_passes/expectations.py
@@ -201,6 +201,10 @@ expectations: A list of data_types.Expectations to remove. expectation_file: A filepath pointing to an expectation file to remove lines from. + + Returns: + A set of strings containing URLs of bugs associated with the removed + expectations. """ header = validate_tag_consistency.TAG_HEADER @@ -210,6 +214,7 @@ output_contents = '' in_disable_block = False disable_block_reason = '' + removed_urls = set() for line in input_contents.splitlines(True): # Auto-add any comments or empty lines stripped_line = line.strip() @@ -260,12 +265,18 @@ 'Would have removed expectation %s, but it has an inline disable ' 'comment with reason %s', stripped_line.split('#')[0], _GetDisableReasonFromComment(line)) + else: + reason = list_parser.expectations[0].reason + if reason: + removed_urls.add(reason) else: output_contents += line with open(expectation_file, 'w') as f: f.write(output_contents) + return removed_urls + def _GetDisableReasonFromComment(line): return line.split(FINDER_DISABLE_COMMENT, 1)[1].strip()
diff --git a/content/test/gpu/unexpected_passes/expectations_unittest.py b/content/test/gpu/unexpected_passes/expectations_unittest.py index f3a95633..b7ceaa4 100644 --- a/content/test/gpu/unexpected_passes/expectations_unittest.py +++ b/content/test/gpu/unexpected_passes/expectations_unittest.py
@@ -365,7 +365,9 @@ with open(self.filename, 'w') as f: f.write(contents) - expectations.RemoveExpectationsFromFile(stale_expectations, self.filename) + removed_urls = expectations.RemoveExpectationsFromFile( + stale_expectations, self.filename) + self.assertEqual(removed_urls, set(['crbug.com/1234'])) with open(self.filename) as f: self.assertEqual(f.read(), expected_contents) @@ -397,23 +399,25 @@ contents = validate_tag_consistency.TAG_HEADER + """ crbug.com/1234 [ win ] foo/test [ Failure ] # finder:disable -crbug.com/1234 [ win ] foo/test [ Failure ] -crbug.com/1234 [ win ] foo/test [ Failure ] +crbug.com/2345 [ win ] foo/test [ Failure ] +crbug.com/3456 [ win ] foo/test [ Failure ] # finder:enable -crbug.com/1234 [ win ] foo/test [ Failure ] +crbug.com/4567 [ win ] foo/test [ Failure ] """ stale_expectations = [ data_types.Expectation('foo/test', ['win'], ['Failure']) ] expected_contents = validate_tag_consistency.TAG_HEADER + """ # finder:disable -crbug.com/1234 [ win ] foo/test [ Failure ] -crbug.com/1234 [ win ] foo/test [ Failure ] +crbug.com/2345 [ win ] foo/test [ Failure ] +crbug.com/3456 [ win ] foo/test [ Failure ] # finder:enable """ with open(self.filename, 'w') as f: f.write(contents) - expectations.RemoveExpectationsFromFile(stale_expectations, self.filename) + removed_urls = expectations.RemoveExpectationsFromFile( + stale_expectations, self.filename) + self.assertEqual(removed_urls, set(['crbug.com/1234', 'crbug.com/4567'])) with open(self.filename) as f: self.assertEqual(f.read(), expected_contents) @@ -421,18 +425,20 @@ """Tests that expectations with inline disable comments are not removed.""" contents = validate_tag_consistency.TAG_HEADER + """ crbug.com/1234 [ win ] foo/test [ Failure ] -crbug.com/1234 [ win ] foo/test [ Failure ] # finder:disable -crbug.com/1234 [ win ] foo/test [ Failure ] +crbug.com/2345 [ win ] foo/test [ Failure ] # finder:disable +crbug.com/3456 [ win ] foo/test [ Failure ] """ stale_expectations = [ data_types.Expectation('foo/test', ['win'], ['Failure']) ] expected_contents = validate_tag_consistency.TAG_HEADER + """ -crbug.com/1234 [ win ] foo/test [ Failure ] # finder:disable +crbug.com/2345 [ win ] foo/test [ Failure ] # finder:disable """ with open(self.filename, 'w') as f: f.write(contents) - expectations.RemoveExpectationsFromFile(stale_expectations, self.filename) + removed_urls = expectations.RemoveExpectationsFromFile( + stale_expectations, self.filename) + self.assertEqual(removed_urls, set(['crbug.com/1234', 'crbug.com/3456'])) with open(self.filename) as f: self.assertEqual(f.read(), expected_contents)
diff --git a/content/test/gpu/unexpected_passes/result_output.py b/content/test/gpu/unexpected_passes/result_output.py index 28ea4b6e1..7c6e1f7 100644 --- a/content/test/gpu/unexpected_passes/result_output.py +++ b/content/test/gpu/unexpected_passes/result_output.py
@@ -6,6 +6,7 @@ Also probably a good example of how to *not* write HTML. """ +import collections import logging import sys import tempfile @@ -136,6 +137,9 @@ SECTION_UNUSED = ('Unused Expectations (Indicative Of The Configuration No ' 'Longer Being Tested Or Tags Changing)') +MAX_BUGS_PER_LINE = 5 +MAX_CHARACTERS_PER_CL_LINE = 72 + def OutputResults(stale_dict, semi_stale_dict, @@ -430,3 +434,81 @@ def _AddStatsToStr(s, stats): return '%s (%d/%d)' % (s, stats.passed_builds, stats.total_builds) + + +def OutputRemovedUrls(removed_urls): + """Outputs URLs of removed expectations for easier consumption by the user. + + Outputs both a string suitable for passing to Chrome via the command line to + open all bugs in the browser and a string suitable for copying into the CL + description to associate the CL with all the affected bugs. + + Args: + removed_urls: A set or list of strings containing bug URLs. + """ + removed_urls = list(removed_urls) + removed_urls.sort() + _OutputUrlsForCommandLine(removed_urls) + _OutputUrlsForClDescription(removed_urls) + + +def _OutputUrlsForCommandLine(urls, file_handle=None): + """Outputs |urls| for opening in a browser. + + The output string is meant to be passed to a browser via the command line in + order to open all URLs in that browser, e.g. + + `google-chrome https://crbug.com/1234 https://crbug.com/2345` + + Args: + urls: A list of strings containing URLs to output. + file_handle: A file handle to write the string to. Defaults to stdout. + """ + file_handle = file_handle or sys.stdout + + def _StartsWithHttp(url): + return url.startswith('https://') or url.startswith('http://') + + urls = [u if _StartsWithHttp(u) else 'https://%s' % u for u in urls] + file_handle.write('Affected bugs: %s\n' % ' '.join(urls)) + + +def _OutputUrlsForClDescription(urls, file_handle=None): + """Outputs |urls| for use in a CL description. + + Output adheres to the line length recommendation and max number of bugs per + line supported in Gerrit. + + Args: + urls: A list of strings containing URLs to output. + file_handle: A file handle to write the string to. Defaults to stdout. + """ + file_handle = file_handle or sys.stdout + urls = collections.deque(urls) + + output_str = '' + current_line = '' + bugs_on_line = 0 + while len(urls): + current_bug = urls.popleft() + current_bug = current_bug.split('crbug.com/', 1)[1] + # Handles cases like crbug.com/angleproject/1234. + current_bug = current_bug.replace('/', ':') + + # First bug on the line. + if not current_line: + current_line = 'Bug: %s' % current_bug + # Bug or length limit hit for line. + elif (len(current_line) + len(current_bug) + 2 > MAX_CHARACTERS_PER_CL_LINE + or bugs_on_line >= MAX_BUGS_PER_LINE): + output_str += current_line + '\n' + bugs_on_line = 0 + current_line = 'Bug: %s' % current_bug + # Can add to current line. + else: + current_line += ', %s' % current_bug + + bugs_on_line += 1 + + output_str += current_line + '\n' + file_handle.write('Affected bugs:\n%s' % output_str)
diff --git a/content/test/gpu/unexpected_passes/result_output_unittest.py b/content/test/gpu/unexpected_passes/result_output_unittest.py index 28b7ea61..c70409cc 100644 --- a/content/test/gpu/unexpected_passes/result_output_unittest.py +++ b/content/test/gpu/unexpected_passes/result_output_unittest.py
@@ -435,6 +435,117 @@ self._file_handle) +class OutputUrlsForCommandLineUnittest(fake_filesystem_unittest.TestCase): + def setUp(self): + self.setUpPyfakefs() + self._file_handle = tempfile.NamedTemporaryFile(delete=False) + self._filepath = self._file_handle.name + + def testOutput(self): + """Tests that the output is correct.""" + urls = [ + 'https://crbug.com/1234', + 'https://crbug.com/angleproject/1234', + 'http://crbug.com/2345', + 'crbug.com/3456', + ] + result_output._OutputUrlsForCommandLine(urls, self._file_handle) + self._file_handle.close() + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs: ' + 'https://crbug.com/1234 ' + 'https://crbug.com/angleproject/1234 ' + 'http://crbug.com/2345 ' + 'https://crbug.com/3456\n')) + + +class OutputUrlsForClDescriptionUnittest(fake_filesystem_unittest.TestCase): + def setUp(self): + self.setUpPyfakefs() + self._file_handle = tempfile.NamedTemporaryFile(delete=False) + self._filepath = self._file_handle.name + + def testSingleLine(self): + """Tests when all bugs can fit on a single line.""" + urls = [ + 'crbug.com/1234', + 'https://crbug.com/angleproject/2345', + ] + result_output._OutputUrlsForClDescription(urls, self._file_handle) + self._file_handle.close() + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs:\n' + 'Bug: 1234, angleproject:2345\n')) + + def testBugLimit(self): + """Tests that only a certain number of bugs are allowed per line.""" + urls = [ + 'crbug.com/1', + 'crbug.com/2', + 'crbug.com/3', + 'crbug.com/4', + 'crbug.com/5', + 'crbug.com/6', + ] + result_output._OutputUrlsForClDescription(urls, self._file_handle) + self._file_handle.close() + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs:\n' + 'Bug: 1, 2, 3, 4, 5\n' + 'Bug: 6\n')) + + def testLengthLimit(self): + """Tests that only a certain number of characters are allowed per line.""" + urls = [ + 'crbug.com/averylongprojectthatwillgooverthelinelength/1', + 'crbug.com/averylongprojectthatwillgooverthelinelength/2', + ] + result_output._OutputUrlsForClDescription(urls, self._file_handle) + self._file_handle.close() + with open(self._filepath) as f: + self.assertEqual(f.read(), + ('Affected bugs:\n' + 'Bug: averylongprojectthatwillgooverthelinelength:1\n' + 'Bug: averylongprojectthatwillgooverthelinelength:2\n')) + + project_name = (result_output.MAX_CHARACTERS_PER_CL_LINE - len('Bug: ') - + len(':1, 2')) * 'a' + urls = [ + 'crbug.com/%s/1' % project_name, + 'crbug.com/2', + ] + with open(self._filepath, 'w') as f: + result_output._OutputUrlsForClDescription(urls, f) + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs:\n' + 'Bug: %s:1, 2\n' % project_name)) + + project_name += 'a' + urls = [ + 'crbug.com/%s/1' % project_name, + 'crbug.com/2', + ] + with open(self._filepath, 'w') as f: + result_output._OutputUrlsForClDescription(urls, f) + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs:\n' + 'Bug: %s:1\nBug: 2\n' % project_name)) + + def testSingleBugOverLineLimit(self): + """Tests the behavior when a single bug by itself is over the line limit.""" + project_name = result_output.MAX_CHARACTERS_PER_CL_LINE * 'a' + urls = [ + 'crbug.com/%s/1' % project_name, + 'crbug.com/2', + ] + result_output._OutputUrlsForClDescription(urls, self._file_handle) + self._file_handle.close() + with open(self._filepath) as f: + self.assertEqual(f.read(), ('Affected bugs:\n' + 'Bug: %s:1\n' + 'Bug: 2\n' % project_name)) + + def _Dedent(s): output = '' for line in s.splitlines(True):
diff --git a/content/web_test/renderer/web_view_test_proxy.cc b/content/web_test/renderer/web_view_test_proxy.cc index 26e244ec..ace2e77 100644 --- a/content/web_test/renderer/web_view_test_proxy.cc +++ b/content/web_test/renderer/web_view_test_proxy.cc
@@ -43,7 +43,8 @@ blink::WebNavigationPolicy policy, network::mojom::WebSandboxFlags sandbox_flags, const blink::SessionStorageNamespaceId& session_storage_namespace_id, - bool& consumed_user_gesture) { + bool& consumed_user_gesture, + const base::Optional<blink::WebImpression>& impression) { if (test_runner_->ShouldDumpNavigationPolicy()) { test_runner_->PrintMessage( "Default policy for createView for '" + @@ -61,7 +62,7 @@ } return RenderViewImpl::CreateView( creator, request, features, frame_name, policy, sandbox_flags, - session_storage_namespace_id, consumed_user_gesture); + session_storage_namespace_id, consumed_user_gesture, impression); } void WebViewTestProxy::PrintPage(blink::WebLocalFrame* frame) {
diff --git a/content/web_test/renderer/web_view_test_proxy.h b/content/web_test/renderer/web_view_test_proxy.h index 2c694e04..96f0faa6c 100644 --- a/content/web_test/renderer/web_view_test_proxy.h +++ b/content/web_test/renderer/web_view_test_proxy.h
@@ -71,7 +71,8 @@ blink::WebNavigationPolicy policy, network::mojom::WebSandboxFlags sandbox_flags, const blink::SessionStorageNamespaceId& session_storage_namespace_id, - bool& consumed_user_gesture) override; + bool& consumed_user_gesture, + const base::Optional<blink::WebImpression>& impression) override; void PrintPage(blink::WebLocalFrame* frame) override; blink::WebString AcceptLanguages() override;
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.cc b/device/bluetooth/dbus/bluez_dbus_manager.cc index b8847dec..9144a1bf 100644 --- a/device/bluetooth/dbus/bluez_dbus_manager.cc +++ b/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -263,7 +263,7 @@ CreateGlobalInstance(system_bus, BluezDBusThreadManager::Get()->GetSystemBus(), false /* use_dbus_stubs */); -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) // BluetoothSystem, the client that needs the extra connection, is not // implemented on Linux, so no need for an extra Bus. CreateGlobalInstance(BluezDBusThreadManager::Get()->GetSystemBus(), nullptr,
diff --git a/device/fido/fido_discovery_factory.h b/device/fido/fido_discovery_factory.h index 2d0aa82..7d6c6887 100644 --- a/device/fido/fido_discovery_factory.h +++ b/device/fido/fido_discovery_factory.h
@@ -89,10 +89,10 @@ WinWebAuthnApi* win_webauthn_api() const; #endif // defined(OS_WIN) -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Records the callback to generates request_id. void set_generate_request_id_callback(base::RepeatingCallback<uint32_t()>); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) protected: static std::vector<std::unique_ptr<FidoDiscoveryBase>> SingleDiscovery( @@ -117,9 +117,9 @@ #if defined(OS_WIN) WinWebAuthnApi* win_webauthn_api_ = nullptr; #endif // defined(OS_WIN) -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) base::RepeatingCallback<uint32_t()> generate_request_id_callback_; -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) base::flat_set<VidPid> hid_ignore_list_; };
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index 12a68a4..6695c63a 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -145,6 +145,10 @@ sources += [ "openxr/context_provider_callbacks.h", + "openxr/openxr_anchor_manager.cc", + "openxr/openxr_anchor_manager.h", + "openxr/openxr_anchor_request.cc", + "openxr/openxr_anchor_request.h", "openxr/openxr_api_wrapper.cc", "openxr/openxr_api_wrapper.h", "openxr/openxr_controller.cc",
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni index 2867929..8a82546c 100644 --- a/device/vr/buildflags/buildflags.gni +++ b/device/vr/buildflags/buildflags.gni
@@ -4,6 +4,7 @@ import("//build/config/chrome_build.gni") import("//build/config/chromecast_build.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/gclient_args.gni") declare_args() { @@ -23,7 +24,7 @@ # the binary size impact is small and allows many VR tests to run on Linux enable_vr = enable_gvr_services || enable_openxr || (is_linux && (current_cpu == "x64" || current_cpu == "x86") && - !is_chromecast) + !is_chromeos_lacros && !is_chromecast) # Whether to include VR extras like test APKs in non-VR-specific targets include_vr_data = false
diff --git a/device/vr/openxr/openxr_anchor_manager.cc b/device/vr/openxr/openxr_anchor_manager.cc new file mode 100644 index 0000000..dd4ad4b --- /dev/null +++ b/device/vr/openxr/openxr_anchor_manager.cc
@@ -0,0 +1,128 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/vr/openxr/openxr_anchor_manager.h" +#include "device/vr/openxr/openxr_util.h" + +namespace device { + +namespace { +device::Pose XrPoseToDevicePose(const XrPosef& pose) { + gfx::Quaternion orientation{pose.orientation.x, pose.orientation.y, + pose.orientation.z, pose.orientation.w}; + gfx::Point3F position{pose.position.x, pose.position.y, pose.position.z}; + return device::Pose{position, orientation}; +} +} // namespace + +OpenXrAnchorManager::~OpenXrAnchorManager() { + for (const auto& it : openxr_anchors_) { + DestroyAnchorData(it.second); + } +} + +OpenXrAnchorManager::OpenXrAnchorManager( + const OpenXrExtensionHelper& extension_helper, + XrSession session, + XrSpace mojo_space) + : extension_helper_(extension_helper), + session_(session), + mojo_space_(mojo_space) {} + +AnchorId OpenXrAnchorManager::CreateAnchor(XrPosef pose, + XrSpace space, + XrTime predicted_display_time) { + XrSpatialAnchorMSFT xr_anchor; + XrSpatialAnchorCreateInfoMSFT anchor_create_info{ + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT}; + anchor_create_info.space = space; + anchor_create_info.pose = pose; + anchor_create_info.time = predicted_display_time; + + DCHECK(extension_helper_.ExtensionMethods().xrCreateSpatialAnchorMSFT != + nullptr); + DCHECK(extension_helper_.ExtensionMethods().xrCreateSpatialAnchorSpaceMSFT != + nullptr); + DCHECK(extension_helper_.ExtensionMethods().xrDestroySpatialAnchorMSFT != + nullptr); + + if (XR_FAILED(extension_helper_.ExtensionMethods().xrCreateSpatialAnchorMSFT( + session_, &anchor_create_info, &xr_anchor))) { + return kInvalidAnchorId; + } + + XrSpace anchor_space; + XrSpatialAnchorSpaceCreateInfoMSFT space_create_info{ + XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT}; + space_create_info.anchor = xr_anchor; + space_create_info.poseInAnchorSpace = PoseIdentity(); + if (FAILED( + extension_helper_.ExtensionMethods().xrCreateSpatialAnchorSpaceMSFT( + session_, &space_create_info, &anchor_space))) { + (void)extension_helper_.ExtensionMethods().xrDestroySpatialAnchorMSFT( + xr_anchor); + return kInvalidAnchorId; + } + + AnchorId anchor_id = anchor_id_generator_.GenerateNextId(); + openxr_anchors_.insert({anchor_id, AnchorData{xr_anchor, anchor_space}}); + return anchor_id; +} + +XrSpace OpenXrAnchorManager::GetAnchorSpace(AnchorId anchor_id) const { + auto it = openxr_anchors_.find(anchor_id); + if (it == openxr_anchors_.end()) { + return XR_NULL_HANDLE; + } + return it->second.space; +} + +void OpenXrAnchorManager::DestroyAnchorData(const AnchorData& anchor_data) { + (void)xrDestroySpace(anchor_data.space); + (void)extension_helper_.ExtensionMethods().xrDestroySpatialAnchorMSFT( + anchor_data.anchor); +} + +void OpenXrAnchorManager::DetachAnchor(AnchorId anchor_id) { + auto it = openxr_anchors_.find(anchor_id); + if (it == openxr_anchors_.end()) { + return; + } + + DestroyAnchorData(it->second); + openxr_anchors_.erase(it); +} + +mojom::XRAnchorsDataPtr OpenXrAnchorManager::GetCurrentAnchorsData( + XrTime predicted_display_time) const { + std::vector<uint64_t> all_anchors_ids(openxr_anchors_.size()); + std::vector<mojom::XRAnchorDataPtr> updated_anchors(openxr_anchors_.size()); + + uint32_t index = 0; + for (const auto& map_entry : openxr_anchors_) { + const AnchorId anchor_id = map_entry.first; + const XrSpace anchor_space = map_entry.second.space; + all_anchors_ids[index] = anchor_id.GetUnsafeValue(); + + XrSpaceLocation anchor_from_mojo = {XR_TYPE_SPACE_LOCATION}; + if (FAILED(xrLocateSpace(anchor_space, mojo_space_, predicted_display_time, + &anchor_from_mojo)) || + !(anchor_from_mojo.locationFlags & + XR_SPACE_LOCATION_POSITION_VALID_BIT) || + !(anchor_from_mojo.locationFlags & + XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) { + updated_anchors[index] = + mojom::XRAnchorData::New(anchor_id.GetUnsafeValue(), base::nullopt); + } else { + updated_anchors[index] = + mojom::XRAnchorData::New(anchor_id.GetUnsafeValue(), + XrPoseToDevicePose(anchor_from_mojo.pose)); + } + index++; + } + + return mojom::XRAnchorsData::New(std::move(all_anchors_ids), + std::move(updated_anchors)); +} +} // namespace device
diff --git a/device/vr/openxr/openxr_anchor_manager.h b/device/vr/openxr/openxr_anchor_manager.h new file mode 100644 index 0000000..c7aea18 --- /dev/null +++ b/device/vr/openxr/openxr_anchor_manager.h
@@ -0,0 +1,57 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_OPENXR_OPENXR_ANCHOR_MANAGER_H_ +#define DEVICE_VR_OPENXR_OPENXR_ANCHOR_MANAGER_H_ + +#include <map> + +#include "base/numerics/checked_math.h" +#include "base/numerics/math_constants.h" +#include "base/optional.h" +#include "device/vr/openxr/openxr_util.h" +#include "device/vr/public/mojom/vr_service.mojom.h" + +namespace device { + +class OpenXrAnchorManager { + public: + OpenXrAnchorManager(const OpenXrExtensionHelper& extension_helper, + XrSession session, + XrSpace mojo_space); + ~OpenXrAnchorManager(); + + AnchorId CreateAnchor(XrPosef pose, + XrSpace space, + XrTime predicted_display_time); + XrSpace GetAnchorSpace(AnchorId anchor_id) const; + void DetachAnchor(AnchorId anchor_id); + device::mojom::XRAnchorsDataPtr GetCurrentAnchorsData( + XrTime predicted_display_time) const; + + private: + const OpenXrExtensionHelper& extension_helper_; + XrSession session_; + XrSpace mojo_space_; // The intermediate space that mojom poses are + // represented in (currently defined as local space) + + // Each OpenXR anchor produces a space handle which tracks the location of the + // anchor. We create and cache this space here in order to avoid complex + // resource tracking. + struct AnchorData { + XrSpatialAnchorMSFT anchor; + XrSpace + space; // The XrSpace tracking this anchor relative to other XrSpaces + }; + + void DestroyAnchorData(const AnchorData& anchor_data); + + AnchorId::Generator anchor_id_generator_; // 0 is not a valid anchor ID + std::map<AnchorId, AnchorData> openxr_anchors_; + DISALLOW_COPY_AND_ASSIGN(OpenXrAnchorManager); +}; + +} // namespace device + +#endif // DEVICE_VR_OPENXR_OPENXR_ANCHOR_MANAGER_H_
diff --git a/device/vr/openxr/openxr_anchor_request.cc b/device/vr/openxr/openxr_anchor_request.cc new file mode 100644 index 0000000..74481cd --- /dev/null +++ b/device/vr/openxr/openxr_anchor_request.cc
@@ -0,0 +1,37 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/vr/openxr/openxr_anchor_request.h" + +namespace device { + +CreateAnchorRequest::CreateAnchorRequest( + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform native_origin_from_anchor, + CreateAnchorCallback callback) + : native_origin_information_(native_origin_information), + native_origin_from_anchor_(native_origin_from_anchor), + request_start_time_(base::TimeTicks::Now()), + callback_(std::move(callback)) {} +CreateAnchorRequest::CreateAnchorRequest(CreateAnchorRequest&& other) = default; +CreateAnchorRequest::~CreateAnchorRequest() = default; + +const mojom::XRNativeOriginInformation& +CreateAnchorRequest::GetNativeOriginInformation() const { + return native_origin_information_; +} + +const gfx::Transform& CreateAnchorRequest::GetNativeOriginFromAnchor() const { + return native_origin_from_anchor_; +} + +const base::TimeTicks& CreateAnchorRequest::GetRequestStartTime() const { + return request_start_time_; +} + +CreateAnchorCallback CreateAnchorRequest::TakeCallback() { + return std::move(callback_); +} + +} // namespace device
diff --git a/device/vr/openxr/openxr_anchor_request.h b/device/vr/openxr/openxr_anchor_request.h new file mode 100644 index 0000000..7ab61b48 --- /dev/null +++ b/device/vr/openxr/openxr_anchor_request.h
@@ -0,0 +1,44 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_OPENXR_OPENXR_ANCHOR_REQUEST_H_ +#define DEVICE_VR_OPENXR_OPENXR_ANCHOR_REQUEST_H_ + +#include "base/callback.h" +#include "base/time/time.h" +#include "device/vr/public/mojom/vr_service.mojom.h" +#include "ui/gfx/transform.h" + +namespace device { + +using CreateAnchorCallback = + base::OnceCallback<void(device::mojom::CreateAnchorResult, + uint64_t anchor_id)>; + +class CreateAnchorRequest { + public: + const mojom::XRNativeOriginInformation& GetNativeOriginInformation() const; + const gfx::Transform& GetNativeOriginFromAnchor() const; + const base::TimeTicks& GetRequestStartTime() const; + + CreateAnchorCallback TakeCallback(); + + CreateAnchorRequest( + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform native_origin_from_anchor, + CreateAnchorCallback callback); + CreateAnchorRequest(CreateAnchorRequest&& other); + ~CreateAnchorRequest(); + + private: + const mojom::XRNativeOriginInformation native_origin_information_; + const gfx::Transform native_origin_from_anchor_; + const base::TimeTicks request_start_time_; + + CreateAnchorCallback callback_; +}; + +} // namespace device + +#endif // DEVICE_VR_OPENXR_OPENXR_ANCHOR_REQUEST_H_
diff --git a/device/vr/openxr/openxr_api_wrapper.cc b/device/vr/openxr/openxr_api_wrapper.cc index ed6fa7f..56fdac4 100644 --- a/device/vr/openxr/openxr_api_wrapper.cc +++ b/device/vr/openxr/openxr_api_wrapper.cc
@@ -58,6 +58,7 @@ } void OpenXrApiWrapper::Reset() { + anchor_manager_.reset(); unbounded_space_ = XR_NULL_HANDLE; local_space_ = XR_NULL_HANDLE; stage_space_ = XR_NULL_HANDLE; @@ -254,6 +255,15 @@ return GetMojoBlendMode(blend_mode_); } +OpenXrAnchorManager* OpenXrApiWrapper::GetOrCreateAnchorManager( + const OpenXrExtensionHelper& extension_helper) { + if (session_ && !anchor_manager_) { + anchor_manager_ = std::make_unique<OpenXrAnchorManager>( + extension_helper, session_, local_space_); + } + return anchor_manager_.get(); +} + bool OpenXrApiWrapper::UpdateAndGetSessionEnded() { // Ensure we have the latest state from the OpenXR runtime. if (XR_FAILED(ProcessEvents())) { @@ -381,6 +391,23 @@ return XR_SUCCESS; } +XrSpace OpenXrApiWrapper::GetReferenceSpace( + device::mojom::XRReferenceSpaceType type) const { + switch (type) { + case device::mojom::XRReferenceSpaceType::kLocal: + return local_space_; + case device::mojom::XRReferenceSpaceType::kViewer: + return view_space_; + case device::mojom::XRReferenceSpaceType::kBoundedFloor: + return stage_space_; + case device::mojom::XRReferenceSpaceType::kUnbounded: + return unbounded_space_; + // Ignore local-floor as that has no direct space + case device::mojom::XRReferenceSpaceType::kLocalFloor: + return XR_NULL_HANDLE; + } +} + XrResult OpenXrApiWrapper::CreateSpace(XrReferenceSpaceType type, XrSpace* space) { DCHECK(HasSession());
diff --git a/device/vr/openxr/openxr_api_wrapper.h b/device/vr/openxr/openxr_api_wrapper.h index 60a94f91..3d56471 100644 --- a/device/vr/openxr/openxr_api_wrapper.h +++ b/device/vr/openxr/openxr_api_wrapper.h
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/optional.h" +#include "device/vr/openxr/openxr_anchor_manager.h" #include "device/vr/openxr/openxr_util.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/vr_export.h" @@ -50,9 +51,12 @@ std::unique_ptr<OpenXRInputHelper>* input_helper, const OpenXrExtensionHelper& extension_helper); + XrSpace GetReferenceSpace(device::mojom::XRReferenceSpaceType type) const; + XrResult BeginFrame(Microsoft::WRL::ComPtr<ID3D11Texture2D>* texture); XrResult EndFrame(); bool HasPendingFrame() const; + bool HasFrameState() const; XrResult GetHeadPose(base::Optional<gfx::Quaternion>* orientation, base::Optional<gfx::Point3F>* position, @@ -77,6 +81,9 @@ device::mojom::XREnvironmentBlendMode PickEnvironmentBlendModeForSession( device::mojom::XRSessionMode session_mode); + OpenXrAnchorManager* GetOrCreateAnchorManager( + const OpenXrExtensionHelper& extension_helper); + bool CanEnableAntiAliasing() const; static void DEVICE_VR_EXPORT SetTestHook(VRTestHook* hook); @@ -109,7 +116,6 @@ bool HasSession() const; bool HasColorSwapChain() const; bool HasSpace(XrReferenceSpaceType type) const; - bool HasFrameState() const; uint32_t GetRecommendedSwapchainSampleCount() const; XrResult UpdateStageBounds(); @@ -159,6 +165,8 @@ std::vector<XrView> head_from_eye_views_; std::vector<XrCompositionLayerProjectionView> layer_projection_views_; + std::unique_ptr<OpenXrAnchorManager> anchor_manager_; + base::WeakPtrFactory<OpenXrApiWrapper> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(OpenXrApiWrapper);
diff --git a/device/vr/openxr/openxr_device.cc b/device/vr/openxr/openxr_device.cc index 23a5b2c..53a4cd6a 100644 --- a/device/vr/openxr/openxr_device.cc +++ b/device/vr/openxr/openxr_device.cc
@@ -99,6 +99,21 @@ void OpenXrDevice::RequestSession( mojom::XRRuntimeSessionOptionsPtr options, mojom::XRRuntime::RequestSessionCallback callback) { + // Check feature support and reject session request if we cannot fulfil it + // TODO(https://crbug.com/995377): Currently OpenXR features are declared + // statically, but we may only know a runtime's true support for a feature + // dynamically + const bool anchorsRequired = base::Contains( + options->required_features, device::mojom::XRSessionFeature::ANCHORS); + const bool anchorsSupported = + extension_helper_.ExtensionEnumeration()->ExtensionSupported( + XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME); + if (anchorsRequired && !anchorsSupported) { + // Reject session request + std::move(callback).Run(nullptr, mojo::NullRemote()); + return; + } + EnsureRenderLoop(); if (!render_loop_->IsRunning()) {
diff --git a/device/vr/openxr/openxr_extension_helper.cc b/device/vr/openxr/openxr_extension_helper.cc index 892cf3d..cb59272c 100644 --- a/device/vr/openxr/openxr_extension_helper.cc +++ b/device/vr/openxr/openxr_extension_helper.cc
@@ -41,6 +41,22 @@ reinterpret_cast<PFN_xrVoidFunction*>( const_cast<PFN_xrGetD3D11GraphicsRequirementsKHR*>( &extension_methods_.xrGetD3D11GraphicsRequirementsKHR))); + + (void)xrGetInstanceProcAddr( + instance, "xrCreateSpatialAnchorMSFT", + reinterpret_cast<PFN_xrVoidFunction*>( + const_cast<PFN_xrCreateSpatialAnchorMSFT*>( + &extension_methods_.xrCreateSpatialAnchorMSFT))); + (void)xrGetInstanceProcAddr( + instance, "xrDestroySpatialAnchorMSFT", + reinterpret_cast<PFN_xrVoidFunction*>( + const_cast<PFN_xrDestroySpatialAnchorMSFT*>( + &extension_methods_.xrDestroySpatialAnchorMSFT))); + (void)xrGetInstanceProcAddr( + instance, "xrCreateSpatialAnchorSpaceMSFT", + reinterpret_cast<PFN_xrVoidFunction*>( + const_cast<PFN_xrCreateSpatialAnchorSpaceMSFT*>( + &extension_methods_.xrCreateSpatialAnchorSpaceMSFT))); } } // namespace device
diff --git a/device/vr/openxr/openxr_extension_helper.h b/device/vr/openxr/openxr_extension_helper.h index 1523d37..4e3035e 100644 --- a/device/vr/openxr/openxr_extension_helper.h +++ b/device/vr/openxr/openxr_extension_helper.h
@@ -14,8 +14,14 @@ namespace device { struct OpenXrExtensionMethods { + // D3D PFN_xrGetD3D11GraphicsRequirementsKHR xrGetD3D11GraphicsRequirementsKHR{ nullptr}; + + // Anchors + PFN_xrCreateSpatialAnchorMSFT xrCreateSpatialAnchorMSFT{nullptr}; + PFN_xrDestroySpatialAnchorMSFT xrDestroySpatialAnchorMSFT{nullptr}; + PFN_xrCreateSpatialAnchorSpaceMSFT xrCreateSpatialAnchorSpaceMSFT{nullptr}; }; class OpenXrExtensionEnumeration {
diff --git a/device/vr/openxr/openxr_render_loop.cc b/device/vr/openxr/openxr_render_loop.cc index 7147149..728d0211 100644 --- a/device/vr/openxr/openxr_render_loop.cc +++ b/device/vr/openxr/openxr_render_loop.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/optional.h" + #include "device/vr/openxr/openxr_render_loop.h" #include "components/viz/common/gpu/context_provider.h" @@ -9,9 +11,8 @@ #include "device/vr/openxr/openxr_input_helper.h" #include "device/vr/util/stage_utils.h" #include "device/vr/util/transform_utils.h" +#include "mojo/public/cpp/bindings/message.h" #include "ui/gfx/geometry/angle_conversions.h" -#include "ui/gfx/transform.h" -#include "ui/gfx/transform_util.h" namespace device { @@ -30,7 +31,14 @@ DCHECK(instance_ != XR_NULL_HANDLE); } +void OpenXrRenderLoop::DisposeActiveAnchorCallbacks() { + for (auto& create_anchor : create_anchor_requests_) { + create_anchor.TakeCallback().Run(mojom::CreateAnchorResult::FAILURE, 0); + } +} + OpenXrRenderLoop::~OpenXrRenderLoop() { + DisposeActiveAnchorCallbacks(); Stop(); } @@ -77,6 +85,19 @@ current_display_info_.Clone())); } + if (anchors_enabled_) { + OpenXrAnchorManager* anchor_manager = + openxr_->GetOrCreateAnchorManager(extension_helper_); + + ProcessCreateAnchorRequests(anchor_manager, + frame_data->input_state.value()); + + if (anchor_manager) { + frame_data->anchors_data = anchor_manager->GetCurrentAnchorsData( + openxr_->GetPredictedDisplayTime()); + } + } + return frame_data; } @@ -132,12 +153,47 @@ // Has to reset input_helper_ before reset openxr_. If we destroy openxr_ // first, input_helper_destructor will try to call the actual openxr runtime // rather than the mock in tests. + DisposeActiveAnchorCallbacks(); input_helper_.reset(); openxr_ = nullptr; current_display_info_ = nullptr; texture_helper_.Reset(); } +void OpenXrRenderLoop::EnableSupportedFeatures( + const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, + const std::vector<device::mojom::XRSessionFeature>& optionalFeatures) { + const bool anchors_supported = + extension_helper_.ExtensionEnumeration()->ExtensionSupported( + XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME); + // Filter out features that are requested but not supported + auto required_extension_enabled_filter = + [anchors_supported](device::mojom::XRSessionFeature feature) { + if (feature == device::mojom::XRSessionFeature::ANCHORS && + !anchors_supported) { + return false; + } + return true; + }; + + enabled_features_.clear(); + // Currently, the initial filtering of supported devices happens on the + // browser side (BrowserXRRuntimeImpl::SupportsFeature()), so if we have + // reached this point, it is safe to assume that all requested features are + // enabled. + // TODO(https://crbug.com/995377): revisit the approach when the bug is fixed. + std::copy(requiredFeatures.begin(), requiredFeatures.end(), + std::inserter(enabled_features_, enabled_features_.begin())); + std::copy_if(optionalFeatures.begin(), optionalFeatures.end(), + std::inserter(enabled_features_, enabled_features_.begin()), + required_extension_enabled_filter); + + // Cache feature support + const bool anchors_requested = + enabled_features_.count(device::mojom::XRSessionFeature::ANCHORS) != 0; + anchors_enabled_ = anchors_requested && anchors_supported; +} + device::mojom::XREnvironmentBlendMode OpenXrRenderLoop::GetEnvironmentBlendMode( device::mojom::XRSessionMode session_mode) { return openxr_->PickEnvironmentBlendModeForSession(session_mode); @@ -278,6 +334,146 @@ } } +void OpenXrRenderLoop::GetEnvironmentIntegrationProvider( + mojo::PendingAssociatedReceiver< + device::mojom::XREnvironmentIntegrationProvider> environment_provider) { + DVLOG(2) << __func__; + + environment_receiver_.reset(); + environment_receiver_.Bind(std::move(environment_provider)); +} + +void OpenXrRenderLoop::SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + const std::vector<mojom::EntityTypeForHitTest>& entity_types, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider::SubscribeToHitTestCallback + callback) { + mojo::ReportBadMessage( + "OpenXrRenderLoop::SubscribeToHitTest not yet implemented"); +} + +void OpenXrRenderLoop::SubscribeToHitTestForTransientInput( + const std::string& profile_name, + const std::vector<mojom::EntityTypeForHitTest>& entity_types, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider:: + SubscribeToHitTestForTransientInputCallback callback) { + mojo::ReportBadMessage( + "OpenXrRenderLoop::SubscribeToHitTestForTransientInput not yet " + "implemented"); +} + +void OpenXrRenderLoop::UnsubscribeFromHitTest(uint64_t subscription_id) { + mojo::ReportBadMessage( + "OpenXrRenderLoop::UnsubscribeFromHitTest not yet implemented"); +} + +base::Optional<OpenXrRenderLoop::XrLocation> +OpenXrRenderLoop::GetXrLocationFromReferenceSpace( + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform& native_origin_from_anchor) const { + // Floor corresponds to offset from local * local, so we must apply the + // offset to get the correct pose in the local space. + auto type = native_origin_information.get_reference_space_type(); + if (type == device::mojom::XRReferenceSpaceType::kLocalFloor) { + const mojom::VRStageParametersPtr& current_stage_parameters = + GetCurrentStageParameters(); + if (!current_stage_parameters) { + return base::nullopt; + } + return XrLocation{ + GfxTransformToXrPose(current_stage_parameters->mojo_from_floor * + native_origin_from_anchor), + openxr_->GetReferenceSpace( + device::mojom::XRReferenceSpaceType::kLocal)}; + } + + return XrLocation{GfxTransformToXrPose(native_origin_from_anchor), + openxr_->GetReferenceSpace(type)}; +} + +base::Optional<OpenXrRenderLoop::XrLocation> +OpenXrRenderLoop::GetXrLocationFromNativeOriginInformation( + const OpenXrAnchorManager* anchor_manager, + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform& native_origin_from_anchor, + const std::vector<mojom::XRInputSourceStatePtr>& input_state) const { + switch (native_origin_information.which()) { + case mojom::XRNativeOriginInformation::Tag::INPUT_SOURCE_ID: + // Currently unimplemented as only anchors are supported and are never + // created relative to input sources + return base::nullopt; + case mojom::XRNativeOriginInformation::Tag::REFERENCE_SPACE_TYPE: + return GetXrLocationFromReferenceSpace(native_origin_information, + native_origin_from_anchor); + case mojom::XRNativeOriginInformation::Tag::PLANE_ID: + // Unsupported for now + return base::nullopt; + case mojom::XRNativeOriginInformation::Tag::ANCHOR_ID: + return XrLocation{GfxTransformToXrPose(native_origin_from_anchor), + anchor_manager->GetAnchorSpace(AnchorId( + native_origin_information.get_anchor_id()))}; + } +} + +void OpenXrRenderLoop::CreateAnchor( + mojom::XRNativeOriginInformationPtr native_origin_information, + const device::Pose& native_origin_from_anchor, + CreateAnchorCallback callback) { + create_anchor_requests_.emplace_back(*native_origin_information, + native_origin_from_anchor.ToTransform(), + std::move(callback)); +} + +void OpenXrRenderLoop::ProcessCreateAnchorRequests( + OpenXrAnchorManager* anchor_manager, + const std::vector<mojom::XRInputSourceStatePtr>& input_state) { + for (auto& request : create_anchor_requests_) { + base::Optional<XrLocation> anchor_location = + GetXrLocationFromNativeOriginInformation( + anchor_manager, request.GetNativeOriginInformation(), + request.GetNativeOriginFromAnchor(), input_state); + if (!anchor_location.has_value()) { + request.TakeCallback().Run(device::mojom::CreateAnchorResult::FAILURE, 0); + continue; + } + + AnchorId anchor_id = kInvalidAnchorId; + if (openxr_->HasFrameState()) { + XrTime display_time = openxr_->GetPredictedDisplayTime(); + anchor_id = anchor_manager->CreateAnchor( + anchor_location->pose, anchor_location->space, display_time); + } + + if (anchor_id.is_null()) { + request.TakeCallback().Run(device::mojom::CreateAnchorResult::FAILURE, 0); + } else { + request.TakeCallback().Run(device::mojom::CreateAnchorResult::SUCCESS, + anchor_id.GetUnsafeValue()); + } + } + create_anchor_requests_.clear(); +} + +void OpenXrRenderLoop::CreatePlaneAnchor( + mojom::XRNativeOriginInformationPtr native_origin_information, + const device::Pose& native_origin_from_anchor, + uint64_t plane_id, + CreatePlaneAnchorCallback callback) { + mojo::ReportBadMessage( + "OpenXrRenderLoop::CreatePlaneAnchor not yet implemented"); +} + +void OpenXrRenderLoop::DetachAnchor(uint64_t anchor_id) { + OpenXrAnchorManager* anchor_manager = + openxr_->GetOrCreateAnchorManager(extension_helper_); + if (!anchor_manager) { + return; + } + anchor_manager->DetachAnchor(AnchorId(anchor_id)); +} + void OpenXrRenderLoop::StartContextProviderIfNeeded() { DCHECK(task_runner()->BelongsToCurrentThread()); // We could arrive here in scenarios where we've shutdown the render loop.
diff --git a/device/vr/openxr/openxr_render_loop.h b/device/vr/openxr/openxr_render_loop.h index 96434e8..ee59424 100644 --- a/device/vr/openxr/openxr_render_loop.h +++ b/device/vr/openxr/openxr_render_loop.h
@@ -12,8 +12,18 @@ #include "base/macros.h" #include "components/viz/common/gpu/context_lost_observer.h" #include "device/vr/openxr/context_provider_callbacks.h" +#include "device/vr/openxr/openxr_anchor_manager.h" +#include "device/vr/openxr/openxr_anchor_request.h" #include "device/vr/openxr/openxr_util.h" #include "device/vr/windows/compositor_base.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_associated_remote.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/platform/platform_handle.h" #include "third_party/openxr/src/include/openxr/openxr.h" struct XrView; @@ -24,6 +34,7 @@ class OpenXRInputHelper; class OpenXrRenderLoop : public XRCompositorCommon, + public mojom::XREnvironmentIntegrationProvider, public viz::ContextLostObserver { public: OpenXrRenderLoop( @@ -46,6 +57,10 @@ bool PreComposite() override; bool HasSessionEnded() override; bool SubmitCompositedFrame() override; + void EnableSupportedFeatures( + const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, + const std::vector<device::mojom::XRSessionFeature>& optionalFeatures) + override; device::mojom::XREnvironmentBlendMode GetEnvironmentBlendMode( device::mojom::XRSessionMode session_mode) override; device::mojom::XRInteractionMode GetInteractionMode( @@ -62,6 +77,57 @@ mojom::VREyeParametersPtr* eye) const; void UpdateStageParameters(); + void DisposeActiveAnchorCallbacks(); + + // XREnvironmentIntegrationProvider + void GetEnvironmentIntegrationProvider( + mojo::PendingAssociatedReceiver< + device::mojom::XREnvironmentIntegrationProvider> environment_provider) + override; + + void SubscribeToHitTest( + mojom::XRNativeOriginInformationPtr native_origin_information, + const std::vector<mojom::EntityTypeForHitTest>& entity_types, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider::SubscribeToHitTestCallback + callback) override; + void SubscribeToHitTestForTransientInput( + const std::string& profile_name, + const std::vector<mojom::EntityTypeForHitTest>& entity_types, + mojom::XRRayPtr ray, + mojom::XREnvironmentIntegrationProvider:: + SubscribeToHitTestForTransientInputCallback callback) override; + void UnsubscribeFromHitTest(uint64_t subscription_id) override; + void CreateAnchor( + mojom::XRNativeOriginInformationPtr native_origin_information, + const device::Pose& native_origin_from_anchor, + CreateAnchorCallback callback) override; + void CreatePlaneAnchor( + mojom::XRNativeOriginInformationPtr native_origin_information, + const device::Pose& native_origin_from_anchor, + uint64_t plane_id, + CreatePlaneAnchorCallback callback) override; + void DetachAnchor(uint64_t anchor_id) override; + + void ProcessCreateAnchorRequests( + OpenXrAnchorManager* anchor_manager, + const std::vector<mojom::XRInputSourceStatePtr>& input_state); + + // An XrPosef with the space it is relative to + struct XrLocation { + XrPosef pose; + XrSpace space; + }; + base::Optional<XrLocation> GetXrLocationFromNativeOriginInformation( + const OpenXrAnchorManager* anchor_manager, + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform& native_origin_from_anchor, + const std::vector<mojom::XRInputSourceStatePtr>& input_state) const; + base::Optional<XrLocation> GetXrLocationFromReferenceSpace( + const mojom::XRNativeOriginInformation& native_origin_information, + const gfx::Transform& native_origin_from_anchor) const; + + // viz::ContextLostObserver void StartContextProviderIfNeeded(); void OnContextProviderCreated( scoped_refptr<viz::ContextProvider> context_provider); @@ -75,10 +141,17 @@ std::unique_ptr<OpenXrApiWrapper> openxr_; std::unique_ptr<OpenXRInputHelper> input_helper_; + bool anchors_enabled_{false}; + + std::vector<CreateAnchorRequest> create_anchor_requests_; + base::RepeatingCallback<void(mojom::VRDisplayInfoPtr)> on_display_info_changed_; mojom::VRDisplayInfoPtr current_display_info_; + mojo::AssociatedReceiver<mojom::XREnvironmentIntegrationProvider> + environment_receiver_{this}; + scoped_refptr<viz::ContextProvider> context_provider_; VizContextProviderFactoryAsync context_provider_factory_async_;
diff --git a/device/vr/openxr/openxr_util.cc b/device/vr/openxr/openxr_util.cc index 4d727d1..0cf90c62 100644 --- a/device/vr/openxr/openxr_util.cc +++ b/device/vr/openxr/openxr_util.cc
@@ -12,6 +12,9 @@ #include "base/win/scoped_handle.h" #include "build/build_config.h" #include "components/version_info/version_info.h" +#include "ui/gfx/geometry/angle_conversions.h" +#include "ui/gfx/transform.h" +#include "ui/gfx/transform_util.h" namespace device { @@ -21,6 +24,21 @@ return pose; } +XrPosef GfxTransformToXrPose(const gfx::Transform& transform) { + gfx::DecomposedTransform decomposed_transform; + bool decomposition_result = + gfx::DecomposeTransform(&decomposed_transform, transform); + // This pose should always be a simple translation and rotation so this should + // always be true + DCHECK(decomposition_result); + return { + {decomposed_transform.quaternion.x(), decomposed_transform.quaternion.y(), + decomposed_transform.quaternion.z(), + decomposed_transform.quaternion.w()}, + {decomposed_transform.translate[0], decomposed_transform.translate[1], + decomposed_transform.translate[2]}}; +} + XrResult GetSystem(XrInstance instance, XrSystemId* system) { XrSystemGetInfo system_info = {XR_TYPE_SYSTEM_GET_INFO}; system_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; @@ -132,6 +150,13 @@ extensions.push_back(kMSFTHandInteractionExtensionName); } + const bool anchorsExtensionSupported = + extension_enumeration.ExtensionSupported( + XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME); + if (anchorsExtensionSupported) { + extensions.push_back(XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME); + } + instance_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); instance_create_info.enabledExtensionNames = extensions.data();
diff --git a/device/vr/openxr/openxr_util.h b/device/vr/openxr/openxr_util.h index 1c9f7ed8..5afc3774 100644 --- a/device/vr/openxr/openxr_util.h +++ b/device/vr/openxr/openxr_util.h
@@ -9,10 +9,16 @@ #include <vector> #include "base/logging.h" +#include "base/util/type_safety/id_type.h" #include "device/vr/openxr/openxr_defs.h" #include "device/vr/openxr/openxr_extension_helper.h" #include "third_party/openxr/src/include/openxr/openxr.h" #include "third_party/openxr/src/include/openxr/openxr_platform.h" +#include "ui/gfx/transform.h" + +using AnchorId = util::IdTypeU64<class AnchorTag>; +constexpr AnchorId kInvalidAnchorId = + AnchorId(0); // IdTypeU64 invalid value is 0 namespace device { // These macros aren't common in Chromium and generally discouraged, so define @@ -48,6 +54,7 @@ // Returns the identity pose, where the position is {0, 0, 0} and the // orientation is {0, 0, 0, 1}. XrPosef PoseIdentity(); +XrPosef GfxTransformToXrPose(const gfx::Transform& transform); XrResult GetSystem(XrInstance instance, XrSystemId* system);
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc index 51c4b9e..71444bb 100644 --- a/device/vr/windows/compositor_base.cc +++ b/device/vr/windows/compositor_base.cc
@@ -251,17 +251,11 @@ session->data_provider = frame_data_receiver_.BindNewPipeAndPassRemote(); session->submit_frame_sink = std::move(submit_frame_sink); - // Currently, the initial filtering of supported devices happens on the - // browser side (BrowserXRRuntimeImpl::SupportsFeature()), so if we have - // reached this point, it is safe to assume that all requested features are - // enabled. - // TODO(https://crbug.com/995377): revisit the approach when the bug is fixed. + EnableSupportedFeatures(options->required_features, + options->optional_features); session->enabled_features.insert(session->enabled_features.end(), - options->required_features.begin(), - options->required_features.end()); - session->enabled_features.insert(session->enabled_features.end(), - options->optional_features.begin(), - options->optional_features.end()); + enabled_features_.begin(), + enabled_features_.end()); session->device_config = device::mojom::XRSessionDeviceConfig::New(); session->device_config->uses_input_eventing = UsesInputEventing(); @@ -315,6 +309,11 @@ } } +const mojom::VRStageParametersPtr& +XRCompositorCommon::GetCurrentStageParameters() const { + return current_stage_parameters_; +} + void XRCompositorCommon::SetStageParameters( mojom::VRStageParametersPtr stage_parameters) { // If the stage parameters are identical no need to update them.
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h index ba79ba4..6b0801b 100644 --- a/device/vr/windows/compositor_base.h +++ b/device/vr/windows/compositor_base.h
@@ -39,6 +39,10 @@ virtual bool SubmitCompositedFrame() = 0; virtual void HandleDeviceLost(); virtual void OnLayerBoundsChanged(); + // Sets enabled_features_ based on what features are supported + virtual void EnableSupportedFeatures( + const std::vector<device::mojom::XRSessionFeature>& requiredFeatures, + const std::vector<device::mojom::XRSessionFeature>& optionalFeatures) = 0; virtual device::mojom::XREnvironmentBlendMode GetEnvironmentBlendMode( device::mojom::XRSessionMode session_mode); virtual device::mojom::XRInteractionMode GetInteractionMode( @@ -78,13 +82,14 @@ void GetEnvironmentIntegrationProvider( mojo::PendingAssociatedReceiver< device::mojom::XREnvironmentIntegrationProvider> environment_provider) - final; + override; void RequestOverlay(mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver); protected: virtual bool UsesInputEventing(); void SetVisibilityState(mojom::XRVisibilityState visibility_state); + const mojom::VRStageParametersPtr& GetCurrentStageParameters() const; void SetStageParameters(mojom::VRStageParametersPtr stage_parameters); #if defined(OS_WIN) D3D11TextureHelper texture_helper_; @@ -99,6 +104,8 @@ // Derived classes override this to be notified to clear its pending frame. virtual void ClearPendingFrameInternal() {} + std::unordered_set<device::mojom::XRSessionFeature> enabled_features_; + private: // base::Thread overrides: void Init() final;
diff --git a/docs/callback.md b/docs/callback.md index 412242c3..8e038a8 100644 --- a/docs/callback.md +++ b/docs/callback.md
@@ -232,6 +232,49 @@ other_task_runner->PostTask(FROM_HERE, std::move(task)); ``` +### Splitting a OnceCallback in two + +If a callback is only run once, but two references need to be held to the +callback, using a `base::OnceCallback` can be clearer than a +`base::RepeatingCallback`, from an intent and semantics point of view. +`base::SplitOnceCallback()` takes a `base::OnceCallback` and returns a pair of +callbacks with the same signature. When either of the returned callback is run, +the original callback is invoked. Running the leftover callback will result in a +crash. +This can be useful when passing a `base::OnceCallback` to a function that may or +may not take ownership of the callback. E.g, when an object creation could fail: + +```cpp +std::unique_ptr<FooTask> CreateFooTask(base::OnceClosure task) { + std::pair<base::OnceClosure,base::OnceClosure> split + = base::SplitOnceCallback(std::move(task)); + + std::unique_ptr<FooTask> foo = TryCreateFooTask(std::move(split.first)); + if (foo) + return foo; + + return CreateFallbackFooTask(std::move(split.second)); +} +``` + +While it is best to use a single callback to report success/failure, some APIs +already take multiple callbacks. `base::SplitOnceCallback()` can be used to +split a completion callback and help in such a case: + +```cpp +using StatusCallback = base::OnceCallback<void(FooStatus)>; +void DoOperation(StatusCallback done_cb) { + std::pair<StatusCallback, StatusCallback> split + = base::SplitOnceCallback(std::move(done_cb)); + + InnerWork(BindOnce(std::move(split.first), STATUS_OK), + BindOnce(std::move(split.second), STATUS_ABORTED)); +} + +void InnerWork(base::OnceClosure work_done_cb, + base::OnceClosure work_aborted_cb); +``` + ## Quick reference for basic stuff ### Binding A Bare Function
diff --git a/extensions/browser/api/lock_screen_data/data_item.cc b/extensions/browser/api/lock_screen_data/data_item.cc index 0857514c..da47ef2 100644 --- a/extensions/browser/api/lock_screen_data/data_item.cc +++ b/extensions/browser/api/lock_screen_data/data_item.cc
@@ -261,10 +261,10 @@ : OperationResult::kFailed; } -void OnGetRegisteredValues(const DataItem::RegisteredValuesCallback& callback, +void OnGetRegisteredValues(DataItem::RegisteredValuesCallback callback, std::unique_ptr<OperationResult> result, std::unique_ptr<base::DictionaryValue> values) { - callback.Run(*result, std::move(values)); + std::move(callback).Run(*result, std::move(values)); } } // namespace @@ -275,12 +275,12 @@ ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, const std::string& extension_id, - const RegisteredValuesCallback& callback) { + RegisteredValuesCallback callback) { scoped_refptr<const Extension> extension = ExtensionRegistry::Get(context)->GetExtensionById( extension_id, ExtensionRegistry::ENABLED); if (!extension) { - callback.Run(OperationResult::kUnknownExtension, nullptr); + std::move(callback).Run(OperationResult::kUnknownExtension, nullptr); return; } @@ -297,8 +297,8 @@ base::Unretained(value_store_cache), base::Bind(&GetRegisteredItems, result_ptr, values_ptr), extension), - base::BindOnce(&OnGetRegisteredValues, callback, std::move(result), - std::move(values))); + base::BindOnce(&OnGetRegisteredValues, std::move(callback), + std::move(result), std::move(values))); } // static @@ -307,12 +307,12 @@ ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, const std::string& extension_id, - const base::Closure& callback) { + base::OnceClosure callback) { task_runner->PostTaskAndReply( FROM_HERE, base::BindOnce(&ValueStoreCache::DeleteStorageSoon, base::Unretained(value_store_cache), extension_id), - callback); + std::move(callback)); } DataItem::DataItem(const std::string& id, @@ -330,12 +330,12 @@ DataItem::~DataItem() = default; -void DataItem::Register(const WriteCallback& callback) { +void DataItem::Register(WriteCallback callback) { scoped_refptr<const Extension> extension = ExtensionRegistry::Get(context_)->GetExtensionById( extension_id_, ExtensionRegistry::ENABLED); if (!extension) { - callback.Run(OperationResult::kUnknownExtension); + std::move(callback).Run(OperationResult::kUnknownExtension); return; } @@ -349,16 +349,15 @@ base::Unretained(value_store_cache_), base::Bind(&RegisterItem, result_ptr, id()), extension), base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(), - callback, std::move(result))); + std::move(callback), std::move(result))); } -void DataItem::Write(const std::vector<char>& data, - const WriteCallback& callback) { +void DataItem::Write(const std::vector<char>& data, WriteCallback callback) { scoped_refptr<const Extension> extension = ExtensionRegistry::Get(context_)->GetExtensionById( extension_id_, ExtensionRegistry::ENABLED); if (!extension) { - callback.Run(OperationResult::kUnknownExtension); + std::move(callback).Run(OperationResult::kUnknownExtension); return; } @@ -373,15 +372,15 @@ base::Bind(&WriteImpl, result_ptr, id_, data, crypto_key_), extension), base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(), - callback, std::move(result))); + std::move(callback), std::move(result))); } -void DataItem::Read(const ReadCallback& callback) { +void DataItem::Read(ReadCallback callback) { scoped_refptr<const Extension> extension = ExtensionRegistry::Get(context_)->GetExtensionById( extension_id_, ExtensionRegistry::ENABLED); if (!extension) { - callback.Run(OperationResult::kUnknownExtension, nullptr); + std::move(callback).Run(OperationResult::kUnknownExtension, nullptr); return; } @@ -401,15 +400,15 @@ base::Bind(&ReadImpl, result_ptr, data_ptr, id_, crypto_key_), extension), base::BindOnce(&DataItem::OnReadDone, weak_ptr_factory_.GetWeakPtr(), - callback, std::move(result), std::move(data))); + std::move(callback), std::move(result), std::move(data))); } -void DataItem::Delete(const WriteCallback& callback) { +void DataItem::Delete(WriteCallback callback) { scoped_refptr<const Extension> extension = ExtensionRegistry::Get(context_)->GetExtensionById( extension_id_, ExtensionRegistry::ENABLED); if (!extension) { - callback.Run(OperationResult::kUnknownExtension); + std::move(callback).Run(OperationResult::kUnknownExtension); return; } std::unique_ptr<OperationResult> result = @@ -422,18 +421,18 @@ base::Unretained(value_store_cache_), base::Bind(&DeleteImpl, result_ptr, id_), extension), base::BindOnce(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(), - callback, std::move(result))); + std::move(callback), std::move(result))); } -void DataItem::OnWriteDone(const DataItem::WriteCallback& callback, +void DataItem::OnWriteDone(WriteCallback callback, std::unique_ptr<OperationResult> success) { - callback.Run(*success); + std::move(callback).Run(*success); } -void DataItem::OnReadDone(const DataItem::ReadCallback& callback, +void DataItem::OnReadDone(ReadCallback callback, std::unique_ptr<OperationResult> success, std::unique_ptr<std::vector<char>> data) { - callback.Run(*success, std::move(data)); + std::move(callback).Run(*success, std::move(data)); } } // namespace lock_screen_data
diff --git a/extensions/browser/api/lock_screen_data/data_item.h b/extensions/browser/api/lock_screen_data/data_item.h index 636f161..9ae14ea 100644 --- a/extensions/browser/api/lock_screen_data/data_item.h +++ b/extensions/browser/api/lock_screen_data/data_item.h
@@ -33,13 +33,13 @@ // Wrapper around a per extension value store backed lock screen data item. class DataItem { public: - using WriteCallback = base::Callback<void(OperationResult result)>; + using WriteCallback = base::OnceCallback<void(OperationResult result)>; using ReadCallback = - base::Callback<void(OperationResult result, - std::unique_ptr<std::vector<char>> data)>; + base::OnceCallback<void(OperationResult result, + std::unique_ptr<std::vector<char>> data)>; using RegisteredValuesCallback = - base::Callback<void(OperationResult result, - std::unique_ptr<base::DictionaryValue> values)>; + base::OnceCallback<void(OperationResult result, + std::unique_ptr<base::DictionaryValue> values)>; // Gets all registered data items for the extension with the provided // extension ID - the items are returned as a DictionaryValue with keys set @@ -49,7 +49,7 @@ ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, const std::string& extension_id, - const RegisteredValuesCallback& callback); + RegisteredValuesCallback callback); // Clears data item value store for the extension with the provided extension // ID. @@ -57,7 +57,7 @@ ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, const std::string& extension_id, - const base::Closure& callback); + base::OnceClosure callback); // |id| - Data item ID. // |extension_id| - The extension that owns the item. @@ -82,20 +82,19 @@ virtual ~DataItem(); // Registers the data item in the persistent data item storage. - virtual void Register(const WriteCallback& callback); + virtual void Register(WriteCallback callback); // Sets the data item content, saving it to persistent data storage. // This will fail if the data item is not registered. - virtual void Write(const std::vector<char>& data, - const WriteCallback& callback); + virtual void Write(const std::vector<char>& data, WriteCallback callback); // Gets the data item content from the persistent data storage. // This will fail is the item is not registered. - virtual void Read(const ReadCallback& callback); + virtual void Read(ReadCallback callback); // Unregisters the data item, and clears previously persisted data item // content. - virtual void Delete(const WriteCallback& callback); + virtual void Delete(WriteCallback callback); const std::string& id() const { return id_; } @@ -104,12 +103,12 @@ private: // Internal callback for write operations - wraps |callback| to ensure // |callback| is not run after |this| has been destroyed. - void OnWriteDone(const WriteCallback& callback, + void OnWriteDone(WriteCallback callback, std::unique_ptr<OperationResult> result); // Internal callback for the read operation - wraps |callback| to ensure // |callback| is not run after |this| has been destroyed. - void OnReadDone(const ReadCallback& callback, + void OnReadDone(ReadCallback callback, std::unique_ptr<OperationResult> result, std::unique_ptr<std::vector<char>> data);
diff --git a/extensions/browser/api/lock_screen_data/data_item_unittest.cc b/extensions/browser/api/lock_screen_data/data_item_unittest.cc index 677bb5a..9f134ee 100644 --- a/extensions/browser/api/lock_screen_data/data_item_unittest.cc +++ b/extensions/browser/api/lock_screen_data/data_item_unittest.cc
@@ -141,7 +141,8 @@ OperationResult result = OperationResult::kFailed; base::RunLoop run_loop; - item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Register( + base::BindOnce(&WriteCallback, run_loop.QuitClosure(), &result)); run_loop.Run(); EXPECT_EQ(OperationResult::kSuccess, result); @@ -195,8 +196,8 @@ const std::vector<char>& data) { OperationResult result = OperationResult::kFailed; base::RunLoop run_loop; - item->Write(data, - base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Write( + data, base::BindOnce(&WriteCallback, run_loop.QuitClosure(), &result)); run_loop.Run(); return result; } @@ -207,8 +208,8 @@ OperationResult result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; base::RunLoop run_loop; - item->Read(base::Bind(&ReadCallback, run_loop.QuitClosure(), &result, - &read_content)); + item->Read(base::BindOnce(&ReadCallback, run_loop.QuitClosure(), &result, + &read_content)); run_loop.Run(); if (data) *data = std::move(read_content); @@ -218,7 +219,8 @@ OperationResult DeleteItemAndWaitForResult(DataItem* item) { OperationResult result = OperationResult::kFailed; base::RunLoop run_loop; - item->Delete(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Delete( + base::BindOnce(&WriteCallback, run_loop.QuitClosure(), &result)); run_loop.Run(); return result; } @@ -226,7 +228,8 @@ OperationResult RegisterItemAndWaitForResult(DataItem* item) { OperationResult result = OperationResult::kFailed; base::RunLoop run_loop; - item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Register( + base::BindOnce(&WriteCallback, run_loop.QuitClosure(), &result)); run_loop.Run(); return result; } @@ -555,8 +558,8 @@ std::vector<char> first_write = {'f', 'i', 'l', 'e', '_', '1'}; std::vector<char> second_write = {'f', 'i', 'l', 'e', '_', '2'}; - writer->Write(first_write, - base::Bind(&WriteCallback, base::DoNothing(), &write_result)); + writer->Write(first_write, base::BindOnce(&WriteCallback, base::DoNothing(), + &write_result)); EXPECT_EQ(OperationResult::kSuccess, WriteItemAndWaitForResult(writer.get(), second_write)); @@ -675,7 +678,8 @@ "data_id", extension()->id(), GenerateKey("key_1")); std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'}; - writer->Write(content, base::Bind(&WriteCallbackNotCalled, "Reset writer")); + writer->Write(content, + base::BindOnce(&WriteCallbackNotCalled, "Reset writer")); writer.reset(); std::unique_ptr<DataItem> reader = @@ -686,12 +690,12 @@ ASSERT_TRUE(read_content); EXPECT_EQ(content, *read_content); - reader->Read(base::Bind(&ReadCallbackNotCalled, "Reset read")); + reader->Read(base::BindOnce(&ReadCallbackNotCalled, "Reset read")); reader.reset(); std::unique_ptr<DataItem> deleter = CreateDataItem("data_id", extension()->id(), GenerateKey("key_1")); - deleter->Delete(base::Bind(&WriteCallbackNotCalled, "Reset deleter")); + deleter->Delete(base::BindOnce(&WriteCallbackNotCalled, "Reset deleter")); deleter.reset(); DrainTaskRunner();
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc b/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc index 2b6b32c..23ecf54 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc +++ b/extensions/browser/api/lock_screen_data/lock_screen_data_api.cc
@@ -124,7 +124,7 @@ storage->GetItemContent( extension_id(), params->id, - base::Bind(&LockScreenDataGetContentFunction::OnDone, this)); + base::BindOnce(&LockScreenDataGetContentFunction::OnDone, this)); return RespondLater(); } @@ -160,7 +160,7 @@ storage->SetItemContent( extension_id(), params->id, std::vector<char>(params->data.begin(), params->data.end()), - base::Bind(&LockScreenDataSetContentFunction::OnDone, this)); + base::BindOnce(&LockScreenDataSetContentFunction::OnDone, this)); return RespondLater(); } @@ -191,8 +191,9 @@ if (!storage) return RespondNow(Error("Not available")); - storage->DeleteItem(extension_id(), params->id, - base::Bind(&LockScreenDataDeleteFunction::OnDone, this)); + storage->DeleteItem( + extension_id(), params->id, + base::BindOnce(&LockScreenDataDeleteFunction::OnDone, this)); return RespondLater(); }
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc index bc37645..51c143c3 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc +++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.cc
@@ -92,26 +92,28 @@ content::BrowserContext* context, ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, - const DataItem::RegisteredValuesCallback& callback) { + DataItem::RegisteredValuesCallback callback) { if (g_test_registered_items_getter_callback) { - g_test_registered_items_getter_callback->Run(extension_id, callback); + g_test_registered_items_getter_callback->Run(extension_id, + std::move(callback)); return; } - DataItem::GetRegisteredValuesForExtension( - context, value_store_cache, task_runner, extension_id, callback); + DataItem::GetRegisteredValuesForExtension(context, value_store_cache, + task_runner, extension_id, + std::move(callback)); } void DeleteAllItems(const std::string& extension_id, content::BrowserContext* context, ValueStoreCache* value_store_cache, base::SequencedTaskRunner* task_runner, - const base::Closure& callback) { + base::OnceClosure callback) { if (g_test_delete_all_items_callback) { - g_test_delete_all_items_callback->Run(extension_id, callback); + g_test_delete_all_items_callback->Run(extension_id, std::move(callback)); return; } DataItem::DeleteAllItemsForExtension(context, value_store_cache, task_runner, - extension_id, callback); + extension_id, std::move(callback)); } } // namespace @@ -234,8 +236,8 @@ const CreateCallback& callback) { EnsureCacheForExtensionLoaded( extension_id, - base::Bind(&LockScreenItemStorage::CreateItemImpl, - weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); + base::BindOnce(&LockScreenItemStorage::CreateItemImpl, + weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); } void LockScreenItemStorage::GetAllForExtension( @@ -243,38 +245,36 @@ const DataItemListCallback& callback) { EnsureCacheForExtensionLoaded( extension_id, - base::Bind(&LockScreenItemStorage::GetAllForExtensionImpl, - weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); + base::BindOnce(&LockScreenItemStorage::GetAllForExtensionImpl, + weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); } -void LockScreenItemStorage::SetItemContent( - const std::string& extension_id, - const std::string& item_id, - const std::vector<char>& data, - const LockScreenItemStorage::WriteCallback& callback) { +void LockScreenItemStorage::SetItemContent(const std::string& extension_id, + const std::string& item_id, + const std::vector<char>& data, + WriteCallback callback) { EnsureCacheForExtensionLoaded( - extension_id, base::Bind(&LockScreenItemStorage::SetItemContentImpl, - weak_ptr_factory_.GetWeakPtr(), extension_id, - item_id, data, callback)); + extension_id, base::BindOnce(&LockScreenItemStorage::SetItemContentImpl, + weak_ptr_factory_.GetWeakPtr(), extension_id, + item_id, data, std::move(callback))); } -void LockScreenItemStorage::GetItemContent( - const std::string& extension_id, - const std::string& item_id, - const LockScreenItemStorage::ReadCallback& callback) { +void LockScreenItemStorage::GetItemContent(const std::string& extension_id, + const std::string& item_id, + ReadCallback callback) { EnsureCacheForExtensionLoaded( - extension_id, base::Bind(&LockScreenItemStorage::GetItemContentImpl, - weak_ptr_factory_.GetWeakPtr(), extension_id, - item_id, callback)); + extension_id, base::BindOnce(&LockScreenItemStorage::GetItemContentImpl, + weak_ptr_factory_.GetWeakPtr(), extension_id, + item_id, std::move(callback))); } void LockScreenItemStorage::DeleteItem(const std::string& extension_id, const std::string& item_id, - const WriteCallback& callback) { + WriteCallback callback) { EnsureCacheForExtensionLoaded( - extension_id, base::Bind(&LockScreenItemStorage::DeleteItemImpl, - weak_ptr_factory_.GetWeakPtr(), extension_id, - item_id, callback)); + extension_id, base::BindOnce(&LockScreenItemStorage::DeleteItemImpl, + weak_ptr_factory_.GetWeakPtr(), extension_id, + item_id, std::move(callback))); } void LockScreenItemStorage::OnExtensionUninstalled( @@ -313,10 +313,9 @@ CreateDataItem(base::GenerateGUID(), extension_id, context_, value_store_cache_.get(), task_runner_.get(), crypto_key_); DataItem* item_ptr = item.get(); - item_ptr->Register(base::Bind(&LockScreenItemStorage::OnItemRegistered, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(std::move(item)), extension_id, - tick_clock_->NowTicks(), callback)); + item_ptr->Register(base::BindOnce( + &LockScreenItemStorage::OnItemRegistered, weak_ptr_factory_.GetWeakPtr(), + std::move(item), extension_id, tick_clock_->NowTicks(), callback)); } void LockScreenItemStorage::GetAllForExtensionImpl( @@ -339,48 +338,48 @@ callback.Run(items); } -void LockScreenItemStorage::SetItemContentImpl( - const std::string& extension_id, - const std::string& item_id, - const std::vector<char>& data, - const LockScreenItemStorage::WriteCallback& callback) { +void LockScreenItemStorage::SetItemContentImpl(const std::string& extension_id, + const std::string& item_id, + const std::vector<char>& data, + WriteCallback callback) { DataItem* item = FindItem(extension_id, item_id); if (!item) { - callback.Run(OperationResult::kNotFound); + std::move(callback).Run(OperationResult::kNotFound); return; } - item->Write(data, base::Bind(&LockScreenItemStorage::OnItemWritten, - weak_ptr_factory_.GetWeakPtr(), - tick_clock_->NowTicks(), callback)); + item->Write(data, + base::BindOnce(&LockScreenItemStorage::OnItemWritten, + weak_ptr_factory_.GetWeakPtr(), + tick_clock_->NowTicks(), std::move(callback))); } void LockScreenItemStorage::GetItemContentImpl(const std::string& extension_id, const std::string& item_id, - const ReadCallback& callback) { + ReadCallback callback) { DataItem* item = FindItem(extension_id, item_id); if (!item) { - callback.Run(OperationResult::kNotFound, nullptr); + std::move(callback).Run(OperationResult::kNotFound, nullptr); return; } - item->Read(base::Bind(&LockScreenItemStorage::OnItemRead, - weak_ptr_factory_.GetWeakPtr(), tick_clock_->NowTicks(), - callback)); + item->Read(base::BindOnce(&LockScreenItemStorage::OnItemRead, + weak_ptr_factory_.GetWeakPtr(), + tick_clock_->NowTicks(), std::move(callback))); } void LockScreenItemStorage::DeleteItemImpl(const std::string& extension_id, const std::string& item_id, - const WriteCallback& callback) { + WriteCallback callback) { DataItem* item = FindItem(extension_id, item_id); if (!item) { - callback.Run(OperationResult::kNotFound); + std::move(callback).Run(OperationResult::kNotFound); return; } - item->Delete(base::Bind(&LockScreenItemStorage::OnItemDeleted, - weak_ptr_factory_.GetWeakPtr(), extension_id, item_id, - tick_clock_->NowTicks(), callback)); + item->Delete(base::BindOnce( + &LockScreenItemStorage::OnItemDeleted, weak_ptr_factory_.GetWeakPtr(), + extension_id, item_id, tick_clock_->NowTicks(), std::move(callback))); } void LockScreenItemStorage::OnItemRegistered(std::unique_ptr<DataItem> item, @@ -418,7 +417,7 @@ } void LockScreenItemStorage::OnItemWritten(const base::TimeTicks& start_time, - const WriteCallback& callback, + WriteCallback callback, OperationResult result) { if (result == OperationResult::kSuccess) { UMA_HISTOGRAM_TIMES( @@ -430,12 +429,12 @@ tick_clock_->NowTicks() - start_time); } - callback.Run(result); + std::move(callback).Run(result); } void LockScreenItemStorage::OnItemRead( const base::TimeTicks& start_time, - const ReadCallback& callback, + ReadCallback callback, OperationResult result, std::unique_ptr<std::vector<char>> data) { if (result == OperationResult::kSuccess) { @@ -448,13 +447,13 @@ tick_clock_->NowTicks() - start_time); } - callback.Run(result, std::move(data)); + std::move(callback).Run(result, std::move(data)); } void LockScreenItemStorage::OnItemDeleted(const std::string& extension_id, const std::string& item_id, const base::TimeTicks& start_time, - const WriteCallback& callback, + WriteCallback callback, OperationResult result) { if (result == OperationResult::kSuccess) { UMA_HISTOGRAM_TIMES( @@ -474,19 +473,19 @@ data_item_cache_[extension_id].data_items.size()))); } - callback.Run(result); + std::move(callback).Run(result); } void LockScreenItemStorage::EnsureCacheForExtensionLoaded( const std::string& extension_id, - const base::Closure& callback) { + base::OnceClosure callback) { CachedExtensionData* data = &data_item_cache_[extension_id]; if (data->state == CachedExtensionData::State::kLoaded) { - callback.Run(); + std::move(callback).Run(); return; } - data->load_callbacks.push_back(callback); + data->load_callbacks.push_back(std::move(callback)); if (data->state == CachedExtensionData::State::kRemoving || data->state == CachedExtensionData::State::kLoading) { @@ -502,9 +501,9 @@ GetRegisteredItems(extension_id, context_, value_store_cache_.get(), task_runner_.get(), - base::Bind(&LockScreenItemStorage::OnGotExtensionItems, - weak_ptr_factory_.GetWeakPtr(), extension_id, - tick_clock_->NowTicks())); + base::BindOnce(&LockScreenItemStorage::OnGotExtensionItems, + weak_ptr_factory_.GetWeakPtr(), + extension_id, tick_clock_->NowTicks())); } void LockScreenItemStorage::OnItemsMigratedForExtension( @@ -515,9 +514,9 @@ data_item_cache_[extension_id].state = CachedExtensionData::State::kLoading; GetRegisteredItems(extension_id, context_, value_store_cache_.get(), task_runner_.get(), - base::Bind(&LockScreenItemStorage::OnGotExtensionItems, - weak_ptr_factory_.GetWeakPtr(), extension_id, - tick_clock_->NowTicks())); + base::BindOnce(&LockScreenItemStorage::OnGotExtensionItems, + weak_ptr_factory_.GetWeakPtr(), + extension_id, tick_clock_->NowTicks())); } void LockScreenItemStorage::OnGotExtensionItems( @@ -678,10 +677,10 @@ void LockScreenItemStorage::RunExtensionDataLoadCallbacks( CachedExtensionData* cache_data) { - std::vector<base::Closure> callbacks; + std::vector<base::OnceClosure> callbacks; callbacks.swap(cache_data->load_callbacks); for (auto& callback : callbacks) - callback.Run(); + std::move(callback).Run(); } } // namespace lock_screen_data
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h index a5a4721..c1731038 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h +++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage.h
@@ -108,18 +108,18 @@ void SetItemContent(const std::string& extension_id, const std::string& item_id, const std::vector<char>& data, - const WriteCallback& callback); + WriteCallback callback); // Retrieves the content of the item identified by |item_id| that is // associated with the provided extension. void GetItemContent(const std::string& extension_id, const std::string& item_id, - const ReadCallback& callback); + ReadCallback callback); // Deletes the data item associated with the extension. void DeleteItem(const std::string& extension_id, const std::string& item_id, - const WriteCallback& callback); + WriteCallback callback); // extensions::ExtensionRegistryObserver: void OnExtensionUninstalled(content::BrowserContext* browser_context, @@ -140,15 +140,16 @@ ValueStoreMigratorFactoryCallback* factory_callback); // Used in tests to inject fake data items implementations. - using ItemFactoryCallback = - base::Callback<std::unique_ptr<DataItem>(const std::string& id, - const std::string& extension_id, - const std::string& crypto_key)>; - using RegisteredItemsGetter = - base::Callback<void(const std::string& extension_id, - const DataItem::RegisteredValuesCallback& callback)>; - using ItemStoreDeleter = base::Callback<void(const std::string& extension_id, - const base::Closure& callback)>; + using ItemFactoryCallback = base::RepeatingCallback<std::unique_ptr<DataItem>( + const std::string& id, + const std::string& extension_id, + const std::string& crypto_key)>; + using RegisteredItemsGetter = base::RepeatingCallback<void( + const std::string& extension_id, + DataItem::RegisteredValuesCallback callback)>; + using ItemStoreDeleter = + base::RepeatingCallback<void(const std::string& extension_id, + base::OnceClosure callback)>; static void SetItemProvidersForTesting( RegisteredItemsGetter* item_fetch_callback, ItemFactoryCallback* factory_callback, @@ -185,7 +186,7 @@ // When the initial data item list is being loaded, contains the callback // waiting for the load to finish. When the initial data item set is loaded, // all of the callbacks in this list will be run. - std::vector<base::Closure> load_callbacks; + std::vector<base::OnceClosure> load_callbacks; }; // Maps an extension ID to data items associated with the extension. @@ -213,19 +214,19 @@ void SetItemContentImpl(const std::string& extension_id, const std::string& item_id, const std::vector<char>& data, - const WriteCallback& callback); + WriteCallback callback); void GetItemContentImpl(const std::string& extension_id, const std::string& item_id, - const ReadCallback& callback); + ReadCallback callback); void DeleteItemImpl(const std::string& extension_id, const std::string& item_id, - const WriteCallback& callback); + WriteCallback callback); // Defers |callback| until the cached data item set is loaded for the // extension. If the data is already loaded, |callback| will be run // immediately. void EnsureCacheForExtensionLoaded(const std::string& extension_id, - const base::Closure& callback); + base::OnceClosure callback); // Callback for loading initial set of known data items for an extension. void OnGotExtensionItems(const std::string& extension_id, @@ -244,13 +245,13 @@ // Callback for data item write operation - it invokes the callback with the // operation result. void OnItemWritten(const base::TimeTicks& start_time, - const WriteCallback& callback, + WriteCallback callback, OperationResult result); // Callback for data item read operation - it invokes the callback with the // operation result. void OnItemRead(const base::TimeTicks& start_time, - const ReadCallback& callback, + ReadCallback callback, OperationResult result, std::unique_ptr<std::vector<char>> data); @@ -259,7 +260,7 @@ void OnItemDeleted(const std::string& extension_id, const std::string& item_id, const base::TimeTicks& start_time, - const WriteCallback& callback, + WriteCallback callback, OperationResult result); // Finds a data item associated with the extension.
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc b/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc index 8417f22..e3172eb 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc +++ b/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc
@@ -157,22 +157,20 @@ void RemoveAll() { items_.clear(); } // Gets the set of registered data items. - void HandleGetRequest(const DataItem::RegisteredValuesCallback& callback) { + void HandleGetRequest(DataItem::RegisteredValuesCallback callback) { if (!throttle_get_) { - RunCallback(callback); + RunCallback(std::move(callback)); return; } ASSERT_TRUE(pending_callback_.is_null()); - pending_callback_ = callback; + pending_callback_ = std::move(callback); } // Completes a pending |HandleGetRequest| request. void RunPendingCallback() { ASSERT_FALSE(pending_callback_.is_null()); - DataItem::RegisteredValuesCallback callback = pending_callback_; - pending_callback_.Reset(); - RunCallback(callback); + RunCallback(std::move(pending_callback_)); } bool HasPendingCallback() const { return !pending_callback_.is_null(); } @@ -182,9 +180,10 @@ void set_throttle_get(bool throttle_get) { throttle_get_ = throttle_get; } private: - void RunCallback(const DataItem::RegisteredValuesCallback& callback) { - callback.Run(fail_ ? OperationResult::kFailed : OperationResult::kSuccess, - ItemsToValue()); + void RunCallback(DataItem::RegisteredValuesCallback callback) { + std::move(callback).Run( + fail_ ? OperationResult::kFailed : OperationResult::kSuccess, + ItemsToValue()); } std::unique_ptr<base::DictionaryValue> ItemsToValue() { @@ -250,31 +249,31 @@ ~OperationQueue() = default; - void Register(const DataItem::WriteCallback& callback) { + void Register(DataItem::WriteCallback callback) { bool registered = item_registry_->Add(id_); - callback.Run(registered ? OperationResult::kSuccess - : OperationResult::kFailed); + std::move(callback).Run(registered ? OperationResult::kSuccess + : OperationResult::kFailed); } void AddWrite(const std::vector<char>& data, - const DataItem::WriteCallback& callback) { + DataItem::WriteCallback callback) { PendingOperation operation(OperationType::kWrite); operation.data = data; - operation.write_callback = callback; + operation.write_callback = std::move(callback); pending_operations_.emplace(std::move(operation)); } - void AddRead(const DataItem::ReadCallback& callback) { + void AddRead(DataItem::ReadCallback callback) { PendingOperation operation(OperationType::kRead); - operation.read_callback = callback; + operation.read_callback = std::move(callback); pending_operations_.emplace(std::move(operation)); } - void AddDelete(const DataItem::WriteCallback& callback) { + void AddDelete(DataItem::WriteCallback callback) { PendingOperation operation(OperationType::kDelete); - operation.delete_callback = callback; + operation.delete_callback = std::move(callback); pending_operations_.emplace(std::move(operation)); } @@ -288,7 +287,7 @@ ASSERT_FALSE(pending_operations_.empty()); ASSERT_FALSE(deleted_); - const PendingOperation& operation = pending_operations_.front(); + PendingOperation& operation = pending_operations_.front(); ASSERT_EQ(expected_type, operation.type); @@ -296,9 +295,9 @@ case OperationType::kWrite: { if (result == OperationResult::kSuccess) content_ = operation.data; - DataItem::WriteCallback callback = operation.write_callback; + DataItem::WriteCallback callback = std::move(operation.write_callback); pending_operations_.pop(); - callback.Run(result); + std::move(callback).Run(result); break; } case OperationType::kDelete: { @@ -308,9 +307,9 @@ content_ = std::vector<char>(); } - DataItem::WriteCallback callback = operation.delete_callback; + DataItem::WriteCallback callback = std::move(operation.delete_callback); pending_operations_.pop(); - callback.Run(result); + std::move(callback).Run(result); break; } case OperationType::kRead: { @@ -320,9 +319,9 @@ content_.end()); } - DataItem::ReadCallback callback = operation.read_callback; + DataItem::ReadCallback callback = std::move(operation.read_callback); pending_operations_.pop(); - callback.Run(result, std::move(result_data)); + std::move(callback).Run(result, std::move(result_data)); break; } default: @@ -365,21 +364,20 @@ ~TestDataItem() override = default; - void Register(const WriteCallback& callback) override { - operations_->Register(callback); + void Register(WriteCallback callback) override { + operations_->Register(std::move(callback)); } - void Write(const std::vector<char>& data, - const WriteCallback& callback) override { - operations_->AddWrite(data, callback); + void Write(const std::vector<char>& data, WriteCallback callback) override { + operations_->AddWrite(data, std::move(callback)); } - void Read(const ReadCallback& callback) override { - operations_->AddRead(callback); + void Read(ReadCallback callback) override { + operations_->AddRead(std::move(callback)); } - void Delete(const WriteCallback& callback) override { - operations_->AddDelete(callback); + void Delete(WriteCallback callback) override { + operations_->AddDelete(std::move(callback)); } private: @@ -483,12 +481,12 @@ LockScreenItemStorage::SetValueStoreMigratorFactoryForTesting( &migrator_factory_); - item_factory_ = base::Bind(&LockScreenItemStorageTest::CreateItem, - base::Unretained(this)); - registered_items_getter_ = base::Bind( + item_factory_ = base::BindRepeating(&LockScreenItemStorageTest::CreateItem, + base::Unretained(this)); + registered_items_getter_ = base::BindRepeating( &LockScreenItemStorageTest::GetRegisteredItems, base::Unretained(this)); - item_store_deleter_ = base::Bind(&LockScreenItemStorageTest::RemoveAllItems, - base::Unretained(this)); + item_store_deleter_ = base::BindRepeating( + &LockScreenItemStorageTest::RemoveAllItems, base::Unretained(this)); LockScreenItemStorage::SetItemProvidersForTesting( ®istered_items_getter_, &item_factory_, &item_store_deleter_); @@ -530,7 +528,7 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), id, content, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); if (!item_operations->HasPendingOperations()) { ADD_FAILURE() << "Write not registered"; return false; @@ -735,19 +733,19 @@ } void GetRegisteredItems(const std::string& extension_id, - const DataItem::RegisteredValuesCallback& callback) { + DataItem::RegisteredValuesCallback callback) { if (extension()->id() != extension_id) { - callback.Run(OperationResult::kUnknownExtension, nullptr); + std::move(callback).Run(OperationResult::kUnknownExtension, nullptr); return; } - item_registry_->HandleGetRequest(callback); + item_registry_->HandleGetRequest(std::move(callback)); } void RemoveAllItems(const std::string& extension_id, - const base::Closure& callback) { + base::OnceClosure callback) { ASSERT_EQ(extension()->id(), extension_id); item_registry_->RemoveAll(); - callback.Run(); + std::move(callback).Run(); } std::unique_ptr<LockScreenItemStorage> lock_screen_item_storage_; @@ -819,7 +817,7 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), item->id(), content, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); item_operations->CompleteNextOperation(OperationQueue::OperationType::kWrite, OperationResult::kSuccess); @@ -832,7 +830,7 @@ lock_screen_item_storage()->GetItemContent( extension()->id(), item->id(), - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); item_operations->CompleteNextOperation(OperationQueue::OperationType::kRead, OperationResult::kSuccess); @@ -842,7 +840,7 @@ OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), item->id(), - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); item_operations->CompleteNextOperation(OperationQueue::OperationType::kDelete, OperationResult::kSuccess); @@ -863,20 +861,20 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), item_id, {'x'}, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); EXPECT_EQ(OperationResult::kNotFound, write_result); OperationResult read_result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; lock_screen_item_storage()->GetItemContent( extension()->id(), item_id, - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); EXPECT_EQ(OperationResult::kNotFound, read_result); OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), "non_existen", - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); EXPECT_EQ(OperationResult::kNotFound, delete_result); OperationQueue* operations = GetOperations(item_id); @@ -891,7 +889,7 @@ write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), new_item->id(), {'y'}, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); OperationQueue* new_item_operations = GetOperations(new_item->id()); ASSERT_TRUE(new_item_operations); @@ -920,13 +918,13 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), item_id, {'x'}, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); OperationResult read_result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; lock_screen_item_storage()->GetItemContent( extension()->id(), item_id, - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); std::vector<std::string> items; lock_screen_item_storage()->GetAllForExtension( @@ -936,7 +934,7 @@ OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), item_id, - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); OperationQueue* operations = GetOperations(item_id); ASSERT_TRUE(operations); @@ -989,38 +987,38 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), "non_existent", content, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); EXPECT_EQ(OperationResult::kNotFound, write_result); write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( "non_existent", item->id(), content, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); EXPECT_EQ(OperationResult::kNotFound, write_result); OperationResult read_result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; lock_screen_item_storage()->GetItemContent( extension()->id(), "non_existent", - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); EXPECT_EQ(OperationResult::kNotFound, read_result); read_result = OperationResult::kFailed; lock_screen_item_storage()->GetItemContent( "non_existent", item->id(), - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); EXPECT_EQ(OperationResult::kNotFound, read_result); OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), "non_existen", - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); EXPECT_EQ(OperationResult::kNotFound, delete_result); delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( "non_existent", item->id(), - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); EXPECT_EQ(OperationResult::kNotFound, delete_result); } @@ -1035,7 +1033,7 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), item->id(), {'x'}, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); operations->CompleteNextOperation(OperationQueue::OperationType::kWrite, OperationResult::kInvalidKey); EXPECT_EQ(OperationResult::kInvalidKey, write_result); @@ -1044,7 +1042,7 @@ std::unique_ptr<std::vector<char>> read_content; lock_screen_item_storage()->GetItemContent( extension()->id(), item->id(), - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); operations->CompleteNextOperation(OperationQueue::OperationType::kRead, OperationResult::kWrongKey); EXPECT_EQ(OperationResult::kWrongKey, read_result); @@ -1101,7 +1099,7 @@ OperationResult delete_result; lock_screen_item_storage()->DeleteItem( extension()->id(), item_id, - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); OperationQueue* operations = GetOperations(item_id); ASSERT_TRUE(operations); operations->CompleteNextOperation(OperationQueue::OperationType::kDelete, @@ -1173,7 +1171,7 @@ OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), item_id, - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); OperationQueue* operations = GetOperations(item_id); ASSERT_TRUE(operations); operations->CompleteNextOperation(OperationQueue::OperationType::kDelete, @@ -1261,13 +1259,13 @@ OperationResult write_result = OperationResult::kFailed; lock_screen_item_storage()->SetItemContent( extension()->id(), initial_item_id, {'x'}, - base::Bind(&RecordWriteResult, &write_result)); + base::BindOnce(&RecordWriteResult, &write_result)); OperationResult read_result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; lock_screen_item_storage()->GetItemContent( extension()->id(), migrated_item_id, - base::Bind(&RecordReadResult, &read_result, &read_content)); + base::BindOnce(&RecordReadResult, &read_result, &read_content)); std::vector<std::string> items; lock_screen_item_storage()->GetAllForExtension( @@ -1277,7 +1275,7 @@ OperationResult delete_result = OperationResult::kFailed; lock_screen_item_storage()->DeleteItem( extension()->id(), initial_item_id, - base::Bind(&RecordWriteResult, &delete_result)); + base::BindOnce(&RecordWriteResult, &delete_result)); OperationQueue* initial_item_operations = GetOperations(initial_item_id); ASSERT_TRUE(initial_item_operations);
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl.cc b/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl.cc index 05d68e8..0bbed56 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl.cc +++ b/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl.cc
@@ -57,8 +57,9 @@ DataItem::DeleteAllItemsForExtension( context_, target_store_cache_, task_runner_, extension_id, - base::Bind(&LockScreenValueStoreMigratorImpl::DeleteItemsFromSourceStore, - weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); + base::BindOnce( + &LockScreenValueStoreMigratorImpl::DeleteItemsFromSourceStore, + weak_ptr_factory_.GetWeakPtr(), extension_id, callback)); } LockScreenValueStoreMigratorImpl::MigrationData::MigrationData() = default; @@ -118,8 +119,8 @@ context_, target_store_cache_, task_runner_, crypto_key_); migration_items_[extension_id].current_source->Read( - base::Bind(&LockScreenValueStoreMigratorImpl::OnCurrentItemRead, - weak_ptr_factory_.GetWeakPtr(), extension_id)); + base::BindOnce(&LockScreenValueStoreMigratorImpl::OnCurrentItemRead, + weak_ptr_factory_.GetWeakPtr(), extension_id)); } void LockScreenValueStoreMigratorImpl::OnCurrentItemRead( @@ -137,9 +138,9 @@ } if (result == OperationResult::kSuccess) { - migration_items_[extension_id].current_target->Register(base::Bind( + migration_items_[extension_id].current_target->Register(base::BindOnce( &LockScreenValueStoreMigratorImpl::OnTargetItemRegistered, - weak_ptr_factory_.GetWeakPtr(), extension_id, base::Passed(&data))); + weak_ptr_factory_.GetWeakPtr(), extension_id, std::move(data))); } else { OnTargetItemWritten(extension_id, OperationResult::kFailed); } @@ -158,8 +159,8 @@ result == OperationResult::kAlreadyRegistered) { migration_items_[extension_id].current_target->Write( *data, - base::Bind(&LockScreenValueStoreMigratorImpl::OnTargetItemWritten, - weak_ptr_factory_.GetWeakPtr(), extension_id)); + base::BindOnce(&LockScreenValueStoreMigratorImpl::OnTargetItemWritten, + weak_ptr_factory_.GetWeakPtr(), extension_id)); } else { OnTargetItemWritten(extension_id, OperationResult::kFailed); } @@ -176,8 +177,8 @@ migration_items_[extension_id].current_target->Delete(base::DoNothing()); migration_items_[extension_id].current_source->Delete( - base::Bind(&LockScreenValueStoreMigratorImpl::OnCurrentItemMigrated, - weak_ptr_factory_.GetWeakPtr(), extension_id)); + base::BindOnce(&LockScreenValueStoreMigratorImpl::OnCurrentItemMigrated, + weak_ptr_factory_.GetWeakPtr(), extension_id)); } void LockScreenValueStoreMigratorImpl::OnCurrentItemMigrated( @@ -191,7 +192,7 @@ const base::Closure& callback) { DataItem::DeleteAllItemsForExtension( context_, source_store_cache_, task_runner_, extension_id, - base::Bind( + base::BindOnce( &LockScreenValueStoreMigratorImpl::RunClearDataForExtensionCallback, weak_ptr_factory_.GetWeakPtr(), callback)); }
diff --git a/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc b/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc index 9689453..596a6f3 100644 --- a/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc +++ b/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc
@@ -204,7 +204,8 @@ OperationResult RegisterDataItem(DataItem* item) { base::RunLoop run_loop; OperationResult result = OperationResult::kFailed; - item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Register( + base::BindOnce(&WriteCallback, run_loop.QuitClosure(), &result)); run_loop.Run(); return result; } @@ -213,8 +214,8 @@ const std::vector<char>& content) { base::RunLoop run_loop; OperationResult result = OperationResult::kFailed; - item->Write(content, - base::Bind(&WriteCallback, run_loop.QuitClosure(), &result)); + item->Write(content, base::BindOnce(&WriteCallback, run_loop.QuitClosure(), + &result)); run_loop.Run(); return result; } @@ -224,8 +225,8 @@ OperationResult result = OperationResult::kFailed; std::unique_ptr<std::vector<char>> read_content; base::RunLoop run_loop; - item->Read(base::Bind(&ReadCallback, run_loop.QuitClosure(), &result, - &read_content)); + item->Read(base::BindOnce(&ReadCallback, run_loop.QuitClosure(), &result, + &read_content)); run_loop.Run(); if (data) *data = std::move(read_content);
diff --git a/extensions/browser/api/vpn_provider/vpn_provider_api.cc b/extensions/browser/api/vpn_provider/vpn_provider_api.cc index df1be5bc..f2a80c6 100644 --- a/extensions/browser/api/vpn_provider/vpn_provider_api.cc +++ b/extensions/browser/api/vpn_provider/vpn_provider_api.cc
@@ -205,12 +205,12 @@ // be used, requiring a mapping between the two. service->CreateConfiguration( extension_id(), extension()->name(), params->name, - base::Bind( + base::BindOnce( &VpnProviderCreateConfigFunction::SignalCallCompletionSuccessWithId, this, params->name), - base::Bind(&VpnProviderNotifyConnectionStateChangedFunction:: - SignalCallCompletionFailure, - this)); + base::BindOnce(&VpnProviderNotifyConnectionStateChangedFunction:: + SignalCallCompletionFailure, + this)); return RespondLater(); } @@ -233,11 +233,11 @@ service->DestroyConfiguration( extension_id(), params->id, - base::Bind(&VpnProviderDestroyConfigFunction::SignalCallCompletionSuccess, - this), - base::Bind(&VpnProviderNotifyConnectionStateChangedFunction:: - SignalCallCompletionFailure, - this)); + base::BindOnce( + &VpnProviderDestroyConfigFunction::SignalCallCompletionSuccess, this), + base::BindOnce(&VpnProviderNotifyConnectionStateChangedFunction:: + SignalCallCompletionFailure, + this)); return RespondLater(); } @@ -267,12 +267,12 @@ service->SetParameters( extension_id(), parameter_value, - base::Bind(&VpnProviderSetParametersFunction:: - SignalCallCompletionSuccessWithWarning, - this), - base::Bind(&VpnProviderNotifyConnectionStateChangedFunction:: - SignalCallCompletionFailure, - this)); + base::BindOnce(&VpnProviderSetParametersFunction:: + SignalCallCompletionSuccessWithWarning, + this), + base::BindOnce(&VpnProviderNotifyConnectionStateChangedFunction:: + SignalCallCompletionFailure, + this)); return RespondLater(); } @@ -325,12 +325,12 @@ service->NotifyConnectionStateChanged( extension_id(), params->state, - base::Bind(&VpnProviderNotifyConnectionStateChangedFunction:: - SignalCallCompletionSuccess, - this), - base::Bind(&VpnProviderNotifyConnectionStateChangedFunction:: - SignalCallCompletionFailure, - this)); + base::BindOnce(&VpnProviderNotifyConnectionStateChangedFunction:: + SignalCallCompletionSuccess, + this), + base::BindOnce(&VpnProviderNotifyConnectionStateChangedFunction:: + SignalCallCompletionFailure, + this)); return RespondLater(); }
diff --git a/extensions/browser/api/vpn_provider/vpn_service.cc b/extensions/browser/api/vpn_provider/vpn_service.cc index ea5f3286..65fd06b 100644 --- a/extensions/browser/api/vpn_provider/vpn_service.cc +++ b/extensions/browser/api/vpn_provider/vpn_service.cc
@@ -163,14 +163,14 @@ void Bind(const std::string& extension_id, const std::string& configuration_id, const std::string& configuration_name, - SuccessOnceCallback success, - FailureOnceCallback failure, + SuccessCallback success, + FailureCallback failure, std::unique_ptr<content::PepperVpnProviderResourceHostProxy> pepper_vpn_provider_proxy) override; void SendPacket(const std::string& extension_id, const std::vector<char>& data, - SuccessOnceCallback success, - FailureOnceCallback failure) override; + SuccessCallback success, + FailureCallback failure) override; private: base::WeakPtr<VpnService> vpn_service_; @@ -186,8 +186,8 @@ const std::string& extension_id, const std::string& configuration_id, const std::string& configuration_name, - SuccessOnceCallback success, - FailureOnceCallback failure, + SuccessCallback success, + FailureCallback failure, std::unique_ptr<content::PepperVpnProviderResourceHostProxy> pepper_vpn_provider_proxy) { if (!vpn_service_) { @@ -203,8 +203,8 @@ void VpnService::VpnServiceProxyImpl::SendPacket( const std::string& extension_id, const std::vector<char>& data, - SuccessOnceCallback success, - FailureOnceCallback failure) { + SuccessCallback success, + FailureCallback failure) { if (!vpn_service_) { NOTREACHED(); return; @@ -354,23 +354,24 @@ void VpnService::CreateConfiguration(const std::string& extension_id, const std::string& extension_name, const std::string& configuration_name, - const SuccessCallback& success, - const FailureCallback& failure) { + SuccessCallback success, + FailureCallback failure) { if (configuration_name.empty()) { - failure.Run(std::string(), std::string("Empty name not supported.")); + std::move(failure).Run(std::string(), + std::string("Empty name not supported.")); return; } const std::string key = GetKey(extension_id, configuration_name); if (base::Contains(key_to_configuration_map_, key)) { - failure.Run(std::string(), std::string("Name not unique.")); + std::move(failure).Run(std::string(), std::string("Name not unique.")); return; } const NetworkProfile* profile = network_profile_handler_->GetProfileForUserhash(userid_hash_); if (!profile) { - failure.Run( + std::move(failure).Run( std::string(), std::string("No user profile for unshared network configuration.")); return; @@ -396,27 +397,29 @@ network_configuration_handler_->CreateShillConfiguration( properties, - base::Bind(&VpnService::OnCreateConfigurationSuccess, - weak_factory_.GetWeakPtr(), success, configuration), - base::Bind(&VpnService::OnCreateConfigurationFailure, - weak_factory_.GetWeakPtr(), failure, configuration)); + base::BindOnce(&VpnService::OnCreateConfigurationSuccess, + weak_factory_.GetWeakPtr(), std::move(success), + configuration), + base::BindOnce(&VpnService::OnCreateConfigurationFailure, + weak_factory_.GetWeakPtr(), std::move(failure), + configuration)); } void VpnService::DestroyConfiguration(const std::string& extension_id, const std::string& configuration_id, - const SuccessCallback& success, - const FailureCallback& failure) { + SuccessCallback success, + FailureCallback failure) { // The ID is the configuration name for now. This may change in the future. const std::string key = GetKey(extension_id, configuration_id); if (!base::Contains(key_to_configuration_map_, key)) { - failure.Run(std::string(), std::string("Unauthorized access.")); + std::move(failure).Run(std::string(), std::string("Unauthorized access.")); return; } VpnConfiguration* configuration = key_to_configuration_map_[key].get(); const std::string service_path = configuration->service_path(); if (service_path.empty()) { - failure.Run(std::string(), std::string("Pending create.")); + std::move(failure).Run(std::string(), std::string("Pending create.")); return; } if (active_configuration_ == configuration) { @@ -427,29 +430,29 @@ network_configuration_handler_->RemoveConfiguration( service_path, /*remove_confirmer=*/base::nullopt, - base::Bind(&VpnService::OnRemoveConfigurationSuccess, - weak_factory_.GetWeakPtr(), success), - base::Bind(&VpnService::OnRemoveConfigurationFailure, - weak_factory_.GetWeakPtr(), failure)); + base::BindOnce(&VpnService::OnRemoveConfigurationSuccess, + weak_factory_.GetWeakPtr(), std::move(success)), + base::BindOnce(&VpnService::OnRemoveConfigurationFailure, + weak_factory_.GetWeakPtr(), std::move(failure))); } void VpnService::SetParameters(const std::string& extension_id, const base::DictionaryValue& parameters, - const StringCallback& success, - const FailureCallback& failure) { + StringCallback success, + FailureCallback failure) { if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { - failure.Run(std::string(), std::string("Unauthorized access.")); + std::move(failure).Run(std::string(), std::string("Unauthorized access.")); return; } shill_client_->SetParameters(active_configuration_->object_path(), parameters, - success, failure); + std::move(success), std::move(failure)); } void VpnService::SendPacket(const std::string& extension_id, const std::vector<char>& data, - SuccessOnceCallback success, - FailureOnceCallback failure) { + SuccessCallback success, + FailureCallback failure) { if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { std::move(failure).Run(std::string(), std::string("Unauthorized access.")); return; @@ -467,16 +470,16 @@ void VpnService::NotifyConnectionStateChanged(const std::string& extension_id, api_vpn::VpnConnectionState state, - const SuccessCallback& success, - const FailureCallback& failure) { + SuccessCallback success, + FailureCallback failure) { if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id)) { - failure.Run(std::string(), std::string("Unauthorized access.")); + std::move(failure).Run(std::string(), std::string("Unauthorized access.")); return; } shill_client_->UpdateConnectionState(active_configuration_->object_path(), - static_cast<uint32_t>(state), success, - failure); + static_cast<uint32_t>(state), + std::move(success), std::move(failure)); } bool VpnService::VerifyConfigExistsForTesting( @@ -504,7 +507,7 @@ DestroyConfiguration(extension->id(), // Extension ID iter->configuration_name(), // Configuration name base::DoNothing(), - base::Bind(DoNothingFailureCallback)); + base::BindOnce(DoNothingFailureCallback)); } } @@ -543,7 +546,7 @@ } void VpnService::OnCreateConfigurationSuccess( - const VpnService::SuccessCallback& callback, + VpnService::SuccessCallback callback, VpnConfiguration* configuration, const std::string& service_path, const std::string& guid) { @@ -551,28 +554,28 @@ service_path_to_configuration_map_[service_path] = configuration; shill_client_->AddShillThirdPartyVpnObserver(configuration->object_path(), configuration); - callback.Run(); + std::move(callback).Run(); } void VpnService::OnCreateConfigurationFailure( - const VpnService::FailureCallback& callback, + VpnService::FailureCallback callback, VpnConfiguration* configuration, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { DestroyConfigurationInternal(configuration); - callback.Run(error_name, std::string()); + std::move(callback).Run(error_name, std::string()); } void VpnService::OnRemoveConfigurationSuccess( - const VpnService::SuccessCallback& callback) { - callback.Run(); + VpnService::SuccessCallback callback) { + std::move(callback).Run(); } void VpnService::OnRemoveConfigurationFailure( - const VpnService::FailureCallback& callback, + VpnService::FailureCallback callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data) { - callback.Run(error_name, std::string()); + std::move(callback).Run(error_name, std::string()); } void VpnService::SendSignalToExtension( @@ -625,8 +628,8 @@ const std::string& extension_id, const std::string& configuration_id, const std::string& configuration_name, - SuccessOnceCallback success, - FailureOnceCallback failure, + SuccessCallback success, + FailureCallback failure, std::unique_ptr<content::PepperVpnProviderResourceHostProxy> pepper_vpn_provider_proxy) { // The ID is the configuration name for now. This may change in the future.
diff --git a/extensions/browser/api/vpn_provider/vpn_service.h b/extensions/browser/api/vpn_provider/vpn_service.h index d25eb13..7482a50 100644 --- a/extensions/browser/api/vpn_provider/vpn_service.h +++ b/extensions/browser/api/vpn_provider/vpn_service.h
@@ -55,17 +55,12 @@ public NetworkStateHandlerObserver, public extensions::ExtensionRegistryObserver { public: - using SuccessOnceCallback = base::OnceClosure; - using StringCallback = base::Callback<void(const std::string& result)>; - using FailureOnceCallback = + using SuccessCallback = base::OnceClosure; + using StringCallback = base::OnceCallback<void(const std::string& result)>; + using FailureCallback = base::OnceCallback<void(const std::string& error_name, const std::string& error_message)>; - // TODO(crbug.com/1007786): Delete these and rename the OnceCallback versions - // to replace these once they are no longer used. - using SuccessCallback = base::Callback<SuccessOnceCallback::RunType>; - using FailureCallback = base::Callback<FailureOnceCallback::RunType>; - VpnService(content::BrowserContext* browser_context, const std::string& userid_hash, extensions::ExtensionRegistry* extension_registry, @@ -106,32 +101,32 @@ void CreateConfiguration(const std::string& extension_id, const std::string& extension_name, const std::string& configuration_name, - const SuccessCallback& success, - const FailureCallback& failure); + SuccessCallback success, + FailureCallback failure); // Destroys the VPN configuration with |configuration_id| after verifying that // it belongs to the extension with id |extension_id|. // Calls |success| or |failure| based on the outcome. void DestroyConfiguration(const std::string& extension_id, const std::string& configuration_id, - const SuccessCallback& success, - const FailureCallback& failure); + SuccessCallback success, + FailureCallback failure); // Set |parameters| for the active VPN configuration after verifying that it // belongs to the extension with id |extension_id|. // Calls |success| or |failure| based on the outcome. void SetParameters(const std::string& extension_id, const base::DictionaryValue& parameters, - const StringCallback& success, - const FailureCallback& failure); + StringCallback success, + FailureCallback failure); // Sends an IP packet contained in |data| to the active VPN configuration // after verifying that it belongs to the extension with id |extension_id|. // Calls |success| or |failure| based on the outcome. void SendPacket(const std::string& extension_id, const std::vector<char>& data, - SuccessOnceCallback success, - FailureOnceCallback failure); + SuccessCallback success, + FailureCallback failure); // Notifies connection state |state| to the active VPN configuration after // verifying that it belongs to the extension with id |extension_id|. @@ -139,8 +134,8 @@ void NotifyConnectionStateChanged( const std::string& extension_id, extensions::api::vpn_provider::VpnConnectionState state, - const SuccessCallback& success, - const FailureCallback& failure); + SuccessCallback success, + FailureCallback failure); // Verifies if a configuration with name |configuration_name| exists for the // extension with id |extension_id|. @@ -173,24 +168,24 @@ std::map<std::string, std::unique_ptr<VpnConfiguration>>; // Callback used to indicate that configuration was successfully created. - void OnCreateConfigurationSuccess(const SuccessCallback& callback, + void OnCreateConfigurationSuccess(SuccessCallback callback, VpnConfiguration* configuration, const std::string& service_path, const std::string& guid); // Callback used to indicate that configuration creation failed. void OnCreateConfigurationFailure( - const FailureCallback& callback, + FailureCallback callback, VpnConfiguration* configuration, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data); // Callback used to indicate that removing a configuration succeeded. - void OnRemoveConfigurationSuccess(const SuccessCallback& callback); + void OnRemoveConfigurationSuccess(SuccessCallback callback); // Callback used to indicate that removing a configuration failed. void OnRemoveConfigurationFailure( - const FailureCallback& callback, + FailureCallback callback, const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data); @@ -228,8 +223,8 @@ void Bind(const std::string& extension_id, const std::string& configuration_id, const std::string& configuration_name, - SuccessOnceCallback success, - FailureOnceCallback failure, + SuccessCallback success, + FailureCallback failure, std::unique_ptr<content::PepperVpnProviderResourceHostProxy> pepper_vpn_provider_proxy);
diff --git a/infra/config/dev/dev.star b/infra/config/dev/dev.star index 4b7a49c..c75f222 100644 --- a/infra/config/dev/dev.star +++ b/infra/config/dev/dev.star
@@ -53,8 +53,12 @@ ], ) -# Launch Swarming tasks in "realms-aware mode", crbug.com/1136313. -luci.builder.defaults.experiments.set({"luci.use_realms": 100}) +luci.builder.defaults.experiments.set({ + # Launch Swarming tasks in "realms-aware mode", crbug.com/1136313. + "luci.use_realms": 100, + # Enable resultsink for dev swarming tasks. + "chromium.resultdb.result_sink": 100, +}) exec("//dev/swarming.star")
diff --git a/infra/config/generated/cr-buildbucket-dev.cfg b/infra/config/generated/cr-buildbucket-dev.cfg index f4521ee..43b976c 100644 --- a/infra/config/generated/cr-buildbucket-dev.cfg +++ b/infra/config/generated/cr-buildbucket-dev.cfg
@@ -40,6 +40,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -71,6 +75,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -102,6 +110,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -134,6 +146,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -165,6 +181,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -196,6 +216,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 } @@ -227,6 +251,10 @@ build_numbers: YES service_account: "chromium-ci-builder-dev@chops-service-accounts.iam.gserviceaccount.com" experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { key: "luci.use_realms" value: 100 }
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd index af8d7c2c..edd1fdf 100644 --- a/ios/chrome/app/strings/ios_chromium_strings.grd +++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -214,6 +214,9 @@ <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_CHROME_DATA" desc="Turns off and on all the sync data (like bookmarks, history and others). [iOS only]"> Sync Your Chromium Data </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON" desc="Text for system biometric authentication dialog to explain why authentication is required when the user attempts to enable the setting to protect incognito tabs with biometric auth. [iOS only]"> + Let Chromium lock your Incognito tabs. + </message> <message name="IDS_IOS_LOCATION_AUTHORIZATION_ALERT" desc="Specifies the reason for sending the user's location to Google [Length: unlimited] [iOS only]."> Get a better Google experience in Chromium based on your location. </message>
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1 new file mode 100644 index 0000000..d6bc0ffa --- /dev/null +++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1
@@ -0,0 +1 @@ +78589957693ed0e9f957f06852fa1f6d0bdac1d7 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index 785fd1f..b6e4558 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -214,6 +214,9 @@ <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_CHROME_DATA" desc="Turns off and on all the sync data (like bookmarks, history and others). [iOS only]"> Sync Your Chrome Data </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON" desc="Text for system biometric authentication dialog to explain why authentication is required when the user attempts to enable the setting to protect incognito tabs with biometric auth. [iOS only]"> + Let Chrome lock your Incognito tabs. + </message> <message name="IDS_IOS_LOCATION_AUTHORIZATION_ALERT" desc="Specifies the reason for sending the user's location to Google [Length: unlimited] [iOS only]."> Get a better Google experience in Chrome based on your location. </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1 new file mode 100644 index 0000000..d6bc0ffa --- /dev/null +++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON.png.sha1
@@ -0,0 +1 @@ +78589957693ed0e9f957f06852fa1f6d0bdac1d7 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 28c872b..618485a 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -930,6 +930,24 @@ <message name="IDS_IOS_ICON_SEARCH" desc="Accessibility label for the search icon [iOS only]."> Search </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_SYSTEM_DIALOG_REASON" desc="Text for system biometric authentication dialog to explain why authentication is required when the user attempts to authenticate to access incognito tabs. [iOS only]"> + Use <ph name="BIOMETRIC_AUTHENITCATION_TYPE">$1<ex>Face ID</ex></ph> to unlock your Incognito tabs. + </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS" desc="Button to go to non-incognito tabs on a screen that blocks incognito tabs until biometric authetication. [iOS only]"> + See Other Tabs + </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON" desc="Button to initiate biometric authentication on a screen that blocks incognito tabs until biometric authetication. [iOS only]"> + Unlock With <ph name="BIOMETRIC_AUTHENITCATION_TYPE">$1<ex>Face ID</ex></ph> + </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON_VOICEOVER_LABEL" desc="Voiceover label on the button that starts biometric authentication on a screen that blocks incognito tabs until biometric authetication. [iOS only]"> + Unlock Incognito Tabs With <ph name="BIOMETRIC_AUTHENITCATION_TYPE">$1<ex>Face ID</ex></ph> + </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_SETTING_NAME" desc="Name of the Setting to protect incognito tabs with biometric authentication, e.g. Face ID or Touch ID. [iOS only]"> + Lock Incognito tabs when you close Chrome + </message> + <message name="IDS_IOS_INCOGNITO_REAUTH_PASSCODE" desc="The passcode (pin code or password) used instead of biometric authentication, e.g. Face ID or Touch ID, for device authentication. [iOS only]"> + Passcode + </message> <message name="IDS_IOS_INFO_BUTTON_ACCESSIBILITY_HINT" desc="Action hint for the info button of the TableViewInfoButtonCell. This is spoken by VoiceOver. [iOS only]"> Double tap for more information </message> @@ -2312,6 +2330,18 @@ <message name="IDS_IOS_TAB_GRID_INCOGNITO_TABS_EMPTY_TITLE" desc="Title shown above a message on the incognito tab switcher when there are no incognito tabs. [iOS only]"> You'll find your Incognito tabs here </message> + <message name="IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_MESSAGE" desc="Message shown in the Incognito Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to disabled. [iOS only]"> + Your organization turned off private browsing. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> + </message> + <message name="IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_TITLE" desc="Title shown above a message in the Incognito Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to disabled. [iOS only]"> + Incognito Mode is Unavailable + </message> + <message name="IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_MESSAGE" desc="Message shown in the Recent Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to forced. [iOS only]"> + Your organization requires you to browse privately. Tabs aren't saved in Incognito mode. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> + </message> + <message name="IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_TITLE" desc="Title shown above a message in the Recent Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to forced. [iOS only]"> + Recent Tabs are Unavailable + </message> <message name="IDS_IOS_TAB_GRID_REGULAR_TABS_EMPTY_STATE_TITLE" desc="Title shown in the Regular Tabs page (as opposed to the Incognito Tabs page) when the grid is empty. [iOS only]"> No Open Tabs </message> @@ -2327,6 +2357,12 @@ <message name="IDS_IOS_TAB_GRID_REGULAR_TABS_EMPTY_MESSAGE" desc="Message shown underneath a title on the regular tab switcher when there are no tabs, explaining why to use the regular tab switcher. [iOS only]"> Open tabs to visit different pages at the same time </message> + <message name="IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_MESSAGE" desc="Message shown in the Regular Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to forced. [iOS only]"> + Your organization requires you to browse privately. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> + </message> + <message name="IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_TITLE" desc="Title shown above a message in the Regular Tabs page of the tab grid when the IncognitoModeAvailability enterprise policy is set to forced. [iOS only]"> + Only Incognito Mode is Available + </message> <message name="IDS_IOS_TAB_GRID_CREATE_NEW_INCOGNITO_TAB" desc="The accessibility label for the button that creates new incognito tabs. [iOS only]"> Create new incognito tab. </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS.png.sha1 new file mode 100644 index 0000000..b66e8bbd --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS.png.sha1
@@ -0,0 +1 @@ +1c374800107fa7411922002566f6c1b9625103a3 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_PASSCODE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_PASSCODE.png.sha1 new file mode 100644 index 0000000..61ee5bb --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_PASSCODE.png.sha1
@@ -0,0 +1 @@ +02856c37a70520d0a72ae9fc6e99b12f718f58b4 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SETTING_NAME.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SETTING_NAME.png.sha1 new file mode 100644 index 0000000..bf323223 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SETTING_NAME.png.sha1
@@ -0,0 +1 @@ +4f06b511b226e1cccc3abacd6362998af0c1703c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SYSTEM_DIALOG_REASON.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SYSTEM_DIALOG_REASON.png.sha1 new file mode 100644 index 0000000..17c3350 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_SYSTEM_DIALOG_REASON.png.sha1
@@ -0,0 +1 @@ +d65960a3254c617dbdd2777dfe09c5c8d0b9123b \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON.png.sha1 new file mode 100644 index 0000000..b66e8bbd --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON.png.sha1
@@ -0,0 +1 @@ +1c374800107fa7411922002566f6c1b9625103a3 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON_VOICEOVER_LABEL.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON_VOICEOVER_LABEL.png.sha1 new file mode 100644 index 0000000..b66e8bbd --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON_VOICEOVER_LABEL.png.sha1
@@ -0,0 +1 @@ +1c374800107fa7411922002566f6c1b9625103a3 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_MESSAGE.png.sha1 new file mode 100644 index 0000000..1c6a10b --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +fe6825ceac5003ce617dffa5601b32e1c330fd27 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_TITLE.png.sha1 new file mode 100644 index 0000000..1b61715a --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_INCOGNITO_TABS_UNAVAILABLE_TITLE.png.sha1
@@ -0,0 +1 @@ +8baa7028337b30506a7e4fa9b60355870e0048d6 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_MESSAGE.png.sha1 new file mode 100644 index 0000000..1e6b87f4 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +5c261cec0cd219677f6e4e9d6f660d082951c6b4 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_TITLE.png.sha1 new file mode 100644 index 0000000..cee5da9 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_RECENT_TABS_UNAVAILABLE_TITLE.png.sha1
@@ -0,0 +1 @@ +31de1cbb899faa1b47c4476bb7d62b102656d4ab \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_MESSAGE.png.sha1 new file mode 100644 index 0000000..f8344e456 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_MESSAGE.png.sha1
@@ -0,0 +1 @@ +bb7821a31452dae47c50fdb6c32371e7e4aa9dfa \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_TITLE.png.sha1 new file mode 100644 index 0000000..5012f3d2 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TAB_GRID_REGULAR_TABS_UNAVAILABLE_TITLE.png.sha1
@@ -0,0 +1 @@ +eac9f509403b34bea25b03d710df4db7b5b36fa3 \ No newline at end of file
diff --git a/ios/chrome/browser/complex_tasks/ios_task_tab_helper_unittest.mm b/ios/chrome/browser/complex_tasks/ios_task_tab_helper_unittest.mm index b987182..ad9b57b 100644 --- a/ios/chrome/browser/complex_tasks/ios_task_tab_helper_unittest.mm +++ b/ios/chrome/browser/complex_tasks/ios_task_tab_helper_unittest.mm
@@ -8,7 +8,6 @@ #import "ios/web/public/test/fakes/fake_navigation_context.h" #import "ios/web/public/test/fakes/fake_navigation_manager.h" #import "ios/web/public/test/fakes/fake_web_state.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" #import "ios/web/public/test/web_test_with_web_state.h" #include "url/gurl.h"
diff --git a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.h b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.h index 8b4f10e9..d5cde26a 100644 --- a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.h +++ b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.h
@@ -51,6 +51,10 @@ - (void)finishPageLoadForWebState:(web::WebState*)webState loadSuccess:(BOOL)loadSuccess; +// Marks the user as new without triggering the iOS system prompt to authorize +// the use of location +- (void)systemPromptSkippedForNewUser; + @end #endif // IOS_CHROME_BROWSER_GEOLOCATION_OMNIBOX_GEOLOCATION_CONTROLLER_H_
diff --git a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm index cdc01ad..0664fb227 100644 --- a/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm +++ b/ios/chrome/browser/geolocation/omnibox_geolocation_controller.mm
@@ -369,6 +369,10 @@ } } +- (void)systemPromptSkippedForNewUser { + _newUser = YES; +} + #pragma mark - Private - (BOOL)enabled {
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm index 6df0224b..a453d1f 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
@@ -12,7 +12,7 @@ #include "ios/chrome/browser/passwords/ios_chrome_change_password_url_service_factory.h" #import "ios/web/public/navigation/navigation_manager.h" #import "ios/web/public/test/fakes/fake_web_client.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #import "ios/web/public/test/navigation_test_util.h" #include "ios/web/public/test/web_task_environment.h" #include "ios/web/public/test/web_test.h" @@ -156,7 +156,7 @@ std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request); network::TestURLLoaderFactory test_url_loader_factory_; - web::TestWebStateDelegate delegate_; + web::FakeWebStateDelegate delegate_; }; GURL WellKnownChangePasswordTabHelperTest::GetNavigatedUrl() const { @@ -165,7 +165,7 @@ GURL url = web_state()->GetCurrentURL(&trust_level); // When redirecting with WebState::OpenURL() |web_state_| is not // updated, we only see the registered request in - // TestWebStateDelegate::last_open_url_request(). + // FakeWebStateDelegate::last_open_url_request(). if (delegate_.last_open_url_request()) { url = delegate_.last_open_url_request()->params.url; }
diff --git a/ios/chrome/browser/ui/first_run/location_permissions_coordinator.mm b/ios/chrome/browser/ui/first_run/location_permissions_coordinator.mm index 2afd99ab..e086211 100644 --- a/ios/chrome/browser/ui/first_run/location_permissions_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/location_permissions_coordinator.mm
@@ -4,6 +4,8 @@ #import "ios/chrome/browser/ui/first_run/location_permissions_coordinator.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h" #import "ios/chrome/browser/ui/first_run/location_permissions_view_controller.h" #import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h" @@ -12,7 +14,23 @@ #error "This file requires ARC support." #endif -@interface LocationPermissionsCoordinator () <ConfirmationAlertActionHandler> +namespace { + +// Histogram enum values for the user engagement of this modal. +enum class LocationPermissionsFirstRunModalIOSEnum { + // The primary action button was tapped. The system prompt is shown. + kLocationPromptShown = 0, + // The First Run location permissions modal was dismissed. + kDismissed = 1, + // kMaxValue should share the value of the highest enumerator. + kMaxValue = kDismissed, +}; + +} + +@interface LocationPermissionsCoordinator () < + ConfirmationAlertActionHandler, + UIAdaptivePresentationControllerDelegate> // The fullscreen confirmation modal promo view controller this coordiantor // manages. @@ -31,6 +49,7 @@ self.locationPermissionsViewController.actionHandler = self; self.locationPermissionsViewController.modalPresentationStyle = UIModalPresentationFormSheet; + self.locationPermissionsViewController.presentationController.delegate = self; [self.baseViewController presentViewController:self.locationPermissionsViewController animated:YES @@ -45,16 +64,30 @@ [super stop]; } +#pragma mark - UIAdaptivePresentationControllerDelegate + +- (void)presentationControllerDidDismiss: + (UIPresentationController*)presentationController { + [self logModalInteractionForAction:LocationPermissionsFirstRunModalIOSEnum:: + kDismissed]; + [[OmniboxGeolocationController sharedInstance] systemPromptSkippedForNewUser]; +} + #pragma mark - ConfirmationAlertActionHandler - (void)confirmationAlertPrimaryAction { + [self logModalInteractionForAction:LocationPermissionsFirstRunModalIOSEnum:: + kLocationPromptShown]; [self.handler dismissLocationPermissionsExplanationModal]; [[OmniboxGeolocationController sharedInstance] triggerSystemPromptForNewUser:YES]; } - (void)confirmationAlertSecondaryAction { + [self logModalInteractionForAction:LocationPermissionsFirstRunModalIOSEnum:: + kDismissed]; [self.handler dismissLocationPermissionsExplanationModal]; + [[OmniboxGeolocationController sharedInstance] systemPromptSkippedForNewUser]; } - (void)confirmationAlertDismissAction { @@ -65,4 +98,12 @@ // No-op. } +#pragma mark - Private + +- (void)logModalInteractionForAction: + (LocationPermissionsFirstRunModalIOSEnum)action { + base::UmaHistogramEnumeration( + "IOS.LocationPermissions.FirstRunModal.Interaction", action); +} + @end
diff --git a/ios/chrome/browser/ui/incognito_reauth/BUILD.gn b/ios/chrome/browser/ui/incognito_reauth/BUILD.gn index 27e265c7..5a9be57 100644 --- a/ios/chrome/browser/ui/incognito_reauth/BUILD.gn +++ b/ios/chrome/browser/ui/incognito_reauth/BUILD.gn
@@ -10,6 +10,22 @@ frameworks = [ "UIKit.framework" ] } +source_set("incognito_reauth_util") { + configs += [ "//build/config/compiler:enable_arc" ] + sources = [ + "incognito_reauth_util.h", + "incognito_reauth_util.mm", + ] + deps = [ + "//ios/chrome/app/strings:ios_strings_grit", + "//ui/base", + ] + frameworks = [ + "UIKit.framework", + "LocalAuthentication.framework", + ] +} + source_set("incognito_reauth_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ @@ -17,11 +33,13 @@ "incognito_reauth_view.h", "incognito_reauth_view.mm", ] - deps = [ "//ios/chrome/common/ui/util" ] - frameworks = [ - "UIKit.framework", - "LocalAuthentication.framework", + deps = [ + ":incognito_reauth_util", + "//ios/chrome/app/strings:ios_strings_grit", + "//ios/chrome/common/ui/util", + "//ui/base", ] + frameworks = [ "UIKit.framework" ] } source_set("incognito_reauth_scene_agent") { @@ -35,9 +53,11 @@ deps = [ ":incognito_reauth_commands", ":incognito_reauth_ui", + ":incognito_reauth_util", "//base", "//components/pref_registry", "//components/prefs", + "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser", "//ios/chrome/browser:pref_names", "//ios/chrome/browser/ui:feature_flags", @@ -46,6 +66,7 @@ "//ios/chrome/browser/ui/util:multiwindow_util", "//ios/chrome/browser/web_state_list", "//ios/chrome/common/ui/reauthentication", + "//ui/base", ] frameworks = [ "UIKit.framework" ] }
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.mm b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.mm index 787209d9..d7f9071 100644 --- a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.mm +++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.mm
@@ -6,15 +6,19 @@ #include "base/check.h" #import "base/ios/crb_protocol_observers.h" +#include "base/strings/sys_string_conversions.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "ios/chrome/browser/application_context.h" #import "ios/chrome/browser/main/browser.h" #include "ios/chrome/browser/pref_names.h" +#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h" #import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/common/ui/reauthentication/reauthentication_protocol.h" +#include "ios/chrome/grit/ios_strings.h" +#include "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -81,11 +85,13 @@ return; } + NSString* authReason = l10n_util::GetNSStringF( + IDS_IOS_INCOGNITO_REAUTH_SYSTEM_DIALOG_REASON, + base::SysNSStringToUTF16(biometricAuthenticationTypeString())); + __weak IncognitoReauthSceneAgent* weakSelf = self; - // TODO(crbug.com/1138892): add localized text [self.reauthModule - attemptReauthWithLocalizedReason: - @"[Test String] Authenticate for incognito access" + attemptReauthWithLocalizedReason:authReason canReusePreviousAuth:false handler:^(ReauthenticationResult result) { BOOL success =
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h new file mode 100644 index 0000000..7ddea91d --- /dev/null +++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h
@@ -0,0 +1,13 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_UTIL_H_ +#define IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_UTIL_H_ + +#import <Foundation/Foundation.h> + +// A string defining the authentication type, e.g. "Face ID" or "Touch ID". +NSString* biometricAuthenticationTypeString(); + +#endif // IOS_CHROME_BROWSER_UI_INCOGNITO_REAUTH_INCOGNITO_REAUTH_UTIL_H_
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.mm b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.mm new file mode 100644 index 0000000..d724d69 --- /dev/null +++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.mm
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h" + +#import <LocalAuthentication/LocalAuthentication.h> +#include "ios/chrome/grit/ios_strings.h" +#include "ui/base/l10n/l10n_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +NSString* biometricAuthenticationTypeString() { + LAContext* ctx = [[LAContext alloc] init]; + // Call canEvaluatePolicy:error: once to populate biometrics type + [ctx canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics + error:nil]; + switch (ctx.biometryType) { + case LABiometryTypeFaceID: + return @"Face ID"; + case LABiometryTypeTouchID: + return @"Touch ID"; + default: + return l10n_util::GetNSString(IDS_IOS_INCOGNITO_REAUTH_PASSCODE); + } +}
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm index 274b8331..807c2cfc 100644 --- a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm +++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm
@@ -4,9 +4,11 @@ #import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.h" -#import <LocalAuthentication/LocalAuthentication.h> - +#include "base/strings/sys_string_conversions.h" +#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_util.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" +#include "ios/chrome/grit/ios_strings.h" +#include "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -35,16 +37,21 @@ blurBackgroundView.isAccessibilityElement = YES; AddSameConstraints(self, blurBackgroundView); + NSString* unlockButtonTitle = l10n_util::GetNSStringF( + IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON, + base::SysNSStringToUTF16(biometricAuthenticationTypeString())); _authenticateButton = [IncognitoReauthView newRoundButtonWithBlurEffect:blurEffect]; - [_authenticateButton - setTitle:[IncognitoReauthView authenticationActionLabel] - forState:UIControlStateNormal]; + [_authenticateButton setTitle:unlockButtonTitle + forState:UIControlStateNormal]; + _authenticateButton.accessibilityLabel = l10n_util::GetNSStringF( + IDS_IOS_INCOGNITO_REAUTH_UNLOCK_BUTTON_VOICEOVER_LABEL, + base::SysNSStringToUTF16(biometricAuthenticationTypeString())); _tabSwitcherButton = [IncognitoReauthView newRoundButtonWithBlurEffect:blurEffect]; - // TODO(crbug.com/1138892): add localized text. - [_tabSwitcherButton setTitle:@"[Test String] Go to Tab Switcher" + [_tabSwitcherButton setTitle:l10n_util::GetNSString( + IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS) forState:UIControlStateNormal]; UIStackView* stackView = [[UIStackView alloc] @@ -59,22 +66,6 @@ return self; } -+ (NSString*)authenticationActionLabel { - LAContext* ctx = [[LAContext alloc] init]; - // Call canEvaluatePolicy:error: once to populate biometrics type - [ctx canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics - error:nil]; - switch (ctx.biometryType) { - case LABiometryTypeFaceID: - return @"Face ID"; - case LABiometryTypeTouchID: - return @"Touch ID"; - default: - // TODO(crbug.com/1138892): add localized text. - return @"[Test String] Passcode"; - } -} - + (UIButton*)newRoundButtonWithBlurEffect:(UIBlurEffect*)blurEffect { UIButton* button = [[UIButton alloc] init]; button.backgroundColor = [UIColor clearColor];
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 4e372c1..0b811564 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -952,6 +952,12 @@ // opportunity to present the iOS system location alert. [[OmniboxGeolocationController sharedInstance] triggerSystemPromptForNewUser:YES]; + } else if (location_permissions_field_trial:: + IsInRemoveFirstRunPromptGroup()) { + // If in RemoveFirstRunPrompt group, the system prompt will be delayed until + // the site requests location information. + [[OmniboxGeolocationController sharedInstance] + systemPromptSkippedForNewUser]; } }
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index 8f18cd4..31156805 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -146,6 +146,7 @@ "//ios/chrome/browser/ui/alert_coordinator", "//ios/chrome/browser/ui/authentication", "//ios/chrome/browser/ui/authentication/cells", + "//ios/chrome/browser/ui/authentication/signin:signin_headers", "//ios/chrome/browser/ui/autofill/cells", "//ios/chrome/browser/ui/colors", "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h index b55e71f..9c755a6 100644 --- a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h +++ b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h
@@ -10,7 +10,14 @@ // Static popover presenting the information of the enterprise. @interface EnterpriseInfoPopoverViewController : PopoverLabelViewController -- (instancetype)initWithEnterpriseName:(NSString*)enterpriseName +// Initializes the popover with default primary text, and secondary text based +// on the given |enterpriseName|. +- (instancetype)initWithEnterpriseName:(NSString*)enterpriseName; + +// Initializes the popover with the given |message| as primary text, and +// secondary text based on the given |enterpriseName|. +- (instancetype)initWithMessage:(NSString*)message + enterpriseName:(NSString*)enterpriseName NS_DESIGNATED_INITIALIZER; - (instancetype)initWithMessage:(NSString*)message NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm index b3f2c7ad..94d9f83 100644 --- a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm +++ b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm
@@ -24,9 +24,8 @@ NSString* const kChromeManagementURL = @"chrome://management"; -NSAttributedString* PrimaryMessage() { - NSString* fullText = - l10n_util::GetNSString(IDS_IOS_ENTERPRISE_MANAGED_SETTING_MESSAGE); +NSAttributedString* PrimaryMessage(NSString* fullText) { + DCHECK(fullText); NSDictionary* generalAttributes = @{ NSForegroundColorAttributeName : [UIColor colorNamed:kTextPrimaryColor], NSFontAttributeName : [UIFont preferredFontForTextStyle:UIFontTextStyleBody] @@ -98,8 +97,15 @@ @implementation EnterpriseInfoPopoverViewController - (instancetype)initWithEnterpriseName:(NSString*)enterpriseName { + NSString* message = + l10n_util::GetNSString(IDS_IOS_ENTERPRISE_MANAGED_SETTING_MESSAGE); + return [self initWithMessage:message enterpriseName:enterpriseName]; +} + +- (instancetype)initWithMessage:(NSString*)message + enterpriseName:(NSString*)enterpriseName { return - [super initWithPrimaryAttributedString:PrimaryMessage() + [super initWithPrimaryAttributedString:PrimaryMessage(message) secondaryAttributedString:SecondaryMessage(enterpriseName)]; }
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm index 91b2e070..ce337ea 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
@@ -214,8 +214,8 @@ } _incognitoReauthItem = [[SettingsSwitchItem alloc] initWithType:ItemTypeIncognitoReauth]; - // TODO(crbug.com/1138892) : add localized string. - _incognitoReauthItem.text = @"[Test String] Incognito Authentication"; + _incognitoReauthItem.text = + l10n_util::GetNSString(IDS_IOS_INCOGNITO_REAUTH_SETTING_NAME); _incognitoReauthItem.on = self.incognitoReauthPref.value; return _incognitoReauthItem; } @@ -342,10 +342,10 @@ switchView.on = false; } else { __weak PrivacyTableViewController* weakSelf = self; - // TODO(crbug.com/1138892): add localized text [self.reauthModule attemptReauthWithLocalizedReason: - @"[Test String] Authenticate for incognito access" + l10n_util::GetNSString( + IDS_IOS_INCOGNITO_REAUTH_SET_UP_SYSTEM_DIALOG_REASON) canReusePreviousAuth:false handler:^(ReauthenticationResult result) { BOOL success =
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index ede7673..a5c9742 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -48,6 +48,7 @@ #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h" #import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h" #import "ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h" +#import "ios/chrome/browser/ui/authentication/signin/signin_utils.h" #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/settings/about_chrome_table_view_controller.h" @@ -396,7 +397,13 @@ AuthenticationService* authService = AuthenticationServiceFactory::GetForBrowserState(_browserState); - if (!authService->IsAuthenticated()) { + // If sign-in is disabled by policy, replace the sign-in / account section + // with an info button view item. + if (!signin::IsSigninAllowed(_browserState->GetPrefs())) { + [model addSectionWithIdentifier:SettingsSectionIdentifierSignIn]; + [model addItem:[self signinDisabledTextItem] + toSectionWithIdentifier:SettingsSectionIdentifierSignIn]; + } else if (!authService->IsAuthenticated()) { // Sign in section [model addSectionWithIdentifier:SettingsSectionIdentifierSignIn]; if ([SigninPromoViewMediator @@ -558,6 +565,26 @@ return signInTextItem; } +- (TableViewItem*)signinDisabledTextItem { + TableViewInfoButtonItem* signinDisabledItem = [[TableViewInfoButtonItem alloc] + initWithType:SettingsItemTypeSigninDisabled]; + signinDisabledItem.text = + l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_TITLE); + signinDisabledItem.detailText = + l10n_util::GetNSString(IDS_IOS_SETTINGS_SIGNIN_DISABLED); + signinDisabledItem.accessibilityHint = + l10n_util::GetNSString(IDS_IOS_TOGGLE_SETTING_MANAGED_ACCESSIBILITY_HINT); + signinDisabledItem.accessibilityIdentifier = kSettingsSignInDisabledCellId; + signinDisabledItem.image = + CircularImageFromImage(ios::GetChromeBrowserProvider() + ->GetSigninResourcesProvider() + ->GetDefaultAvatar(), + kAccountProfilePhotoDimension); + signinDisabledItem.textColor = [UIColor colorNamed:kTextSecondaryColor]; + signinDisabledItem.tintColor = [UIColor colorNamed:kGrey300Color]; + return signinDisabledItem; +} + - (TableViewItem*)googleServicesCellItem { return [self detailItemWithType:SettingsItemTypeGoogleServices text:l10n_util::GetNSString( @@ -643,7 +670,8 @@ initWithType:SettingsItemTypeManagedDefaultSearchEngine]; managedDefaultSearchEngineItem.text = l10n_util::GetNSString(IDS_IOS_SEARCH_ENGINE_SETTING_TITLE); - managedDefaultSearchEngineItem.iconImageName = kSettingsSearchEngineImageName; + managedDefaultSearchEngineItem.image = + [UIImage imageNamed:kSettingsSearchEngineImageName]; managedDefaultSearchEngineItem.accessibilityHint = l10n_util::GetNSString(IDS_IOS_TOGGLE_SETTING_MANAGED_ACCESSIBILITY_HINT); @@ -959,6 +987,15 @@ forControlEvents:UIControlEventTouchUpInside]; break; } + case SettingsItemTypeSigninDisabled: { + TableViewInfoButtonCell* managedCell = + base::mac::ObjCCastStrict<TableViewInfoButtonCell>(cell); + [managedCell.trailingButton + addTarget:self + action:@selector(didTapSigninDisabledInfoButton:) + forControlEvents:UIControlEventTouchUpInside]; + break; + } default: break; } @@ -1097,13 +1134,33 @@ #pragma mark - Actions -// Called when the user clicks on the information button of a managed -// settings UI cell. Shows a contextual bubble with the information of the -// enterprise. +// Called when the user taps on the information button of a managed setting's UI +// cell. +- (void)didTapSigninDisabledInfoButton:(UIButton*)buttonView { + NSString* popoverMessage = + l10n_util::GetNSString(IDS_IOS_SETTINGS_SIGNIN_DISABLED_POPOVER_TEXT); + EnterpriseInfoPopoverViewController* popover = + [[EnterpriseInfoPopoverViewController alloc] + initWithMessage:popoverMessage + enterpriseName:nil]; + + [self showEnterprisePopover:popover forInfoButton:buttonView]; +} + +// Called when the user taps on the information button of the sign-in setting +// while sign-in is disabled by policy. - (void)didTapManagedUIInfoButton:(UIButton*)buttonView { - EnterpriseInfoPopoverViewController* bubbleViewController = + EnterpriseInfoPopoverViewController* popover = [[EnterpriseInfoPopoverViewController alloc] initWithEnterpriseName:nil]; - bubbleViewController.delegate = self; + + [self showEnterprisePopover:popover forInfoButton:buttonView]; +} + +// Shows a contextual bubble explaining that the tapped setting is managed and +// includes a link to the chrome://management page. +- (void)showEnterprisePopover:(EnterpriseInfoPopoverViewController*)popover + forInfoButton:(UIButton*)buttonView { + popover.delegate = self; // Disable the button when showing the bubble. // The button will be enabled when close the bubble in @@ -1112,13 +1169,12 @@ buttonView.enabled = NO; // Set the anchor and arrow direction of the bubble. - bubbleViewController.popoverPresentationController.sourceView = buttonView; - bubbleViewController.popoverPresentationController.sourceRect = - buttonView.bounds; - bubbleViewController.popoverPresentationController.permittedArrowDirections = + popover.popoverPresentationController.sourceView = buttonView; + popover.popoverPresentationController.sourceRect = buttonView.bounds; + popover.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny; - [self presentViewController:bubbleViewController animated:YES completion:nil]; + [self presentViewController:popover animated:YES completion:nil]; } #pragma mark Switch Actions
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h b/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h index 0128677..c0f33f97 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h
@@ -46,6 +46,7 @@ SettingsItemTypeArticlesForYou, SettingsItemTypeSafetyCheck, SettingsItemTypeDefaultBrowser, + SettingsItemTypeSigninDisabled, }; // The accessibility identifier of the settings TableView. @@ -54,6 +55,10 @@ // The accessibility identifier of the sign in cell. extern NSString* const kSettingsSignInCellId; +// The accessibility identifier of the sign in cell when sign-in is disabled by +// policy. +extern NSString* const kSettingsSignInDisabledCellId; + // The accessibility identifier of the account cell. extern NSString* const kSettingsAccountCellId;
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.mm index 82d4490..c02e7fb0 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller_constants.mm
@@ -10,6 +10,8 @@ NSString* const kSettingsTableViewId = @"kSettingsTableViewId"; NSString* const kSettingsSignInCellId = @"kSettingsSignInCellId"; +NSString* const kSettingsSignInDisabledCellId = + @"kSettingsSignInDisabledCellId"; NSString* const kSettingsAccountCellId = @"kSettingsAccountCellId"; NSString* const kSettingsSearchEngineCellId = @"kSettingsSearchEngineCellId"; NSString* const kSettingsManagedSearchEngineCellId =
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm index c702ec6..675c649 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller_unittest.mm
@@ -4,10 +4,18 @@ #import "ios/chrome/browser/ui/settings/settings_table_view_controller.h" +#import "base/test/scoped_command_line.h" #import "base/test/task_environment.h" +#import "components/pref_registry/pref_registry_syncable.h" +#import "components/prefs/pref_service.h" +#import "components/signin/public/base/signin_pref_names.h" #import "components/sync/driver/mock_sync_service.h" +#import "components/sync_preferences/pref_service_mock_factory.h" +#import "components/sync_preferences/pref_service_syncable.h" #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#import "ios/chrome/browser/chrome_switches.h" #import "ios/chrome/browser/main/test_browser.h" +#import "ios/chrome/browser/prefs/browser_prefs.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_fake.h" @@ -20,7 +28,9 @@ #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h" #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h" +#include "ios/chrome/grit/ios_chromium_strings.h" #import "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" @@ -37,6 +47,10 @@ using ::testing::NiceMock; using ::testing::Return; +using sync_preferences::PrefServiceMockFactory; +using sync_preferences::PrefServiceSyncable; +using user_prefs::PrefRegistrySyncable; +using web::WebTaskEnvironment; namespace { std::unique_ptr<KeyedService> CreateMockSyncService( @@ -63,6 +77,7 @@ AuthenticationServiceFactory::GetInstance(), base::BindRepeating( &AuthenticationServiceFake::CreateAuthenticationService)); + builder.SetPrefService(CreatePrefService()); chrome_browser_state_ = builder.Build(); WebStateList* web_state_list = nullptr; @@ -91,6 +106,15 @@ ChromeTableViewControllerTest::TearDown(); } + std::unique_ptr<PrefServiceSyncable> CreatePrefService() { + PrefServiceMockFactory factory; + scoped_refptr<PrefRegistrySyncable> registry(new PrefRegistrySyncable); + std::unique_ptr<PrefServiceSyncable> prefs = + factory.CreateSyncable(registry.get()); + RegisterBrowserStatePrefs(registry.get()); + return prefs; + } + ChromeTableViewController* InstantiateController() override { return [[SettingsTableViewController alloc] initWithBrowser:browser_.get() @@ -151,3 +175,27 @@ sync_item.detailText, l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNC_ON)); } + +// Verifies that the sign-in setting item is replaced by the managed sign-in +// item if sign-in is disabled by policy. +TEST_F(SettingsTableViewControllerTest, SigninDisabled) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->AppendSwitch( + switches::kInstallBrowserSigninHandler); + chrome_browser_state_->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false); + CreateController(); + CheckController(); + + NSArray* signin_items = [controller().tableViewModel + itemsInSectionWithIdentifier:SettingsSectionIdentifier:: + SettingsSectionIdentifierSignIn]; + ASSERT_EQ(1U, signin_items.count); + + TableViewInfoButtonItem* signin_item = + static_cast<TableViewInfoButtonItem*>(signin_items[0]); + ASSERT_NSEQ(signin_item.text, + l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_TITLE)); + ASSERT_NSEQ(signin_item.detailText, + l10n_util::GetNSString(IDS_IOS_SETTINGS_SIGNIN_DISABLED)); + ASSERT_NE(signin_item.image, nil); +}
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm index 4e1357c..1db1114 100644 --- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm +++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -377,8 +377,8 @@ initWithType:ItemTypeTableViewInfoButtonWithImage]; tableViewInfoButtonItemWithLeadingImage.text = @"Info button item"; tableViewInfoButtonItemWithLeadingImage.statusText = @"Status"; - tableViewInfoButtonItemWithLeadingImage.iconImageName = - @"settings_article_suggestions"; + tableViewInfoButtonItemWithLeadingImage.image = + [UIImage imageNamed:@"settings_article_suggestions"]; [model addItem:tableViewInfoButtonItemWithLeadingImage toSectionWithIdentifier:SectionIdentifierSettings];
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h index 7643f528..61d666f 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h
@@ -12,8 +12,8 @@ // TableViewInfoButtonItem is a model class that uses TableViewInfoButtonCell. @interface TableViewInfoButtonItem : TableViewItem -// The filename for the leading icon. If empty, no icon will be shown. -@property(nonatomic, copy) NSString* iconImageName; +// The UIImage for the leading image. If nil, no image will be shown. +@property(nonatomic, strong) UIImage* image; // Tint color for the icon. @property(nonatomic, strong) UIColor* tintColor; @@ -21,6 +21,9 @@ // The main text string. @property(nonatomic, copy) NSString* text; +// The color of the main text. +@property(nonatomic, strong) UIColor* textColor; + // The detail text string. @property(nonatomic, copy) NSString* detailText;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.mm index 9400e583..a1ee32a5 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.mm
@@ -26,6 +26,9 @@ withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; cell.textLabel.text = self.text; + if (self.textColor) { + cell.textLabel.textColor = self.textColor; + } if (self.detailText) { cell.detailTextLabel.text = self.detailText; [cell updatePaddingForDetailText:YES]; @@ -39,11 +42,7 @@ cell.selectionStyle = UITableViewCellSelectionStyleNone; // Update the icon image, if one is present. - UIImage* iconImage = nil; - if ([self.iconImageName length]) { - iconImage = [UIImage imageNamed:self.iconImageName]; - } - [cell setIconImage:iconImage withTintColor:self.tintColor]; + [cell setIconImage:self.image withTintColor:self.tintColor]; } @end
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm index fdd9449..1aea9ad 100644 --- a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm +++ b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm
@@ -15,7 +15,7 @@ #include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/web/chrome_web_test.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -50,7 +50,7 @@ return InfoBarManagerImpl::FromWebState(web_state()); } - web::TestWebStateDelegate web_state_delegate_; + web::FakeWebStateDelegate web_state_delegate_; }; // Tests ShouldBlockPopup method. This test changes content settings without
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 index c8c89b3..6de753f 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -0114c336adb33325d148efd99aa0f643d53531b8 \ No newline at end of file +de654378bbf0a74d626daa79dc838fb2876444e4 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 index 6d1f2b30..5e6a2cb 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -b1af96ab9f3895e1cda65b3bcbdec1b87a3de58b \ No newline at end of file +61ad6e54b577c0bde9cb9eef59ff41d53e455370 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 index 6393c46..622c8c5 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -a7e658d35c177cba5561b8907aeb530d41737037 \ No newline at end of file +b6362a3e1f19d5482748384ef276040af506368e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 index dacb302..16190caf 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -686ab5409c6722c1789135f59ce0365185be0de2 \ No newline at end of file +b731d0feb710b5e1def1f9ffd758c6c51ace4d2d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 index 2a0f867..3686341 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -fdd19e13ce3b88db633c961ab1a2b464dad85e2b \ No newline at end of file +a89ae00e87759465366eac23e4330f804bfe2a31 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 index 626e124..52aa4bdd 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -0b06118a4acac41403c31f82eb1527a045b48d74 \ No newline at end of file +41732b01adb26c0d55b3cb6e99d118d291647031 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 index 3fdb2c52b..96f528a 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -f3c8ac6d8ce75243de294820aca33b7b22df885a \ No newline at end of file +9b564cc539ed938da626b5149af2b897384fa39c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 index 9e1f8b8..4f73a0d 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -e724729deb0d00af077a966470cfe985b4229256 \ No newline at end of file +4cea067acbfea54b8bcd66e461fe075d2482e0c6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 index f21addff..b6191d8 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -41271b830dc00f96f8d72b3b0b34614306dbc066 \ No newline at end of file +017771985e2200e689cf266b05ec0f758369075f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 index eac6ce47..51ce7de 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -1e80febdcc5345a5ab8c0b6833d652ddbc581a57 \ No newline at end of file +1899a2b075e85b7a9f8b4740931fa47397006708 \ No newline at end of file
diff --git a/ios/web/public/test/fakes/BUILD.gn b/ios/web/public/test/fakes/BUILD.gn index 049e64d6..ab478bf 100644 --- a/ios/web/public/test/fakes/BUILD.gn +++ b/ios/web/public/test/fakes/BUILD.gn
@@ -52,6 +52,8 @@ "fake_download_task.mm", "fake_find_in_page_manager_delegate.h", "fake_find_in_page_manager_delegate.mm", + "fake_java_script_dialog_presenter.h", + "fake_java_script_dialog_presenter.mm", "fake_navigation_context.h", "fake_navigation_context.mm", "fake_navigation_manager.h", @@ -64,16 +66,13 @@ "fake_web_frames_manager.mm", "fake_web_state.h", "fake_web_state.mm", + "fake_web_state_delegate.h", + "fake_web_state_delegate.mm", "fake_web_state_observer.h", "fake_web_state_observer.mm", "fake_web_state_observer_util.h", "fake_web_state_observer_util.mm", "fake_web_state_policy_decider.h", "fake_web_state_policy_decider.mm", - "test_browser_state.h", - "test_java_script_dialog_presenter.h", - "test_java_script_dialog_presenter.mm", - "test_web_state_delegate.h", - "test_web_state_delegate.mm", ] }
diff --git a/ios/web/public/test/fakes/test_java_script_dialog_presenter.h b/ios/web/public/test/fakes/fake_java_script_dialog_presenter.h similarity index 79% rename from ios/web/public/test/fakes/test_java_script_dialog_presenter.h rename to ios/web/public/test/fakes/fake_java_script_dialog_presenter.h index 5793a8b9..35bab148 100644 --- a/ios/web/public/test/fakes/test_java_script_dialog_presenter.h +++ b/ios/web/public/test/fakes/fake_java_script_dialog_presenter.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_WEB_PUBLIC_TEST_FAKES_TEST_JAVA_SCRIPT_DIALOG_PRESENTER_H_ -#define IOS_WEB_PUBLIC_TEST_FAKES_TEST_JAVA_SCRIPT_DIALOG_PRESENTER_H_ +#ifndef IOS_WEB_PUBLIC_TEST_FAKES_FAKE_JAVA_SCRIPT_DIALOG_PRESENTER_H_ +#define IOS_WEB_PUBLIC_TEST_FAKES_FAKE_JAVA_SCRIPT_DIALOG_PRESENTER_H_ #include <memory> #include <vector> @@ -12,9 +12,9 @@ namespace web { -struct TestJavaScriptDialog { - TestJavaScriptDialog(); - ~TestJavaScriptDialog(); +struct FakeJavaScriptDialog { + FakeJavaScriptDialog(); + ~FakeJavaScriptDialog(); WebState* web_state = nullptr; GURL origin_url; JavaScriptDialogType java_script_dialog_type; @@ -23,13 +23,13 @@ DialogClosedCallback callback; }; -// Test presenter to check that the JavaScriptDialogPresenter methods are called +// Fake presenter to check that the JavaScriptDialogPresenter methods are called // as expected. |RunJavaScriptDialog| always calls |callback| with // |callback_success_argument| and |callback_user_input_argument| values. -class TestJavaScriptDialogPresenter : public JavaScriptDialogPresenter { +class FakeJavaScriptDialogPresenter : public JavaScriptDialogPresenter { public: - TestJavaScriptDialogPresenter(); - ~TestJavaScriptDialogPresenter() override; + FakeJavaScriptDialogPresenter(); + ~FakeJavaScriptDialogPresenter() override; // JavaScriptDialogPresenter overrides: void RunJavaScriptDialog(WebState* web_state, @@ -55,7 +55,7 @@ bool cancel_dialogs_called() const { return cancel_dialogs_called_; } // Returns a vector of requested dialogs. - const std::vector<std::unique_ptr<TestJavaScriptDialog>>& requested_dialogs() + const std::vector<std::unique_ptr<FakeJavaScriptDialog>>& requested_dialogs() const { return requested_dialogs_; } @@ -74,15 +74,15 @@ // Executes all non-executed callbacks in |requested_dialogs_|. void ExecuteAllDialogCallbacks(); // Executes the callback for |dialog|. - void ExecuteDialogCallback(TestJavaScriptDialog* dialog); + void ExecuteDialogCallback(FakeJavaScriptDialog* dialog); bool callback_execution_paused_ = false; bool cancel_dialogs_called_ = false; - std::vector<std::unique_ptr<TestJavaScriptDialog>> requested_dialogs_; + std::vector<std::unique_ptr<FakeJavaScriptDialog>> requested_dialogs_; bool callback_success_argument_ = false; NSString* callback_user_input_argument_; }; } // namespace web -#endif // IOS_WEB_PUBLIC_TEST_FAKES_TEST_JAVA_SCRIPT_DIALOG_PRESENTER_H_ +#endif // IOS_WEB_PUBLIC_TEST_FAKES_FAKE_JAVA_SCRIPT_DIALOG_PRESENTER_H_
diff --git a/ios/web/public/test/fakes/test_java_script_dialog_presenter.mm b/ios/web/public/test/fakes/fake_java_script_dialog_presenter.mm similarity index 66% rename from ios/web/public/test/fakes/test_java_script_dialog_presenter.mm rename to ios/web/public/test/fakes/fake_java_script_dialog_presenter.mm index e6c6a23e..b5e2b44 100644 --- a/ios/web/public/test/fakes/test_java_script_dialog_presenter.mm +++ b/ios/web/public/test/fakes/fake_java_script_dialog_presenter.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/web/public/test/fakes/test_java_script_dialog_presenter.h" +#import "ios/web/public/test/fakes/fake_java_script_dialog_presenter.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -10,27 +10,26 @@ namespace web { -TestJavaScriptDialog::TestJavaScriptDialog() = default; +FakeJavaScriptDialog::FakeJavaScriptDialog() = default; -TestJavaScriptDialog::~TestJavaScriptDialog() = default; +FakeJavaScriptDialog::~FakeJavaScriptDialog() = default; -TestJavaScriptDialogPresenter::TestJavaScriptDialogPresenter() = default; +FakeJavaScriptDialogPresenter::FakeJavaScriptDialogPresenter() = default; -TestJavaScriptDialogPresenter::~TestJavaScriptDialogPresenter() { +FakeJavaScriptDialogPresenter::~FakeJavaScriptDialogPresenter() { // Unpause callback execution so that all callbacks are executed before // deallocation. set_callback_execution_paused(false); } -void TestJavaScriptDialogPresenter::RunJavaScriptDialog( +void FakeJavaScriptDialogPresenter::RunJavaScriptDialog( WebState* web_state, const GURL& origin_url, JavaScriptDialogType java_script_dialog_type, NSString* message_text, NSString* default_prompt_text, DialogClosedCallback callback) { - std::unique_ptr<TestJavaScriptDialog> dialog = - std::make_unique<TestJavaScriptDialog>(); + auto dialog = std::make_unique<FakeJavaScriptDialog>(); dialog->web_state = web_state; dialog->origin_url = origin_url; dialog->java_script_dialog_type = java_script_dialog_type; @@ -44,19 +43,19 @@ ExecuteDialogCallback(requested_dialogs_.back().get()); } -void TestJavaScriptDialogPresenter::CancelDialogs(WebState* web_state) { +void FakeJavaScriptDialogPresenter::CancelDialogs(WebState* web_state) { cancel_dialogs_called_ = true; } -void TestJavaScriptDialogPresenter::ExecuteAllDialogCallbacks() { +void FakeJavaScriptDialogPresenter::ExecuteAllDialogCallbacks() { DCHECK(!callback_execution_paused()); - for (std::unique_ptr<TestJavaScriptDialog>& dialog : requested_dialogs_) { + for (std::unique_ptr<FakeJavaScriptDialog>& dialog : requested_dialogs_) { ExecuteDialogCallback(dialog.get()); } } -void TestJavaScriptDialogPresenter::ExecuteDialogCallback( - TestJavaScriptDialog* dialog) { +void FakeJavaScriptDialogPresenter::ExecuteDialogCallback( + FakeJavaScriptDialog* dialog) { DialogClosedCallback& callback = dialog->callback; if (!callback.is_null()) { std::move(callback).Run(callback_success_argument_,
diff --git a/ios/web/public/test/fakes/test_web_state_delegate.h b/ios/web/public/test/fakes/fake_web_state_delegate.h similarity index 78% rename from ios/web/public/test/fakes/test_web_state_delegate.h rename to ios/web/public/test/fakes/fake_web_state_delegate.h index 18fddbf..c714c25 100644 --- a/ios/web/public/test/fakes/test_web_state_delegate.h +++ b/ios/web/public/test/fakes/fake_web_state_delegate.h
@@ -2,21 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef IOS_WEB_PUBLIC_TEST_FAKES_TEST_WEB_STATE_DELEGATE_H_ -#define IOS_WEB_PUBLIC_TEST_FAKES_TEST_WEB_STATE_DELEGATE_H_ +#ifndef IOS_WEB_PUBLIC_TEST_FAKES_FAKE_WEB_STATE_DELEGATE_H_ +#define IOS_WEB_PUBLIC_TEST_FAKES_FAKE_WEB_STATE_DELEGATE_H_ #import <Foundation/Foundation.h> #include <memory> #include <set> -#import "ios/web/public/test/fakes/test_java_script_dialog_presenter.h" +#import "ios/web/public/test/fakes/fake_java_script_dialog_presenter.h" #import "ios/web/public/web_state_delegate.h" namespace web { // Encapsulates parameters passed to CreateNewWebState. -struct TestCreateNewWebStateRequest { +struct FakeCreateNewWebStateRequest { WebState* web_state = nullptr; GURL url; GURL opener_url; @@ -24,32 +24,32 @@ }; // Encapsulates parameters passed to CloseWebState. -struct TestCloseWebStateRequest { +struct FakeCloseWebStateRequest { WebState* web_state = nullptr; }; // Encapsulates parameters passed to OpenURLFromWebState. -struct TestOpenURLRequest { - TestOpenURLRequest(); - TestOpenURLRequest(const TestOpenURLRequest&); - ~TestOpenURLRequest(); +struct FakeOpenURLRequest { + FakeOpenURLRequest(); + FakeOpenURLRequest(const FakeOpenURLRequest&); + ~FakeOpenURLRequest(); WebState* web_state = nullptr; WebState::OpenURLParams params; }; // Encapsulates parameters passed to ShowRepostFormWarningDialog. -struct TestRepostFormRequest { - TestRepostFormRequest(); - ~TestRepostFormRequest(); +struct FakeRepostFormRequest { + FakeRepostFormRequest(); + ~FakeRepostFormRequest(); WebState* web_state = nullptr; base::OnceCallback<void(bool)> callback; }; // Encapsulates parameters passed to OnAuthRequired. -struct TestAuthenticationRequest { - TestAuthenticationRequest(); - TestAuthenticationRequest(TestAuthenticationRequest&&); - ~TestAuthenticationRequest(); +struct FakeAuthenticationRequest { + FakeAuthenticationRequest(); + FakeAuthenticationRequest(FakeAuthenticationRequest&&); + ~FakeAuthenticationRequest(); WebState* web_state = nullptr; NSURLProtectionSpace* protection_space; NSURLCredential* credential; @@ -57,18 +57,18 @@ }; // Encapsulates information about popup. -struct TestPopup { - TestPopup(const GURL& url, const GURL& opener_url) +struct FakePopup { + FakePopup(const GURL& url, const GURL& opener_url) : url(url), opener_url(opener_url) {} GURL url; GURL opener_url; }; // Fake WebStateDelegate used for testing purposes. -class TestWebStateDelegate : public WebStateDelegate { +class FakeWebStateDelegate : public WebStateDelegate { public: - TestWebStateDelegate(); - ~TestWebStateDelegate() override; + FakeWebStateDelegate(); + ~FakeWebStateDelegate() override; // WebStateDelegate overrides: WebState* CreateNewWebState(WebState* source, @@ -84,7 +84,7 @@ void ShowRepostFormWarningDialog( WebState* source, base::OnceCallback<void(bool)> callback) override; - TestJavaScriptDialogPresenter* GetTestJavaScriptDialogPresenter(); + FakeJavaScriptDialogPresenter* GetFakeJavaScriptDialogPresenter(); void OnAuthRequired(WebState* source, NSURLProtectionSpace* protection_space, NSURLCredential* proposed_credential, @@ -107,7 +107,7 @@ } // Returns list of all popups requested via CreateNewWebState. - const std::vector<TestPopup>& popups() const { return popups_; } + const std::vector<FakePopup>& popups() const { return popups_; } // True if the WebStateDelegate HandleContextMenu method has been called. bool handle_context_menu_called() const { @@ -115,23 +115,23 @@ } // Returns the last Web State creation request passed to |CreateNewWebState|. - TestCreateNewWebStateRequest* last_create_new_web_state_request() const { + FakeCreateNewWebStateRequest* last_create_new_web_state_request() const { return last_create_new_web_state_request_.get(); } // Returns the last Web State closing request passed to |CloseWebState|. - TestCloseWebStateRequest* last_close_web_state_request() const { + FakeCloseWebStateRequest* last_close_web_state_request() const { return last_close_web_state_request_.get(); } // Returns the last Open URL request passed to |OpenURLFromWebState|. - TestOpenURLRequest* last_open_url_request() const { + FakeOpenURLRequest* last_open_url_request() const { return last_open_url_request_.get(); } // Returns the last Repost Form request passed to // |ShowRepostFormWarningDialog|. - TestRepostFormRequest* last_repost_form_request() const { + FakeRepostFormRequest* last_repost_form_request() const { return last_repost_form_request_.get(); } @@ -142,7 +142,7 @@ } // Returns the last HTTP Authentication request passed to |OnAuthRequired|. - TestAuthenticationRequest* last_authentication_request() const { + FakeAuthenticationRequest* last_authentication_request() const { return last_authentication_request_.get(); } @@ -193,16 +193,16 @@ std::vector<std::unique_ptr<WebState>> closed_child_windows_; // A page can open popup if its URL is in this set. std::set<GURL> allowed_popups_; - std::vector<TestPopup> popups_; + std::vector<FakePopup> popups_; bool handle_context_menu_called_ = false; - std::unique_ptr<TestCreateNewWebStateRequest> + std::unique_ptr<FakeCreateNewWebStateRequest> last_create_new_web_state_request_; - std::unique_ptr<TestCloseWebStateRequest> last_close_web_state_request_; - std::unique_ptr<TestOpenURLRequest> last_open_url_request_; - std::unique_ptr<TestRepostFormRequest> last_repost_form_request_; + std::unique_ptr<FakeCloseWebStateRequest> last_close_web_state_request_; + std::unique_ptr<FakeOpenURLRequest> last_open_url_request_; + std::unique_ptr<FakeRepostFormRequest> last_repost_form_request_; bool get_java_script_dialog_presenter_called_ = false; - TestJavaScriptDialogPresenter java_script_dialog_presenter_; - std::unique_ptr<TestAuthenticationRequest> last_authentication_request_; + FakeJavaScriptDialogPresenter java_script_dialog_presenter_; + std::unique_ptr<FakeAuthenticationRequest> last_authentication_request_; GURL last_link_url_; bool should_preview_link_ = false; bool should_allow_app_launching_ = false; @@ -212,4 +212,4 @@ } // namespace web -#endif // IOS_WEB_PUBLIC_TEST_FAKES_TEST_WEB_STATE_DELEGATE_H_ +#endif // IOS_WEB_PUBLIC_TEST_FAKES_FAKE_WEB_STATE_DELEGATE_H_
diff --git a/ios/web/public/test/fakes/test_web_state_delegate.mm b/ios/web/public/test/fakes/fake_web_state_delegate.mm similarity index 65% rename from ios/web/public/test/fakes/test_web_state_delegate.mm rename to ios/web/public/test/fakes/fake_web_state_delegate.mm index dbc5cf46..fde105b 100644 --- a/ios/web/public/test/fakes/test_web_state_delegate.mm +++ b/ios/web/public/test/fakes/fake_web_state_delegate.mm
@@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/web/public/test/fakes/test_web_state_delegate.h" - +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -11,38 +10,38 @@ namespace web { -TestOpenURLRequest::TestOpenURLRequest() +FakeOpenURLRequest::FakeOpenURLRequest() : params(GURL(), Referrer(), WindowOpenDisposition::UNKNOWN, ui::PAGE_TRANSITION_LINK, false) {} -TestOpenURLRequest::~TestOpenURLRequest() = default; +FakeOpenURLRequest::~FakeOpenURLRequest() = default; -TestOpenURLRequest::TestOpenURLRequest(const TestOpenURLRequest&) = default; +FakeOpenURLRequest::FakeOpenURLRequest(const FakeOpenURLRequest&) = default; -TestRepostFormRequest::TestRepostFormRequest() = default; +FakeRepostFormRequest::FakeRepostFormRequest() = default; -TestRepostFormRequest::~TestRepostFormRequest() = default; +FakeRepostFormRequest::~FakeRepostFormRequest() = default; -TestAuthenticationRequest::TestAuthenticationRequest() {} +FakeAuthenticationRequest::FakeAuthenticationRequest() {} -TestAuthenticationRequest::~TestAuthenticationRequest() = default; +FakeAuthenticationRequest::~FakeAuthenticationRequest() = default; -TestAuthenticationRequest::TestAuthenticationRequest( - TestAuthenticationRequest&&) = default; +FakeAuthenticationRequest::FakeAuthenticationRequest( + FakeAuthenticationRequest&&) = default; -TestWebStateDelegate::TestWebStateDelegate() {} +FakeWebStateDelegate::FakeWebStateDelegate() {} -TestWebStateDelegate::~TestWebStateDelegate() = default; +FakeWebStateDelegate::~FakeWebStateDelegate() = default; -WebState* TestWebStateDelegate::CreateNewWebState(WebState* source, +WebState* FakeWebStateDelegate::CreateNewWebState(WebState* source, const GURL& url, const GURL& opener_url, bool initiated_by_user) { last_create_new_web_state_request_ = - std::make_unique<TestCreateNewWebStateRequest>(); + std::make_unique<FakeCreateNewWebStateRequest>(); last_create_new_web_state_request_->web_state = source; last_create_new_web_state_request_->url = url; last_create_new_web_state_request_->opener_url = opener_url; @@ -50,7 +49,7 @@ if (!initiated_by_user && allowed_popups_.find(opener_url) == allowed_popups_.end()) { - popups_.push_back(TestPopup(url, opener_url)); + popups_.push_back(FakePopup(url, opener_url)); return nullptr; } @@ -62,8 +61,8 @@ return child_windows_.back().get(); } -void TestWebStateDelegate::CloseWebState(WebState* source) { - last_close_web_state_request_ = std::make_unique<TestCloseWebStateRequest>(); +void FakeWebStateDelegate::CloseWebState(WebState* source) { + last_close_web_state_request_ = std::make_unique<FakeCloseWebStateRequest>(); last_close_web_state_request_->web_state = source; // Remove WebState from |child_windows_|. @@ -76,65 +75,65 @@ } } -WebState* TestWebStateDelegate::OpenURLFromWebState( +WebState* FakeWebStateDelegate::OpenURLFromWebState( WebState* web_state, const WebState::OpenURLParams& params) { - last_open_url_request_ = std::make_unique<TestOpenURLRequest>(); + last_open_url_request_ = std::make_unique<FakeOpenURLRequest>(); last_open_url_request_->web_state = web_state; last_open_url_request_->params = params; return nullptr; } -JavaScriptDialogPresenter* TestWebStateDelegate::GetJavaScriptDialogPresenter( +JavaScriptDialogPresenter* FakeWebStateDelegate::GetJavaScriptDialogPresenter( WebState*) { get_java_script_dialog_presenter_called_ = true; return &java_script_dialog_presenter_; } -void TestWebStateDelegate::HandleContextMenu(WebState*, +void FakeWebStateDelegate::HandleContextMenu(WebState*, const ContextMenuParams&) { handle_context_menu_called_ = true; } -void TestWebStateDelegate::ShowRepostFormWarningDialog( +void FakeWebStateDelegate::ShowRepostFormWarningDialog( WebState* source, base::OnceCallback<void(bool)> callback) { - last_repost_form_request_ = std::make_unique<TestRepostFormRequest>(); + last_repost_form_request_ = std::make_unique<FakeRepostFormRequest>(); last_repost_form_request_->web_state = source; last_repost_form_request_->callback = std::move(callback); } -TestJavaScriptDialogPresenter* -TestWebStateDelegate::GetTestJavaScriptDialogPresenter() { +FakeJavaScriptDialogPresenter* +FakeWebStateDelegate::GetFakeJavaScriptDialogPresenter() { return &java_script_dialog_presenter_; } -void TestWebStateDelegate::OnAuthRequired( +void FakeWebStateDelegate::OnAuthRequired( WebState* source, NSURLProtectionSpace* protection_space, NSURLCredential* credential, AuthCallback callback) { - last_authentication_request_ = std::make_unique<TestAuthenticationRequest>(); + last_authentication_request_ = std::make_unique<FakeAuthenticationRequest>(); last_authentication_request_->web_state = source; last_authentication_request_->protection_space = protection_space; last_authentication_request_->credential = credential; last_authentication_request_->auth_callback = std::move(callback); } -bool TestWebStateDelegate::ShouldPreviewLink(WebState* source, +bool FakeWebStateDelegate::ShouldPreviewLink(WebState* source, const GURL& link_url) { last_link_url_ = link_url; return should_preview_link_; } -UIViewController* TestWebStateDelegate::GetPreviewingViewController( +UIViewController* FakeWebStateDelegate::GetPreviewingViewController( WebState* source, const GURL& link_url) { last_link_url_ = link_url; return previewing_view_controller_; } -void TestWebStateDelegate::CommitPreviewingViewController( +void FakeWebStateDelegate::CommitPreviewingViewController( WebState* source, UIViewController* previewing_view_controller) { last_previewing_view_controller_ = previewing_view_controller;
diff --git a/ios/web/public/test/fakes/test_browser_state.h b/ios/web/public/test/fakes/test_browser_state.h deleted file mode 100644 index 6c9f94f..0000000 --- a/ios/web/public/test/fakes/test_browser_state.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_WEB_PUBLIC_TEST_FAKES_TEST_BROWSER_STATE_H_ -#define IOS_WEB_PUBLIC_TEST_FAKES_TEST_BROWSER_STATE_H_ - -#include "ios/web/public/test/fakes/fake_browser_state.h" - -// TODO(crbug.com/688063): Remove this file after updating all clients to import -// fake_browser_state.h and use FakeBrowserState class. - -namespace web { -using TestBrowserState = FakeBrowserState; -} - -#endif // IOS_WEB_PUBLIC_TEST_FAKES_TEST_BROWSER_STATE_H_
diff --git a/ios/web/test/web_int_test.h b/ios/web/test/web_int_test.h index 6539f4c..46b080b 100644 --- a/ios/web/test/web_int_test.h +++ b/ios/web/test/web_int_test.h
@@ -11,7 +11,7 @@ #import "base/ios/block_types.h" #include "base/macros.h" #import "ios/web/public/navigation/navigation_manager.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #include "ios/web/public/test/web_test.h" #import "ios/web/public/web_state.h" @@ -66,7 +66,7 @@ // or NSNotFound if it is not present. NSInteger GetIndexOfNavigationItem(const web::NavigationItem* item); - web::TestWebStateDelegate web_state_delegate_; + web::FakeWebStateDelegate web_state_delegate_; private: // WebState used to load pages.
diff --git a/ios/web/web_state/http_auth_inttest.mm b/ios/web/web_state/http_auth_inttest.mm index e12f4e80..428dd932 100644 --- a/ios/web/web_state/http_auth_inttest.mm +++ b/ios/web/web_state/http_auth_inttest.mm
@@ -5,7 +5,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #import "base/test/ios/wait_util.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #import "ios/web/public/test/js_test_util.h" #import "ios/web/public/test/navigation_test_util.h" #import "ios/web/public/test/web_test_with_web_state.h" @@ -40,7 +40,7 @@ }); } net::EmbeddedTestServer server_; - TestWebStateDelegate delegate_; + FakeWebStateDelegate delegate_; }; // Tests successful basic authentication.
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index d8239ad..c0ccd82 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -37,9 +37,9 @@ #include "ios/web/public/test/fakes/fake_browser_state.h" #include "ios/web/public/test/fakes/fake_download_controller_delegate.h" #import "ios/web/public/test/fakes/fake_web_client.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #include "ios/web/public/test/fakes/fake_web_state_observer.h" #import "ios/web/public/test/fakes/fake_web_state_policy_decider.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" #import "ios/web/public/test/web_view_content_test_util.h" #include "ios/web/public/web_state_observer.h" #import "ios/web/security/wk_web_view_security_util.h" @@ -361,23 +361,23 @@ void SetUp() override { WebTestWithWebState::SetUp(); LoadHtml(@"<html><body></body></html>", page_url_); - web_state()->SetDelegate(&test_web_delegate_); + web_state()->SetDelegate(&web_state_delegate_); } void TearDown() override { web_state()->SetDelegate(nullptr); WebTestWithWebState::TearDown(); } - TestJavaScriptDialogPresenter* js_dialog_presenter() { - return test_web_delegate_.GetTestJavaScriptDialogPresenter(); + FakeJavaScriptDialogPresenter* js_dialog_presenter() { + return web_state_delegate_.GetFakeJavaScriptDialogPresenter(); } - const std::vector<std::unique_ptr<TestJavaScriptDialog>>& + const std::vector<std::unique_ptr<FakeJavaScriptDialog>>& requested_dialogs() { return js_dialog_presenter()->requested_dialogs(); } const GURL& page_url() { return page_url_; } private: - TestWebStateDelegate test_web_delegate_; + FakeWebStateDelegate web_state_delegate_; GURL page_url_; }; @@ -957,13 +957,13 @@ TEST_F(CRWWebControllerPolicyDeciderTest, ClosedWebState) { static CRWWebControllerPolicyDeciderTest* test_fixture = nullptr; test_fixture = this; - class FakeWebStateDelegate : public TestWebStateDelegate { + class CloseWebStateDelegate : public FakeWebStateDelegate { public: void CloseWebState(WebState* source) override { test_fixture->DestroyWebState(); } }; - FakeWebStateDelegate delegate; + CloseWebStateDelegate delegate; web_state()->SetDelegate(&delegate); FakeWebStatePolicyDecider policy_decider(web_state()); @@ -1083,7 +1083,7 @@ // URL of a page which opens child windows. const GURL opener_url_; - TestWebStateDelegate delegate_; + FakeWebStateDelegate delegate_; }; // Tests that absence of web state delegate is handled gracefully.
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index 1dd2c9b..a48e6a6b 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -29,11 +29,11 @@ #import "ios/web/public/session/serializable_user_data_manager.h" #import "ios/web/public/test/fakes/async_web_state_policy_decider.h" #include "ios/web/public/test/fakes/fake_browser_state.h" +#import "ios/web/public/test/fakes/fake_java_script_dialog_presenter.h" #import "ios/web/public/test/fakes/fake_navigation_context.h" #import "ios/web/public/test/fakes/fake_web_frame.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #import "ios/web/public/test/fakes/fake_web_state_observer.h" -#import "ios/web/public/test/fakes/test_java_script_dialog_presenter.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" #include "ios/web/public/test/web_test.h" #import "ios/web/public/test/web_view_content_test_util.h" #import "ios/web/public/ui/context_menu_params.h" @@ -426,7 +426,7 @@ // Tests that WebStateDelegate methods appropriately called. TEST_F(WebStateImplTest, DelegateTest) { - TestWebStateDelegate delegate; + FakeWebStateDelegate delegate; web_state_->SetDelegate(&delegate); // Test that CreateNewWebState() is called. @@ -434,7 +434,7 @@ GURL opener_url("https://opener.test/"); EXPECT_FALSE(delegate.last_create_new_web_state_request()); web_state_->CreateNewWebState(child_url, opener_url, true); - TestCreateNewWebStateRequest* create_new_web_state_request = + FakeCreateNewWebStateRequest* create_new_web_state_request = delegate.last_create_new_web_state_request(); ASSERT_TRUE(create_new_web_state_request); EXPECT_EQ(web_state_.get(), create_new_web_state_request->web_state); @@ -455,7 +455,7 @@ ui::PAGE_TRANSITION_LINK, true); EXPECT_FALSE(delegate.last_open_url_request()); web_state_->OpenURL(params); - TestOpenURLRequest* open_url_request = delegate.last_open_url_request(); + FakeOpenURLRequest* open_url_request = delegate.last_open_url_request(); ASSERT_TRUE(open_url_request); EXPECT_EQ(web_state_.get(), open_url_request->web_state); WebState::OpenURLParams actual_params = open_url_request->params; @@ -502,8 +502,8 @@ EXPECT_EQ(delegate.last_repost_form_request()->web_state, web_state_.get()); // Test that GetJavaScriptDialogPresenter() is called. - TestJavaScriptDialogPresenter* presenter = - delegate.GetTestJavaScriptDialogPresenter(); + FakeJavaScriptDialogPresenter* presenter = + delegate.GetFakeJavaScriptDialogPresenter(); EXPECT_FALSE(delegate.get_java_script_dialog_presenter_called()); EXPECT_TRUE(presenter->requested_dialogs().empty()); EXPECT_FALSE(presenter->cancel_dialogs_called()); @@ -1155,14 +1155,14 @@ // Tests that CanTakeSnapshot() is false when a JavaScript dialog is being // presented. TEST_F(WebStateImplTest, DisallowSnapshotsDuringDialogPresentation) { - TestWebStateDelegate delegate; + FakeWebStateDelegate delegate; web_state_->SetDelegate(&delegate); EXPECT_TRUE(web_state_->CanTakeSnapshot()); // Pause the callback execution to allow testing while the dialog is // presented. - delegate.GetTestJavaScriptDialogPresenter()->set_callback_execution_paused( + delegate.GetFakeJavaScriptDialogPresenter()->set_callback_execution_paused( true); web_state_->RunJavaScriptDialog(GURL(), JAVASCRIPT_DIALOG_TYPE_ALERT, @"message", @"", @@ -1173,7 +1173,7 @@ EXPECT_FALSE(web_state_->CanTakeSnapshot()); // Unpause the presenter and verify that snapshots are enabled again. - delegate.GetTestJavaScriptDialogPresenter()->set_callback_execution_paused( + delegate.GetFakeJavaScriptDialogPresenter()->set_callback_execution_paused( false); EXPECT_TRUE(web_state_->CanTakeSnapshot()); }
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm index 4dd7ee9..1fd3a88 100644 --- a/ios/web/web_state/web_state_unittest.mm +++ b/ios/web/web_state/web_state_unittest.mm
@@ -24,7 +24,7 @@ #import "ios/web/public/session/crw_session_storage.h" #import "ios/web/public/test/error_test_util.h" #import "ios/web/public/test/fakes/fake_web_client.h" -#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/fakes/fake_web_state_delegate.h" #import "ios/web/public/test/web_test_with_web_state.h" #import "ios/web/public/test/web_view_content_test_util.h" #import "ios/web/public/web_client.h" @@ -96,14 +96,14 @@ // Tests that executing user JavaScript registers user interaction. TEST_F(WebStateTest, UserScriptExecution) { - web::TestWebStateDelegate delegate; + web::FakeWebStateDelegate delegate; web_state()->SetDelegate(&delegate); ASSERT_TRUE(delegate.child_windows().empty()); ASSERT_TRUE(LoadHtml("<html></html>")); web_state()->ExecuteUserJavaScript(@"window.open('', target='_blank');"); - web::TestWebStateDelegate* delegate_ptr = &delegate; + web::FakeWebStateDelegate* delegate_ptr = &delegate; bool suceess = WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ // Child window can only be open if the user interaction was registered. return delegate_ptr->child_windows().size() == 1;
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 16819ba..f383322 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc
@@ -701,7 +701,7 @@ #if defined(OS_MAC) // static -scoped_refptr<VideoFrame> VideoFrame::WrapIOSurface( +scoped_refptr<VideoFrame> VideoFrame::WrapUnacceleratedIOSurface( gfx::GpuMemoryBufferHandle handle, const gfx::Rect& visible_rect, base::TimeDelta timestamp) {
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index a0ace7a..4185e3c 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -292,8 +292,11 @@ base::TimeDelta timestamp); // Wraps a provided IOSurface with a VideoFrame. The IOSurface is retained - // and locked for the lifetime of the VideoFrame. - static scoped_refptr<VideoFrame> WrapIOSurface( + // and locked for the lifetime of the VideoFrame. This is for unaccelerated + // (CPU-only) access to the IOSurface, and is not efficient. It is the path + // that video capture uses when hardware acceleration is disabled. + // https://crbug.com/1125879 + static scoped_refptr<VideoFrame> WrapUnacceleratedIOSurface( gfx::GpuMemoryBufferHandle handle, const gfx::Rect& visible_rect, base::TimeDelta timestamp);
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc index 5497ee0f..2474f4f4 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -866,6 +866,21 @@ break; } + case H264NALU::kSEIMessage: { + H264SEIMessage sei_msg; + result = parser_.ParseSEI(&sei_msg); + if (result == H264Parser::kOk && + sei_msg.type == H264SEIMessage::kSEIRecoveryPoint && + sei_msg.recovery_point.recovery_frame_cnt == 0) { + // We only support immediate recovery points. Supporting future points + // would require dropping |recovery_frame_cnt| frames when needed. + frame->has_recovery_point = true; + } + nalus.push_back(nalu); + data_size += kNALUHeaderLength + nalu.size; + break; + } + case H264NALU::kSliceDataA: case H264NALU::kSliceDataB: case H264NALU::kSliceDataC: @@ -941,7 +956,7 @@ } } - if (frame->is_idr) + if (frame->is_idr || frame->has_recovery_point) waiting_for_idr_ = false; // If no IDR has been seen yet, skip decoding. Note that Flash sends
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.h b/media/gpu/mac/vt_video_decode_accelerator_mac.h index 5ec5bed..55fb17e 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.h +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.h
@@ -113,6 +113,7 @@ // Slice header information. bool has_slice = false; bool is_idr = false; + bool has_recovery_point = false; bool has_mmco5 = false; int32_t pic_order_cnt = 0; int32_t reorder_window = 0;
diff --git a/media/video/h265_parser.cc b/media/video/h265_parser.cc index a1f106f..61fcbbc3 100644 --- a/media/video/h265_parser.cc +++ b/media/video/h265_parser.cc
@@ -583,10 +583,8 @@ TRUE_OR_RETURN(sps->sps_max_num_reorder_pics[i] >= sps->sps_max_num_reorder_pics[i - 1]); } - READ_UE_OR_RETURN(&sps->sps_max_latency_increase_plus1[i]); - sps->sps_max_latency_pictures[i] = sps->sps_max_num_reorder_pics[i] + - sps->sps_max_latency_increase_plus1[i] - - 1; + int sps_max_latency_increase_plus1; + READ_UE_OR_RETURN(&sps_max_latency_increase_plus1); } if (!sps_sub_layer_ordering_info_present_flag) { // Fill in the default values for the other sublayers. @@ -597,9 +595,6 @@ sps->sps_max_num_reorder_pics[sps->sps_max_sub_layers_minus1]; sps->sps_max_latency_increase_plus1[i] = sps->sps_max_latency_increase_plus1[sps->sps_max_sub_layers_minus1]; - sps->sps_max_latency_pictures[i] = - sps->sps_max_num_reorder_pics[i] + - sps->sps_max_latency_increase_plus1[i] - 1; } } READ_UE_OR_RETURN(&sps->log2_min_luma_coding_block_size_minus3); @@ -676,11 +671,8 @@ IN_RANGE_OR_RETURN(log2_min_ipcm_cb_size_y, std::min(min_cb_log2_size_y, 5), std::min(sps->ctb_log2_size_y, 5)); READ_UE_OR_RETURN(&sps->log2_diff_max_min_pcm_luma_coding_block_size); - int log2_max_ipcm_cb_size_y = - log2_min_ipcm_cb_size_y + - sps->log2_diff_max_min_pcm_luma_coding_block_size; - TRUE_OR_RETURN(log2_max_ipcm_cb_size_y <= - std::min(sps->ctb_log2_size_y, 5)); + TRUE_OR_RETURN(sps->log2_diff_max_min_pcm_luma_coding_block_size <= + std::min(sps->ctb_log2_size_y, 5) - log2_min_ipcm_cb_size_y); READ_BOOL_OR_RETURN(&sps->pcm_loop_filter_disabled_flag); } READ_UE_OR_RETURN(&sps->num_short_term_ref_pic_sets);
diff --git a/media/video/h265_parser.h b/media/video/h265_parser.h index 87805b2a..e322aa813 100644 --- a/media/video/h265_parser.h +++ b/media/video/h265_parser.h
@@ -250,7 +250,6 @@ int bit_depth_y; int bit_depth_c; int max_pic_order_cnt_lsb; - int sps_max_latency_pictures[kMaxSubLayers]; int ctb_log2_size_y; int pic_width_in_ctbs_y; int pic_height_in_ctbs_y;
diff --git a/mojo/public/java/base/src/org/chromium/mojo_base/BigBufferUtil.java b/mojo/public/java/base/src/org/chromium/mojo_base/BigBufferUtil.java index aefc257e..1256bbb 100644 --- a/mojo/public/java/base/src/org/chromium/mojo_base/BigBufferUtil.java +++ b/mojo/public/java/base/src/org/chromium/mojo_base/BigBufferUtil.java
@@ -29,6 +29,7 @@ region.bufferHandle.map(0, region.size, SharedBufferHandle.MapFlags.NONE); byte[] bytes = new byte[region.size]; byteBuffer.get(bytes); + region.bufferHandle.unmap(byteBuffer); return bytes; } } @@ -49,6 +50,7 @@ ByteBuffer mappedRegion = region.bufferHandle.map(0, bytes.length, SharedBufferHandle.MapFlags.NONE); mappedRegion.put(bytes); + region.bufferHandle.unmap(mappedRegion); buffer.setSharedMemory(region); return buffer; }
diff --git a/net/base/features.cc b/net/base/features.cc index 004ca1e..1e21aa3 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -150,7 +150,7 @@ "TurnOffStreamingMediaCachingAlways", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kLegacyTLSEnforced{"LegacyTLSEnforced", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kSchemefulSameSite{"SchemefulSameSite", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/net/base/net_string_util_icu_alternatives_android.cc b/net/base/net_string_util_icu_alternatives_android.cc index fad7f451..0a18d5d 100644 --- a/net/base/net_string_util_icu_alternatives_android.cc +++ b/net/base/net_string_util_icu_alternatives_android.cc
@@ -121,7 +121,8 @@ output->clear(); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jstring> java_new_str( - env, env->NewString(str.data(), str.length())); + env, + env->NewString(reinterpret_cast<const jchar*>(str.data()), str.length())); if (java_new_str.is_null()) return false; ScopedJavaLocalRef<jstring> java_result =
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h index 19a4741..96098a25 100644 --- a/net/cookies/canonical_cookie.h +++ b/net/cookies/canonical_cookie.h
@@ -308,9 +308,6 @@ // Returns if the cookie with given attributes can be set in context described // by |options| and |params|, and if no, describes why. - // TODO(cfredric): this does not cover checking whether secure cookies are set - // in a secure scheme, since whether the scheme is secure isn't part of - // |options|. CookieAccessResult IsSetPermittedInContext( const GURL& source_url, const CookieOptions& options,
diff --git a/net/http/http_basic_state.cc b/net/http/http_basic_state.cc index 937b070..a836a4f 100644 --- a/net/http/http_basic_state.cc +++ b/net/http/http_basic_state.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/check_op.h" +#include "base/no_destructor.h" #include "base/stl_util.h" #include "net/base/io_buffer.h" #include "net/http/http_request_info.h" @@ -74,4 +75,11 @@ connection_->reuse_type() == ClientSocketHandle::UNUSED_IDLE; } +const std::vector<std::string>& HttpBasicState::GetDnsAliases() const { + static const base::NoDestructor<std::vector<std::string>> emptyvector_result; + return (connection_ && connection_->socket()) + ? connection_->socket()->GetDnsAliases() + : *emptyvector_result; +} + } // namespace net
diff --git a/net/http/http_basic_state.h b/net/http/http_basic_state.h index a99c0354..5fd1ee51 100644 --- a/net/http/http_basic_state.h +++ b/net/http/http_basic_state.h
@@ -66,6 +66,11 @@ // ClientSocketHandle::is_reused(). bool IsConnectionReused() const; + // Retrieves any DNS aliases for the remote endpoint. The alias chain order + // is preserved in reverse, from canonical name (i.e. address record name) + // through to query name. + const std::vector<std::string>& GetDnsAliases() const; + private: scoped_refptr<GrowableIOBuffer> read_buf_;
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc index be386b3..0c47f4a 100644 --- a/net/http/http_basic_stream.cc +++ b/net/http/http_basic_stream.cc
@@ -196,6 +196,10 @@ request_headers_callback_ = std::move(callback); } +const std::vector<std::string>& HttpBasicStream::GetDnsAliases() const { + return state_.GetDnsAliases(); +} + void HttpBasicStream::OnHandshakeConfirmed(CompletionOnceCallback callback, int rv) { if (rv == OK) {
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h index f5944f10..412656f 100644 --- a/net/http/http_basic_stream.h +++ b/net/http/http_basic_stream.h
@@ -91,6 +91,8 @@ void SetRequestHeadersCallback(RequestHeadersCallback callback) override; + const std::vector<std::string>& GetDnsAliases() const override; + private: HttpStreamParser* parser() const { return state_.parser(); }
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc index 9380e879..63da861 100644 --- a/net/http/http_response_body_drainer_unittest.cc +++ b/net/http/http_response_body_drainer_unittest.cc
@@ -14,6 +14,7 @@ #include "base/location.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/no_destructor.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" @@ -142,6 +143,11 @@ void SetPriority(RequestPriority priority) override {} + const std::vector<std::string>& GetDnsAliases() const override { + static const base::NoDestructor<std::vector<std::string>> nullvector_result; + return *nullvector_result; + } + // Methods to tweak/observer mock behavior: void set_stall_reads_forever() { stall_reads_forever_ = true; }
diff --git a/net/http/http_stream.h b/net/http/http_stream.h index 8310330e..b2d66ac5 100644 --- a/net/http/http_stream.h +++ b/net/http/http_stream.h
@@ -191,6 +191,11 @@ // Set the idempotency of the request. No-op by default. virtual void SetRequestIdempotency(Idempotency idempotency) {} + // Retrieves any DNS aliases for the remote endpoint. The alias chain order + // is preserved in reverse, from canonical name (i.e. address record name) + // through to query name. + virtual const std::vector<std::string>& GetDnsAliases() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(HttpStream); };
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc index 8e4e6facd..1c204de 100644 --- a/net/http/http_stream_factory_unittest.cc +++ b/net/http/http_stream_factory_unittest.cc
@@ -14,6 +14,7 @@ #include "base/compiler_specific.h" #include "base/memory/ptr_util.h" +#include "base/no_destructor.h" #include "base/optional.h" #include "base/run_loop.h" #include "base/stl_util.h" @@ -164,6 +165,10 @@ void PopulateNetErrorDetails(NetErrorDetails* details) override { return; } void SetPriority(RequestPriority priority) override {} HttpStream* RenewStreamForAuth() override { return nullptr; } + const std::vector<std::string>& GetDnsAliases() const override { + static const base::NoDestructor<std::vector<std::string>> nullvector_result; + return *nullvector_result; + } std::unique_ptr<WebSocketStream> Upgrade() override { return std::unique_ptr<WebSocketStream>();
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 15dc1629..215f813 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc
@@ -9,6 +9,7 @@ #include "base/auto_reset.h" #include "base/bind.h" #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" #include "base/strings/string_split.h" #include "base/threading/thread_task_runner_handle.h" #include "net/base/ip_endpoint.h" @@ -424,6 +425,11 @@ } } +const std::vector<std::string>& QuicHttpStream::GetDnsAliases() const { + static const base::NoDestructor<std::vector<std::string>> emptyvector_result; + return *emptyvector_result; +} + void QuicHttpStream::ReadTrailingHeaders() { int rv = stream_->ReadTrailingHeaders( &trailing_header_block_,
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h index d5b45617..d176131 100644 --- a/net/quic/quic_http_stream.h +++ b/net/quic/quic_http_stream.h
@@ -68,6 +68,7 @@ void PopulateNetErrorDetails(NetErrorDetails* details) override; void SetPriority(RequestPriority priority) override; void SetRequestIdempotency(Idempotency idempotency) override; + const std::vector<std::string>& GetDnsAliases() const override; static HttpResponseInfo::ConnectionInfo ConnectionInfoFromQuicVersion( quic::ParsedQuicVersion quic_version);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index e583878..e6cc8359 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1003,6 +1003,17 @@ : public SSLClientSocketTest, public ::testing::WithParamInterface<uint16_t> { protected: + SSLClientSocketVersionTest() { + // If the test is using legacy TLS versions, explicitly disable warnings + // (e.g., to cover cases like post-interstitial or when legacy TLS is + // explicitly allowed via configuration). + if (version() < SSL_PROTOCOL_VERSION_TLS1_2) { + SSLContextConfig config; + config.version_min_warn = SSL_PROTOCOL_VERSION_TLS1; + ssl_config_service_->UpdateSSLConfigAndNotify(config); + } + } + uint16_t version() const { return GetParam(); } SSLServerConfig GetServerConfig() { @@ -1026,6 +1037,14 @@ socket_factory_); socket_factory_ = wrapped_socket_factory_.get(); } + // If the test is using legacy TLS versions, explicitly disable warnings + // (e.g., to cover cases like post-interstitial or when legacy TLS is + // explicitly allowed via configuration). + if (version() < SSL_PROTOCOL_VERSION_TLS1_2) { + SSLContextConfig config; + config.version_min_warn = SSL_PROTOCOL_VERSION_TLS1; + ssl_config_service_->UpdateSSLConfigAndNotify(config); + } } // Convienient wrapper to call Read()/ReadIfReady() depending on whether @@ -5482,6 +5501,13 @@ SSLContextConfig config; config.version_max = SSL_PROTOCOL_VERSION_TLS1_3; + // If the test is using legacy TLS versions, explicitly disable warnings + // (e.g., to cover cases like post-interstitial or when legacy TLS is + // explicitly allowed via configuration). + if (tls_max_version() < + SpawnedTestServer::SSLOptions::TLS_MAX_VERSION_TLS1_2) { + config.version_min_warn = SSL_PROTOCOL_VERSION_TLS1; + } ssl_config_service_->UpdateSSLConfigAndNotify(config); CertVerifyResult verify_result; @@ -5554,6 +5580,11 @@ SSLContextConfig client_context_config; client_context_config.version_min = GetParam().version; client_context_config.version_max = GetParam().version; + // If the test is using legacy TLS versions, explicitly disable warnings + // (e.g., to cover cases like post-interstitial or when legacy TLS is + // explicitly allowed via configuration). + if (GetParam().version < SSL_PROTOCOL_VERSION_TLS1_2) + client_context_config.version_min_warn = SSL_PROTOCOL_VERSION_TLS1; ssl_config_service_->UpdateSSLConfigAndNotify(client_context_config); SSLConfig client_config; @@ -5866,18 +5897,12 @@ histograms.ExpectUniqueSample(kReasonHistogram, ssl_early_data_accepted, 1); } -TEST_F(SSLClientSocketTest, VersionOverride) { - // Enable all test features in the server. +TEST_F(SSLClientSocketTest, VersionMaxOverride) { SSLServerConfig server_config; - server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2; + server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_3; ASSERT_TRUE( StartEmbeddedTestServer(EmbeddedTestServer::CERT_OK, server_config)); - SSLContextConfig context_config; - context_config.version_min = SSL_PROTOCOL_VERSION_TLS1_1; - context_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; - ssl_config_service_->UpdateSSLConfigAndNotify(context_config); - // Connecting normally uses the global configuration. SSLConfig config; int rv; @@ -5885,7 +5910,7 @@ EXPECT_THAT(rv, IsOk()); SSLInfo info; ASSERT_TRUE(sock_->GetSSLInfo(&info)); - EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_1, + EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_3, SSLConnectionStatusToVersion(info.connection_status)); // Individual sockets may override the maximum version. @@ -5895,6 +5920,23 @@ ASSERT_TRUE(sock_->GetSSLInfo(&info)); EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_2, SSLConnectionStatusToVersion(info.connection_status)); +} + +TEST_F(SSLClientSocketTest, VersionMinOverride) { + SSLServerConfig server_config; + server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2; + ASSERT_TRUE( + StartEmbeddedTestServer(EmbeddedTestServer::CERT_OK, server_config)); + + // Connecting normally uses the global configuration. + SSLConfig config; + int rv; + ASSERT_TRUE(CreateAndConnectSSLClientSocket(config, &rv)); + EXPECT_THAT(rv, IsOk()); + SSLInfo info; + ASSERT_TRUE(sock_->GetSSLInfo(&info)); + EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_2, + SSLConnectionStatusToVersion(info.connection_status)); // Individual sockets may also override the minimum version. config.version_min_override = SSL_PROTOCOL_VERSION_TLS1_3;
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc index 37d4570..80cd41c 100644 --- a/net/spdy/spdy_http_stream.cc +++ b/net/spdy/spdy_http_stream.cc
@@ -13,6 +13,7 @@ #include "base/check_op.h" #include "base/location.h" #include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" @@ -711,4 +712,9 @@ } } +const std::vector<std::string>& SpdyHttpStream::GetDnsAliases() const { + static const base::NoDestructor<std::vector<std::string>> emptyvector_result; + return *emptyvector_result; +} + } // namespace net
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h index d2bb2d4..a64b1bea 100644 --- a/net/spdy/spdy_http_stream.h +++ b/net/spdy/spdy_http_stream.h
@@ -83,6 +83,7 @@ bool GetRemoteEndpoint(IPEndPoint* endpoint) override; void PopulateNetErrorDetails(NetErrorDetails* details) override; void SetPriority(RequestPriority priority) override; + const std::vector<std::string>& GetDnsAliases() const override; // SpdyStream::Delegate implementation. void OnHeadersSent() override;
diff --git a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp index 3ed7590e..b8aad56 100644 --- a/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp +++ b/net/third_party/mozilla_security_manager/nsPKCS12Blob.cpp
@@ -54,11 +54,10 @@ // unicodeToItem // -// For the NSS PKCS#12 library, must convert PRUnichars (shorts) to +// For the NSS PKCS#12 library, must convert base::char16s (shorts) to // a buffer of octets. Must handle byte order correctly. // TODO: Is there a Mozilla way to do this? In the string lib? -void unicodeToItem(const PRUnichar *uni, SECItem *item) -{ +void unicodeToItem(const base::char16* uni, SECItem* item) { int len = 0; while (uni[len++] != 0); SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len);
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc index 8fd1f57..abf25b4 100644 --- a/net/websockets/websocket_basic_handshake_stream.cc +++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -390,6 +390,11 @@ return handshake_stream.release(); } +const std::vector<std::string>& WebSocketBasicHandshakeStream::GetDnsAliases() + const { + return state_.GetDnsAliases(); +} + std::unique_ptr<WebSocketStream> WebSocketBasicHandshakeStream::Upgrade() { // The HttpStreamParser object has a pointer to our ClientSocketHandle. Make // sure it does not touch it again before it is destroyed.
diff --git a/net/websockets/websocket_basic_handshake_stream.h b/net/websockets/websocket_basic_handshake_stream.h index a3576c2..1b92ded4 100644 --- a/net/websockets/websocket_basic_handshake_stream.h +++ b/net/websockets/websocket_basic_handshake_stream.h
@@ -74,7 +74,7 @@ void SetPriority(RequestPriority priority) override; void PopulateNetErrorDetails(NetErrorDetails* details) override; HttpStream* RenewStreamForAuth() override; - + const std::vector<std::string>& GetDnsAliases() const override; // This is called from the top level once correct handshake response headers // have been received. It creates an appropriate subclass of WebSocketStream
diff --git a/net/websockets/websocket_basic_handshake_stream_test.cc b/net/websockets/websocket_basic_handshake_stream_test.cc index 1df0a16..0653a473 100644 --- a/net/websockets/websocket_basic_handshake_stream_test.cc +++ b/net/websockets/websocket_basic_handshake_stream_test.cc
@@ -22,6 +22,7 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/websockets/websocket_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "url/gurl.h" #include "url/origin.h" @@ -85,5 +86,72 @@ EXPECT_FALSE(socket_ptr->IsConnected()); } +TEST(WebSocketBasicHandshakeStreamTest, DnsAliasesCanBeAccessed) { + std::string request = WebSocketStandardRequest( + "/", "www.example.org", + url::Origin::Create(GURL("http://origin.example.org")), "", ""); + std::string response = WebSocketStandardResponse(""); + MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, request.c_str())}; + MockRead reads[] = {MockRead(SYNCHRONOUS, 1, response.c_str()), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)}; + + IPEndPoint end_point(IPAddress(127, 0, 0, 1), 80); + SequencedSocketData sequenced_socket_data( + MockConnect(SYNCHRONOUS, OK, end_point), reads, writes); + auto socket = std::make_unique<MockTCPClientSocket>( + AddressList(end_point), nullptr, &sequenced_socket_data); + const int connect_result = socket->Connect(CompletionOnceCallback()); + EXPECT_EQ(connect_result, OK); + + std::vector<std::string> aliases({"alias1", "alias2", "www.example.org"}); + socket->SetDnsAliases(aliases); + EXPECT_THAT(socket->GetDnsAliases(), + testing::ElementsAre("alias1", "alias2", "www.example.org")); + + const MockTCPClientSocket* const socket_ptr = socket.get(); + auto handle = std::make_unique<ClientSocketHandle>(); + handle->SetSocket(std::move(socket)); + EXPECT_THAT(handle->socket()->GetDnsAliases(), + testing::ElementsAre("alias1", "alias2", "www.example.org")); + + DummyConnectDelegate delegate; + WebSocketEndpointLockManager endpoint_lock_manager; + TestWebSocketStreamRequestAPI stream_request_api; + std::vector<std::string> extensions = { + "permessage-deflate; client_max_window_bits"}; + WebSocketBasicHandshakeStream basic_handshake_stream( + std::move(handle), &delegate, false, {}, extensions, &stream_request_api, + &endpoint_lock_manager); + basic_handshake_stream.SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ=="); + HttpRequestInfo request_info; + request_info.url = GURL("ws://www.example.com/"); + request_info.method = "GET"; + request_info.traffic_annotation = + MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + TestCompletionCallback callback1; + NetLogWithSource net_log; + const int result1 = + callback1.GetResult(basic_handshake_stream.InitializeStream( + &request_info, true, LOWEST, net_log, callback1.callback())); + EXPECT_EQ(result1, OK); + + auto request_headers = WebSocketCommonTestHeaders(); + HttpResponseInfo response_info; + TestCompletionCallback callback2; + const int result2 = callback2.GetResult(basic_handshake_stream.SendRequest( + request_headers, &response_info, callback2.callback())); + EXPECT_EQ(result2, OK); + + TestCompletionCallback callback3; + const int result3 = callback3.GetResult( + basic_handshake_stream.ReadResponseHeaders(callback2.callback())); + EXPECT_EQ(result3, OK); + + EXPECT_TRUE(socket_ptr->IsConnected()); + + EXPECT_THAT(basic_handshake_stream.GetDnsAliases(), + testing::ElementsAre("alias1", "alias2", "www.example.org")); +} + } // namespace } // namespace net
diff --git a/net/websockets/websocket_end_to_end_test.cc b/net/websockets/websocket_end_to_end_test.cc index d12fedd..79b58de 100644 --- a/net/websockets/websocket_end_to_end_test.cc +++ b/net/websockets/websocket_end_to_end_test.cc
@@ -32,8 +32,11 @@ #include "net/base/host_port_pair.h" #include "net/base/ip_endpoint.h" #include "net/base/isolation_info.h" +#include "net/base/load_flags.h" +#include "net/base/net_errors.h" #include "net/base/proxy_delegate.h" #include "net/base/url_util.h" +#include "net/cert/ct_policy_status.h" #include "net/http/http_request_headers.h" #include "net/log/net_log.h" #include "net/proxy_resolution/configured_proxy_resolution_service.h" @@ -42,6 +45,8 @@ #include "net/proxy_resolution/proxy_config_service_fixed.h" #include "net/proxy_resolution/proxy_config_with_annotation.h" #include "net/proxy_resolution/proxy_info.h" +#include "net/socket/socket_test_util.h" +#include "net/test/cert_test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -52,8 +57,10 @@ #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_test_util.h" +#include "net/url_request/websocket_handshake_userdata_key.h" #include "net/websockets/websocket_channel.h" #include "net/websockets/websocket_event_interface.h" +#include "net/websockets/websocket_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #include "url/origin.h" @@ -70,13 +77,6 @@ static const char kEchoServer[] = "echo-with-no-extension"; -// Simplify changing URL schemes. -GURL ReplaceUrlScheme(const GURL& in_url, const base::StringPiece& scheme) { - GURL::Replacements replacements; - replacements.SetSchemeStr(scheme); - return in_url.ReplaceComponents(replacements); -} - // An implementation of WebSocketEventInterface that waits for and records the // results of the connect. class ConnectTestingEventInterface : public WebSocketEventInterface { @@ -504,81 +504,6 @@ EXPECT_FALSE(ConnectAndWait(ws_url)); } -// Regression test for crbug.com/455215 "HSTS not applied to WebSocket" -TEST_F(WebSocketEndToEndTest, HstsHttpsToWebSocket) { - EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS); - https_server.SetSSLConfig( - net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN); - https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest"); - - SpawnedTestServer::SSLOptions ssl_options( - SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); - SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options, - GetWebSocketTestDataDirectory()); - - ASSERT_TRUE(https_server.Start()); - ASSERT_TRUE(wss_server.Start()); - InitialiseContext(); - // Set HSTS via https: - TestDelegate delegate; - GURL https_page = https_server.GetURL("/hsts-headers.html"); - std::unique_ptr<URLRequest> request(context_.CreateRequest( - https_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); - request->Start(); - delegate.RunUntilComplete(); - EXPECT_EQ(OK, delegate.request_status()); - - // Check HSTS with ws: - // Change the scheme from wss: to ws: to verify that it is switched back. - GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws"); - EXPECT_TRUE(ConnectAndWait(ws_url)); -} - -TEST_F(WebSocketEndToEndTest, HstsWebSocketToHttps) { - EmbeddedTestServer https_server(net::EmbeddedTestServer::Type::TYPE_HTTPS); - https_server.SetSSLConfig( - net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN); - https_server.ServeFilesFromSourceDirectory("net/data/url_request_unittest"); - - SpawnedTestServer::SSLOptions ssl_options( - SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); - SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options, - GetWebSocketTestDataDirectory()); - ASSERT_TRUE(https_server.Start()); - ASSERT_TRUE(wss_server.Start()); - InitialiseContext(); - // Set HSTS via wss: - GURL wss_url = wss_server.GetURL("set-hsts"); - EXPECT_TRUE(ConnectAndWait(wss_url)); - - // Verify via http: - TestDelegate delegate; - GURL http_page = - ReplaceUrlScheme(https_server.GetURL("/simple.html"), "http"); - std::unique_ptr<URLRequest> request(context_.CreateRequest( - http_page, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS)); - request->Start(); - delegate.RunUntilComplete(); - EXPECT_EQ(OK, delegate.request_status()); - EXPECT_TRUE(request->url().SchemeIs("https")); -} - -TEST_F(WebSocketEndToEndTest, HstsWebSocketToWebSocket) { - SpawnedTestServer::SSLOptions ssl_options( - SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN); - SpawnedTestServer wss_server(SpawnedTestServer::TYPE_WSS, ssl_options, - GetWebSocketTestDataDirectory()); - ASSERT_TRUE(wss_server.Start()); - InitialiseContext(); - // Set HSTS via wss: - GURL wss_url = wss_server.GetURL("set-hsts"); - EXPECT_TRUE(ConnectAndWait(wss_url)); - - // Verify via wss: - GURL ws_url = ReplaceUrlScheme(wss_server.GetURL(kEchoServer), "ws"); - EXPECT_TRUE(ConnectAndWait(ws_url)); -} - // Regression test for crbug.com/180504 "WebSocket handshake fails when HTTP // headers have trailing LWS". TEST_F(WebSocketEndToEndTest, TrailingWhitespace) { @@ -609,6 +534,161 @@ event_interface_->extensions()); } +// These are not true end-to-end tests as the SpawnedTestServer doesn't +// support TLS 1.2. +// TODO(ricea): Make these be true end-to-end tests again when +// SpawnedTestServer supports TLS 1.2 or EmbeddedTestServer supports +// WebSockets. +class WebSocketHstsTest : public TestWithTaskEnvironment { + protected: + WebSocketHstsTest() : context_(true) { + context_.set_client_socket_factory(&socket_factory_); + context_.Init(); + } + + void MakeHttpConnection(const GURL& url) { + // Set up SSL details, because otherwise HSTS headers aren't processed. + SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK); + ssl_socket_data.ssl_info.cert = + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); + ssl_socket_data.ssl_info.is_issued_by_known_root = true; + ssl_socket_data.ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS; + ssl_socket_data.ssl_info.cert_status = 0; + socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data); + + req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_, + TRAFFIC_ANNOTATION_FOR_TESTS); + + MockWrite writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: keep-alive\r\n" + "User-Agent: \r\n" + "Accept-Encoding: gzip, deflate\r\n" + "Accept-Language: en-us,fr\r\n\r\n")}; + MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n" + "Strict-Transport-Security: max-age=123; " + "includeSubdomains\r\n\r\n"), + MockRead(ASYNC, 0)}; + + StaticSocketDataProvider data(reads, writes); + socket_factory_.AddSocketDataProvider(&data); + + req_->Start(); + base::RunLoop().RunUntilIdle(); + } + + void MakeWebsocketConnection(const GURL& url) { + // Set up SSL details, because otherwise HSTS headers aren't processed. + SSLSocketDataProvider ssl_socket_data(net::ASYNC, net::OK); + ssl_socket_data.ssl_info.cert = + ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); + ssl_socket_data.ssl_info.is_issued_by_known_root = true; + ssl_socket_data.ssl_info.ct_policy_compliance = + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS; + ssl_socket_data.ssl_info.cert_status = 0; + socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data); + + req_ = context_.CreateRequest(url, DEFAULT_PRIORITY, &delegate_, + TRAFFIC_ANNOTATION_FOR_TESTS); + + HttpRequestHeaders headers; + headers.SetHeader("Connection", "Upgrade"); + headers.SetHeader("Upgrade", "websocket"); + headers.SetHeader("Origin", "null"); + headers.SetHeader("Sec-WebSocket-Version", "13"); + req_->SetExtraRequestHeaders(headers); + + MockWrite writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.example.org\r\n" + "Connection: Upgrade\r\n" + "Upgrade: websocket\r\n" + "Origin: null\r\n" + "Sec-WebSocket-Version: 13\r\n" + "User-Agent: \r\n" + "Accept-Encoding: gzip, deflate\r\n" + "Accept-Language: en-us,fr\r\n" + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Extensions: permessage-deflate; " + "client_max_window_bits\r\n\r\n")}; + MockRead reads[] = { + MockRead("HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" + "Strict-Transport-Security: max-age=123; " + "includeSubdomains\r\n\r\n"), + MockRead(ASYNC, 0)}; + + StaticSocketDataProvider data(reads, writes); + socket_factory_.AddSocketDataProvider(&data); + + req_->SetUserData( + kWebSocketHandshakeUserDataKey, + std::make_unique<TestWebSocketHandshakeStreamCreateHelper>()); + req_->SetLoadFlags(LOAD_DISABLE_CACHE); + req_->Start(); + base::RunLoop().RunUntilIdle(); + } + + TestURLRequestContext context_; + MockClientSocketFactory socket_factory_; + TestDelegate delegate_; + std::unique_ptr<URLRequest> req_; +}; + +// Regression test for crbug.com/455215 "HSTS not applied to WebSocket" +TEST_F(WebSocketHstsTest, HTTPSToWebSocket) { + // Set HSTS via https: + MakeHttpConnection(GURL("https://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + + ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL( + "www.example.org")); + + // Check HSTS by starting a request over ws: and verifying that it gets + // ugpraded to wss:. + MakeWebsocketConnection(GURL("ws://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + EXPECT_TRUE(delegate_.response_completed()); + EXPECT_TRUE(req_->url().SchemeIs("wss")); +} + +TEST_F(WebSocketHstsTest, WebSocketToHTTP) { + // Set HSTS via wss: + MakeWebsocketConnection(GURL("wss://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + EXPECT_TRUE(delegate_.response_completed()); + + ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL( + "www.example.org")); + + // Check HSTS by starting a request over http: and verifying that it gets + // ugpraded to https:. + MakeHttpConnection(GURL("http://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + EXPECT_TRUE(req_->url().SchemeIs("https")); +} + +TEST_F(WebSocketHstsTest, WebSocketToWebSocket) { + // Set HSTS via wss: + MakeWebsocketConnection(GURL("wss://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + EXPECT_TRUE(delegate_.response_completed()); + + ASSERT_TRUE(context_.transport_security_state()->ShouldUpgradeToSSL( + "www.example.org")); + + // Check HSTS by starting a request over ws: and verifying that it gets + // ugpraded to wss:. + MakeWebsocketConnection(GURL("ws://www.example.org")); + EXPECT_EQ(OK, delegate_.request_status()); + EXPECT_TRUE(delegate_.response_completed()); + EXPECT_TRUE(req_->url().SchemeIs("wss")); +} + } // namespace } // namespace net
diff --git a/net/websockets/websocket_http2_handshake_stream.cc b/net/websockets/websocket_http2_handshake_stream.cc index ce60d0c..ee56bd42 100644 --- a/net/websockets/websocket_http2_handshake_stream.cc +++ b/net/websockets/websocket_http2_handshake_stream.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/check_op.h" +#include "base/no_destructor.h" #include "base/notreached.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" @@ -236,6 +237,12 @@ return nullptr; } +const std::vector<std::string>& WebSocketHttp2HandshakeStream::GetDnsAliases() + const { + static const base::NoDestructor<std::vector<std::string>> emptyvector_result; + return *emptyvector_result; +} + std::unique_ptr<WebSocketStream> WebSocketHttp2HandshakeStream::Upgrade() { DCHECK(extension_params_.get());
diff --git a/net/websockets/websocket_http2_handshake_stream.h b/net/websockets/websocket_http2_handshake_stream.h index 634806f..f6d0b02 100644 --- a/net/websockets/websocket_http2_handshake_stream.h +++ b/net/websockets/websocket_http2_handshake_stream.h
@@ -86,6 +86,7 @@ void SetPriority(RequestPriority priority) override; void PopulateNetErrorDetails(NetErrorDetails* details) override; HttpStream* RenewStreamForAuth() override; + const std::vector<std::string>& GetDnsAliases() const override; // WebSocketHandshakeStreamBase methods.
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index 9b8d3730..e101717b 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc
@@ -239,6 +239,10 @@ constexpr char kJSGetThumbnailWidth[] = "width"; constexpr char kJSGetThumbnailHeight[] = "height"; +// Set read only to disable interaction with content (Page -> Plugin) +constexpr char kJSSetReadOnlyType[] = "setReadOnly"; +constexpr char kJSEnableReadOnly[] = "enableReadOnly"; + constexpr int kFindResultCooldownMs = 100; // Do not save files with over 100 MB. This cap should be kept in sync with and @@ -657,6 +661,8 @@ RotateClockwise(); } else if (type == kJSRotateCounterclockwiseType) { RotateCounterclockwise(); + } else if (type == kJSSetReadOnlyType) { + HandleSetReadOnlyMessage(dict); } else if (type == kJSSetTwoUpViewType) { HandleSetTwoUpViewMessage(dict); } else if (type == kJSDisplayAnnotationsType) { @@ -1075,94 +1081,6 @@ SetTickmarks(tickmarks_); } -std::unique_ptr<Graphics> OutOfProcessInstance::CreatePaintGraphics( - const gfx::Size& size) { - auto graphics = std::make_unique<PepperGraphics>(this, size); - DCHECK(!graphics->pepper_graphics().is_null()); - return graphics; -} - -bool OutOfProcessInstance::BindPaintGraphics(Graphics& graphics) { - return BindGraphics(static_cast<PepperGraphics&>(graphics).pepper_graphics()); -} - -void OutOfProcessInstance::OnPaint(const std::vector<gfx::Rect>& paint_rects, - std::vector<PaintReadyRect>* ready, - std::vector<gfx::Rect>* pending) { - base::AutoReset<bool> auto_reset_in_paint(&in_paint_, true); - if (image_data_.is_null()) { - DCHECK(plugin_size_.IsEmpty()); - return; - } - if (first_paint_) { - first_paint_ = false; - pp::Rect rect = pp::Rect(pp::Point(), image_data_.size()); - FillRect(rect, background_color_); - ready->push_back(PaintReadyRect(rect, image_data_, /*flush_now=*/true)); - } - - if (!received_viewport_message_ || !needs_reraster_) - return; - - engine()->PrePaint(); - - for (const auto& paint_rect : paint_rects) { - // Intersect with plugin area since there could be pending invalidates from - // when the plugin area was larger. - pp::Rect rect = PPRectFromRect(paint_rect); - rect = rect.Intersect(pp::Rect(pp::Point(), plugin_size_)); - if (rect.IsEmpty()) - continue; - - pp::Rect pdf_rect = available_area_.Intersect(rect); - if (!pdf_rect.IsEmpty()) { - pdf_rect.Offset(available_area_.x() * -1, 0); - - std::vector<gfx::Rect> pdf_ready; - std::vector<gfx::Rect> pdf_pending; - engine()->Paint(RectFromPPRect(pdf_rect), skia_image_data_, pdf_ready, - pdf_pending); - for (auto& ready_rect : pdf_ready) { - ready_rect.Offset(VectorFromPPPoint(available_area_.point())); - ready->push_back( - PaintReadyRect(PPRectFromRect(ready_rect), image_data_)); - } - for (auto& pending_rect : pdf_pending) { - pending_rect.Offset(VectorFromPPPoint(available_area_.point())); - pending->push_back(pending_rect); - } - } - - // Ensure the region above the first page (if any) is filled; - int32_t first_page_ypos = engine()->GetNumberOfPages() == 0 - ? 0 - : engine()->GetPageScreenRect(0).y(); - if (rect.y() < first_page_ypos) { - pp::Rect region = rect.Intersect(pp::Rect( - pp::Point(), pp::Size(plugin_size_.width(), first_page_ypos))); - ready->push_back(PaintReadyRect(region, image_data_)); - FillRect(region, background_color_); - } - - for (const auto& background_part : background_parts_) { - pp::Rect intersection = background_part.location.Intersect(rect); - if (!intersection.IsEmpty()) { - FillRect(intersection, background_part.color); - ready->push_back(PaintReadyRect(intersection, image_data_)); - } - } - } - - engine()->PostPaint(); - - if (!deferred_invalidates_.empty()) { - pp::Module::Get()->core()->CallOnMainThread( - 0, PPCompletionCallbackFromResultCallback( - base::BindOnce(&OutOfProcessInstance::InvalidateAfterPaintDone, - weak_factory_.GetWeakPtr()))); - } -} - void OutOfProcessInstance::DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result) { if (result == PP_OK) { @@ -1906,6 +1824,18 @@ } } +void OutOfProcessInstance::HandleSetReadOnlyMessage( + const pp::VarDictionary& dict) { + if (!base::FeatureList::IsEnabled(features::kPDFViewerUpdate) || + !base::FeatureList::IsEnabled(features::kPdfViewerPresentationMode) || + !dict.Get(pp::Var(kJSEnableReadOnly)).is_bool()) { + NOTREACHED(); + return; + } + + engine()->SetReadOnly(dict.Get(pp::Var(kJSEnableReadOnly)).AsBool()); +} + void OutOfProcessInstance::HandleSetTwoUpViewMessage( const pp::VarDictionary& dict) { if (!base::FeatureList::IsEnabled(features::kPDFViewerUpdate) || @@ -2270,6 +2200,94 @@ return pp::Var(url).is_string(); } +std::unique_ptr<Graphics> OutOfProcessInstance::CreatePaintGraphics( + const gfx::Size& size) { + auto graphics = std::make_unique<PepperGraphics>(this, size); + DCHECK(!graphics->pepper_graphics().is_null()); + return graphics; +} + +bool OutOfProcessInstance::BindPaintGraphics(Graphics& graphics) { + return BindGraphics(static_cast<PepperGraphics&>(graphics).pepper_graphics()); +} + +void OutOfProcessInstance::OnPaint(const std::vector<gfx::Rect>& paint_rects, + std::vector<PaintReadyRect>* ready, + std::vector<gfx::Rect>* pending) { + base::AutoReset<bool> auto_reset_in_paint(&in_paint_, true); + if (image_data_.is_null()) { + DCHECK(plugin_size_.IsEmpty()); + return; + } + if (first_paint_) { + first_paint_ = false; + pp::Rect rect = pp::Rect(pp::Point(), image_data_.size()); + FillRect(rect, background_color_); + ready->push_back(PaintReadyRect(rect, image_data_, /*flush_now=*/true)); + } + + if (!received_viewport_message_ || !needs_reraster_) + return; + + engine()->PrePaint(); + + for (const auto& paint_rect : paint_rects) { + // Intersect with plugin area since there could be pending invalidates from + // when the plugin area was larger. + pp::Rect rect = PPRectFromRect(paint_rect); + rect = rect.Intersect(pp::Rect(pp::Point(), plugin_size_)); + if (rect.IsEmpty()) + continue; + + pp::Rect pdf_rect = available_area_.Intersect(rect); + if (!pdf_rect.IsEmpty()) { + pdf_rect.Offset(available_area_.x() * -1, 0); + + std::vector<gfx::Rect> pdf_ready; + std::vector<gfx::Rect> pdf_pending; + engine()->Paint(RectFromPPRect(pdf_rect), skia_image_data_, pdf_ready, + pdf_pending); + for (auto& ready_rect : pdf_ready) { + ready_rect.Offset(VectorFromPPPoint(available_area_.point())); + ready->push_back( + PaintReadyRect(PPRectFromRect(ready_rect), image_data_)); + } + for (auto& pending_rect : pdf_pending) { + pending_rect.Offset(VectorFromPPPoint(available_area_.point())); + pending->push_back(pending_rect); + } + } + + // Ensure the region above the first page (if any) is filled; + int32_t first_page_ypos = engine()->GetNumberOfPages() == 0 + ? 0 + : engine()->GetPageScreenRect(0).y(); + if (rect.y() < first_page_ypos) { + pp::Rect region = rect.Intersect(pp::Rect( + pp::Point(), pp::Size(plugin_size_.width(), first_page_ypos))); + ready->push_back(PaintReadyRect(region, image_data_)); + FillRect(region, background_color_); + } + + for (const auto& background_part : background_parts_) { + pp::Rect intersection = background_part.location.Intersect(rect); + if (!intersection.IsEmpty()) { + FillRect(intersection, background_part.color); + ready->push_back(PaintReadyRect(intersection, image_data_)); + } + } + } + + engine()->PostPaint(); + + if (!deferred_invalidates_.empty()) { + pp::Module::Get()->core()->CallOnMainThread( + 0, PPCompletionCallbackFromResultCallback( + base::BindOnce(&OutOfProcessInstance::InvalidateAfterPaintDone, + weak_factory_.GetWeakPtr()))); + } +} + void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url, int dest_page_index) { DCHECK(IsPrintPreview());
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h index 4b9c371..e3d94324 100644 --- a/pdf/out_of_process_instance.h +++ b/pdf/out_of_process_instance.h
@@ -52,7 +52,6 @@ public pp::Instance, public pp::Find_Private, public pp::Printing_Dev, - public PaintManager::Client, public PreviewModeClient::Client { public: explicit OutOfProcessInstance(PP_Instance instance); @@ -72,13 +71,6 @@ void SelectFindResult(bool forward) override; void StopFind() override; - // pp::PaintManager::Client: - std::unique_ptr<Graphics> CreatePaintGraphics(const gfx::Size& size) override; - bool BindPaintGraphics(Graphics& graphics) override; - void OnPaint(const std::vector<gfx::Rect>& paint_rects, - std::vector<PaintReadyRect>* ready, - std::vector<gfx::Rect>* pending) override; - // pp::Printing_Dev: uint32_t QuerySupportedPrintOutputFormats() override; int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) override; @@ -166,6 +158,11 @@ void SetSelectedText(const std::string& selected_text) override; void SetLinkUnderCursor(const std::string& link_under_cursor) override; bool IsValidLink(const std::string& url) override; + std::unique_ptr<Graphics> CreatePaintGraphics(const gfx::Size& size) override; + bool BindPaintGraphics(Graphics& graphics) override; + void OnPaint(const std::vector<gfx::Rect>& paint_rects, + std::vector<PaintReadyRect>* ready, + std::vector<gfx::Rect>* pending) override; // PreviewModeClient::Client: void PreviewDocumentLoadComplete() override; @@ -199,6 +196,7 @@ void HandleResetPrintPreviewModeMessage(const pp::VarDictionary& dict); void HandleSaveAttachmentMessage(const pp::VarDictionary& dict); void HandleSaveMessage(const pp::VarDictionary& dict); + void HandleSetReadOnlyMessage(const pp::VarDictionary& dict); void HandleSetTwoUpViewMessage(const pp::VarDictionary& dict); void HandleUpdateScrollMessage(const pp::VarDictionary& dict); void HandleViewportMessage(const pp::VarDictionary& dict);
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index c4008b0..392c0576 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h
@@ -366,6 +366,8 @@ virtual void ZoomUpdated(double new_zoom_level) = 0; virtual void RotateClockwise() = 0; virtual void RotateCounterclockwise() = 0; + virtual bool IsReadOnly() const = 0; + virtual void SetReadOnly(bool enable) = 0; virtual void SetTwoUpView(bool enable) = 0; virtual void DisplayAnnotations(bool display) = 0;
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h index 566ca4f..dd5677f 100644 --- a/pdf/pdf_view_plugin_base.h +++ b/pdf/pdf_view_plugin_base.h
@@ -13,6 +13,7 @@ #include <string> #include "base/memory/weak_ptr.h" +#include "pdf/paint_manager.h" #include "pdf/pdfium/pdfium_form_filler.h" namespace chrome_pdf { @@ -22,7 +23,8 @@ // Common base to share code between the two plugin implementations, // `OutOfProcessInstance` (Pepper) and `PdfViewWebPlugin` (Blink). -class PdfViewPluginBase : public PDFEngine::Client { +class PdfViewPluginBase : public PDFEngine::Client, + public PaintManager::Client { public: PdfViewPluginBase(const PdfViewPluginBase& other) = delete; PdfViewPluginBase& operator=(const PdfViewPluginBase& other) = delete;
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc index 354234c..4143faa 100644 --- a/pdf/pdf_view_web_plugin.cc +++ b/pdf/pdf_view_web_plugin.cc
@@ -309,6 +309,26 @@ return base::Value(url).is_string(); } +std::unique_ptr<Graphics> PdfViewWebPlugin::CreatePaintGraphics( + const gfx::Size& size) { + auto graphics = SkiaGraphics::Create(size); + DCHECK(graphics); + return graphics; +} + +bool PdfViewWebPlugin::BindPaintGraphics(Graphics& graphics) { + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} + +// TODO(https://crbug.com/1099020): To be implemented as a Pepper-free version +// of `OutOfProcessInstance::OnPaint()` +void PdfViewWebPlugin::OnPaint(const std::vector<gfx::Rect>& paint_rects, + std::vector<PaintReadyRect>* ready, + std::vector<gfx::Rect>* pending) { + NOTIMPLEMENTED_LOG_ONCE(); +} + bool PdfViewWebPlugin::IsValid() const { return container_ && container_->GetDocument().GetFrame(); } @@ -340,26 +360,6 @@ options); } -std::unique_ptr<Graphics> PdfViewWebPlugin::CreatePaintGraphics( - const gfx::Size& size) { - auto graphics = SkiaGraphics::Create(size); - DCHECK(graphics); - return graphics; -} - -bool PdfViewWebPlugin::BindPaintGraphics(Graphics& graphics) { - NOTIMPLEMENTED_LOG_ONCE(); - return false; -} - -// TODO(https://crbug.com/1099020): To be implemented as a Pepper-free version -// of `OutOfProcessInstance::OnPaint()` -void PdfViewWebPlugin::OnPaint(const std::vector<gfx::Rect>& paint_rects, - std::vector<PaintReadyRect>* ready, - std::vector<gfx::Rect>* pending) { - NOTIMPLEMENTED_LOG_ONCE(); -} - base::WeakPtr<PdfViewPluginBase> PdfViewWebPlugin::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h index c3d1d10..00ecc52a 100644 --- a/pdf/pdf_view_web_plugin.h +++ b/pdf/pdf_view_web_plugin.h
@@ -21,8 +21,7 @@ // Skeleton for a `blink::WebPlugin` to replace `OutOfProcessInstance`. class PdfViewWebPlugin final : public PdfViewPluginBase, public blink::WebPlugin, - public BlinkUrlLoader::Client, - public PaintManager::Client { + public BlinkUrlLoader::Client { public: explicit PdfViewWebPlugin(const blink::WebPluginParams& params); PdfViewWebPlugin(const PdfViewWebPlugin& other) = delete; @@ -105,6 +104,11 @@ void SetSelectedText(const std::string& selected_text) override; void SetLinkUnderCursor(const std::string& link_under_cursor) override; bool IsValidLink(const std::string& url) override; + std::unique_ptr<Graphics> CreatePaintGraphics(const gfx::Size& size) override; + bool BindPaintGraphics(Graphics& graphics) override; + void OnPaint(const std::vector<gfx::Rect>& paint_rects, + std::vector<PaintReadyRect>* ready, + std::vector<gfx::Rect>* pending) override; // BlinkUrlLoader::Client: bool IsValid() const override; @@ -115,13 +119,6 @@ std::unique_ptr<blink::WebAssociatedURLLoader> CreateAssociatedURLLoader( const blink::WebAssociatedURLLoaderOptions& options) override; - // PaintManager::Client: - std::unique_ptr<Graphics> CreatePaintGraphics(const gfx::Size& size) override; - bool BindPaintGraphics(Graphics& graphics) override; - void OnPaint(const std::vector<gfx::Rect>& paint_rects, - std::vector<PaintReadyRect>* ready, - std::vector<gfx::Rect>* pending) override; - protected: // PdfViewPluginBase: base::WeakPtr<PdfViewPluginBase> GetWeakPtr() override;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index a517bb4b..640024dc2 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -2058,6 +2058,14 @@ ProposeNextDocumentLayout(); } +bool PDFiumEngine::IsReadOnly() const { + return read_only_; +} + +void PDFiumEngine::SetReadOnly(bool enable) { + read_only_ = enable; +} + void PDFiumEngine::SetTwoUpView(bool enable) { desired_layout_options_.set_two_up_view_enabled(enable); ProposeNextDocumentLayout();
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 2dca35c..39b957d 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -102,6 +102,8 @@ void ZoomUpdated(double new_zoom_level) override; void RotateClockwise() override; void RotateCounterclockwise() override; + bool IsReadOnly() const override; + void SetReadOnly(bool enable) override; void SetTwoUpView(bool enable) override; void DisplayAnnotations(bool display) override; gfx::Size ApplyDocumentLayout( @@ -828,6 +830,10 @@ bool edit_mode_ = false; + // When true, interactive portions of the content, such as forms and links, + // are restricted. + bool read_only_ = false; + PDFiumPrint print_; base::WeakPtrFactory<PDFiumEngine> weak_factory_{this};
diff --git a/remoting/host/input_injector_mac.cc b/remoting/host/input_injector_mac.cc index e14494d..f4619af 100644 --- a/remoting/host/input_injector_mac.cc +++ b/remoting/host/input_injector_mac.cc
@@ -50,7 +50,9 @@ if (eventRef) { CGEventSetFlags(eventRef, static_cast<CGEventFlags>(flags)); if (!unicode.empty()) - CGEventKeyboardSetUnicodeString(eventRef, unicode.size(), &(unicode[0])); + CGEventKeyboardSetUnicodeString( + eventRef, unicode.size(), + reinterpret_cast<const UniChar*>(unicode.data())); CGEventPost(kCGSessionEventTap, eventRef); } }
diff --git a/remoting/host/keyboard_layout_monitor_mac.cc b/remoting/host/keyboard_layout_monitor_mac.cc index 6f85d01..71bec35 100644 --- a/remoting/host/keyboard_layout_monitor_mac.cc +++ b/remoting/host/keyboard_layout_monitor_mac.cc
@@ -204,7 +204,9 @@ } key_actions[shift_level].set_character( - base::UTF16ToUTF8(base::StringPiece16(result_array, result_length))); + base::UTF16ToUTF8(base::StringPiece16( + reinterpret_cast<const base::char16*>(result_array), + result_length))); } if (key_actions.size() == 0) {
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn index c6609b5..7c36810c 100644 --- a/services/device/BUILD.gn +++ b/services/device/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") import("//testing/test.gni") @@ -195,7 +196,7 @@ ] } - if (is_linux && use_udev) { + if ((is_linux || is_chromeos_lacros) && use_udev) { sources += [ "generic_sensor/platform_sensor_and_provider_unittest_linux.cc" ] }
diff --git a/services/device/battery/BUILD.gn b/services/device/battery/BUILD.gn index f63e0ba..f2a1bc3 100644 --- a/services/device/battery/BUILD.gn +++ b/services/device/battery/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") import("//mojo/public/tools/bindings/mojom.gni") @@ -37,7 +38,7 @@ "//chromeos/dbus/power:power_manager_proto", ] sources += [ "battery_status_manager_chromeos.cc" ] - } else if (is_linux && use_dbus) { + } else if ((is_linux || is_chromeos_lacros) && use_dbus) { configs += [ "//build/config/linux/dbus" ] deps += [ "//dbus" ] sources += [
diff --git a/services/device/generic_sensor/BUILD.gn b/services/device/generic_sensor/BUILD.gn index b2d85ab0..d192a5be 100644 --- a/services/device/generic_sensor/BUILD.gn +++ b/services/device/generic_sensor/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") if (is_android) { @@ -82,7 +83,7 @@ ] } - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "linux/sensor_data_linux.cc", "linux/sensor_data_linux.h", @@ -108,7 +109,7 @@ } } - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ "//chromeos/components/sensors", "//chromeos/components/sensors/mojom",
diff --git a/services/device/generic_sensor/platform_sensor_provider.cc b/services/device/generic_sensor/platform_sensor_provider.cc index a50f733d..1040ea8e 100644 --- a/services/device/generic_sensor/platform_sensor_provider.cc +++ b/services/device/generic_sensor/platform_sensor_provider.cc
@@ -4,6 +4,8 @@ #include "services/device/generic_sensor/platform_sensor_provider.h" +#include "build/chromeos_buildflags.h" + #if defined(OS_MAC) #include "services/device/generic_sensor/platform_sensor_provider_mac.h" #elif defined(OS_ANDROID) @@ -15,9 +17,9 @@ #include "services/device/generic_sensor/platform_sensor_provider_win.h" #include "services/device/generic_sensor/platform_sensor_provider_winrt.h" #include "services/device/public/cpp/device_features.h" -#elif defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_CHROMEOS_ASH) #include "services/device/generic_sensor/platform_sensor_provider_chromeos.h" -#elif defined(OS_LINUX) && defined(USE_UDEV) +#elif (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_UDEV) #include "services/device/generic_sensor/platform_sensor_provider_linux.h" #endif @@ -35,9 +37,9 @@ } else { return std::make_unique<PlatformSensorProviderWin>(); } -#elif defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_CHROMEOS_ASH) return std::make_unique<PlatformSensorProviderChromeOS>(); -#elif defined(OS_LINUX) && defined(USE_UDEV) +#elif (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_UDEV) return std::make_unique<PlatformSensorProviderLinux>(); #else return nullptr;
diff --git a/services/device/geolocation/BUILD.gn b/services/device/geolocation/BUILD.gn index ac1cc95..11145c0 100644 --- a/services/device/geolocation/BUILD.gn +++ b/services/device/geolocation/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") if (is_android) { @@ -105,7 +106,7 @@ "wifi_data_provider_chromeos.h", ] deps += [ "//chromeos/network" ] - } else if (is_linux && use_dbus) { + } else if ((is_linux || is_chromeos_lacros) && use_dbus) { sources += [ "wifi_data_provider_linux.cc", "wifi_data_provider_linux.h",
diff --git a/services/device/time_zone_monitor/BUILD.gn b/services/device/time_zone_monitor/BUILD.gn index 41e2fdb6..00d3464 100644 --- a/services/device/time_zone_monitor/BUILD.gn +++ b/services/device/time_zone_monitor/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chromeos/ui_mode.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/features.gni") if (is_android) { @@ -39,7 +40,7 @@ deps += [ "//ui/gfx" ] } - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "time_zone_monitor_linux.cc" ] }
diff --git a/services/device/usb/mojo/device_manager_impl_unittest.cc b/services/device/usb/mojo/device_manager_impl_unittest.cc index 7323934..2d6f0b3 100644 --- a/services/device/usb/mojo/device_manager_impl_unittest.cc +++ b/services/device/usb/mojo/device_manager_impl_unittest.cc
@@ -17,6 +17,7 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "build/chromeos_buildflags.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/device/public/mojom/usb_enumeration_options.mojom.h"
diff --git a/services/device/usb/usb_service_linux.cc b/services/device/usb/usb_service_linux.cc index 86445ad4..c9011af 100644 --- a/services/device/usb/usb_service_linux.cc +++ b/services/device/usb/usb_service_linux.cc
@@ -24,6 +24,7 @@ #include "base/threading/scoped_blocking_call.h" #include "base/threading/sequenced_task_runner_handle.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/device_event_log/device_event_log.h" #include "device/udev_linux/udev_watcher.h" #include "services/device/usb/usb_device_handle.h"
diff --git a/services/device/usb/usb_service_linux.h b/services/device/usb/usb_service_linux.h index fe133b6..61dd142 100644 --- a/services/device/usb/usb_service_linux.h +++ b/services/device/usb/usb_service_linux.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" +#include "build/chromeos_buildflags.h" #include "services/device/usb/usb_service.h" namespace device {
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 02bf262b..238fc37 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -2300,7 +2300,8 @@ net::CookieCryptoDelegate* crypto_delegate = nullptr; if (params_->enable_encrypted_cookies) { -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !BUILDFLAG(IS_CHROMECAST) +#if (defined(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \ + !BUILDFLAG(IS_CHROMECAST) DCHECK(network_service_->os_crypt_config_set()) << "NetworkService::SetCryptConfig must be called before creating a " "NetworkContext with encrypted cookies.";
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index 7d45f16..ea0388a 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -85,7 +85,7 @@ // Enables Cross-Origin Opener Policy (COOP) reporting. // https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e const base::Feature kCrossOriginOpenerPolicyReporting{ - "CrossOriginOpenerPolicyReporting", base::FEATURE_DISABLED_BY_DEFAULT}; + "CrossOriginOpenerPolicyReporting", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables Cross-Origin Opener Policy (COOP) access reporting. // https://github.com/camillelamy/explainers/blob/master/coop_reporting.md#report-blocked-accesses-to-other-windows
diff --git a/services/network/trust_tokens/test/trust_token_request_handler.cc b/services/network/trust_tokens/test/trust_token_request_handler.cc index bedffdfb..9e8b03e3 100644 --- a/services/network/trust_tokens/test/trust_token_request_handler.cc +++ b/services/network/trust_tokens/test/trust_token_request_handler.cc
@@ -64,10 +64,26 @@ return p.expiry <= base::Time::Now(); } +std::string UnavailableLocalOperationFallbackToString( + mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback + fallback) { + switch (fallback) { + case mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kReturnWithError: + return "return_with_error"; + case mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kWebIssuance: + return "web_issuance"; + }; +} + } // namespace TrustTokenRequestHandler::Options::Options() = default; TrustTokenRequestHandler::Options::~Options() = default; +TrustTokenRequestHandler::Options::Options(const Options&) = default; +TrustTokenRequestHandler::Options& TrustTokenRequestHandler::Options::operator=( + const Options&) = default; struct TrustTokenRequestHandler::Rep { // The protocol version to use. @@ -79,6 +95,13 @@ // Issue at most this many tokens per issuance. int batch_size; + // These values determine which Platform Provided Trust Tokens-related + // arguments should be included in returned key commitments: + std::set<mojom::TrustTokenKeyCommitmentResult::Os> + specify_platform_issuance_on; + mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback + unavailable_local_operation_fallback; + // Expect that client-side signing operations succeeded or failed according to // the value of this field. SigningOutcome client_signing_outcome; @@ -239,6 +262,22 @@ .InMicroseconds())); } + if (!rep_->specify_platform_issuance_on.empty()) { + value.SetStringKey("unavailable_local_operation_fallback", + UnavailableLocalOperationFallbackToString( + rep_->unavailable_local_operation_fallback)); + + base::Value oses(base::Value::Type::LIST); + for (auto os : rep_->specify_platform_issuance_on) { + switch (os) { + case mojom::TrustTokenKeyCommitmentResult::Os::kAndroid: + oses.Append("android"); + break; + }; + } + value.SetKey("request_issuance_locally_on", std::move(oses)); + } + // It's OK to be a bit crashy in exceptional failure cases because it // indicates a serious coding error in this test-only code; we'd like to find // this out sooner rather than later. @@ -368,6 +407,10 @@ for (int i = 0; i < options.num_keys; ++i) { rep_->issuance_keys.push_back(GenerateIssuanceKeyPair(i)); } + + rep_->specify_platform_issuance_on = options.specify_platform_issuance_on; + rep_->unavailable_local_operation_fallback = + options.unavailable_local_operation_fallback; } } // namespace test
diff --git a/services/network/trust_tokens/test/trust_token_request_handler.h b/services/network/trust_tokens/test/trust_token_request_handler.h index c2184bf..2a4bb7d8 100644 --- a/services/network/trust_tokens/test/trust_token_request_handler.h +++ b/services/network/trust_tokens/test/trust_token_request_handler.h
@@ -13,6 +13,7 @@ #include "base/synchronization/lock.h" #include "base/time/time.h" #include "net/http/http_request_headers.h" +#include "services/network/public/mojom/trust_tokens.mojom.h" #include "url/gurl.h" namespace network { @@ -57,6 +58,8 @@ struct Options final { Options(); ~Options(); + Options(const Options&); + Options& operator=(const Options&); // The number of issuance key pairs to provide via key commitment results. int num_keys = 1; @@ -85,6 +88,18 @@ ServerOperationOutcome::kExecuteOperationAsNormal; ServerOperationOutcome redemption_outcome = ServerOperationOutcome::kExecuteOperationAsNormal; + + // The following two fields specify operating systems on which to specify + // that the browser should attempt platform-provided trust token issuance + // instead of sending requests directly to the issuer's server, and the + // fallback behavior when these operations are unavailable. This information + // will be included in GetKeyCommitmentRecord's returned commitments. + std::set<mojom::TrustTokenKeyCommitmentResult::Os> + specify_platform_issuance_on; + mojom::TrustTokenKeyCommitmentResult::UnavailableLocalOperationFallback + unavailable_local_operation_fallback = + mojom::TrustTokenKeyCommitmentResult:: + UnavailableLocalOperationFallback::kReturnWithError; }; // Updates the handler's options, resetting its internal state.
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc index 10adf83..74028e08 100644 --- a/services/tracing/public/cpp/perfetto/perfetto_config.cc +++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -79,7 +79,11 @@ // Capture system trace events if supported and enabled. The datasources will // only emit events if system tracing is enabled in |chrome_config|. if (!privacy_filtering_enabled) { -#if defined(OS_CHROMEOS) || (BUILDFLAG(IS_CHROMECAST) && defined(OS_LINUX)) +// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is +// complete. +#if defined(OS_CHROMEOS) || \ + (BUILDFLAG(IS_CHROMECAST) && \ + (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))) if (source_names.empty() || source_names.count(tracing::mojom::kSystemTraceDataSourceName) == 1) { AddDataSourceConfig(perfetto_config,
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 23c227bc..ac78802 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -240,11 +240,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -254,7 +254,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -317,11 +317,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -331,7 +331,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -394,11 +394,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -408,7 +408,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -471,11 +471,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -485,7 +485,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -769,11 +769,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -783,7 +783,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -846,11 +846,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -860,7 +860,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -923,11 +923,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -937,7 +937,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1000,11 +1000,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -1014,7 +1014,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1298,11 +1298,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -1312,7 +1312,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1375,11 +1375,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -1389,7 +1389,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1452,11 +1452,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -1466,7 +1466,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1529,11 +1529,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -1543,7 +1543,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1827,11 +1827,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -1841,7 +1841,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1904,11 +1904,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -1918,7 +1918,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -1981,11 +1981,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.121", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 87.0.4280.122", "resultdb": { "enable": true }, @@ -1995,7 +1995,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M87", - "revision": "version:87.0.4280.121" + "revision": "version:87.0.4280.122" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -2058,11 +2058,11 @@ "--bucket", "chromium-result-details", "--test-name", - "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52" + "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.52", + "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.55", "resultdb": { "enable": true }, @@ -2072,7 +2072,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M88", - "revision": "version:88.0.4324.52" + "revision": "version:88.0.4324.55" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 729fc897..a32c551 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -25977,7 +25977,8 @@ "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", "--gs-results-bucket=chromium-result-details", - "--recover-devices" + "--recover-devices", + "--vmodule=*xr_frame*=0,*xr_session*=1,*vr*=1,*xr*=2" ], "merge": { "args": [
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index 5b37f24..24b3eb91 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -3833,7 +3833,7 @@ "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" }, { - "experiment_percentage": 25, + "experiment_percentage": 10, "isolate_profile_data": true, "merge": { "args": [], @@ -3848,7 +3848,7 @@ } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 10 + "shards": 20 }, "test": "browser_tests", "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index f62fffd..3850433 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -520,7 +520,10 @@ }, }, 'Mac10.13 Tests':{ - 'experiment_percentage': 25 # https://crbug.com/1042757 + 'experiment_percentage': 10, # https://crbug.com/1042757 + 'swarming': { + 'shards': 20, + }, }, 'Mac10.13 Tests (dbg)': { 'swarming': { @@ -826,6 +829,13 @@ 'android-code-coverage-native', # https://crbug.com/1018780 ], 'modifications': { + 'android-lollipop-arm-rel': { + 'args': [ + # TODO(crbug.com/1159619): Remove once the cause of the flakes is + # determined with the extra logging. + '--vmodule=*xr_frame*=0,*xr_session*=1,*vr*=1,*xr*=2', + ], + }, # Use "--remove-system-package" according to crbug.com/931947#c1 'android-nougat-arm64-rel': { 'args': [ @@ -834,7 +844,7 @@ '--remove-system-package=com.google.vr.vrcore', '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk', ], - } + }, }, }, 'chrome_public_test_vr_apk-vega': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index e6efb88..b70a2561 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -319,13 +319,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=88', ], - 'identifier': 'Implementation Tests For 88.0.4324.52', + 'identifier': 'Implementation Tests For 88.0.4324.55', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M88', - 'revision': 'version:88.0.4324.52', + 'revision': 'version:88.0.4324.55', } ], }, @@ -342,13 +342,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--impl-version=87', ], - 'identifier': 'Implementation Tests For 87.0.4280.121', + 'identifier': 'Implementation Tests For 87.0.4280.122', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M87', - 'revision': 'version:87.0.4280.121', + 'revision': 'version:87.0.4280.122', } ], }, @@ -388,13 +388,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--client-version=88', ], - 'identifier': 'Client Tests For 88.0.4324.52', + 'identifier': 'Client Tests For 88.0.4324.55', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M88', - 'revision': 'version:88.0.4324.52', + 'revision': 'version:88.0.4324.55', } ], }, @@ -411,13 +411,13 @@ '../../weblayer/browser/android/javatests/skew/expectations.txt', '--client-version=87', ], - 'identifier': 'Client Tests For 87.0.4280.121', + 'identifier': 'Client Tests For 87.0.4280.122', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M87', - 'revision': 'version:87.0.4280.121', + 'revision': 'version:87.0.4280.122', } ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index d72a0db..ec6e7431 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -5268,6 +5268,25 @@ ] } ], + "OriginIsolationHeader": [ + { + "platforms": [ + "android", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "OriginIsolationHeader" + ] + } + ] + } + ], "OutOfBlinkCors": [ { "platforms": [ @@ -8083,7 +8102,12 @@ { "name": "Enabled", "params": { - "summary_card_poster_url": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" + "base_url": "https://staging-gsaprototype-pa.sandbox.googleapis.com", + "default_locale": "en", + "experiment_tag": "", + "fetch_frequency": "15", + "summary_card_poster_url": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", + "use_animated_gif_url": "false" }, "enable_features": [ "VideoTutorials"
diff --git a/third_party/.gitignore b/third_party/.gitignore index e789259..dd70593 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -89,7 +89,6 @@ /gemmlowp/src /gles2_conform /glfw/src -/glslang/src /gn/ /gnu_binutils/ /google_android_play_core/core-*.aar @@ -218,9 +217,6 @@ /snappy/src /soda /speex -/spirv-cross/spirv-cross -/spirv-headers/src -/SPIRV-Tools/src /sqlite/src /sqlite4java/lib/ /subresource-filter-ruleset/data/UnindexedRules @@ -239,6 +235,7 @@ /usrsctp/usrsctplib /v8-i18n /valgrind +/vulkan-deps /vulkan_memory_allocator /wayland/src /wayland-protocols/src
diff --git a/third_party/SPIRV-Tools/DIR_METADATA b/third_party/SPIRV-Tools/DIR_METADATA deleted file mode 100644 index 376e229..0000000 --- a/third_party/SPIRV-Tools/DIR_METADATA +++ /dev/null
@@ -1,5 +0,0 @@ -monorail { - component: "Internals>GPU>Internals" -} - -team_email: "graphics-dev@chromium.org"
diff --git a/third_party/SPIRV-Tools/LICENSE b/third_party/SPIRV-Tools/LICENSE deleted file mode 100644 index d645695..0000000 --- a/third_party/SPIRV-Tools/LICENSE +++ /dev/null
@@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.
diff --git a/third_party/SPIRV-Tools/OWNERS b/third_party/SPIRV-Tools/OWNERS deleted file mode 100644 index caff5903..0000000 --- a/third_party/SPIRV-Tools/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -vmiura@chromium.org -dsinclair@chromium.org
diff --git a/third_party/SPIRV-Tools/README.chromium b/third_party/SPIRV-Tools/README.chromium deleted file mode 100644 index 7225182..0000000 --- a/third_party/SPIRV-Tools/README.chromium +++ /dev/null
@@ -1,15 +0,0 @@ -Name: SPIR-V Tools -Short Name: SPIRV-Tools -URL: https://github.com/KhronosGroup/SPIRV-Tools.git -Version: Unknown -Security Critical: yes -License: Apache 2.0 -License File: LICENSE - -Description: -The SPIR-V Tools project provides an API and commands for processing -SPIR-V modules. - -Local Modifications: -Added OWNERS, README.chromium. -Ported build rules from CMake to GN.
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index fa2cdba..647efc5 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -858,5 +858,12 @@ const base::Feature kWebRtcDistinctWorkerThread{ "WebRtcDistinctWorkerThread", base::FEATURE_DISABLED_BY_DEFAULT}; +// When enabled, the SubresourceFilter receives calls from the ResourceLoader +// to perform additional checks against any aliases found from DNS CNAME records +// for the requested URL. +const base::Feature kSendCnameAliasesToSubresourceFilterFromRenderer{ + "SendCnameAliasesToSubresourceFilterFromRenderer", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace blink
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 8863bf3..1f1e0cf 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -348,6 +348,11 @@ BLINK_COMMON_EXPORT extern const base::Feature kWebRtcDistinctWorkerThread; +// Performs additional SubresourceFilter checks when CNAME aliases are found +// for the host of a requested URL. +BLINK_COMMON_EXPORT extern const base::Feature + kSendCnameAliasesToSubresourceFilterFromRenderer; + } // namespace features } // namespace blink
diff --git a/third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom b/third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom index efceb52..0798555 100644 --- a/third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom +++ b/third_party/blink/public/mojom/file_system_access/native_file_system_file_handle.mojom
@@ -26,7 +26,7 @@ AsBlob() => (NativeFileSystemError result, mojo_base.mojom.FileInfo info, SerializedBlob? blob); // Returns a FileWriter object. The FileWriter provides write operations on a file. - CreateFileWriter(bool keep_existing_data) => ( + CreateFileWriter(bool keep_existing_data, bool auto_close) => ( NativeFileSystemError result, pending_remote<NativeFileSystemFileWriter>? writer); // Returns true if |other| represents the same file on disk as this handle.
diff --git a/third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom b/third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom index 6686c2b..4c0f510 100644 --- a/third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom +++ b/third_party/blink/public/mojom/file_system_access/native_file_system_file_writer.mojom
@@ -32,6 +32,13 @@ // Closes the file writer. This will materialize the writes operations on the // intended file target in the case of atomic writes. + // Specify the |autoClose| flag to ensure Close() is automatically invoked + // when the mojo pipe closes. // Returns whether the operation succeeded. Close() => (NativeFileSystemError result); + + // Aborts the write operation, resulting in the writes not being committed, + // even if autoClose is specified. All further operations will be rejected. + // Returns whether the write operation was aborted successfully. + Abort() => (NativeFileSystemError result); };
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom index 57d82a3..af720508 100644 --- a/third_party/blink/public/mojom/frame/frame.mojom +++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -675,9 +675,12 @@ // Toggles render throttling on a remote frame. |is_throttled| indicates // whether the current frame should be throttled based on its viewport - // visibility, and |subtree_throttled| indicates that an ancestor frame has - // been throttled, so all descendant frames also should be throttled. - UpdateRenderThrottlingStatus(bool is_throttled, bool subtree_throttled); + // visibility; |subtree_throttled| indicates that an ancestor frame has + // been throttled, so all descendant frames also should be throttled; and + // |display_locked| indicates that an iframe is display locked by an ancestor + // of its <iframe> element in the parent process. + UpdateRenderThrottlingStatus( + bool is_throttled, bool subtree_throttled, bool display_locked); // Notifies the browser that the associated frame has changed its visibility // status. Visibility status changes occur when the frame moves in/out
diff --git a/third_party/blink/public/mojom/page/widget.mojom b/third_party/blink/public/mojom/page/widget.mojom index 5eecf07..a5731b65 100644 --- a/third_party/blink/public/mojom/page/widget.mojom +++ b/third_party/blink/public/mojom/page/widget.mojom
@@ -100,7 +100,8 @@ SetInheritedEffectiveTouchActionForSubFrame(cc.mojom.TouchAction touch_action); // Toggles render throttling for an out-of-process iframe. - UpdateRenderThrottlingStatusForSubFrame(bool is_throttled, bool subtree_throttled); + UpdateRenderThrottlingStatusForSubFrame( + bool is_throttled, bool subtree_throttled, bool display_locked); // When the browser receives a call to RenderFrameProxyHost::SetIsInert // from the parent widget's embedding renderer changing its inertness,
diff --git a/third_party/blink/public/platform/web_url_response.h b/third_party/blink/public/platform/web_url_response.h index 4126241..058ff959 100644 --- a/third_party/blink/public/platform/web_url_response.h +++ b/third_party/blink/public/platform/web_url_response.h
@@ -327,6 +327,11 @@ // Whether this resource is from a MHTML archive. BLINK_PLATFORM_EXPORT bool FromArchive() const; + // Sets any DNS aliases for the requested URL. The alias chain order is + // expected to be in reverse, from canonical name (i.e. address record name) + // through to query name. + BLINK_PLATFORM_EXPORT void SetDnsAliases(const WebVector<WebString>&); + #if INSIDE_BLINK protected: // Permit subclasses to set arbitrary ResourceResponse pointer as
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h index 402c393..5a5afda 100644 --- a/third_party/blink/public/web/web_ax_object.h +++ b/third_party/blink/public/web/web_ax_object.h
@@ -81,9 +81,7 @@ BLINK_EXPORT bool operator>(const WebAXObject& other) const; BLINK_EXPORT bool operator>=(const WebAXObject& other) const; BLINK_EXPORT static WebAXObject FromWebNode(const WebNode&); - BLINK_EXPORT static WebAXObject FromWebDocument( - const WebDocument&, - bool update_layout_if_necessary = true); + BLINK_EXPORT static WebAXObject FromWebDocument(const WebDocument&); BLINK_EXPORT static WebAXObject FromWebDocumentByID(const WebDocument&, int); BLINK_EXPORT static WebAXObject FromWebDocumentFocused( const WebDocument&,
diff --git a/third_party/blink/public/web/web_view_client.h b/third_party/blink/public/web/web_view_client.h index 8c8220f..50c14b8 100644 --- a/third_party/blink/public/web/web_view_client.h +++ b/third_party/blink/public/web/web_view_client.h
@@ -31,12 +31,14 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_VIEW_CLIENT_H_ #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_VIEW_CLIENT_H_ +#include "base/optional.h" #include "base/strings/string_piece.h" #include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h" #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h" #include "third_party/blink/public/common/feature_policy/feature_policy_features.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-forward.h" +#include "third_party/blink/public/platform/web_impression.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/web/web_ax_enums.h" #include "third_party/blink/public/web/web_frame.h" @@ -70,7 +72,8 @@ WebNavigationPolicy policy, network::mojom::WebSandboxFlags, const SessionStorageNamespaceId& session_storage_namespace_id, - bool& consumed_user_gesture) { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) { return nullptr; }
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni index 886e30de..a1049e5 100644 --- a/third_party/blink/renderer/bindings/idl_in_core.gni +++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -106,9 +106,9 @@ "//third_party/blink/renderer/core/css/style_media.idl", "//third_party/blink/renderer/core/css/style_sheet.idl", "//third_party/blink/renderer/core/css/style_sheet_list.idl", - "//third_party/blink/renderer/core/document_transition/document_create_transition.idl", "//third_party/blink/renderer/core/document_transition/document_transition.idl", "//third_party/blink/renderer/core/document_transition/document_transition_init.idl", + "//third_party/blink/renderer/core/document_transition/document_transition_supplement.idl", "//third_party/blink/renderer/core/dom/abort_controller.idl", "//third_party/blink/renderer/core/dom/abort_signal.idl", "//third_party/blink/renderer/core/dom/accessibility_role.idl",
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 5222090b..b779e079 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
@@ -67,6 +67,7 @@ # in the various generators for ComputedStyle. self._field_alias_expander = FieldAliasExpander(file_paths[1]) + # _alias_offset must be a power of 2. self._alias_offset = 1024 # 0: CSSPropertyID::kInvalid # 1: CSSPropertyID::kVariable @@ -224,7 +225,7 @@ updated_alias['enum_key'] = enum_key_for_css_property_alias( alias['name']) updated_alias['enum_value'] = aliased_property['enum_value'] + \ - self._alias_offset + self._alias_offset * len(aliased_property['aliases']) updated_alias['superclass'] = 'CSSUnresolvedProperty' updated_alias['namespace_group'] = \ 'Shorthand' if aliased_property['longhands'] else 'Longhand'
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 bc7c717..c6044f4 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
@@ -29,8 +29,8 @@ 'core/css/templates/css_property_names.h.tmpl') def generate_header(self): return { - 'alias_offset': - self._css_properties.alias_offset, + 'alias_mask': + hex(0xffffffff - self._css_properties.alias_offset + 1), 'class_name': self.class_name, 'property_enums':
diff --git a/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl index 159f178..f474a36 100644 --- a/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl +++ b/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
@@ -83,10 +83,10 @@ inline CSSPropertyID resolveCSSPropertyID(CSSPropertyID id) { - return convertToCSSPropertyID(static_cast<int>(id) & ~{{alias_offset}}); + return convertToCSSPropertyID(static_cast<int>(id) & ~{{alias_mask}}); } -inline bool isPropertyAlias(CSSPropertyID id) { return static_cast<int>(id) & {{alias_offset}}; } +inline bool isPropertyAlias(CSSPropertyID id) { return static_cast<int>(id) & {{alias_mask}}; } CSSPropertyID CORE_EXPORT unresolvedCSSPropertyID(const ExecutionContext*, const WTF::String&);
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 869265d..db7a92d0 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -408,6 +408,8 @@ "testing/intersection_observer_test_helper.h", "testing/mock_clipboard_host.cc", "testing/mock_clipboard_host.h", + "testing/mock_function_scope.cc", + "testing/mock_function_scope.h", "testing/mock_hyphenation.cc", "testing/mock_hyphenation.h", "testing/mock_policy_container_host.cc", @@ -1382,14 +1384,12 @@ "layout/ng/inline/ng_fragment_items_builder_test.cc", "layout/ng/inline/ng_fragment_items_test.cc", "layout/ng/inline/ng_inline_cursor_test.cc", - "layout/ng/inline/ng_inline_fragment_traversal_test.cc", "layout/ng/inline/ng_inline_items_builder_test.cc", "layout/ng/inline/ng_inline_layout_algorithm_test.cc", "layout/ng/inline/ng_inline_node_test.cc", "layout/ng/inline/ng_line_breaker_test.cc", "layout/ng/inline/ng_offset_mapping_test.cc", "layout/ng/inline/ng_physical_line_box_fragment_test.cc", - "layout/ng/inline/ng_physical_text_fragment_test.cc", "layout/ng/list/layout_ng_list_item_test.cc", "layout/ng/ng_absolute_utils_test.cc", "layout/ng/ng_base_layout_algorithm_test.cc",
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni index 268f088..cf2e127 100644 --- a/third_party/blink/renderer/core/core_idl_files.gni +++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -531,7 +531,7 @@ "css/cssom/element_computed_style_map.idl", "css/font_face_source.idl", "css/property_registration.idl", - "document_transition/document_create_transition.idl", + "document_transition/document_transition_supplement.idl", "dom/accessibility_role.idl", "dom/aria_attributes.idl", "dom/aria_relationship_attributes.idl",
diff --git a/third_party/blink/renderer/core/css/counter_style.cc b/third_party/blink/renderer/core/css/counter_style.cc index dabac75..c4863346 100644 --- a/third_party/blink/renderer/core/css/counter_style.cc +++ b/third_party/blink/renderer/core/css/counter_style.cc
@@ -286,7 +286,12 @@ } } - // TODO(crbug.com/687225): Implement 'prefix', 'suffix' and 'speak-as'. + if (const CSSValue* prefix = rule.GetPrefix()) + prefix_ = SymbolToString(*prefix); + if (const CSSValue* suffix = rule.GetSuffix()) + suffix_ = SymbolToString(*suffix); + + // TODO(crbug.com/687225): Implement 'speak-as'. } void CounterStyle::ResolveExtends(const CounterStyle& extended) { @@ -320,7 +325,12 @@ if (!style_rule_->GetRange()) range_ = extended.range_; - // TODO(crbug.com/687225): Implement 'prefix', 'suffix' and 'speak-as'. + if (!style_rule_->GetPrefix()) + prefix_ = extended.prefix_; + if (!style_rule_->GetSuffix()) + prefix_ = extended.suffix_; + + // TODO(crbug.com/687225): Implement 'speak-as'. } void CounterStyle::ResetExtends() {
diff --git a/third_party/blink/renderer/core/css/counter_style.h b/third_party/blink/renderer/core/css/counter_style.h index f54f5b2d..6e915d3 100644 --- a/third_party/blink/renderer/core/css/counter_style.h +++ b/third_party/blink/renderer/core/css/counter_style.h
@@ -37,6 +37,9 @@ // https://drafts.csswg.org/css-counter-styles/#generate-a-counter String GenerateRepresentation(int value) const; + String GetPrefix() const { return prefix_; } + String GetSuffix() const { return suffix_; } + AtomicString GetExtendsName() const { return extends_name_; } const CounterStyle& GetExtendedStyle() const { return *extended_style_; } bool HasUnresolvedExtends() const { @@ -104,6 +107,9 @@ // Value of 'range' descriptor. Empty vector means 'auto'. Vector<std::pair<int, int>> range_; + String prefix_; + String suffix_ = ". "; + String negative_prefix_ = "-"; String negative_suffix_;
diff --git a/third_party/blink/renderer/core/document_transition/build.gni b/third_party/blink/renderer/core/document_transition/build.gni index 0d90c49a..92f3747 100644 --- a/third_party/blink/renderer/core/document_transition/build.gni +++ b/third_party/blink/renderer/core/document_transition/build.gni
@@ -3,8 +3,8 @@ # found in the LICENSE file. blink_core_sources_document_transition = [ - "document_create_transition.cc", - "document_create_transition.h", "document_transition.cc", "document_transition.h", + "document_transition_supplement.cc", + "document_transition_supplement.h", ]
diff --git a/third_party/blink/renderer/core/document_transition/document_create_transition.cc b/third_party/blink/renderer/core/document_transition/document_create_transition.cc deleted file mode 100644 index 1940cc9..0000000 --- a/third_party/blink/renderer/core/document_transition/document_create_transition.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/document_transition/document_create_transition.h" - -#include "third_party/blink/renderer/core/document_transition/document_transition.h" -#include "third_party/blink/renderer/core/dom/document.h" - -namespace blink { - -// static -DocumentTransition* DocumentCreateTransition::createTransition( - Document& document, - const DocumentTransitionInit* init) { - return MakeGarbageCollected<DocumentTransition>(&document, init); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_create_transition.h b/third_party/blink/renderer/core/document_transition/document_create_transition.h deleted file mode 100644 index 360afb9..0000000 --- a/third_party/blink/renderer/core/document_transition/document_create_transition.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_CREATE_TRANSITION_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_CREATE_TRANSITION_H_ - -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" - -namespace blink { -class DocumentTransition; -class DocumentTransitionInit; - -class CORE_EXPORT DocumentCreateTransition { - STATIC_ONLY(DocumentCreateTransition); - - public: - static DocumentTransition* createTransition(Document&, - const DocumentTransitionInit*); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_CREATE_TRANSITION_H_
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.cc b/third_party/blink/renderer/core/document_transition/document_transition.cc index 6731e4c..484a5e9 100644 --- a/third_party/blink/renderer/core/document_transition/document_transition.cc +++ b/third_party/blink/renderer/core/document_transition/document_transition.cc
@@ -7,26 +7,163 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { +namespace { -DocumentTransition::DocumentTransition(Document* document, - const DocumentTransitionInit* init) - : document_(document) {} +const int32_t kDefaultDurationMs = 300; + +DocumentTransition::Request::Effect ParseEffect(const String& input) { + using MapType = HashMap<String, DocumentTransition::Request::Effect>; + DEFINE_STATIC_LOCAL( + MapType*, lookup_map, + (new MapType{ + {"cover-down", DocumentTransition::Request::Effect::kCoverDown}, + {"cover-left", DocumentTransition::Request::Effect::kCoverLeft}, + {"cover-right", DocumentTransition::Request::Effect::kCoverRight}, + {"cover-up", DocumentTransition::Request::Effect::kCoverUp}, + {"explode", DocumentTransition::Request::Effect::kExplode}, + {"fade", DocumentTransition::Request::Effect::kFade}, + {"implode", DocumentTransition::Request::Effect::kImplode}, + {"reveal-down", DocumentTransition::Request::Effect::kRevealDown}, + {"reveal-left", DocumentTransition::Request::Effect::kRevealLeft}, + {"reveal-right", DocumentTransition::Request::Effect::kRevealRight}, + {"reveal-up", DocumentTransition::Request::Effect::kRevealUp}})); + + auto it = lookup_map->find(input); + return it != lookup_map->end() ? it->value + : DocumentTransition::Request::Effect::kNone; +} + +} // namespace + +DocumentTransition::DocumentTransition(Document* document) + : ExecutionContextLifecycleObserver(document->GetExecutionContext()), + document_(document) {} void DocumentTransition::Trace(Visitor* visitor) const { visitor->Trace(document_); + visitor->Trace(prepare_promise_resolver_); ScriptWrappable::Trace(visitor); + ActiveScriptWrappable::Trace(visitor); + ExecutionContextLifecycleObserver::Trace(visitor); } -ScriptPromise DocumentTransition::prepare(ScriptState* script_state) { - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); - auto promise = resolver->Promise(); - resolver->Resolve(); - return promise; +void DocumentTransition::ContextDestroyed() { + if (prepare_promise_resolver_) { + prepare_promise_resolver_->Detach(); + prepare_promise_resolver_ = nullptr; + } } -void DocumentTransition::start() {} +bool DocumentTransition::HasPendingActivity() const { + if (prepare_promise_resolver_) + return true; + return false; +} + +ScriptPromise DocumentTransition::prepare( + ScriptState* script_state, + const DocumentTransitionInit* params) { + // Reject any previous prepare promises. + if (state_ == State::kPreparing || state_ == State::kPrepared) { + if (prepare_promise_resolver_) { + prepare_promise_resolver_->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kAbortError, "Aborted due to prepare() call")); + prepare_promise_resolver_ = nullptr; + } + state_ = State::kIdle; + } + + // Increment the sequence id before any early outs so we will correctly + // process callbacks from previous requests. + ++prepare_sequence_id_; + + // If we are not attached to a view, then we can't prepare a transition. + // Reject the promise. We also reject the promise if we're in any state other + // than idle. + if (!document_ || !document_->View() || state_ != State::kIdle) { + return ScriptPromise::RejectWithDOMException( + script_state, + MakeGarbageCollected<DOMException>(DOMExceptionCode::kInvalidStateError, + "Invalid state")); + } + + // We're going to be creating a new transition, initialize the params. + ParseAndSetTransitionParameters(params); + + prepare_promise_resolver_ = + MakeGarbageCollected<ScriptPromiseResolver>(script_state); + + state_ = State::kPreparing; + pending_request_ = Request::CreatePrepare( + effect_, duration_, + ConvertToBaseOnceCallback(CrossThreadBindOnce( + &DocumentTransition::NotifyPrepareCommitted, + WrapCrossThreadWeakPersistent(this), prepare_sequence_id_))); + + NotifyHasChangesToCommit(); + return prepare_promise_resolver_->Promise(); +} + +void DocumentTransition::start() { + if (state_ != State::kPrepared) + return; + + state_ = State::kStarted; + pending_request_ = Request::CreateStart(ConvertToBaseOnceCallback( + CrossThreadBindOnce(&DocumentTransition::NotifyStartCommitted, + WrapCrossThreadWeakPersistent(this)))); +} + +void DocumentTransition::NotifyHasChangesToCommit() { + if (!document_ || !document_->GetPage() || !document_->View()) + return; + + // Schedule a new frame. + document_->GetPage()->Animator().ScheduleVisualUpdate(document_->GetFrame()); + + // Ensure paint artifact compositor does an update, since that's the mechanism + // we use to pass transition requests to the compositor. + document_->View()->SetPaintArtifactCompositorNeedsUpdate(); +} + +void DocumentTransition::NotifyPrepareCommitted(uint32_t sequence_id) { + // This notification is for a different sequence id. + if (sequence_id != prepare_sequence_id_) + return; + + DCHECK(state_ == State::kPreparing); + DCHECK(prepare_promise_resolver_); + + prepare_promise_resolver_->Resolve(); + prepare_promise_resolver_ = nullptr; + state_ = State::kPrepared; +} + +void DocumentTransition::NotifyStartCommitted() { + // TODO(vmpstr): This should only be cleared when the animation is actually + // over which means we need to plumb the callback all the way to viz. + state_ = State::kIdle; +} + +std::unique_ptr<DocumentTransition::Request> +DocumentTransition::TakePendingRequest() { + return std::move(pending_request_); +} + +void DocumentTransition::ParseAndSetTransitionParameters( + const DocumentTransitionInit* params) { + duration_ = base::TimeDelta::FromMilliseconds( + params->hasDuration() ? params->duration() : kDefaultDurationMs); + effect_ = params->hasRootTransition() ? ParseEffect(params->rootTransition()) + : Request::Effect::kNone; +} } // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.h b/third_party/blink/renderer/core/document_transition/document_transition.h index aa0ceaeb..3923b6c 100644 --- a/third_party/blink/renderer/core/document_transition/document_transition.h +++ b/third_party/blink/renderer/core/document_transition/document_transition.h
@@ -6,8 +6,11 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_H_ #include "cc/document_transition/document_transition_request.h" +#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { @@ -16,23 +19,56 @@ class DocumentTransitionInit; class ScriptState; -class CORE_EXPORT DocumentTransition final : public ScriptWrappable { +class CORE_EXPORT DocumentTransition + : public ScriptWrappable, + public ActiveScriptWrappable<DocumentTransition>, + public ExecutionContextLifecycleObserver { DEFINE_WRAPPERTYPEINFO(); public: - DocumentTransition(Document*, const DocumentTransitionInit*); + using Request = cc::DocumentTransitionRequest; + + explicit DocumentTransition(Document*); // GC functionality. void Trace(Visitor* visitor) const override; + // ExecutionContextLifecycleObserver implementation. + void ContextDestroyed() override; + + // ActiveScriptWrappable functionality. + bool HasPendingActivity() const override; + // JavaScript API implementation. - ScriptPromise prepare(ScriptState*); + ScriptPromise prepare(ScriptState*, const DocumentTransitionInit*); void start(); + // This uses std::move semantics to take the request from this object. + std::unique_ptr<Request> TakePendingRequest(); + private: - using Effect = cc::DocumentTransitionRequest::Effect; + friend class DocumentTransitionTest; + + enum class State { kIdle, kPreparing, kPrepared, kStarted }; + + void NotifyHasChangesToCommit(); + + void NotifyPrepareCommitted(uint32_t sequence_id); + void NotifyStartCommitted(); + + void ParseAndSetTransitionParameters(const DocumentTransitionInit* params); Member<Document> document_; + + State state_ = State::kIdle; + + Member<ScriptPromiseResolver> prepare_promise_resolver_; + base::TimeDelta duration_; + Request::Effect effect_ = Request::Effect::kNone; + + std::unique_ptr<Request> pending_request_; + + uint32_t prepare_sequence_id_ = 0u; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.idl b/third_party/blink/renderer/core/document_transition/document_transition.idl index b0a3595..7296c86 100644 --- a/third_party/blink/renderer/core/document_transition/document_transition.idl +++ b/third_party/blink/renderer/core/document_transition/document_transition.idl
@@ -5,14 +5,15 @@ // See third_party/blink/renderer/core/document_transition/README.md. [ + ActiveScriptWrappable, Exposed=Window, RuntimeEnabled=DocumentTransition ] interface DocumentTransition { - // - This can only be called if start() has not been previously called. + // - This should only be called after any previous start() calls have resolved. // - Rejects any previous unresolved prepare() promises. // - Returns a promise that resolves after the transition has been // prepared. - [CallWith=ScriptState] Promise<void> prepare(); + [CallWith=ScriptState] Promise<void> prepare(optional DocumentTransitionInit params = {}); // Can only be called after prepare(), during the task during // which prepare() most recently resolved.
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc b/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc new file mode 100644 index 0000000..7e964ee --- /dev/null +++ b/third_party/blink/renderer/core/document_transition/document_transition_supplement.cc
@@ -0,0 +1,56 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h" + +#include "third_party/blink/renderer/core/document_transition/document_transition.h" +#include "third_party/blink/renderer/core/dom/document.h" + +namespace blink { + +// static +const char DocumentTransitionSupplement::kSupplementName[] = + "DocumentTransition"; + +// static +DocumentTransitionSupplement* DocumentTransitionSupplement::FromIfExists( + Document& document) { + return Supplement<Document>::From<DocumentTransitionSupplement>(document); +} + +// static +DocumentTransitionSupplement* DocumentTransitionSupplement::From( + Document& document) { + auto* supplement = + Supplement<Document>::From<DocumentTransitionSupplement>(document); + if (!supplement) { + supplement = MakeGarbageCollected<DocumentTransitionSupplement>(document); + Supplement<Document>::ProvideTo(document, supplement); + } + return supplement; +} + +// static +DocumentTransition* DocumentTransitionSupplement::documentTransition( + Document& document) { + auto* supplement = From(document); + DCHECK(supplement->GetTransition()); + return supplement->GetTransition(); +} + +DocumentTransition* DocumentTransitionSupplement::GetTransition() { + return transition_; +} + +DocumentTransitionSupplement::DocumentTransitionSupplement(Document& document) + : Supplement<Document>(document), + transition_(MakeGarbageCollected<DocumentTransition>(&document)) {} + +void DocumentTransitionSupplement::Trace(Visitor* visitor) const { + visitor->Trace(transition_); + + Supplement<Document>::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_supplement.h b/third_party/blink/renderer/core/document_transition/document_transition_supplement.h new file mode 100644 index 0000000..c998dbcb --- /dev/null +++ b/third_party/blink/renderer/core/document_transition/document_transition_supplement.h
@@ -0,0 +1,41 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/document_transition/document_transition.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" + +namespace blink { +class DocumentTransition; + +class CORE_EXPORT DocumentTransitionSupplement + : public GarbageCollected<DocumentTransitionSupplement>, + public Supplement<Document> { + public: + static const char kSupplementName[]; + + // Supplement functionality. + static DocumentTransitionSupplement* From(Document&); + static DocumentTransitionSupplement* FromIfExists(Document&); + + static DocumentTransition* documentTransition(Document&); + + DocumentTransition* GetTransition(); + + explicit DocumentTransitionSupplement(Document&); + + // GC functionality. + void Trace(Visitor* visitor) const override; + + private: + Member<DocumentTransition> transition_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SUPPLEMENT_H_
diff --git a/third_party/blink/renderer/core/document_transition/document_create_transition.idl b/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl similarity index 63% rename from third_party/blink/renderer/core/document_transition/document_create_transition.idl rename to third_party/blink/renderer/core/document_transition/document_transition_supplement.idl index 1b1cdf48..cf6c1b8 100644 --- a/third_party/blink/renderer/core/document_transition/document_create_transition.idl +++ b/third_party/blink/renderer/core/document_transition/document_transition_supplement.idl
@@ -3,8 +3,8 @@ // found in the LICENSE file. [ - ImplementedAs=DocumentCreateTransition, + ImplementedAs=DocumentTransitionSupplement, RuntimeEnabled=DocumentTransition ] partial interface Document { - [NewObject] DocumentTransition createTransition(optional DocumentTransitionInit init = {}); + [SameObject] readonly attribute DocumentTransition documentTransition; };
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_test.cc b/third_party/blink/renderer/core/document_transition/document_transition_test.cc index 3f3e8f0..b1d7c57a 100644 --- a/third_party/blink/renderer/core/document_transition/document_transition_test.cc +++ b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
@@ -8,7 +8,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.h" -#include "third_party/blink/renderer/core/document_transition/document_create_transition.h" +#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" namespace blink { @@ -19,36 +19,200 @@ DocumentTransitionTest() : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()), ScopedDocumentTransitionForTest(true) {} + + void SetUp() override { + EnableCompositing(); + RenderingTest::SetUp(); + } + + using State = DocumentTransition::State; + + State GetState(DocumentTransition* transition) const { + return transition->state_; + } }; -TEST_F(DocumentTransitionTest, NewTransitionCreated) { - DocumentTransitionInit init; +TEST_F(DocumentTransitionTest, TransitionObjectPersists) { auto* first_transition = - DocumentCreateTransition::createTransition(GetDocument(), &init); + DocumentTransitionSupplement::documentTransition(GetDocument()); auto* second_transition = - DocumentCreateTransition::createTransition(GetDocument(), &init); + DocumentTransitionSupplement::documentTransition(GetDocument()); EXPECT_TRUE(first_transition); + EXPECT_EQ(GetState(first_transition), State::kIdle); EXPECT_TRUE(second_transition); - EXPECT_NE(first_transition, second_transition); + EXPECT_EQ(first_transition, second_transition); } TEST_F(DocumentTransitionTest, TransitionPreparePromiseResolves) { DocumentTransitionInit init; auto* transition = - DocumentCreateTransition::createTransition(GetDocument(), &init); + DocumentTransitionSupplement::documentTransition(GetDocument()); ASSERT_TRUE(transition); + EXPECT_EQ(GetState(transition), State::kIdle); V8TestingScope v8_scope; ScriptState* script_state = v8_scope.GetScriptState(); ScriptPromiseTester promise_tester(script_state, - transition->prepare(script_state)); + transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); UpdateAllLifecyclePhasesForTest(); promise_tester.WaitUntilSettled(); EXPECT_TRUE(promise_tester.IsFulfilled()); + EXPECT_EQ(GetState(transition), State::kPrepared); +} + +TEST_F(DocumentTransitionTest, AdditionalPrepareRejectsPreviousPromise) { + auto* transition = + DocumentTransitionSupplement::documentTransition(GetDocument()); + + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + + DocumentTransitionInit init; + ScriptPromiseTester first_promise_tester( + script_state, transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); + + ScriptPromiseTester second_promise_tester( + script_state, transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); + + UpdateAllLifecyclePhasesForTest(); + first_promise_tester.WaitUntilSettled(); + second_promise_tester.WaitUntilSettled(); + + EXPECT_TRUE(first_promise_tester.IsRejected()); + EXPECT_TRUE(second_promise_tester.IsFulfilled()); + EXPECT_EQ(GetState(transition), State::kPrepared); +} + +TEST_F(DocumentTransitionTest, EffectParsing) { + // Test default init. + auto* transition = + DocumentTransitionSupplement::documentTransition(GetDocument()); + + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + DocumentTransitionInit default_init; + transition->prepare(script_state, &default_init); + + auto request = transition->TakePendingRequest(); + ASSERT_TRUE(request); + + auto directive = request->ConstructDirective(); + EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kNone); + + // Test "explode" effect parsing. + DocumentTransitionInit explode_init; + explode_init.setRootTransition("explode"); + transition->prepare(script_state, &explode_init); + + request = transition->TakePendingRequest(); + ASSERT_TRUE(request); + + directive = request->ConstructDirective(); + EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kExplode); + + // Test invalid effect parsing. + DocumentTransitionInit invalid_init; + invalid_init.setRootTransition("invalid effect"); + transition->prepare(script_state, &invalid_init); + + request = transition->TakePendingRequest(); + ASSERT_TRUE(request); + + directive = request->ConstructDirective(); + EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kNone); +} + +TEST_F(DocumentTransitionTest, AdditionalPrepareAfterPreparedSucceeds) { + auto* transition = + DocumentTransitionSupplement::documentTransition(GetDocument()); + + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + + DocumentTransitionInit init; + ScriptPromiseTester first_promise_tester( + script_state, transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); + + UpdateAllLifecyclePhasesForTest(); + first_promise_tester.WaitUntilSettled(); + EXPECT_TRUE(first_promise_tester.IsFulfilled()); + EXPECT_EQ(GetState(transition), State::kPrepared); + + ScriptPromiseTester second_promise_tester( + script_state, transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); + + UpdateAllLifecyclePhasesForTest(); + second_promise_tester.WaitUntilSettled(); + EXPECT_TRUE(second_promise_tester.IsFulfilled()); + EXPECT_EQ(GetState(transition), State::kPrepared); +} + +TEST_F(DocumentTransitionTest, TransitionCleanedUpBeforePromiseResolution) { + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + + DocumentTransitionInit init; + ScriptPromiseTester tester( + script_state, + DocumentTransitionSupplement::documentTransition(GetDocument()) + ->prepare(script_state, &init)); + + // ActiveScriptWrappable should keep the transition alive. + ThreadState::Current()->CollectAllGarbageForTesting(); + + UpdateAllLifecyclePhasesForTest(); + tester.WaitUntilSettled(); + EXPECT_TRUE(tester.IsFulfilled()); +} + +TEST_F(DocumentTransitionTest, StartHasNoEffectUnlessPrepared) { + auto* transition = + DocumentTransitionSupplement::documentTransition(GetDocument()); + EXPECT_EQ(GetState(transition), State::kIdle); + EXPECT_FALSE(transition->TakePendingRequest()); + + transition->start(); + + EXPECT_EQ(GetState(transition), State::kIdle); + EXPECT_FALSE(transition->TakePendingRequest()); +} + +TEST_F(DocumentTransitionTest, StartAfterPrepare) { + auto* transition = + DocumentTransitionSupplement::documentTransition(GetDocument()); + + V8TestingScope v8_scope; + ScriptState* script_state = v8_scope.GetScriptState(); + + DocumentTransitionInit init; + ScriptPromiseTester prepare_tester(script_state, + transition->prepare(script_state, &init)); + EXPECT_EQ(GetState(transition), State::kPreparing); + + UpdateAllLifecyclePhasesForTest(); + prepare_tester.WaitUntilSettled(); + EXPECT_TRUE(prepare_tester.IsFulfilled()); + EXPECT_EQ(GetState(transition), State::kPrepared); + + transition->start(); + EXPECT_EQ(GetState(transition), State::kStarted); + + // Take the request. + EXPECT_TRUE(transition->TakePendingRequest()); + + // Subsequent starts should not do anything. + transition->start(); + EXPECT_EQ(GetState(transition), State::kStarted); + EXPECT_FALSE(transition->TakePendingRequest()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 7741122..82f906e 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -5690,42 +5690,6 @@ RemoveAttrNodeList(); } -Node::InsertionNotificationRequest Node::InsertedInto( - ContainerNode& insertion_point) { - DCHECK(!ChildNeedsStyleInvalidation()); - DCHECK(!NeedsStyleInvalidation()); - DCHECK(insertion_point.isConnected() || insertion_point.IsInShadowTree() || - IsContainerNode()); - if (insertion_point.isConnected()) { - SetFlag(kIsConnectedFlag); - insertion_point.GetDocument().IncrementNodeCount(); - } - if (ParentOrShadowHostNode()->IsInShadowTree()) - SetFlag(kIsInShadowTreeFlag); - if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) - cache->ChildrenChanged(&insertion_point); - return kInsertionDone; -} - -void Node::RemovedFrom(ContainerNode& insertion_point) { - DCHECK(insertion_point.isConnected() || IsContainerNode() || - IsInShadowTree()); - if (insertion_point.isConnected()) { - ClearNeedsStyleRecalc(); - ClearChildNeedsStyleRecalc(); - ClearNeedsStyleInvalidation(); - ClearChildNeedsStyleInvalidation(); - ClearFlag(kIsConnectedFlag); - insertion_point.GetDocument().DecrementNodeCount(); - } - if (IsInShadowTree() && !ContainingTreeScope().RootNode().IsShadowRoot()) - ClearFlag(kIsInShadowTreeFlag); - if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) { - cache->Remove(this); - cache->ChildrenChanged(&insertion_point); - } -} - void Element::WillRecalcStyle(const StyleRecalcChange) { DCHECK(HasCustomStyleCallbacks()); }
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc index 5f3ff521f..7338903 100644 --- a/third_party/blink/renderer/core/dom/events/event_target.cc +++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -529,15 +529,18 @@ event_type, listener, options, ®istered_listener); if (added) { if (options->hasSignal()) { + // Instead of passing the entire |options| here, which could create a + // circular reference due to |options| holding a Member<AbortSignal>, just + // pass the |options->capture()| boolean, which is the only thing + // removeEventListener actually uses to find and remove the event + // listener. options->signal()->AddAlgorithm(WTF::Bind( [](EventTarget* event_target, const AtomicString& event_type, - const EventListener* listener, - AddEventListenerOptionsResolved* options) { - event_target->removeEventListener(event_type, listener, options); + const EventListener* listener, bool capture) { + event_target->removeEventListener(event_type, listener, capture); }, WrapWeakPersistent(this), event_type, WrapWeakPersistent(listener), - WrapPersistent( - MakeGarbageCollected<AddEventListenerOptionsResolved>(options)))); + options->capture())); if (const LocalDOMWindow* executing_window = ExecutingWindow()) { if (const Document* document = executing_window->document()) { document->CountUse(WebFeature::kAddEventListenerWithAbortSignal);
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index 67a6392..fa2a312b 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2212,6 +2212,42 @@ layout_object->SetSubtreeShouldDoFullPaintInvalidation(); } +Node::InsertionNotificationRequest Node::InsertedInto( + ContainerNode& insertion_point) { + DCHECK(!ChildNeedsStyleInvalidation()); + DCHECK(!NeedsStyleInvalidation()); + DCHECK(insertion_point.isConnected() || insertion_point.IsInShadowTree() || + IsContainerNode()); + if (insertion_point.isConnected()) { + SetFlag(kIsConnectedFlag); + insertion_point.GetDocument().IncrementNodeCount(); + } + if (ParentOrShadowHostNode()->IsInShadowTree()) + SetFlag(kIsInShadowTreeFlag); + if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) + cache->ChildrenChanged(&insertion_point); + return kInsertionDone; +} + +void Node::RemovedFrom(ContainerNode& insertion_point) { + DCHECK(insertion_point.isConnected() || IsContainerNode() || + IsInShadowTree()); + if (insertion_point.isConnected()) { + ClearNeedsStyleRecalc(); + ClearChildNeedsStyleRecalc(); + ClearNeedsStyleInvalidation(); + ClearChildNeedsStyleInvalidation(); + ClearFlag(kIsConnectedFlag); + insertion_point.GetDocument().DecrementNodeCount(); + } + if (IsInShadowTree() && !ContainingTreeScope().RootNode().IsShadowRoot()) + ClearFlag(kIsInShadowTreeFlag); + if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) { + cache->Remove(this); + cache->ChildrenChanged(&insertion_point); + } +} + String Node::DebugName() const { StringBuilder name; AppendUnsafe(name, DebugNodeName());
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc index 0660d726..f121367 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_node_handler.cc
@@ -26,7 +26,6 @@ bool ShouldSkipInvisibleTextAt(const Text& text, unsigned offset, bool ignores_visibility) { - // TODO(xiaochengh): Get style from NGInlineItem or NGPhysicalTextFragment. const LayoutObject* layout_object = AssociatedLayoutObjectOf(text, offset); if (!layout_object) return true;
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc index 737ca3a..8785a43 100644 --- a/third_party/blink/renderer/core/editing/layout_selection.cc +++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -37,7 +37,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
diff --git a/third_party/blink/renderer/core/editing/substring_util.mm b/third_party/blink/renderer/core/editing/substring_util.mm index f6dba426..2024230 100644 --- a/third_party/blink/renderer/core/editing/substring_util.mm +++ b/third_party/blink/renderer/core/editing/substring_util.mm
@@ -124,7 +124,8 @@ String characters = it.GetTextState().GetTextForTesting(); characters.Ensure16Bit(); NSString* substring = - [[[NSString alloc] initWithCharacters:characters.Characters16() + [[[NSString alloc] initWithCharacters:reinterpret_cast<const UniChar*>( + characters.Characters16()) length:characters.length()] autorelease]; [string replaceCharactersInRange:NSMakeRange(position, 0) withString:substring];
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index 4693c0d..cc8a42ab 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -3745,7 +3745,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) override { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) override { return web_view_helper_.InitializeWithOpener(opener); } void DidFocus() override { did_focus_called_ = true; } @@ -3827,7 +3828,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) override { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) override { return web_view_; }
diff --git a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc index 5921d8b9..93cc917c 100644 --- a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc +++ b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
@@ -112,6 +112,13 @@ "cache hit", DOMException::GetErrorName( DOMExceptionCode::kNoModificationAllowedError)); + case network::mojom::blink::TrustTokenOperationStatus:: + kOperationSuccessfullyFulfilledLocally: + return DOMException::Create( + "Trust Tokens operation satisfied locally, without needing to send " + "the request to its initial destination", + DOMException::GetErrorName( + DOMExceptionCode::kNoModificationAllowedError)); case network::mojom::blink::TrustTokenOperationStatus::kFailedPrecondition: return DOMException::Create( "Precondition failed during Trust Tokens operation",
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.cc b/third_party/blink/renderer/core/frame/ad_tracker.cc index e4b14013..c113027 100644 --- a/third_party/blink/renderer/core/frame/ad_tracker.cc +++ b/third_party/blink/renderer/core/frame/ad_tracker.cc
@@ -208,7 +208,7 @@ bool AdTracker::CalculateIfAdSubresource( ExecutionContext* execution_context, - const ResourceRequest& request, + const KURL& request_url, ResourceType resource_type, const FetchInitiatorInfo& initiator_info, bool known_ad) { @@ -235,7 +235,7 @@ // ad script by IsKnownAdScript. if (resource_type == ResourceType::kScript && known_ad && !is_ad_execution_context) { - AppendToKnownAdScripts(*execution_context, request.Url().GetString()); + AppendToKnownAdScripts(*execution_context, request_url.GetString()); } return known_ad;
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.h b/third_party/blink/renderer/core/frame/ad_tracker.h index 22f14a5..fa7100f 100644 --- a/third_party/blink/renderer/core/frame/ad_tracker.h +++ b/third_party/blink/renderer/core/frame/ad_tracker.h
@@ -21,7 +21,6 @@ class Document; class ExecutionContext; class LocalFrame; -class ResourceRequest; enum class ResourceType : uint8_t; namespace probe { @@ -63,7 +62,7 @@ // Virtual for testing. virtual bool CalculateIfAdSubresource( ExecutionContext* execution_context, - const ResourceRequest& request, + const KURL& request_url, ResourceType resource_type, const FetchInitiatorInfo& initiator_info, bool known_ad);
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc index b26a813f..3c101d6 100644 --- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc +++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -142,20 +142,19 @@ } bool CalculateIfAdSubresource(ExecutionContext* execution_context, - const ResourceRequest& resource_request, + const KURL& request_url, ResourceType resource_type, const FetchInitiatorInfo& initiator_info, bool ad_request) override { - if (!ad_suffix_.IsEmpty() && - resource_request.Url().GetString().EndsWith(ad_suffix_)) { + if (!ad_suffix_.IsEmpty() && request_url.GetString().EndsWith(ad_suffix_)) { ad_request = true; } ad_request = AdTracker::CalculateIfAdSubresource( - execution_context, resource_request, resource_type, initiator_info, + execution_context, request_url, resource_type, initiator_info, ad_request); - String resource_url = resource_request.Url().GetString(); + String resource_url = request_url.GetString(); is_ad_.insert(resource_url, ad_request); if (quit_closure_ && url_to_wait_for_ == resource_url) {
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index e6d010a..2af5c54 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -535,35 +535,28 @@ bool Frame::Swap(WebFrame* frame) { using std::swap; - Frame* old_frame = this; // TODO(dcheng): This should not be reachable. Reaching this implies `Swap()` // is being called on an already-detached frame which should never happen... - if (!old_frame->IsAttached()) + if (!IsAttached()) return false; - FrameOwner* owner = old_frame->Owner(); + // Important: do not cache frame tree pointers (e.g. `previous_sibling_`, + // `next_sibling_`, `first_child_`, `last_child_`) here. It is possible for + // `DetachDocument()` to mutate the frame tree and cause cached values to + // become invalid. + FrameOwner* owner = owner_; FrameSwapScope frame_swap_scope(owner); - Frame* new_frame_parent = WebFrame::ToCoreFrame(*frame) && frame->Parent() - ? WebFrame::ToCoreFrame(*frame->Parent()) - : nullptr; - - Page* page = old_frame->GetPage(); - AtomicString name = old_frame->Tree().GetName(); - Frame* old_frame_opener = old_frame->Opener(); - Frame* old_frame_parent = old_frame->parent_; - Frame* old_frame_previous_sibling = old_frame->previous_sibling_; - Frame* old_frame_next_sibling = old_frame->next_sibling_; + Page* page = page_; + AtomicString name = Tree().GetName(); // Unload the current Document in this frame: this calls unload handlers, // detaches child frames, etc. Since this runs script, make sure this frame // wasn't detached before continuing with the swap. - // FIXME: There is no unit test for this condition, so one needs to be - // written. - if (!old_frame->DetachDocument()) { + if (!DetachDocument()) { // If the Swap() fails, it should be because the frame has been detached // already. Otherwise the caller will not detach the frame when we return // false, and the browser and renderer will disagree about the destruction - // of |old_frame|. - CHECK(!old_frame->IsAttached()); + // of |this|. + CHECK(!IsAttached()); return false; } @@ -571,9 +564,12 @@ // `this` is about to be replaced, so if `provisional_frame_` is set, it // should match `frame` which is being swapped in. DCHECK_EQ(provisional_frame_, WebFrame::ToCoreFrame(*frame)); - provisional_frame_ = nullptr; } + + // TODO(dcheng): This probably isn't necessary if we fix the ordering of + // events in `Swap()`, e.g. `Detach()` should not happen before `new_frame` is + // swapped in. // If there is a local parent, it might incorrectly declare itself complete // during the detach phase of this swap. Suppress its completion until swap is // over, at which point its completion will be correctly dependent on its @@ -586,83 +582,77 @@ v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WindowProxyManager::GlobalProxyVector global_proxies; - old_frame->GetWindowProxyManager()->ClearForSwap(); - old_frame->GetWindowProxyManager()->ReleaseGlobalProxies(global_proxies); + GetWindowProxyManager()->ClearForSwap(); + GetWindowProxyManager()->ReleaseGlobalProxies(global_proxies); // This must be before Detach so DidChangeOpener is not called. - if (old_frame_opener) - old_frame->SetOpenerDoNotNotify(nullptr); + Frame* original_opener = opener_; + if (original_opener) + SetOpenerDoNotNotify(nullptr); // Although the Document in this frame is now unloaded, many resources - // associated with the frame itself have not yet been freed yet. - old_frame->Detach(FrameDetachType::kSwap); + // associated with the frame itself have not yet been freed yet. Note that + // after `Detach()` returns, `this` is detached but *not* yet unlinked from + // the frame tree. + // TODO(dcheng): Merge this into the `DetachDocument()` step above. Executing + // parts of `Detach()` twice is confusing. + Detach(FrameDetachType::kSwap); if (frame->IsWebRemoteFrame()) { CHECK(!WebFrame::ToCoreFrame(*frame)); To<WebRemoteFrameImpl>(frame)->InitializeCoreFrame( - *page, owner, WebFrame::FromFrame(old_frame_parent), nullptr, - FrameInsertType::kInsertLater, name, - &old_frame->window_agent_factory()); + *page, owner, WebFrame::FromFrame(parent_), nullptr, + FrameInsertType::kInsertLater, name, &window_agent_factory()); + // At this point, a `RemoteFrame` will have already updated + // `Page::MainFrame()` or `FrameOwner::ContentFrame()` as appropriate, and + // its `parent_` pointer is also populated. + } else { + // This is local frame created by `WebLocalFrame::CreateProvisional()`. The + // `parent` pointer was set when it was constructed; however, + // `Page::MainFrame()` or `FrameOwner::ContentFrame()` updates are deferred + // until after `new_frame` is linked into the frame tree. + // TODO(dcheng): Make local and remote frame updates more uniform. } Frame* new_frame = WebFrame::ToCoreFrame(*frame); CHECK(new_frame); - // Swaps the |new_frame| and |old_frame| in their frame trees. - // For the |old_frame|, we use the frame tree position prior to the Detach() - // call. - Frame* new_frame_previous_sibling = new_frame->previous_sibling_; - Frame* new_frame_next_sibling = new_frame->next_sibling_; + // At this point, `new_frame->parent_` is correctly set, but `new_frame`'s + // sibling pointers are both still null and not yet updated. In addition, the + // parent frame (if any) still has not updated its `first_child_` and + // `last_child_` pointers. + CHECK_EQ(new_frame->parent_, parent_); + CHECK(!new_frame->previous_sibling_); + CHECK(!new_frame->next_sibling_); + if (previous_sibling_) { + previous_sibling_->next_sibling_ = new_frame; + } + swap(previous_sibling_, new_frame->previous_sibling_); + if (next_sibling_) { + next_sibling_->previous_sibling_ = new_frame; + } + swap(next_sibling_, new_frame->next_sibling_); - new_frame->parent_ = old_frame_parent; - new_frame->previous_sibling_ = old_frame_previous_sibling; - new_frame->next_sibling_ = old_frame_next_sibling; - if (new_frame_previous_sibling) { - new_frame_previous_sibling->next_sibling_ = old_frame; - } - if (new_frame_next_sibling) { - new_frame_next_sibling->previous_sibling_ = old_frame; - } - if (new_frame_parent) { - if (new_frame_parent->first_child_ == new_frame) { - new_frame_parent->first_child_ = old_frame; + if (parent_) { + if (parent_->first_child_ == this) { + parent_->first_child_ = new_frame; } - if (new_frame_parent->last_child_ == new_frame) { - new_frame_parent->last_child_ = old_frame; + if (parent_->last_child_ == this) { + parent_->last_child_ = new_frame; } - } - old_frame->parent_ = new_frame_parent; - old_frame->previous_sibling_ = new_frame_previous_sibling; - old_frame->next_sibling_ = new_frame_next_sibling; - if (old_frame_previous_sibling) { - old_frame_previous_sibling->next_sibling_ = new_frame; - } - if (old_frame_next_sibling) { - old_frame_next_sibling->previous_sibling_ = new_frame; - } - if (old_frame_parent) { - if (old_frame_parent->first_child_ == old_frame) { - old_frame_parent->first_child_ = new_frame; - } - if (old_frame_parent->last_child_ == old_frame) { - old_frame_parent->last_child_ = new_frame; - } + // Not strictly necessary, but keep state as self-consistent as possible. + parent_ = nullptr; } - if (old_frame_opener) { - new_frame->SetOpenerDoNotNotify(old_frame_opener); + if (original_opener) { + new_frame->SetOpenerDoNotNotify(original_opener); } opened_frame_tracker_.TransferTo(new_frame); // Clone the state of the current Frame into the one being swapped in. - // FIXME: This is a bit clunky; this results in pointless decrements and - // increments of connected subframes. if (auto* new_local_frame = DynamicTo<LocalFrame>(new_frame)) { - // TODO(dcheng): in an ideal world, both branches would just use - // WebFrame's initializeCoreFrame() helper. However, Blink - // currently requires a 'provisional' local frame to serve as a - // placeholder for loading state when swapping to a local frame. - // In this case, the core LocalFrame is already initialized, so just - // update a bit of state. + // A `LocalFrame` being swapped in is created provisionally, so + // `Page::MainFrame()` or `FrameOwner::ContentFrame()` needs to be updated + // to point to the newly swapped-in frame. DCHECK_EQ(owner, new_local_frame->Owner()); if (owner) { owner->SetContentFrame(*new_local_frame); @@ -683,12 +673,12 @@ new_frame->GetWindowProxyManager()->SetGlobalProxies(global_proxies); - parent_ = nullptr; - if (auto* frame_owner_element = DynamicTo<HTMLFrameOwnerElement>(owner)) { if (auto* new_local_frame = DynamicTo<LocalFrame>(new_frame)) { probe::FrameOwnerContentUpdated(new_local_frame, frame_owner_element); - } else if (auto* old_local_frame = DynamicTo<LocalFrame>(old_frame)) { + } else if (auto* old_local_frame = DynamicTo<LocalFrame>(this)) { + // TODO(dcheng): What is this probe for? Shouldn't it happen *before* + // detach? probe::FrameOwnerContentUpdated(old_local_frame, frame_owner_element); } }
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc index a7f8eeb7..171d487 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -872,7 +872,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) { auto webview_helper = std::make_unique<WebViewHelper>(); WebView* result = webview_helper->InitializeWithOpener(opener); child_web_views_.push_back(std::move(webview_helper));
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h index f38dcc8e..5f28a822b 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.h +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -307,7 +307,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) override; + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) override; private: WTF::Vector<std::unique_ptr<WebViewHelper>> child_web_views_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 50ee55d..cd9f83c5 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -53,6 +53,7 @@ #include "third_party/blink/renderer/core/css/font_face_set_document.h" #include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h" +#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h" #include "third_party/blink/renderer/core/dom/static_node_list.h" #include "third_party/blink/renderer/core/editing/compute_layer_selection.h" #include "third_party/blink/renderer/core/editing/drag_caret.h" @@ -257,7 +258,6 @@ // doesn't get setup properly. lifecycle_updates_throttled_(!GetFrame().IsMainFrame()), target_state_(DocumentLifecycle::kUninitialized), - past_layout_lifecycle_update_(false), suppress_adjust_view_size_(false), intersection_observation_state_(kNotNeeded), needs_forced_compositing_update_(false), @@ -2360,6 +2360,18 @@ return false; } +void LocalFrameView::PrepareForLifecycleUpdateRecursive() { + // We will run lifecycle phases for LocalFrameViews that are unthrottled; or + // are throttled but require IntersectionObserver steps to run. + if (!ShouldThrottleRendering() || + intersection_observation_state_ == kRequired) { + Lifecycle().EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending); + ForAllChildLocalFrameViews([](LocalFrameView& child) { + child.PrepareForLifecycleUpdateRecursive(); + }); + } +} + // TODO(leviw): We don't assert lifecycle information from documents in child // WebPluginContainerImpls. bool LocalFrameView::UpdateLifecyclePhases( @@ -2406,35 +2418,27 @@ if (frame_->IsLocalRoot()) UpdateLayerDebugInfoEnabled(); - // This is used to guard against reentrance. It is also used in conjunction - // with the current lifecycle state to determine which phases are yet to run - // in this cycle. - base::AutoReset<DocumentLifecycle::LifecycleState> target_state_scope( - &target_state_, target_state); - // This is used to check if we're within a lifecycle update but have passed - // the layout update phase. Note there is a bit of a subtlety here: it's not - // sufficient for us to check the current lifecycle state, since it can be - // past kLayoutClean but the function to run style and layout phase has not - // actually been run yet. Since this bool affects throttling, and throttling, - // in turn, determines whether style and layout function will run, we need a - // separate bool. - base::AutoReset<bool> past_layout_lifecycle_resetter( - &past_layout_lifecycle_update_, false); - - // If we're throttling, then we don't need to update lifecycle phases. The - // throttling status will get updated in RunPostLifecycleSteps(). - if (ShouldThrottleRendering()) { + // If we're throttling and we aren't required to run the IntersectionObserver + // steps, then we don't need to update lifecycle phases. The throttling status + // will get updated in RunPostLifecycleSteps(). + if (ShouldThrottleRendering() && + intersection_observation_state_ < kRequired) { return Lifecycle().GetState() == target_state; } + PrepareForLifecycleUpdateRecursive(); + + // This is used to guard against reentrance. It is also used in conjunction + // with the current lifecycle state to determine which phases are yet to run + // in this cycle. Note that this may change the return value of + // ShouldThrottleRendering(), hence it cannot be moved before the preceeding + // code, which relies on the prior value of ShouldThrottleRendering(). + base::AutoReset<DocumentLifecycle::LifecycleState> target_state_scope( + &target_state_, target_state); + lifecycle_data_.start_time = base::TimeTicks::Now(); ++lifecycle_data_.count; - ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) { - frame_view.Lifecycle().EnsureStateAtMost( - DocumentLifecycle::kVisualUpdatePending); - }); - if (target_state == DocumentLifecycle::kPaintClean) { { TRACE_EVENT0("blink", "LocalFrameView::WillStartLifecycleUpdate"); @@ -2648,7 +2652,10 @@ TRACE_EVENT0("blink,benchmark", "LocalFrameView::RunStyleAndLayoutLifecyclePhases"); UpdateStyleAndLayoutIfNeededRecursive(); - DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean); + DCHECK(ShouldThrottleRendering() || + Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean); + if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean) + return false; frame_->GetDocument() ->GetRootScrollerController() @@ -2669,17 +2676,6 @@ if (target_state == DocumentLifecycle::kLayoutClean) return false; - // This will be reset by AutoReset in the calling function - past_layout_lifecycle_update_ = true; - - // After layout and the |past_layout_lifecycle_update_| update, the value of - // ShouldThrottleRendering() can change. OOPIF local frame roots that are - // throttled can return now that layout is clean. This situation happens if - // the throttling was disabled due to required intersection observation, which - // can now be run. - if (ShouldThrottleRendering()) - return false; - // Now we can run post layout steps in preparation for further phases. ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) { frame_view.PerformScrollAnchoringAdjustments(); @@ -3205,12 +3201,31 @@ }); } + WTF::Vector<std::unique_ptr<DocumentTransition::Request>> + document_transition_requests; + // TODO(vmpstr): We should make this work for subframes as well. + AppendDocumentTransitionRequests(document_transition_requests); + paint_artifact_compositor_->Update( - pre_composited_layers_, viewport_properties, scroll_translation_nodes); + pre_composited_layers_, viewport_properties, scroll_translation_nodes, + std::move(document_transition_requests)); probe::LayerTreePainted(&GetFrame()); } +void LocalFrameView::AppendDocumentTransitionRequests( + WTF::Vector<std::unique_ptr<DocumentTransition::Request>>& requests) { + DCHECK(frame_ && frame_->GetDocument()); + auto* document_transition_supplement = + DocumentTransitionSupplement::FromIfExists(*frame_->GetDocument()); + if (!document_transition_supplement) + return; + auto* document_transition = document_transition_supplement->GetTransition(); + auto pending_request = document_transition->TakePendingRequest(); + if (pending_request) + requests.push_back(std::move(pending_request)); +} + std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON( LayerTreeFlags flags) { auto* root_frame_view = GetFrame().LocalFrameRoot().View(); @@ -4529,7 +4544,20 @@ auto* local_frame_root_view = GetFrame().LocalFrameRoot().View(); if (local_frame_root_view->IsUpdatingLifecycle() && intersection_observation_state_ == kRequired && !IsDisplayLocked()) { - return local_frame_root_view->past_layout_lifecycle_update_; + // IntersectionObserver may rely on sticky positioning, which is not + // resolved until compositing assignments are done. If the resolution of + // sticky positioning is refactored to occur during layout, then the + // required minimum lifecycle state will depend on whether this frame + // requires occlusion tracking, since determining occlusion state requires a + // hit test, which requires the document to be pre-paint clean. So the code + // here would change to something like: + // + // auto min_state = GetFrame().NeedsOcclusionTracking() ? + // DocumentLifecycle::kPrePaintClean : + // DocumentLifecycle::kLayoutClean; + // return Lifecycle().GetState() >= min_state; + return Lifecycle().GetState() >= + DocumentLifecycle::kCompositingAssignmentsClean; } return true;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index d77a40a..29dc0e6 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -34,6 +34,7 @@ #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-blink.h" #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h" #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/document_transition/document_transition.h" #include "third_party/blink/renderer/core/dom/document_lifecycle.h" #include "third_party/blink/renderer/core/frame/frame_view.h" #include "third_party/blink/renderer/core/frame/layout_subtree_root_list.h" @@ -854,6 +855,8 @@ LayoutSVGRoot* EmbeddedReplacedContent() const; + void PrepareForLifecycleUpdateRecursive(); + // Returns whether the lifecycle was successfully updated to the // target state. bool UpdateLifecyclePhases(DocumentLifecycle::LifecycleState target_state, @@ -991,6 +994,10 @@ // StyleEngine instead of the base background color. bool ShouldUseColorAdjustBackground() const; + // Appends the document transition from this view into the given vector. + void AppendDocumentTransitionRequests( + WTF::Vector<std::unique_ptr<DocumentTransition::Request>>&); + LayoutSize size_; typedef HashSet<scoped_refptr<LayoutEmbeddedObject>> EmbeddedObjectSet; @@ -1075,7 +1082,6 @@ // This is set on the local root frame view only. DocumentLifecycle::LifecycleState target_state_; - bool past_layout_lifecycle_update_; using AnchoringAdjustmentQueue = HeapLinkedHashSet<WeakMember<ScrollableArea>>;
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc index 44b6683..32017d4 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_view.cc +++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -339,7 +339,7 @@ // TODO(szager,vmpstr): Send IsSubtreeThrottled() and IsDisplayLocked() as // separate bits. remote_frame_->GetRemoteFrameHostRemote().UpdateRenderThrottlingStatus( - IsHiddenForThrottling(), IsSubtreeThrottled() || IsDisplayLocked()); + IsHiddenForThrottling(), IsSubtreeThrottled(), IsDisplayLocked()); } void RemoteFrameView::VisibilityChanged(
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc index 5e94432..5570a0d50 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -7003,7 +7003,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) override { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) override { EXPECT_TRUE(false); return nullptr; }
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 550ae30..cc07678c 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -487,15 +487,15 @@ void WebFrameWidgetImpl::UpdateRenderThrottlingStatusForSubFrame( bool is_throttled, - bool subtree_throttled) { + bool subtree_throttled, + bool display_locked) { DCHECK(ForSubframe()); // TODO(szager,vmpstr): The parent render process currently rolls up // display_locked into the value of subtree throttled here; display_locked // should be maintained as a separate bit and transmitted between render // processes. LocalRootImpl()->GetFrameView()->UpdateRenderThrottlingStatus( - is_throttled, subtree_throttled, /*display_locked=*/false, - /*recurse=*/true); + is_throttled, subtree_throttled, display_locked, /*recurse=*/true); } #if defined(OS_MAC)
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index 53a180a6..97e54b1 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -681,7 +681,8 @@ // have to have throttling information propagated from parent to child // across processes. void UpdateRenderThrottlingStatusForSubFrame(bool is_throttled, - bool subtree_throttled) override; + bool subtree_throttled, + bool display_locked) override; void EnableDeviceEmulation(const DeviceEmulationParams& parameters) override; void DisableDeviceEmulation() override; // Sets the inert bit on an out-of-process iframe, causing it to ignore
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 5935f8c9..6155650 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -151,6 +151,7 @@ // We need to drop frame dispatcher, to prevent mojo calls from completing. frame_dispatcher_ = nullptr; + DiscardResourceProvider(); if (context_) { UMA_HISTOGRAM_BOOLEAN("Blink.Canvas.HasRendered", bool(ResourceProvider()));
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index 8b32c03..44ab2ac 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -204,7 +204,7 @@ } void HTMLAnchorElement::SetActive(bool active) { - if (HasEditableStyle(*this)) + if (active && HasEditableStyle(*this)) return; HTMLElement::SetActive(active); @@ -560,6 +560,19 @@ frame->MaybeLogAdClickNavigation(); + if (request.HasUserGesture() && HasImpression()) { + // An impression must be attached prior to the + // FindOrCreateFrameForNavigation() call, as that call may result in + // performing a navigation if the call results in creating a new window with + // noopener set. + base::Optional<WebImpression> impression = GetImpressionForNavigation(); + if (impression) + frame_request.SetImpression(*impression); + } + + // Note that we do not need to worry about impressions being attached to + // subframe navigations in the following call, a frame is only + // created/navigated if we are intending to navigate a new window/main frame. Frame* target_frame = frame->Tree().FindOrCreateFrameForNavigation(frame_request, target).frame; @@ -574,16 +587,15 @@ WebFeature::kHTMLAnchorElementHrefTranslateAttribute); } - // Only attach impressions for main frame navigations. - if (target_frame && target_frame->IsMainFrame() && request.HasUserGesture() && - HasImpression()) { - base::Optional<WebImpression> impression = GetImpressionForNavigation(); - if (impression) - frame_request.SetImpression(*impression); - } - - if (target_frame) + if (target_frame) { + // We do not need to attach impressions for navigations to subframes, as the + // Conversion Measurement API only applies to main frame navigations. Clear + // out the impression in that case. + if (!target_frame->IsMainFrame()) { + frame_request.SetImpression(base::nullopt); + } target_frame->Navigate(frame_request, WebFrameLoadType::kStandard); + } } bool IsEnterKeyKeydownEvent(Event& event) {
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc index a972dcb..7fa1e4b 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
@@ -162,8 +162,9 @@ if (!target || (!target->IsBoxModelObject() && !target->IsText())) return nullptr; // If the target is inside a locked subtree, it isn't ever visible. - if (UNLIKELY(DisplayLockUtilities::IsInLockedSubtreeCrossingFrames( - target_element))) { + if (UNLIKELY(target->GetFrameView()->IsDisplayLocked() || + DisplayLockUtilities::IsInLockedSubtreeCrossingFrames( + target_element))) { return nullptr; }
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni index c092d8a1..a51c554 100644 --- a/third_party/blink/renderer/core/layout/build.gni +++ b/third_party/blink/renderer/core/layout/build.gni
@@ -358,8 +358,6 @@ "ng/inline/ng_inline_child_layout_context.h", "ng/inline/ng_inline_cursor.cc", "ng/inline/ng_inline_cursor.h", - "ng/inline/ng_inline_fragment_traversal.cc", - "ng/inline/ng_inline_fragment_traversal.h", "ng/inline/ng_inline_item.cc", "ng/inline/ng_inline_item.h", "ng/inline/ng_inline_item_result.cc", @@ -390,12 +388,8 @@ "ng/inline/ng_offset_mapping_builder.h", "ng/inline/ng_physical_line_box_fragment.cc", "ng/inline/ng_physical_line_box_fragment.h", - "ng/inline/ng_physical_text_fragment.cc", - "ng/inline/ng_physical_text_fragment.h", "ng/inline/ng_ruby_utils.cc", "ng/inline/ng_ruby_utils.h", - "ng/inline/ng_text_fragment_builder.cc", - "ng/inline/ng_text_fragment_builder.h", "ng/inline/ng_text_offset.cc", "ng/inline/ng_text_offset.h", "ng/inline/ng_text_type.h",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index dd036a92..79a3bd65 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2695,6 +2695,10 @@ // object for paint invalidation. if (!NeedsLayout()) SetShouldCheckForPaintInvalidation(); + // In flipped blocks writing mode, our children can change physical location, + // but their flipped location remains the same. + if (HasFlippedBlocksWritingMode()) + SetSubtreeShouldCheckForPaintInvalidation(); } bool LayoutBox::IntersectsVisibleViewport() const { @@ -3491,7 +3495,8 @@ // dirty layout bit(s). Note that we may be here because we are display locked // and have cached a locked layout result. In that case, this function will // not clear the child dirty bits. - ClearNeedsLayout(); + if (NeedsLayout()) + ClearNeedsLayout(); // Optimization: TableConstraintSpaceData can be large, and it is shared // between all the rows in a table. Make constraint space table data for
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index 00eb75d..06497be 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -38,7 +38,6 @@ #include "third_party/blink/renderer/core/layout/line/inline_text_box.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc index 19de025..b5b16c03 100644 --- a/third_party/blink/renderer/core/layout/layout_text.cc +++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -59,7 +59,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/text_autosizer.h" @@ -359,9 +358,9 @@ NGInlineCursor cursor; cursor.MoveTo(*this); for (; cursor; cursor.MoveToNextForSameLayoutObject()) { - // TODO(yosin): We should introduce - // |NGPhysicalTextFragment::IsTruncated()| to skip them instead of using - // |IsHiddenForPaint()| with ordering of fragments. + // TODO(yosin): We should introduce |NGFragmentItem::IsTruncated()| to + // skip them instead of using |IsHiddenForPaint()| with ordering of + // fragments. if (cursor.Current().IsHiddenForPaint()) { in_hidden_for_paint = true; } else if (in_hidden_for_paint) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h index 67803e7..aaed364 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
@@ -17,7 +17,7 @@ class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox { private: // Returns existing or newly created |NGAbstractInlineTextBox|. - // * |cursor| should be attached to |NGPhysicalTextFragment|. + // * |cursor| should be attached to a text item. static scoped_refptr<AbstractInlineTextBox> GetOrCreate( const NGInlineCursor& cursor); static void WillDestroy(const NGInlineCursor& cursor);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc index 7b5e346a..af19cf8 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -13,7 +13,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc index b36a5f62..a945525 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -12,6 +12,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" +#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h" #include "third_party/blink/renderer/platform/wtf/size_assertions.h" namespace blink { @@ -34,34 +35,6 @@ } // namespace -NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text) - : layout_object_(text.GetLayoutObject()), - text_({text.TextShapeResult(), text.TextOffset()}), - rect_({PhysicalOffset(), text.Size()}), - type_(kText), - sub_type_(static_cast<unsigned>(text.TextType())), - style_variant_(static_cast<unsigned>(text.StyleVariant())), - is_hidden_for_paint_(text.IsHiddenForPaint()), - text_direction_(static_cast<unsigned>(text.ResolvedDirection())), - ink_overflow_type_(NGInkOverflow::kNotSet), - is_dirty_(false), - is_last_for_node_(true) { -#if DCHECK_IS_ON() - if (text_.shape_result) { - DCHECK_EQ(text_.shape_result->StartIndex(), StartOffset()); - DCHECK_EQ(text_.shape_result->EndIndex(), EndOffset()); - } -#endif - if (text.TextType() == NGTextType::kLayoutGenerated) { - type_ = kGeneratedText; - // Note: Because of |text_| and |generated_text_| are in same union and - // we initialize |text_| instead of |generated_text_|, we should construct - // |generated_text_.text_| instead copying, |generated_text_.text = ...|. - new (&generated_text_.text) String(text.Text().ToString()); - } - DCHECK(!IsFormattingContextRoot()); -} - NGFragmentItem::NGFragmentItem( const NGInlineItem& inline_item, scoped_refptr<const ShapeResultView> shape_result, @@ -632,6 +605,85 @@ delta_to_next_for_same_layout_object_ = delta; } +// Compute the inline position from text offset, in logical coordinate relative +// to this fragment. +LayoutUnit NGFragmentItem::InlinePositionForOffset( + StringView text, + unsigned offset, + LayoutUnit (*round_function)(float), + AdjustMidCluster adjust_mid_cluster) const { + DCHECK_GE(offset, StartOffset()); + DCHECK_LE(offset, EndOffset()); + DCHECK_EQ(text.length(), TextLength()); + + offset -= StartOffset(); + if (TextShapeResult()) { + // TODO(layout-dev): Move caret position out of ShapeResult and into a + // separate support class that can take a ShapeResult or ShapeResultView. + // Allows for better code separation and avoids the extra copy below. + return round_function( + TextShapeResult()->CreateShapeResult()->CaretPositionForOffset( + offset, text, adjust_mid_cluster)); + } + + // This fragment is a flow control because otherwise ShapeResult exists. + DCHECK(IsFlowControl()); + DCHECK_EQ(1u, text.length()); + if (!offset || UNLIKELY(IsRtl(Style().Direction()))) + return LayoutUnit(); + return IsHorizontal() ? Size().width : Size().height; +} + +LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text, + unsigned offset) const { + return InlinePositionForOffset(text, offset, LayoutUnit::FromFloatRound, + AdjustMidCluster::kToEnd); +} + +std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets( + StringView text, + unsigned start_offset, + unsigned end_offset) const { + DCHECK_LE(start_offset, EndOffset()); + DCHECK_GE(start_offset, StartOffset()); + DCHECK_LE(end_offset, EndOffset()); + + const LayoutUnit start_position = + InlinePositionForOffset(text, start_offset, LayoutUnit::FromFloatFloor, + AdjustMidCluster::kToStart); + const LayoutUnit end_position = InlinePositionForOffset( + text, end_offset, LayoutUnit::FromFloatCeil, AdjustMidCluster::kToEnd); + + // Swap positions if RTL. + return (UNLIKELY(start_position > end_position)) + ? std::make_pair(end_position, start_position) + : std::make_pair(start_position, end_position); +} + +PhysicalRect NGFragmentItem::LocalRect(StringView text, + unsigned start_offset, + unsigned end_offset) const { + if (start_offset == StartOffset() && end_offset == EndOffset()) + return LocalRect(); + LayoutUnit start_position, end_position; + std::tie(start_position, end_position) = + LineLeftAndRightForOffsets(text, start_offset, end_offset); + const LayoutUnit inline_size = end_position - start_position; + switch (GetWritingMode()) { + case WritingMode::kHorizontalTb: + return {start_position, LayoutUnit(), inline_size, Size().height}; + case WritingMode::kVerticalRl: + case WritingMode::kVerticalLr: + case WritingMode::kSidewaysRl: + return {LayoutUnit(), start_position, Size().width, inline_size}; + case WritingMode::kSidewaysLr: + return {LayoutUnit(), Size().height - end_position, Size().width, + inline_size}; + } + NOTREACHED(); + return {}; +} + PositionWithAffinity NGFragmentItem::PositionForPointInText( const PhysicalOffset& point, const NGInlineCursor& cursor) const {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h index 27081784..795317f 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -13,6 +13,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_type.h" #include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -20,7 +21,6 @@ class NGFragmentItems; class NGInlineBreakToken; -class NGPhysicalTextFragment; struct NGTextFragmentPaintInfo; struct NGLogicalLineItem; @@ -70,9 +70,6 @@ // Create appropriate type for |line_item|. NGFragmentItem(NGLogicalLineItem&& line_item, WritingMode writing_mode); - // Create a text item. - // TODO(kojii): Should be able to create without once creating fragments. - explicit NGFragmentItem(const NGPhysicalTextFragment& text); // Create a box item. NGFragmentItem(const NGPhysicalBoxFragment& box, TextDirection resolved_direction);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc index a329602..b257014 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -8,8 +8,6 @@ #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" -#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.cc index 46c4511..3821f38 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.cc
@@ -11,10 +11,9 @@ namespace { struct SameSizeAsNGInlineChildLayoutContext { - NGFragmentItemsBuilder items_builder_; NGLogicalLineItems line_items_; base::Optional<NGInlineLayoutStateStack> box_states_; - void* pointers[1]; + void* pointers[2]; unsigned number; Vector<scoped_refptr<const NGBlockBreakToken>> propagated_float_break_tokens_; }; @@ -27,10 +26,7 @@ } // namespace -NGInlineChildLayoutContext::NGInlineChildLayoutContext( - const NGInlineNode& node, - WritingDirectionMode writing_direction) - : items_builder_(node, writing_direction) {} +NGInlineChildLayoutContext::NGInlineChildLayoutContext() = default; NGInlineChildLayoutContext::~NGInlineChildLayoutContext() = default; NGInlineLayoutStateStack*
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h index 4af78afe..82cd170a 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h
@@ -24,11 +24,16 @@ STACK_ALLOCATED(); public: - NGInlineChildLayoutContext(const NGInlineNode& node, - WritingDirectionMode writing_direction); + NGInlineChildLayoutContext(); ~NGInlineChildLayoutContext(); - NGFragmentItemsBuilder* ItemsBuilder() { return &items_builder_; } + NGFragmentItemsBuilder* ItemsBuilder() { return items_builder_; } + void SetItemsBuilder(NGFragmentItemsBuilder* builder) { + DCHECK(!items_builder_ || !builder); + items_builder_ = builder; + if (builder) + builder->AddLogicalLineItemsPool(&logical_line_items_); + } // Returns an instance of |NGLogicalLineItems|. This is reused when laying out // the next line. @@ -60,7 +65,9 @@ void PropagateBreakToken(scoped_refptr<const NGBlockBreakToken>); private: - NGFragmentItemsBuilder items_builder_; + // TODO(kojii): Probably better to own |NGInlineChildLayoutContext|. While we + // transit, allocating separately is easier. + NGFragmentItemsBuilder* items_builder_ = nullptr; NGLogicalLineItems logical_line_items_;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc deleted file mode 100644 index ea93bad..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc +++ /dev/null
@@ -1,173 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" - -#include "third_party/blink/renderer/core/layout/layout_inline.h" -#include "third_party/blink/renderer/core/layout/layout_object.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" - -namespace blink { - -namespace { - -using Result = NGPhysicalFragmentWithOffset; - -class NGPhysicalFragmentCollectorBase { - STACK_ALLOCATED(); - - public: - virtual Vector<Result> CollectFrom(const NGPhysicalFragment&) = 0; - NGPhysicalFragmentCollectorBase(const NGPhysicalFragmentCollectorBase&) = - delete; - NGPhysicalFragmentCollectorBase& operator=( - const NGPhysicalFragmentCollectorBase&) = delete; - - protected: - explicit NGPhysicalFragmentCollectorBase() = default; - - virtual void Visit() = 0; - - const NGPhysicalFragment& GetFragment() const { return *current_fragment_; } - void SetShouldStopTraversing() { should_stop_traversing_ = true; } - bool HasStoppedTraversing() const { return should_stop_traversing_; } - - void Emit() { - results_.push_back(Result{current_fragment_, current_offset_to_root_}); - } - - // Visits and collets fragments in the subtree rooted at |fragment|. - // |fragment| itself is not visited. - Vector<Result> CollectExclusivelyFrom(const NGPhysicalFragment& fragment) { - current_fragment_ = &fragment; - root_fragment_ = &fragment; - VisitChildren(); - return std::move(results_); - } - - // Visits and collets fragments in the subtree rooted at |fragment|. - // |fragment| itself is visited. - Vector<Result> CollectInclusivelyFrom(const NGPhysicalFragment& fragment) { - current_fragment_ = &fragment; - root_fragment_ = &fragment; - Visit(); - return std::move(results_); - } - - void VisitChildren() { - if (should_stop_traversing_) - return; - - const NGPhysicalFragment& fragment = *current_fragment_; - if (!fragment.IsContainer()) - return; - - // Traverse descendants unless the fragment is laid out separately from the - // inline layout algorithm. - if (&fragment != root_fragment_ && fragment.IsFormattingContextRoot()) - return; - - DCHECK(fragment.IsContainer()); - DCHECK(fragment.IsInline() || fragment.IsLineBox() || - (fragment.IsBlockFlow() && - To<NGPhysicalBoxFragment>(fragment).IsInlineFormattingContext())); - - for (const auto& child : - To<NGPhysicalContainerFragment>(fragment).Children()) { - base::AutoReset<PhysicalOffset> offset_resetter( - ¤t_offset_to_root_, current_offset_to_root_ + child.Offset()); - base::AutoReset<const NGPhysicalFragment*> fragment_resetter( - ¤t_fragment_, child.get()); - Visit(); - - if (should_stop_traversing_) - return; - } - } - - private: - const NGPhysicalFragment* root_fragment_ = nullptr; - const NGPhysicalFragment* current_fragment_ = nullptr; - PhysicalOffset current_offset_to_root_; - Vector<Result> results_; - bool should_stop_traversing_ = false; -}; - -// The visitor emitting all visited fragments. -class DescendantCollector final : public NGPhysicalFragmentCollectorBase { - STACK_ALLOCATED(); - - public: - DescendantCollector() = default; - DescendantCollector(const DescendantCollector&) = delete; - DescendantCollector& operator=(const DescendantCollector&) = delete; - - Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final { - return CollectExclusivelyFrom(fragment); - } - - private: - void Visit() final { - Emit(); - VisitChildren(); - } -}; - -// The visitor emitting fragments generated from the given LayoutInline, -// supporting culled inline. -// Note: Since we apply culled inline per line, we have a fragment for -// LayoutInline in second line but not in first line in -// "t0803-c5502-imrgn-r-01-b-ag.html". -class LayoutInlineCollector final : public NGPhysicalFragmentCollectorBase { - STACK_ALLOCATED(); - - public: - explicit LayoutInlineCollector(const LayoutInline& container) { - CollectInclusiveDescendants(container); - } - LayoutInlineCollector(const LayoutInlineCollector&) = delete; - LayoutInlineCollector& operator=(const LayoutInlineCollector&) = delete; - - Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final { - return CollectExclusivelyFrom(fragment); - } - - private: - void Visit() final { - if (!GetFragment().IsLineBox() && - inclusive_descendants_.Contains(GetFragment().GetLayoutObject())) { - Emit(); - return; - } - VisitChildren(); - } - - void CollectInclusiveDescendants(const LayoutInline& container) { - inclusive_descendants_.insert(&container); - for (const LayoutObject* node = container.FirstChild(); node; - node = node->NextSibling()) { - if (node->IsFloatingOrOutOfFlowPositioned()) - continue; - if (node->IsBox() || node->IsText()) { - inclusive_descendants_.insert(node); - continue; - } - if (!node->IsLayoutInline()) - continue; - CollectInclusiveDescendants(To<LayoutInline>(*node)); - } - } - - HashSet<const LayoutObject*> inclusive_descendants_; -}; - -} // namespace - -// static -Vector<Result> NGInlineFragmentTraversal::DescendantsOf( - const NGPhysicalContainerFragment& container) { - return DescendantCollector().CollectFrom(container); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h deleted file mode 100644 index 195c8af..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_ - -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" - -namespace blink { - -class NGPhysicalContainerFragment; - -// Utility class for traversing the physical fragment tree. -class CORE_EXPORT NGInlineFragmentTraversal { - STATIC_ONLY(NGInlineFragmentTraversal); - - public: - // Returns list of descendants in preorder. Offsets are relative to - // specified fragment. - static Vector<NGPhysicalFragmentWithOffset> DescendantsOf( - const NGPhysicalContainerFragment&); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_FRAGMENT_TRAVERSAL_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc deleted file mode 100644 index 5201d8d..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" - -namespace blink { - -class NGInlineFragmentTraversalTest : public NGLayoutTest { - public: - NGInlineFragmentTraversalTest() : NGLayoutTest() {} - - protected: - const NGPhysicalBoxFragment& GetRootFragmentById(const char* id) const { - const Element* element = GetElementById(id); - DCHECK(element) << id; - const LayoutObject* layout_object = element->GetLayoutObject(); - DCHECK(layout_object) << element; - DCHECK(layout_object->IsLayoutBlockFlow()) << element; - DCHECK(To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0)) - << element; - return *To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0); - } -}; - -#define EXPECT_NEXT_BOX(iter, id) \ - { \ - const auto& current = *iter++; \ - EXPECT_TRUE(current.fragment->IsBox()) << current.fragment->ToString(); \ - EXPECT_EQ(GetLayoutObjectByElementId(id), \ - current.fragment->GetLayoutObject()); \ - } - -#define EXPECT_NEXT_LINE_BOX(iter) \ - { \ - const auto& current = *iter++; \ - EXPECT_TRUE(current.fragment->IsLineBox()) \ - << current.fragment->ToString(); \ - } - -#define EXPECT_NEXT_TEXT(iter, content) \ - { \ - const auto& current = *iter++; \ - EXPECT_TRUE(current.fragment->IsText()) << current.fragment->ToString(); \ - EXPECT_EQ(content, \ - To<NGPhysicalTextFragment>(current.fragment.get())->Text()); \ - } - -TEST_F(NGInlineFragmentTraversalTest, DescendantsOf) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) { - // NGFragmentItem doesn't use |NGInlineFragmentTraversal|. - return; - } - SetBodyInnerHTML( - "<style>* { border: 1px solid}</style>" - "<div id=t>foo<b id=b>bar</b><br>baz</div>"); - const auto descendants = - NGInlineFragmentTraversal::DescendantsOf(GetRootFragmentById("t")); - auto* iter = descendants.begin(); - - EXPECT_NEXT_LINE_BOX(iter); - EXPECT_NEXT_TEXT(iter, "foo"); - EXPECT_NEXT_BOX(iter, "b"); - EXPECT_NEXT_TEXT(iter, "bar"); - EXPECT_NEXT_TEXT(iter, "\n"); - EXPECT_NEXT_LINE_BOX(iter); - EXPECT_NEXT_TEXT(iter, "baz"); - EXPECT_EQ(iter, descendants.end()); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h index 2e759623..8ecda5b7 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -7,7 +7,7 @@ #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc index ea08cbf..f13847d 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -18,9 +18,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h" #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" @@ -757,9 +755,6 @@ const auto* physical_fragment = child.PhysicalFragment(); if (!physical_fragment) continue; - if (physical_fragment->IsText()) - continue; - child.rect.offset += ComputeRelativeOffsetForInline( ConstraintSpace(), physical_fragment->Style()); }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc index 51fa5ff..4e87c6c 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -12,7 +12,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" @@ -51,12 +50,14 @@ builder.SetAvailableSize(size); NGConstraintSpace constraint_space = builder.ToConstraintSpace(); + NGInlineChildLayoutContext context; NGBoxFragmentBuilder container_builder( block_flow, block_flow->Style(), block_flow->Style()->GetWritingDirection()); - NGInlineChildLayoutContext context(inline_node, - container_builder.GetWritingDirection()); - container_builder.SetItemsBuilder(context.ItemsBuilder()); + NGFragmentItemsBuilder items_builder(inline_node, + container_builder.GetWritingDirection()); + container_builder.SetItemsBuilder(&items_builder); + context.SetItemsBuilder(&items_builder); scoped_refptr<const NGLayoutResult> layout_result = inline_node.Layout(constraint_space, nullptr, &context); const auto& line1 = layout_result->PhysicalFragment();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc index ac5b61d12..ef4b14c2 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -14,7 +14,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc index d19df5f..91a90d0 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -10,7 +10,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" @@ -46,32 +45,11 @@ AddChildInternal(&child, child_offset); } -void NGLineBoxFragmentBuilder::AddChildren(NGLogicalLineItems& children) { - children_.ReserveCapacity(children.size()); - - for (auto& child : children) { - if (child.layout_result) { - DCHECK(!child.text_fragment); - AddChild(child.layout_result->PhysicalFragment(), child.Offset()); - child.layout_result.reset(); - } else if (child.text_fragment) { - AddChild(std::move(child.text_fragment), child.Offset()); - DCHECK(!child.text_fragment); - } else if (child.out_of_flow_positioned_box) { - AddOutOfFlowInlineChildCandidate( - NGBlockNode(To<LayoutBox>(child.out_of_flow_positioned_box)), - child.Offset(), child.container_direction); - child.out_of_flow_positioned_box = nullptr; - } - } -} - void NGLineBoxFragmentBuilder::PropagateChildrenData( NGLogicalLineItems& children) { for (unsigned index = 0; index < children.size(); ++index) { auto& child = children[index]; if (child.layout_result) { - DCHECK(!child.text_fragment); PropagateChildData(child.layout_result->PhysicalFragment(), child.Offset());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h index 2b4c517..bf4aca76 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -9,7 +9,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h" @@ -73,16 +72,8 @@ break_token_ = std::move(break_token); } - void AddChild(scoped_refptr<const NGPhysicalTextFragment> child, - const LogicalOffset& offset) { - AddChildInternal(child, offset); - } - void AddChild(const NGPhysicalContainerFragment&, const LogicalOffset&); - // Add all items in ChildList. Skips null Child if any. - void AddChildren(NGLogicalLineItems&); - // Propagate data in |ChildList| without adding them to this builder. When // adding children as fragment items, they appear in the container, but there // are some data that should be propagated through line box fragments.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 2ac02b12..878a9f5e 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -9,7 +9,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h" #include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc index a02ccaa..e735245 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
@@ -7,7 +7,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/platform/fonts/font_baseline.h" #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h" @@ -128,9 +127,6 @@ LayoutUnit NGLineTruncator::TruncateLine(LayoutUnit line_width, NGLogicalLineItems* line_box, NGInlineLayoutStateStack* box_states) { - DCHECK(std::all_of(line_box->begin(), line_box->end(), - [](const auto& item) { return !item.text_fragment; })); - // Shape the ellipsis and compute its inline size. SetupEllipsis(); @@ -402,11 +398,6 @@ void NGLineTruncator::HideChild(NGLogicalLineItem* child) { DCHECK(child->HasInFlowFragment()); - if (const NGPhysicalTextFragment* text = child->text_fragment.get()) { - child->text_fragment = text->CloneAsHiddenForPaint(); - return; - } - if (const NGLayoutResult* layout_result = child->layout_result.get()) { // Need to propagate OOF descendants in this inline-block child. const auto& fragment = @@ -491,7 +482,6 @@ const NGLogicalLineItem& child, base::Optional<NGLogicalLineItem>* truncated_child) { DCHECK(truncated_child && !*truncated_child); - DCHECK(!child.text_fragment); // If the space is not enough, try the next child. if (space_for_child <= 0 && !is_first_child)
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc index 5682c71..a084c9f 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" namespace blink { @@ -39,33 +38,6 @@ return nullptr; } -void NGLogicalLineItems::CreateTextFragments(WritingMode writing_mode, - const String& text_content) { - NGTextFragmentBuilder text_builder(writing_mode); - for (auto& child : *this) { - if (const NGInlineItem* inline_item = child.inline_item) { - if (UNLIKELY(child.text_content)) { - // Create a generated text fragmment. - text_builder.SetText(inline_item->GetLayoutObject(), child.text_content, - inline_item->Style(), inline_item->StyleVariant(), - std::move(child.shape_result), child.MarginSize()); - } else { - // Create a regular text fragmment. - DCHECK((inline_item->Type() == NGInlineItem::kText && - (inline_item->TextType() == NGTextType::kNormal || - inline_item->TextType() == NGTextType::kSymbolMarker)) || - inline_item->Type() == NGInlineItem::kControl); - text_builder.SetItem(text_content, *inline_item, - std::move(child.shape_result), child.text_offset, - child.MarginSize()); - } - text_builder.SetIsHiddenForPaint(child.is_hidden_for_paint); - DCHECK(!child.text_fragment); - child.text_fragment = text_builder.ToTextFragment(); - } - } -} - NGLogicalLineItem* NGLogicalLineItems::FirstInFlowChild() { for (auto& child : *this) { if (child.HasInFlowFragment())
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h index cfce241fb..ca9ab20 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h
@@ -8,8 +8,9 @@ #include "third_party/blink/renderer/core/layout/geometry/logical_rect.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" namespace blink { @@ -120,22 +121,6 @@ rect(source_item.rect), inline_size(this->shape_result->SnappedWidth()), bidi_level(source_item.bidi_level) {} - NGLogicalLineItem(scoped_refptr<const NGPhysicalTextFragment> fragment, - LogicalOffset offset, - LayoutUnit inline_size, - UBiDiLevel bidi_level) - : text_fragment(std::move(fragment)), - rect(offset, LogicalSize()), - inline_size(inline_size), - bidi_level(bidi_level) {} - NGLogicalLineItem(scoped_refptr<const NGPhysicalTextFragment> fragment, - LayoutUnit block_offset, - LayoutUnit inline_size, - UBiDiLevel bidi_level) - : text_fragment(std::move(fragment)), - rect(LayoutUnit(), block_offset, LayoutUnit(), LayoutUnit()), - inline_size(inline_size), - bidi_level(bidi_level) {} // Create an out-of-flow positioned object. NGLogicalLineItem(LayoutObject* out_of_flow_positioned_box, UBiDiLevel bidi_level, @@ -158,11 +143,11 @@ return layout_result && layout_result->PhysicalFragment().IsInlineBox(); } bool HasInFlowFragment() const { - return text_fragment || inline_item || + return inline_item || (layout_result && !layout_result->PhysicalFragment().IsFloating()); } bool HasInFlowOrFloatingFragment() const { - return text_fragment || inline_item || layout_result || layout_object; + return inline_item || layout_result || layout_object; } bool HasOutOfFlowFragment() const { return out_of_flow_positioned_box; } bool HasFragment() const { @@ -194,10 +179,10 @@ const LogicalSize& Size() const { return rect.size; } LogicalSize MarginSize() const { return {inline_size, Size().block_size}; } - const NGPhysicalFragment* PhysicalFragment() const { + const NGPhysicalContainerFragment* PhysicalFragment() const { if (layout_result) return &layout_result->PhysicalFragment(); - return text_fragment.get(); + return nullptr; } const LayoutObject* GetLayoutObject() const; LayoutObject* GetMutableLayoutObject() const; @@ -215,7 +200,6 @@ } scoped_refptr<const NGLayoutResult> layout_result; - scoped_refptr<const NGPhysicalTextFragment> text_fragment; // Data to create a text fragment from. // |inline_item| is null only for ellipsis items. @@ -323,10 +307,6 @@ void MoveInBlockDirection(LayoutUnit); void MoveInBlockDirection(LayoutUnit, unsigned start, unsigned end); - // Create |NGPhysicalTextFragment| for all text children. - void CreateTextFragments(WritingMode writing_mode, - const String& text_content); - private: void WillInsertChild(unsigned index);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc index a3286db..a07a289 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -7,7 +7,6 @@ #include "third_party/blink/renderer/core/editing/editing_utilities.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc index 86cada3f..667f5788 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
@@ -4,8 +4,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" @@ -22,18 +21,10 @@ const LayoutObject* layout_object = container->GetLayoutObject(); DCHECK(layout_object) << container; DCHECK(layout_object->IsLayoutBlockFlow()) << container; - const NGPhysicalBoxFragment* root_fragment = - To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0); - DCHECK(root_fragment) << container; - + NGInlineCursor cursor(*To<LayoutBlockFlow>(layout_object)); Vector<const NGPhysicalLineBoxFragment*> lines; - for (const auto& child : - NGInlineFragmentTraversal::DescendantsOf(*root_fragment)) { - if (const NGPhysicalLineBoxFragment* line = - DynamicTo<NGPhysicalLineBoxFragment>(child.fragment.get())) { - lines.push_back(line); - } - } + for (cursor.MoveToFirstLine(); cursor; cursor.MoveToNextLine()) + lines.push_back(cursor.Current()->LineBoxFragment()); return lines; } @@ -45,9 +36,6 @@ } }; -#define EXPECT_TEXT_FRAGMENT(text, fragment) \ - { EXPECT_EQ(text, To<NGPhysicalTextFragment>(fragment)->Text().ToString()); } - #define EXPECT_BOX_FRAGMENT(id, fragment) \ { \ EXPECT_TRUE(fragment); \
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc deleted file mode 100644 index 268b91ef..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc +++ /dev/null
@@ -1,244 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" - -#include "third_party/blink/renderer/core/dom/node.h" -#include "third_party/blink/renderer/core/layout/geometry/logical_size.h" -#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" -#include "third_party/blink/renderer/core/layout/layout_text_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" -#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h" -#include "third_party/blink/renderer/core/page/page.h" -#include "third_party/blink/renderer/core/style/computed_style.h" -#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" -#include "third_party/blink/renderer/platform/wtf/size_assertions.h" - -namespace blink { - -namespace { - -struct SameSizeAsNGPhysicalTextFragment : NGPhysicalFragment { - void* pointers[3]; - unsigned offsets[2]; -}; - -ASSERT_SIZE(NGPhysicalTextFragment, SameSizeAsNGPhysicalTextFragment); - -} // anonymous namespace - -NGPhysicalTextFragment::NGPhysicalTextFragment(NGTextFragmentBuilder* builder) - : NGPhysicalFragment(builder, - kFragmentText, - static_cast<unsigned>(builder->text_type_)), - text_(builder->text_), - text_offset_(builder->text_offset_), - shape_result_(std::move(builder->shape_result_)) { - DCHECK(shape_result_ || IsFlowControl()) << *this; - base_or_resolved_direction_ = - static_cast<unsigned>(builder->ResolvedDirection()); - ink_overflow_computed_ = false; -} - -bool NGPhysicalTextFragment::IsGeneratedText() const { - if (UNLIKELY(TextType() == NGTextType::kLayoutGenerated)) - return true; - return GetLayoutObject()->IsStyleGenerated(); -} - -LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset( - unsigned offset, - LayoutUnit (*round_function)(float), - AdjustMidCluster adjust_mid_cluster) const { - return NGFragmentItem(*this).InlinePositionForOffset( - Text(), offset, round_function, adjust_mid_cluster); -} - -// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to -// "ng_fragment_item.cc" -// Compute the inline position from text offset, in logical coordinate relative -// to this fragment. -LayoutUnit NGFragmentItem::InlinePositionForOffset( - StringView text, - unsigned offset, - LayoutUnit (*round_function)(float), - AdjustMidCluster adjust_mid_cluster) const { - DCHECK_GE(offset, StartOffset()); - DCHECK_LE(offset, EndOffset()); - DCHECK_EQ(text.length(), TextLength()); - - offset -= StartOffset(); - if (TextShapeResult()) { - // TODO(layout-dev): Move caret position out of ShapeResult and into a - // separate support class that can take a ShapeResult or ShapeResultView. - // Allows for better code separation and avoids the extra copy below. - return round_function( - TextShapeResult()->CreateShapeResult()->CaretPositionForOffset( - offset, text, adjust_mid_cluster)); - } - - // This fragment is a flow control because otherwise ShapeResult exists. - DCHECK(IsFlowControl()); - DCHECK_EQ(1u, text.length()); - if (!offset || UNLIKELY(IsRtl(Style().Direction()))) - return LayoutUnit(); - return IsHorizontal() ? Size().width : Size().height; -} - -// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to -// "ng_fragment_item.cc" -LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text, - unsigned offset) const { - return InlinePositionForOffset(text, offset, LayoutUnit::FromFloatRound, - AdjustMidCluster::kToEnd); -} - -LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset( - unsigned offset) const { - return NGFragmentItem(*this).InlinePositionForOffset(Text(), offset); -} - -std::pair<LayoutUnit, LayoutUnit> -NGPhysicalTextFragment::LineLeftAndRightForOffsets(unsigned start_offset, - unsigned end_offset) const { - return NGFragmentItem(*this).LineLeftAndRightForOffsets(Text(), start_offset, - end_offset); -} - -// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to -// "ng_fragment_item.cc" -std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets( - StringView text, - unsigned start_offset, - unsigned end_offset) const { - DCHECK_LE(start_offset, EndOffset()); - DCHECK_GE(start_offset, StartOffset()); - DCHECK_LE(end_offset, EndOffset()); - - const LayoutUnit start_position = - InlinePositionForOffset(text, start_offset, LayoutUnit::FromFloatFloor, - AdjustMidCluster::kToStart); - const LayoutUnit end_position = InlinePositionForOffset( - text, end_offset, LayoutUnit::FromFloatCeil, AdjustMidCluster::kToEnd); - - // Swap positions if RTL. - return (UNLIKELY(start_position > end_position)) - ? std::make_pair(end_position, start_position) - : std::make_pair(start_position, end_position); -} - -PhysicalRect NGPhysicalTextFragment::LocalRect(unsigned start_offset, - unsigned end_offset) const { - return NGFragmentItem(*this).LocalRect(Text(), start_offset, end_offset); -} - -// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to -// "ng_fragment_item.cc" -PhysicalRect NGFragmentItem::LocalRect(StringView text, - unsigned start_offset, - unsigned end_offset) const { - if (start_offset == StartOffset() && end_offset == EndOffset()) - return LocalRect(); - LayoutUnit start_position, end_position; - std::tie(start_position, end_position) = - LineLeftAndRightForOffsets(text, start_offset, end_offset); - const LayoutUnit inline_size = end_position - start_position; - switch (GetWritingMode()) { - case WritingMode::kHorizontalTb: - return {start_position, LayoutUnit(), inline_size, Size().height}; - case WritingMode::kVerticalRl: - case WritingMode::kVerticalLr: - case WritingMode::kSidewaysRl: - return {LayoutUnit(), start_position, Size().width, inline_size}; - case WritingMode::kSidewaysLr: - return {LayoutUnit(), Size().height - end_position, Size().width, - inline_size}; - } - NOTREACHED(); - return {}; -} - -PhysicalRect NGPhysicalTextFragment::SelfInkOverflow() const { - if (!ink_overflow_computed_) - ComputeSelfInkOverflow(); - if (ink_overflow_) - return ink_overflow_->ink_overflow; - return LocalRect(); -} - -void NGPhysicalTextFragment::ComputeSelfInkOverflow() const { - ink_overflow_computed_ = true; - - if (UNLIKELY(!shape_result_)) { - ink_overflow_ = nullptr; - return; - } - - base::Optional<PhysicalRect> ink_overflow = - NGInkOverflow::ComputeTextInkOverflow(PaintInfo(), Style(), Size()); - if (!ink_overflow) { - ink_overflow_.reset(); - return; - } - if (ink_overflow_) - ink_overflow_->ink_overflow = *ink_overflow; - else - ink_overflow_ = std::make_unique<NGSingleInkOverflow>(*ink_overflow); -} - -scoped_refptr<const NGPhysicalTextFragment> -NGPhysicalTextFragment::CloneAsHiddenForPaint() const { - NGTextFragmentBuilder builder(*this); - builder.SetIsHiddenForPaint(true); - return builder.ToTextFragment(); -} - -unsigned NGPhysicalTextFragment::TextOffsetForPoint( - const PhysicalOffset& point) const { - const ComputedStyle& style = Style(); - const LayoutUnit& point_in_line_direction = - style.IsHorizontalWritingMode() ? point.left : point.top; - if (const ShapeResultView* shape_result = TextShapeResult()) { - // TODO(layout-dev): Move caret logic out of ShapeResult into separate - // support class for code health and to avoid this copy. - return shape_result->CreateShapeResult()->CaretOffsetForHitTest( - point_in_line_direction.ToFloat(), Text(), BreakGlyphs) + - StartOffset(); - } - - // Flow control fragments such as forced line break, tabulation, soft-wrap - // opportunities, etc. do not have ShapeResult. - DCHECK(IsFlowControl()); - - // Zero-inline-size objects such as newline always return the start offset. - LogicalSize size = Size().ConvertToLogical(style.GetWritingMode()); - if (!size.inline_size) - return StartOffset(); - - // Sized objects such as tabulation returns the next offset if the given point - // is on the right half. - LayoutUnit inline_offset = IsLtr(ResolvedDirection()) - ? point_in_line_direction - : size.inline_size - point_in_line_direction; - DCHECK_EQ(1u, TextLength()); - return inline_offset <= size.inline_size / 2 ? StartOffset() : EndOffset(); -} - -UBiDiLevel NGPhysicalTextFragment::BidiLevel() const { - // TODO(xiaochengh): Make the implementation more efficient with, e.g., - // binary search and/or LayoutNGText::InlineItems(). - const auto& items = InlineItemsOfContainingBlock(); - const NGInlineItem* containing_item = std::find_if( - items.begin(), items.end(), [this](const NGInlineItem& item) { - return item.StartOffset() <= StartOffset() && - item.EndOffset() >= EndOffset(); - }); - DCHECK(containing_item); - DCHECK_NE(containing_item, items.end()); - return containing_item->BidiLevel(); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h deleted file mode 100644 index 7684f68..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_ - -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_type.h" -#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" -#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h" -#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" -#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" -#include "third_party/blink/renderer/platform/wtf/casting.h" -#include "third_party/blink/renderer/platform/wtf/text/string_view.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" - -namespace blink { - -class NGTextFragmentBuilder; -class NGPhysicalTextFragment; -struct PhysicalRect; - -enum class AdjustMidCluster; - -class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment { - public: - NGPhysicalTextFragment(NGTextFragmentBuilder*); - - NGTextType TextType() const { return static_cast<NGTextType>(sub_type_); } - // Returns true if the text is generated (from, e.g., list marker, - // pseudo-element, ...) instead of from a DOM text node. - bool IsGeneratedText() const; - // True if this is a forced line break. - bool IsLineBreak() const { - return TextType() == NGTextType::kForcedLineBreak; - } - // True if this is not for painting; i.e., a forced line break, a tabulation, - // or a soft-wrap opportunity. - bool IsFlowControl() const { - return IsLineBreak() || TextType() == NGTextType::kFlowControl; - } - // True if this is an ellpisis generated by `text-overflow: ellipsis`. - bool IsEllipsis() const { - return StyleVariant() == NGStyleVariant::kEllipsis; - } - - bool IsSymbolMarker() const { - return TextType() == NGTextType::kSymbolMarker; - } - - const String& TextContent() const { return text_; } - - // ShapeResult may be nullptr if |IsFlowControl()|. - const ShapeResultView* TextShapeResult() const { return shape_result_.get(); } - - // Start/end offset to the text of the block container. - const NGTextOffset& TextOffset() const { return text_offset_; } - unsigned StartOffset() const { return text_offset_.start; } - unsigned EndOffset() const { return text_offset_.end; } - unsigned TextLength() const { return text_offset_.Length(); } - StringView Text() const { - return StringView(text_, text_offset_.start, TextLength()); - } - - WritingMode GetWritingMode() const { return Style().GetWritingMode(); } - bool IsHorizontal() const { - return IsHorizontalWritingMode(GetWritingMode()); - } - - // Compute the inline position from text offset, in logical coordinate - // relative to this fragment. - LayoutUnit InlinePositionForOffset(unsigned offset) const; - - // The layout box of text in (start, end) range in local coordinate. - // Start and end offsets must be between StartOffset() and EndOffset(). - PhysicalRect LocalRect(unsigned start_offset, unsigned end_offset) const; - using NGPhysicalFragment::LocalRect; - - // The visual bounding box that includes glpyh bounding box and CSS - // properties, in local coordinates. - PhysicalRect SelfInkOverflow() const; - - scoped_refptr<const NGPhysicalTextFragment> CloneAsHiddenForPaint() const; - - scoped_refptr<const NGPhysicalFragment> CloneWithoutOffset() const; - - NGTextFragmentPaintInfo PaintInfo() const { - return NGTextFragmentPaintInfo{text_, StartOffset(), EndOffset(), - TextShapeResult()}; - } - - // Returns the text offset in the fragment placed closest to the given point. - unsigned TextOffsetForPoint(const PhysicalOffset&) const; - - UBiDiLevel BidiLevel() const; - TextDirection ResolvedDirection() const { - return static_cast<TextDirection>(base_or_resolved_direction_); - } - - // Compute line-relative coordinates for given offsets, this is not - // flow-relative: - // https://drafts.csswg.org/css-writing-modes-3/#line-directions - std::pair<LayoutUnit, LayoutUnit> LineLeftAndRightForOffsets( - unsigned start_offset, - unsigned end_offset) const; - - private: - LayoutUnit InlinePositionForOffset(unsigned offset, - LayoutUnit (*round)(float), - AdjustMidCluster) const; - - void ComputeSelfInkOverflow() const; - - // The text of NGInlineNode; i.e., of a parent block. The text for this - // fragment is a substring(start_offset_, end_offset_) of this string. - const String text_; - - // Start and end offset of the parent block text. - const NGTextOffset text_offset_; - const scoped_refptr<const ShapeResultView> shape_result_; - - // Fragments are immutable but allow certain expensive data, specifically ink - // overflow, to be cached as long as it is guaranteed to always recompute to - // the same value. - mutable std::unique_ptr<NGSingleInkOverflow> ink_overflow_; - - friend class NGTextFragmentBuilder; -}; - -template <> -struct DowncastTraits<NGPhysicalTextFragment> { - static bool AllowFrom(const NGPhysicalFragment& fragment) { - return fragment.IsText(); - } -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc deleted file mode 100644 index 6850dafe..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc +++ /dev/null
@@ -1,320 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" - -#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" -#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h" -#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" - -namespace blink { - -class NGPhysicalTextFragmentTest : public NGLayoutTest { - public: - NGPhysicalTextFragmentTest() : NGLayoutTest() {} - - protected: - Vector<scoped_refptr<const NGPhysicalTextFragment>> - CollectTextFragmentsInContainer(const char* container_id) { - const Element* container = GetElementById(container_id); - DCHECK(container) << container_id; - const LayoutObject* layout_object = container->GetLayoutObject(); - DCHECK(layout_object) << container; - DCHECK(layout_object->IsLayoutBlockFlow()) << container; - const auto* root_fragment = - To<LayoutBlockFlow>(layout_object)->GetPhysicalFragment(0); - DCHECK(root_fragment) << container; - - Vector<scoped_refptr<const NGPhysicalTextFragment>> result; - for (const auto& child : - NGInlineFragmentTraversal::DescendantsOf(*root_fragment)) { - if (auto* text_child_fragment = - DynamicTo<NGPhysicalTextFragment>(child.fragment.get())) - result.push_back(text_child_fragment); - } - return result; - } - - static std::string GetText(const NGPhysicalTextFragment& fragment) { - return fragment.Text().ToString().Utf8(); - } -}; - -TEST_F(NGPhysicalTextFragmentTest, LocalRect) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - div { - font: 10px/1 Ahem; - width: 5em; - } - </style> - <div id=container>01234 67890</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(2u, text_fragments.size()); - EXPECT_EQ(PhysicalRect(20, 0, 20, 10), text_fragments[1]->LocalRect(8, 10)); -} - -TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - div { - font: 10px/1 Ahem; - width: 10em; - direction: rtl; - unicode-bidi: bidi-override; - } - </style> - <div id=container>0123456789 123456789</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(2u, text_fragments.size()); - // The 2nd line starts at 12, because the div has a bidi-control. - EXPECT_EQ(12u, text_fragments[1]->StartOffset()); - // TODO(layout-dev): Investigate whether this is correct. - // EXPECT_EQ(PhysicalRect(50, 0, 20, 10), - // text_fragments[1]->LocalRect(14, 16)); -} - -TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - div { - font: 10px/1 Ahem; - height: 5em; - writing-mode: vertical-lr; - } - </style> - <div id=container>01234 67890</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(2u, text_fragments.size()); - EXPECT_EQ(PhysicalRect(0, 20, 10, 20), text_fragments[1]->LocalRect(8, 10)); -} - -TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - div { - font: 10px/1 Ahem; - height: 5em; - writing-mode: vertical-rl; - } - </style> - <div id=container>01234 67890</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(2u, text_fragments.size()); - EXPECT_EQ(PhysicalRect(0, 20, 10, 20), text_fragments[1]->LocalRect(8, 10)); -} - -TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - SetBodyInnerHTML("<div id=div>text</div>"); - - auto text_fragments = CollectTextFragmentsInContainer("div"); - ASSERT_EQ(1u, text_fragments.size()); - - const NGPhysicalTextFragment& text = *text_fragments[0]; - EXPECT_FALSE(text.IsGeneratedText()); -} - -TEST_F(NGPhysicalTextFragmentTest, FirstLetterIsNotAnonymousText) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - SetBodyInnerHTML( - "<style>::first-letter {color:red}</style>" - "<div id=div>text</div>"); - - auto text_fragments = CollectTextFragmentsInContainer("div"); - ASSERT_EQ(2u, text_fragments.size()); - - const NGPhysicalTextFragment& first_letter = *text_fragments[0]; - const NGPhysicalTextFragment& remaining_text = *text_fragments[1]; - EXPECT_FALSE(first_letter.IsGeneratedText()); - EXPECT_FALSE(remaining_text.IsGeneratedText()); -} - -TEST_F(NGPhysicalTextFragmentTest, BeforeAndAfterAreAnonymousText) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - SetBodyInnerHTML( - "<style>::before{content:'x'} ::after{content:'x'}</style>" - "<div id=div>text</div>"); - - auto text_fragments = CollectTextFragmentsInContainer("div"); - ASSERT_EQ(3u, text_fragments.size()); - - const NGPhysicalTextFragment& before = *text_fragments[0]; - const NGPhysicalTextFragment& text = *text_fragments[1]; - const NGPhysicalTextFragment& after = *text_fragments[2]; - EXPECT_TRUE(before.IsGeneratedText()); - EXPECT_FALSE(text.IsGeneratedText()); - EXPECT_TRUE(after.IsGeneratedText()); -} - -TEST_F(NGPhysicalTextFragmentTest, Ellipsis) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - #sample { - font: 10px/1 Ahem; - overflow: hidden; - text-overflow: ellipsis; - width: 4ch; - } - </style> - <p id="sample">abcdef</p> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("sample"); - ASSERT_EQ(3u, text_fragments.size()); - - const NGPhysicalTextFragment& hidden = *text_fragments[0]; - const NGPhysicalTextFragment& truncated = *text_fragments[1]; - const NGPhysicalTextFragment& ellipsis = *text_fragments[2]; - - EXPECT_EQ(NGTextType::kNormal, hidden.TextType()); - EXPECT_FALSE(hidden.IsGeneratedText()); - EXPECT_TRUE(hidden.IsHiddenForPaint()); - EXPECT_EQ(u8"abcdef", GetText(hidden)); - - EXPECT_EQ(NGTextType::kNormal, truncated.TextType()); - EXPECT_FALSE(truncated.IsGeneratedText()); - EXPECT_FALSE(truncated.IsHiddenForPaint()); - EXPECT_EQ(u8"abc", GetText(truncated)); - - EXPECT_EQ(NGTextType::kLayoutGenerated, ellipsis.TextType()); - EXPECT_TRUE(ellipsis.IsGeneratedText()); - EXPECT_FALSE(ellipsis.IsHiddenForPaint()); - EXPECT_EQ(u8"\u2026", GetText(ellipsis)); -} - -TEST_F(NGPhysicalTextFragmentTest, ListMarkerIsGeneratedText) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - SetBodyInnerHTML( - "<ol style='list-style-position:inside'>" - "<li id=list>text</li>" - "</ol>"); - - auto text_fragments = CollectTextFragmentsInContainer("list"); - ASSERT_EQ(2u, text_fragments.size()); - - const NGPhysicalTextFragment& marker = *text_fragments[0]; - const NGPhysicalTextFragment& text = *text_fragments[1]; - EXPECT_TRUE(marker.IsGeneratedText()); - EXPECT_FALSE(text.IsGeneratedText()); -} - -TEST_F(NGPhysicalTextFragmentTest, SoftHyphen) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - #sample { - font: 10px/1 Ahem; - width: 3ch; - } - </style> - <p id="sample">abc­def</p> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("sample"); - ASSERT_EQ(3u, text_fragments.size()); - - const NGPhysicalTextFragment& abc = *text_fragments[0]; - const NGPhysicalTextFragment& shy = *text_fragments[1]; - const NGPhysicalTextFragment& def = *text_fragments[2]; - EXPECT_EQ(NGTextType::kNormal, abc.TextType()); - // Note: ShapeResult::RunInfo.width_ == 0 for U+00AD - EXPECT_EQ(u8"abc\u00AD", GetText(abc)); - EXPECT_EQ(NGTextType::kLayoutGenerated, shy.TextType()); - // Note: |ComputedStyle::HyphenString()| returns "-" or U+2010 based on - // glyph availability. - if (GetText(shy) != "-") - EXPECT_EQ(u8"\u2010", GetText(shy)); - EXPECT_EQ(NGTextType::kNormal, def.TextType()); -} - -TEST_F(NGPhysicalTextFragmentTest, QuotationMarksAreAnonymousText) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - SetBodyInnerHTML("<div id=div><q>text</q></div>"); - - auto text_fragments = CollectTextFragmentsInContainer("div"); - ASSERT_EQ(3u, text_fragments.size()); - - const NGPhysicalTextFragment& open_quote = *text_fragments[0]; - const NGPhysicalTextFragment& text = *text_fragments[1]; - const NGPhysicalTextFragment& closed_quote = *text_fragments[2]; - EXPECT_TRUE(open_quote.IsGeneratedText()); - EXPECT_FALSE(text.IsGeneratedText()); - EXPECT_TRUE(closed_quote.IsGeneratedText()); -} - -TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulation) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - #container { - white-space: pre; - font-family: Ahem; - font-size: 10px; - tab-size: 8; - } - </style> - <div id="container">	</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(1u, text_fragments.size()); - const NGPhysicalTextFragment& text = *text_fragments[0]; - EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(), LayoutUnit()})); - EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(39), LayoutUnit()})); - EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(41), LayoutUnit()})); - EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(80), LayoutUnit()})); -} - -TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulationRtl) { - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) - return; - LoadAhem(); - SetBodyInnerHTML(R"HTML( - <style> - #container { - white-space: pre; - font-family: Ahem; - font-size: 10px; - tab-size: 8; - } - </style> - <div id="container" dir="rtl">	</div> - )HTML"); - auto text_fragments = CollectTextFragmentsInContainer("container"); - ASSERT_EQ(1u, text_fragments.size()); - const NGPhysicalTextFragment& text = *text_fragments[0]; - EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(), LayoutUnit()})); - EXPECT_EQ(1u, text.TextOffsetForPoint({LayoutUnit(39), LayoutUnit()})); - EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(41), LayoutUnit()})); - EXPECT_EQ(0u, text.TextOffsetForPoint({LayoutUnit(80), LayoutUnit()})); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc index 093c5a6..cdd44f2 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
@@ -249,12 +249,10 @@ continue; LayoutUnit item_over = item.BlockOffset(); LayoutUnit item_under = item.BlockEndOffset(); - if (item.text_fragment || item.shape_result) { + if (item.shape_result) { if (const auto* style = item.Style()) { std::tie(item_over, item_under) = AdjustTextOverUnderOffsetsForEmHeight( - item_over, item_under, *style, - item.text_fragment ? *item.text_fragment->TextShapeResult() - : *item.shape_result); + item_over, item_under, *style, *item.shape_result); } } else { const auto* fragment = item.PhysicalFragment();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc deleted file mode 100644 index 8f97076..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h" - -#include "third_party/blink/renderer/core/layout/layout_text_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" -#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" - -namespace blink { - -NGTextFragmentBuilder::NGTextFragmentBuilder( - const NGPhysicalTextFragment& fragment) - : NGFragmentBuilder(fragment), - text_(fragment.text_), - text_offset_(fragment.TextOffset()), - shape_result_(fragment.TextShapeResult()), - text_type_(fragment.TextType()) {} - -void NGTextFragmentBuilder::SetItem( - const String& text_content, - const NGInlineItem& item, - scoped_refptr<const ShapeResultView> shape_result, - const NGTextOffset& text_offset, - const LogicalSize& size) { - DCHECK_NE(item.TextType(), NGTextType::kLayoutGenerated) - << "Please use SetText() instead."; - DCHECK(item.Style()); - - text_type_ = item.TextType(); - text_ = text_content; - text_offset_ = text_offset; - resolved_direction_ = item.Direction(); - SetStyle(item.Style(), item.StyleVariant()); - size_ = size; - shape_result_ = std::move(shape_result); - layout_object_ = item.GetLayoutObject(); -} - -void NGTextFragmentBuilder::SetText( - LayoutObject* layout_object, - const String& text, - scoped_refptr<const ComputedStyle> style, - NGStyleVariant style_variant, - scoped_refptr<const ShapeResultView> shape_result, - const LogicalSize& size) { - DCHECK(layout_object); - DCHECK(style); - DCHECK(shape_result); - - text_type_ = NGTextType::kLayoutGenerated; - text_ = text; - text_offset_ = {shape_result->StartIndex(), shape_result->EndIndex()}; - resolved_direction_ = shape_result->Direction(); - SetStyle(style, style_variant); - size_ = size; - shape_result_ = std::move(shape_result); - layout_object_ = layout_object; -} - -scoped_refptr<const NGPhysicalTextFragment> -NGTextFragmentBuilder::ToTextFragment() { - scoped_refptr<const NGPhysicalTextFragment> fragment = - base::AdoptRef(new NGPhysicalTextFragment(this)); - return fragment; -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h deleted file mode 100644 index 7e90f26..0000000 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_ - -#include "third_party/blink/renderer/core/layout/geometry/logical_size.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" - -namespace blink { - -class LayoutObject; -class ShapeResultView; - -class CORE_EXPORT NGTextFragmentBuilder final : public NGFragmentBuilder { - STACK_ALLOCATED(); - - public: - explicit NGTextFragmentBuilder(WritingMode writing_mode) - : NGFragmentBuilder({writing_mode, TextDirection::kLtr}) {} - - NGTextFragmentBuilder(const NGPhysicalTextFragment& fragment); - - TextDirection ResolvedDirection() const { return resolved_direction_; } - - // NOTE: Takes ownership of the shape result within the item result. - void SetItem(const String& text_content, - const NGInlineItem& inline_item, - scoped_refptr<const ShapeResultView> shape_result, - const NGTextOffset& text_offset, - const LogicalSize& size); - - // Set text for generated text, e.g. hyphen and ellipsis. - void SetText(LayoutObject*, - const String& text, - scoped_refptr<const ComputedStyle>, - NGStyleVariant style_variant, - scoped_refptr<const ShapeResultView>, - const LogicalSize& size); - - // Creates the fragment. Can only be called once. - scoped_refptr<const NGPhysicalTextFragment> ToTextFragment(); - - private: - String text_; - NGTextOffset text_offset_; - scoped_refptr<const ShapeResultView> shape_result_; - - NGTextType text_type_ = NGTextType::kNormal; - - // Set from |NGInlineItem| by |SetItem()|. - TextDirection resolved_direction_ = TextDirection::kLtr; - - friend class NGPhysicalTextFragment; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_FRAGMENT_BUILDER_H_
diff --git a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc index 54c0563..e757ce0 100644 --- a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_operator_layout_algorithm.cc
@@ -44,9 +44,11 @@ DCHECK(!child.NextSibling()); DCHECK(!child.IsOutOfFlowPositioned()); - NGInlineChildLayoutContext context(To<NGInlineNode>(child), - container_builder_.GetWritingDirection()); - container_builder_.SetItemsBuilder(context.ItemsBuilder()); + NGInlineChildLayoutContext context; + NGFragmentItemsBuilder items_builder( + To<NGInlineNode>(child), container_builder_.GetWritingDirection()); + container_builder_.SetItemsBuilder(&items_builder); + context.SetItemsBuilder(&items_builder); scoped_refptr<const NGLayoutResult> child_layout_result = To<NGInlineNode>(child).Layout(ConstraintSpace(), nullptr, &context); container_builder_.AddResult(*child_layout_result, {});
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 8c1b8069..b1e739d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -428,13 +428,26 @@ NOINLINE scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::LayoutWithInlineChildLayoutContext( const NGLayoutInputNode& first_child) { - NGInlineChildLayoutContext context(To<NGInlineNode>(first_child), - container_builder_.GetWritingDirection()); - container_builder_.SetItemsBuilder(context.ItemsBuilder()); - scoped_refptr<const NGLayoutResult> result = Layout(&context); - // |NGFragmentItemsBuilder| is owned by |NGInlineChildLayoutContext| which is - // on stack. Make sure it is no longer referred. + NGInlineChildLayoutContext context; + if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) + return Layout(&context); + return LayoutWithItemsBuilder(To<NGInlineNode>(first_child), &context); +} + +NOINLINE scoped_refptr<const NGLayoutResult> +NGBlockLayoutAlgorithm::LayoutWithItemsBuilder( + const NGInlineNode& first_child, + NGInlineChildLayoutContext* context) { + NGFragmentItemsBuilder items_builder( + first_child, container_builder_.GetWritingDirection()); + container_builder_.SetItemsBuilder(&items_builder); + context->SetItemsBuilder(&items_builder); + scoped_refptr<const NGLayoutResult> result = Layout(context); + // Ensure stack-allocated |NGFragmentItemsBuilder| is not used anymore. + // TODO(kojii): Revisit when the storage of |NGFragmentItemsBuilder| is + // finalized. container_builder_.SetItemsBuilder(nullptr); + context->SetItemsBuilder(nullptr); return result; } @@ -967,6 +980,7 @@ NGInlineNode inline_node, NGPreviousInflowPosition* previous_inflow_position, scoped_refptr<const NGInlineBreakToken>* inline_break_token_out) { + DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()); DCHECK(previous_result_); DCHECK(!inline_node.IsEmptyInline()); DCHECK(container_builder_.BfcBlockOffset()); @@ -1583,7 +1597,8 @@ is_non_empty_inline = !child_inline_node->IsEmptyInline(); // Add reusable line boxes from |previous_result_| if any. - if (is_non_empty_inline && !child_break_token && previous_result_) { + if (is_non_empty_inline && !child_break_token && previous_result_ && + RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) { if (!ResolveBfcBlockOffset(previous_inflow_position)) return NGLayoutResult::kBfcBlockOffsetResolved; DCHECK(container_builder_.BfcBlockOffset());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h index 5fc3cbf..e8c7571 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -68,6 +68,9 @@ private: NOINLINE scoped_refptr<const NGLayoutResult> LayoutWithInlineChildLayoutContext(const NGLayoutInputNode& first_child); + NOINLINE scoped_refptr<const NGLayoutResult> LayoutWithItemsBuilder( + const NGInlineNode& first_child, + NGInlineChildLayoutContext* context); // Lay out again, this time with a predefined good breakpoint that we // discovered in the first pass. This happens when we run out of space in a
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc index f4f715d..3862790d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -7,7 +7,6 @@ #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" @@ -29,55 +28,6 @@ using LineBoxPair = std::pair<const NGPhysicalLineBoxFragment*, const NGPhysicalLineBoxFragment*>; -void GatherInlineContainerFragmentsFromLinebox( - NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map, - HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map, - const NGPhysicalLineBoxFragment& linebox, - const PhysicalOffset linebox_offset) { - for (const auto& descendant : - NGInlineFragmentTraversal::DescendantsOf(linebox)) { - if (!descendant.fragment->IsBox()) - continue; - const LayoutObject* key = descendant.fragment->GetLayoutObject(); - // Key for inline is the continuation root if it exists. - if (key->IsLayoutInline() && key->GetNode()) - key = key->ContinuationRoot(); - auto it = inline_containing_block_map->find(key); - if (it == inline_containing_block_map->end()) { - // Default case, not one of the blocks we are looking for. - continue; - } - base::Optional<NGBoxFragmentBuilder::InlineContainingBlockGeometry>& - containing_block_geometry = it->value; - LineBoxPair& containing_lineboxes = - containing_linebox_map->insert(key, LineBoxPair{nullptr, nullptr}) - .stored_value->value; - DCHECK(containing_block_geometry.has_value() || - !containing_lineboxes.first); - - // |DescendantsOf| returns the offset from the given fragment. Since - // we give it the line box, need to add the |linebox_offset|. - PhysicalRect fragment_rect( - linebox_offset + descendant.offset_to_container_box, - descendant.fragment->Size()); - if (containing_lineboxes.first == &linebox) { - containing_block_geometry->start_fragment_union_rect.Unite(fragment_rect); - } else if (!containing_lineboxes.first) { - containing_lineboxes.first = &linebox; - containing_block_geometry = - NGBoxFragmentBuilder::InlineContainingBlockGeometry{fragment_rect, - PhysicalRect()}; - } - // Skip fragments within an empty line boxes for the end fragment. - if (containing_lineboxes.second == &linebox) { - containing_block_geometry->end_fragment_union_rect.Unite(fragment_rect); - } else if (!containing_lineboxes.second || !linebox.IsEmptyLineBox()) { - containing_lineboxes.second = &linebox; - containing_block_geometry->end_fragment_union_rect = fragment_rect; - } - } -} - template <class Items> void GatherInlineContainerFragmentsFromItems( const Items& items, @@ -541,62 +491,6 @@ return LogicalOffset(); } -void NGBoxFragmentBuilder::ComputeInlineContainerGeometryFromFragmentTree( - InlineContainingBlockMap* inline_containing_block_map) { - if (inline_containing_block_map->IsEmpty()) - return; - - // This function has detailed knowledge of inline fragment tree structure, - // and will break if this changes. - DCHECK_GE(InlineSize(), LayoutUnit()); - DCHECK_GE(FragmentBlockSize(), LayoutUnit()); -#if DCHECK_IS_ON() - // Make sure all entries are continuation root. - for (const auto& entry : *inline_containing_block_map) - DCHECK_EQ(entry.key, entry.key->ContinuationRoot()); -#endif - - HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map; - for (const auto& child : children_) { - if (child.fragment->IsLineBox()) { - const auto& linebox = To<NGPhysicalLineBoxFragment>(*child.fragment); - const PhysicalOffset linebox_offset = child.offset.ConvertToPhysical( - GetWritingDirection(), ToPhysicalSize(Size(), GetWritingMode()), - linebox.Size()); - GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map, - &containing_linebox_map, - linebox, linebox_offset); - } else if (child.fragment->IsBox()) { - const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment); - bool is_anonymous_container = - box_fragment.GetLayoutObject() && - box_fragment.GetLayoutObject()->IsAnonymousBlock(); - if (!is_anonymous_container) - continue; - // If child is an anonymous container, this might be a special case of - // split inlines. The inline container fragments might be inside - // anonymous boxes. To find inline container fragments, traverse - // lineboxes inside anonymous box. - // For more on this special case, see "css container is an inline, with - // inline splitting" comment in NGOutOfFlowLayoutPart::LayoutDescendant. - const PhysicalOffset box_offset = child.offset.ConvertToPhysical( - GetWritingDirection(), ToPhysicalSize(Size(), GetWritingMode()), - box_fragment.Size()); - - // Traverse lineboxes of anonymous box. - for (const auto& box_child : box_fragment.Children()) { - if (box_child->IsLineBox()) { - const auto& linebox = To<NGPhysicalLineBoxFragment>(*box_child); - const PhysicalOffset linebox_offset = box_child.Offset() + box_offset; - GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map, - &containing_linebox_map, - linebox, linebox_offset); - } - } - } - } -} - void NGBoxFragmentBuilder::ComputeInlineContainerGeometry( InlineContainingBlockMap* inline_containing_block_map) { if (inline_containing_block_map->IsEmpty())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h index 1343d93c..91d1ba6 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -201,11 +201,6 @@ // descendants, propagating fragmentainer breaks, and more. void AddResult(const NGLayoutResult&, const LogicalOffset); - void AddChild(scoped_refptr<const NGPhysicalTextFragment> child, - const LogicalOffset& offset) { - AddChildInternal(child, offset); - } - void AddChild(const NGPhysicalContainerFragment&, const LogicalOffset&, const LayoutInline* inline_container = nullptr, @@ -536,8 +531,6 @@ // Computes the geometry required for any inline containing blocks. // |inline_containing_block_map| is a map whose keys specify which inline // containing block geometry is required. - void ComputeInlineContainerGeometryFromFragmentTree( - InlineContainingBlockMap* inline_containing_block_map); void ComputeInlineContainerGeometry( InlineContainingBlockMap* inline_containing_block_map);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc index d9943089..117f65d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -61,37 +61,7 @@ new_inline_container); } - if (const NGPhysicalBoxFragment* fragment = - DynamicTo<NGPhysicalBoxFragment>(&child)) { - if (fragment->HasOutOfFlowPositionedFragmentainerDescendants()) { - const auto& out_of_flow_fragmentainer_descendants = - fragment->OutOfFlowPositionedFragmentainerDescendants(); - const WritingModeConverter empty_outer_size(GetWritingDirection(), - PhysicalSize()); - for (const auto& descendant : out_of_flow_fragmentainer_descendants) { - const NGPhysicalContainerFragment* containing_block_fragment = - descendant.containing_block_fragment.get(); - if (!containing_block_fragment) - containing_block_fragment = fragment; - - LogicalOffset containing_block_offset = converter.ToLogical( - descendant.containing_block_offset, PhysicalSize()); - if (!child.IsFragmentainerBox()) - containing_block_offset.block_offset += child_offset.block_offset; - if (IsBlockFragmentationContextRoot()) { - containing_block_offset.block_offset += - fragmentainer_consumed_block_size_; - } - - NGLogicalStaticPosition static_position = - descendant.static_position.ConvertToLogical(empty_outer_size); - oof_positioned_fragmentainer_descendants_.emplace_back( - descendant.node, static_position, descendant.inline_container, - /* needs_block_offset_adjustment */ false, containing_block_offset, - containing_block_fragment); - } - } - } + PropagateOOFPositionedFragmentainerDescendants(child, child_offset); // We only need to report if inflow or floating elements depend on the // percentage resolution block-size. OOF-positioned children resolve their @@ -156,10 +126,6 @@ last_inline_break_token_ = To<NGInlineBreakToken>(child_break_token); line_count_++; break; - case NGPhysicalFragment::kFragmentText: - default: - NOTREACHED(); - break; } } @@ -305,6 +271,47 @@ } } +void NGContainerFragmentBuilder::PropagateOOFPositionedFragmentainerDescendants( + const NGPhysicalContainerFragment& fragment, + LogicalOffset offset) { + const NGPhysicalBoxFragment* box_fragment = + DynamicTo<NGPhysicalBoxFragment>(&fragment); + // Fragmentainer descendants are only on box fragments. + if (!box_fragment || + !box_fragment->HasOutOfFlowPositionedFragmentainerDescendants()) { + return; + } + + const WritingModeConverter converter(GetWritingDirection(), fragment.Size()); + const WritingModeConverter empty_outer_size(GetWritingDirection(), + PhysicalSize()); + + const auto& out_of_flow_fragmentainer_descendants = + box_fragment->OutOfFlowPositionedFragmentainerDescendants(); + for (const auto& descendant : out_of_flow_fragmentainer_descendants) { + const NGPhysicalContainerFragment* containing_block_fragment = + descendant.containing_block_fragment.get(); + if (!containing_block_fragment) + containing_block_fragment = box_fragment; + + LogicalOffset containing_block_offset = + converter.ToLogical(descendant.containing_block_offset, PhysicalSize()); + if (!fragment.IsFragmentainerBox()) + containing_block_offset.block_offset += offset.block_offset; + if (IsBlockFragmentationContextRoot()) { + containing_block_offset.block_offset += + fragmentainer_consumed_block_size_; + } + + NGLogicalStaticPosition static_position = + descendant.static_position.ConvertToLogical(empty_outer_size); + AddOutOfFlowFragmentainerDescendant( + {descendant.node, static_position, descendant.inline_container, + /* needs_block_offset_adjustment */ false, containing_block_offset, + containing_block_fragment}); + } +} + #if DCHECK_IS_ON() String NGContainerFragmentBuilder::ToString() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h index 4b4d40b..a8225df5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h" #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h" #include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h" #include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h" #include "third_party/blink/renderer/core/layout/ng/ng_early_break.h" @@ -151,6 +150,14 @@ // block layout algorithm, to perform the final OOF layout and positioning. void MoveOutOfFlowDescendantCandidatesToDescendants(); + // Propagate the OOF descendants from a fragment to the builder. Since the OOF + // descendants on the fragment are NGPhysicalOutOfFlowPositionedNodes, we + // first have to create NGLogicalOutOfFlowPositionedNodes copies before + // appending them to our list of descendants. + void PropagateOOFPositionedFragmentainerDescendants( + const NGPhysicalContainerFragment& fragment, + LogicalOffset offset); + void SetIsSelfCollapsing() { is_self_collapsing_ = true; } void SetIsPushedByFloats() { is_pushed_by_floats_ = true; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc index 32210ca7..315c3f2a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h" #include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h index a5a2885..3bdfc5f7 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" #include "third_party/blink/renderer/core/layout/ng/ng_break_token.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/text/writing_direction_mode.h"
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index 73d54af..185cfe1 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -351,13 +351,8 @@ } // Fetch the inline start/end fragment geometry. - if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) { - container_builder_->ComputeInlineContainerGeometry( - &inline_container_fragments); - } else { - container_builder_->ComputeInlineContainerGeometryFromFragmentTree( - &inline_container_fragments); - } + container_builder_->ComputeInlineContainerGeometry( + &inline_container_fragments); LogicalSize container_builder_size = container_builder_->Size(); PhysicalSize container_builder_physical_size = @@ -637,10 +632,17 @@ while (descendants->size() > 0) { for (auto& descendant : *descendants) { - LayoutFragmentainerDescendant(descendant); + scoped_refptr<const NGLayoutResult> result = + LayoutFragmentainerDescendant(descendant); + // TODO(bebeaudr): The final offset of the innermost abspos is wrong. It + // seems like it is off by exactly the offset of the outermost abspos. + // Don't we already take into account that value? + container_builder_->PropagateOOFPositionedFragmentainerDescendants( + result->PhysicalFragment(), result->OutOfFlowPositionedOffset()); } - // Sweep any descendants that might have been added. - // This happens when an absolute container has a fixed child. + // Sweep any descendants that might have been bubbled up from the fragment + // to the |container_builder_|. This happens when we have nested absolute + // position elements. descendants->Shrink(0); container_builder_->SwapOutOfFlowFragmentainerDescendants(descendants); } @@ -657,7 +659,8 @@ } } -void NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant( +scoped_refptr<const NGLayoutResult> +NGOutOfFlowLayoutPart::LayoutFragmentainerDescendant( const NGLogicalOutOfFlowPositionedNode& descendant) { NGBlockNode node = descendant.node; const NGPhysicalContainerFragment* containing_block_fragment = @@ -704,10 +707,10 @@ builder.SetPercentageResolutionSize(container_content_size); NGConstraintSpace descendant_constraint_space = builder.ToConstraintSpace(); - Layout(node, descendant_constraint_space, descendant_static_position, - container_physical_content_size, container_info, - default_writing_direction, /* only_layout */ nullptr, - /* is_fragmentainer_descendant */ true); + return Layout(node, descendant_constraint_space, descendant_static_position, + container_physical_content_size, container_info, + default_writing_direction, /* only_layout */ nullptr, + /* is_fragmentainer_descendant */ true); } scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index e6d6a71..6184c6d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -114,7 +114,8 @@ void LayoutFragmentainerDescendants( Vector<NGLogicalOutOfFlowPositionedNode>* descendants); - void LayoutFragmentainerDescendant(const NGLogicalOutOfFlowPositionedNode&); + scoped_refptr<const NGLayoutResult> LayoutFragmentainerDescendant( + const NGLogicalOutOfFlowPositionedNode&); scoped_refptr<const NGLayoutResult> Layout( NGBlockNode,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 75dd99b4..5e5983b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,7 +14,6 @@ #include "third_party/blink/renderer/core/layout/layout_object_inlines.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc index 187e205..5661d2c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -318,7 +318,7 @@ NGOutlineType outline_type, const LayoutBoxModelObject* containing_block) const { DCHECK(!descendant->IsLayoutObjectDestroyedOrMoved()); - if (descendant->IsText() || descendant->IsListMarker()) + if (descendant->IsListMarker()) return; if (const auto* descendant_box =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc index a7611dc..41b8498d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -12,7 +12,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h" @@ -164,24 +163,6 @@ } } - if (const auto* text = DynamicTo<NGPhysicalTextFragment>(fragment)) { - if (flags_ & NGPhysicalFragment::DumpType) { - builder_->Append("Text"); - has_content = true; - } - has_content = AppendOffsetAndSize(fragment, fragment_offset, has_content); - - if (flags_ & NGPhysicalFragment::DumpTextOffsets) { - if (has_content) - builder_->Append(' '); - builder_->AppendFormat("start: %u end: %u", text->StartOffset(), - text->EndOffset()); - has_content = true; - } - builder_->Append("\n"); - return; - } - if (flags_ & NGPhysicalFragment::DumpType) { builder_->Append("Unknown fragment type"); has_content = true; @@ -350,8 +331,7 @@ is_painted_atomically_(other.is_painted_atomically_), has_collapsed_borders_(other.has_collapsed_borders_), has_baseline_(other.has_baseline_), - has_last_baseline_(other.has_last_baseline_), - ink_overflow_computed_(other.ink_overflow_computed_) { + has_last_baseline_(other.has_last_baseline_) { CHECK(layout_object_); } @@ -364,15 +344,9 @@ case kFragmentBox: delete static_cast<const NGPhysicalBoxFragment*>(this); break; - case kFragmentText: - delete static_cast<const NGPhysicalTextFragment*>(this); - break; case kFragmentLineBox: delete static_cast<const NGPhysicalLineBoxFragment*>(this); break; - default: - NOTREACHED(); - break; } } @@ -449,21 +423,6 @@ DCHECK_EQ(IsAtomicInline(), layout_object_->IsInline() && layout_object_->IsAtomicInlineLevel()); break; - case kFragmentText: - if (To<NGPhysicalTextFragment>(this)->IsGeneratedText()) { - // Ellipsis has the truncated in-flow LayoutObject. - DCHECK(layout_object_->IsText() || - (layout_object_->IsInline() && - layout_object_->IsAtomicInlineLevel()) || - layout_object_->IsLayoutInline()); - } else { - DCHECK(layout_object_->IsText()); - } - DCHECK(!IsFloating()); - DCHECK(!IsOutOfFlowPositioned()); - DCHECK(!IsInlineBox()); - DCHECK(!IsAtomicInline()); - break; case kFragmentLineBox: DCHECK(layout_object_->IsLayoutBlockFlow()); DCHECK(!IsFloating()); @@ -490,13 +449,6 @@ switch (Type()) { case kFragmentBox: return To<NGPhysicalBoxFragment>(*this).ScrollableOverflow(height_type); - case kFragmentText: - if (height_type == TextHeightType::kNormalHeight) - return {{}, Size()}; - return AdjustTextRectForEmHeight( - LocalRect(), Style(), - To<NGPhysicalTextFragment>(this)->TextShapeResult(), - container.Style().GetWritingMode()); case kFragmentLineBox: NOTREACHED() << "You must call NGLineBoxFragment::ScrollableOverflow explicitly."; @@ -571,8 +523,6 @@ UBiDiLevel NGPhysicalFragment::BidiLevel() const { switch (Type()) { - case kFragmentText: - return To<NGPhysicalTextFragment>(*this).BidiLevel(); case kFragmentBox: return To<NGPhysicalBoxFragment>(*this).BidiLevel(); case kFragmentLineBox: @@ -584,8 +534,6 @@ TextDirection NGPhysicalFragment::ResolvedDirection() const { switch (Type()) { - case kFragmentText: - return To<NGPhysicalTextFragment>(*this).ResolvedDirection(); case kFragmentBox: DCHECK(IsInline() && IsAtomicInline()); // TODO(xiaochengh): Store direction in |base_direction_| flag. @@ -634,14 +582,6 @@ output.AppendFormat(", BoxType: '%s'", StringForBoxType(*this).Ascii().c_str()); break; - case kFragmentText: { - const auto& text = To<NGPhysicalTextFragment>(*this); - output.AppendFormat(", TextType: %u, Text: (%u,%u) \"", text.TextType(), - text.StartOffset(), text.EndOffset()); - output.Append(text.Text()); - output.Append("\""); - break; - } case kFragmentLineBox: break; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h index e06ee1f..b8c25e4 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -49,8 +49,7 @@ public: enum NGFragmentType { kFragmentBox = 0, - kFragmentText = 1, - kFragmentLineBox = 2, + kFragmentLineBox = 1, // When adding new values, make sure the bit size of |type_| is large // enough to store. }; @@ -82,7 +81,6 @@ Type() == NGFragmentType::kFragmentLineBox; } bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; } - bool IsText() const { return Type() == NGFragmentType::kFragmentText; } bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; } // Returns the box type of this fragment. @@ -110,9 +108,7 @@ return IsBox() && BoxType() == NGBoxType::kAtomicInline; } // True if this fragment is in-flow in an inline formatting context. - bool IsInline() const { - return IsText() || IsInlineBox() || IsAtomicInline(); - } + bool IsInline() const { return IsInlineBox() || IsAtomicInline(); } bool IsFloating() const { return IsBox() && BoxType() == NGBoxType::kFloating; } @@ -508,7 +504,7 @@ LayoutObject* layout_object_; const PhysicalSize size_; - const unsigned type_ : 2; // NGFragmentType + const unsigned type_ : 1; // NGFragmentType const unsigned sub_type_ : 3; // NGBoxType, NGTextType, or NGLineBoxType const unsigned style_variant_ : 2; // NGStyleVariant const unsigned is_hidden_for_paint_ : 1; @@ -528,10 +524,6 @@ unsigned has_baseline_ : 1; unsigned has_last_baseline_ : 1; - // The following bitfields are only to be used by NGPhysicalTextFragment - // (it's defined here to save memory, since that class has no bitfields). - mutable unsigned ink_overflow_computed_ : 1; - // Note: We've used 32-bit bit field. If you need more bits, please think to // share bit fields, or put them before layout_object_ to fill the gap after // RefCounted on 64-bit systems.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc index 036a8ce..8f76f64 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -227,11 +227,13 @@ // We add both items and line-box fragments for existing mechanisms to work. // We may revisit this in future. See also |NGBoxFragmentBuilder::AddResult|. - if (const NGFragmentItems* previous_items = previous_fragment.Items()) { - auto* items_builder = container_builder_.ItemsBuilder(); - DCHECK(items_builder); - DCHECK_EQ(items_builder->GetWritingDirection(), writing_direction_); - items_builder->AddPreviousItems(previous_fragment, *previous_items); + if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) { + if (const NGFragmentItems* previous_items = previous_fragment.Items()) { + auto* items_builder = container_builder_.ItemsBuilder(); + DCHECK(items_builder); + DCHECK_EQ(items_builder->GetWritingDirection(), writing_direction_); + items_builder->AddPreviousItems(previous_fragment, *previous_items); + } } NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc index 88e16f0c..0f0b732 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -46,17 +46,41 @@ return blocked_reason; } +base::Optional<ResourceRequestBlockedReason> +BaseFetchContext::CanRequestBasedOnSubresourceFilterOnly( + ResourceType type, + const ResourceRequest& resource_request, + const KURL& url, + const ResourceLoaderOptions& options, + ReportingDisposition reporting_disposition, + const base::Optional<ResourceRequest::RedirectInfo>& redirect_info) const { + auto* subresource_filter = GetSubresourceFilter(); + if (subresource_filter && type != ResourceType::kImportResource && + !subresource_filter->AllowLoad(url, resource_request.GetRequestContext(), + reporting_disposition)) { + if (reporting_disposition == ReportingDisposition::kReport) { + DispatchDidBlockRequest(resource_request, options.initiator_info, + ResourceRequestBlockedReason::kSubresourceFilter, + type); + } + return ResourceRequestBlockedReason::kSubresourceFilter; + } + + return base::nullopt; +} + bool BaseFetchContext::CalculateIfAdSubresource( - const ResourceRequest& request, + const ResourceRequestHead& request, + const base::Optional<KURL>& alias_url, ResourceType type, const FetchInitiatorInfo& initiator_info) { - // A base class should override this is they have more signals than just the - // SubresourceFilter. + // A derived class should override this if they have more signals than just + // the SubresourceFilter. SubresourceFilter* filter = GetSubresourceFilter(); + const KURL& url = alias_url ? alias_url.value() : request.Url(); return request.IsAdResource() || - (filter && - filter->IsAdResource(request.Url(), request.GetRequestContext())); + (filter && filter->IsAdResource(url, request.GetRequestContext())); } bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting(
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.h b/third_party/blink/renderer/core/loader/base_fetch_context.h index 48a3d867..c0935aa0 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.h +++ b/third_party/blink/renderer/core/loader/base_fetch_context.h
@@ -39,6 +39,14 @@ const ResourceLoaderOptions&, ReportingDisposition, const base::Optional<ResourceRequest::RedirectInfo>&) const override; + base::Optional<ResourceRequestBlockedReason> + CanRequestBasedOnSubresourceFilterOnly( + ResourceType, + const ResourceRequest&, + const KURL&, + const ResourceLoaderOptions&, + ReportingDisposition, + const base::Optional<ResourceRequest::RedirectInfo>&) const override; base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest( mojom::blink::RequestContextType, network::mojom::RequestDestination request_destination, @@ -67,8 +75,12 @@ virtual std::unique_ptr<WebSocketHandshakeThrottle> CreateWebSocketHandshakeThrottle() = 0; + // If the optional `alias_url` is non-null, it will be used to perform the + // check in place of `resource_request.Url()`, e.g. in the case of DNS + // aliases. bool CalculateIfAdSubresource( - const ResourceRequest& resource_request, + const ResourceRequestHead& resource_request, + const base::Optional<KURL>& alias_url, ResourceType type, const FetchInitiatorInfo& initiator_info) override;
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc index 8ecd4c9..ec4054f 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -986,12 +986,13 @@ } bool FrameFetchContext::CalculateIfAdSubresource( - const ResourceRequest& resource_request, + const ResourceRequestHead& resource_request, + const base::Optional<KURL>& alias_url, ResourceType type, const FetchInitiatorInfo& initiator_info) { - // Mark the resource as an Ad if the SubresourceFilter thinks it's an ad. + // Mark the resource as an Ad if the BaseFetchContext thinks it's an ad. bool known_ad = BaseFetchContext::CalculateIfAdSubresource( - resource_request, type, initiator_info); + resource_request, alias_url, type, initiator_info); if (GetResourceFetcherProperties().IsDetached() || !GetFrame()->GetAdTracker()) { return known_ad; @@ -999,8 +1000,9 @@ // The AdTracker needs to know about the request as well, and may also mark it // as an ad. + const KURL& url = alias_url ? alias_url.value() : resource_request.Url(); return GetFrame()->GetAdTracker()->CalculateIfAdSubresource( - document_->domWindow(), resource_request, type, initiator_info, known_ad); + document_->domWindow(), url, type, initiator_info, known_ad); } bool FrameFetchContext::SendConversionRequestInsteadOfRedirecting(
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h index a1dee87..89d4825f 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.h +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -110,7 +110,8 @@ void Trace(Visitor*) const override; bool CalculateIfAdSubresource( - const ResourceRequest& resource_request, + const ResourceRequestHead& resource_request, + const base::Optional<KURL>& alias_url, ResourceType type, const FetchInitiatorInfo& initiator_info) override;
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc index 0efe39b..f2a8fd2 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -212,7 +212,8 @@ ResourceRequest request(KURL("http://example.com/")); FetchInitiatorInfo initiator_info; EXPECT_EQ(expect_is_ad, GetFetchContext()->CalculateIfAdSubresource( - request, ResourceType::kMock, initiator_info)); + request, base::nullopt /* alias_url */, + ResourceType::kMock, initiator_info)); return reason; } @@ -1390,4 +1391,65 @@ } } +// Tests that CanRequestCanRequestBasedOnSubresourceFilterOnly will block ads +// or not correctly, depending on the FilterPolicy. +TEST_F(FrameFetchContextSubresourceFilterTest, + CanRequestBasedOnSubresourceFilterOnly) { + const struct { + WebDocumentSubresourceFilter::LoadPolicy policy; + base::Optional<ResourceRequestBlockedReason> expected_block_reason; + } kTestCases[] = { + {WebDocumentSubresourceFilter::kDisallow, + ResourceRequestBlockedReason::kSubresourceFilter}, + {WebDocumentSubresourceFilter::kWouldDisallow, base::nullopt}, + {WebDocumentSubresourceFilter::kAllow, base::nullopt}}; + + for (const auto& test : kTestCases) { + SetFilterPolicy(test.policy); + + KURL url("http://ads.com/some_script.js"); + ResourceRequest resource_request(url); + resource_request.SetRequestContext( + mojom::blink::RequestContextType::SCRIPT); + resource_request.SetRequestorOrigin(GetTopFrameOrigin()); + + ResourceLoaderOptions options(nullptr /* world */); + + EXPECT_EQ(test.expected_block_reason, + GetFetchContext()->CanRequestBasedOnSubresourceFilterOnly( + ResourceType::kScript, resource_request, url, options, + ReportingDisposition::kReport, base::nullopt)); + } +} + +// Tests that CalculateIfAdSubresource with an alias URL will tag ads +// correctly according to the SubresourceFilter mode. +TEST_F(FrameFetchContextSubresourceFilterTest, + CalculateIfAdSubresourceWithAliasURL) { + const struct { + WebDocumentSubresourceFilter::LoadPolicy policy; + bool expected_to_be_tagged_ad; + } kTestCases[] = {{WebDocumentSubresourceFilter::kDisallow, true}, + {WebDocumentSubresourceFilter::kWouldDisallow, true}, + {WebDocumentSubresourceFilter::kAllow, false}}; + + for (const auto& test : kTestCases) { + SetFilterPolicy(test.policy); + + KURL url("http://www.example.com"); + KURL alias_url("http://ads.com/some_script.js"); + ResourceRequest resource_request(url); + resource_request.SetRequestContext( + mojom::blink::RequestContextType::SCRIPT); + resource_request.SetRequestorOrigin(GetTopFrameOrigin()); + + ResourceLoaderOptions options(nullptr /* world */); + + EXPECT_EQ(test.expected_to_be_tagged_ad, + GetFetchContext()->CalculateIfAdSubresource( + resource_request, alias_url, ResourceType::kScript, + options.initiator_info)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.h b/third_party/blink/renderer/core/loader/frame_load_request.h index f8cc4f1d..f58eff2a 100644 --- a/third_party/blink/renderer/core/loader/frame_load_request.h +++ b/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -147,11 +147,13 @@ // Impressions are set when a FrameLoadRequest is created for a click on an // anchor tag that has conversion measurement attributes. - void SetImpression(const WebImpression& impression) { + void SetImpression(const base::Optional<WebImpression>& impression) { impression_ = impression; } - const base::Optional<WebImpression>& Impression() { return impression_; } + const base::Optional<WebImpression>& Impression() const { + return impression_; + } bool CanDisplay(const KURL&) const;
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc index ef66eff..d31dd9eb 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -261,7 +261,8 @@ WebLocalFrameImpl::FromFrame(frame), WrappedResourceRequest(r.GetResourceRequest()), features, frame_name, static_cast<WebNavigationPolicy>(r.GetNavigationPolicy()), - sandbox_flags, session_storage_namespace_id, consumed_user_gesture)); + sandbox_flags, session_storage_namespace_id, consumed_user_gesture, + r.Impression())); if (!new_view) return nullptr; return new_view->GetPage();
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc index cfa73a8..28ea879 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -66,7 +66,8 @@ WebNavigationPolicy, network::mojom::blink::WebSandboxFlags, const SessionStorageNamespaceId&, - bool& consumed_user_gesture) override { + bool& consumed_user_gesture, + const base::Optional<WebImpression>&) override { return web_view_helper_.InitializeWithOpener(opener); }
diff --git a/third_party/blink/renderer/core/paint/inline_painter.cc b/third_party/blink/renderer/core/paint/inline_painter.cc index 117dde2..99533680 100644 --- a/third_party/blink/renderer/core/paint/inline_painter.cc +++ b/third_party/blink/renderer/core/paint/inline_painter.cc
@@ -6,7 +6,6 @@ #include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/layout_inline.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/paint/line_box_list_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index e3ae21e..70de99e 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -17,7 +17,6 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h" #include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc index 713a9d5..acddffe 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -7,7 +7,6 @@ #include "third_party/blink/renderer/core/layout/background_bleed_avoidance.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_fragment.h" #include "third_party/blink/renderer/core/paint/background_image_geometry.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc index 17041dd..d764b2f 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/mathml/mathml_radical_element.h" #include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" +#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h" #include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc index 853480a..82b61f9 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -16,7 +16,6 @@ #include "third_party/blink/renderer/core/layout/list_marker.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h" #include "third_party/blink/renderer/core/paint/document_marker_painter.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h index a3b679d..08366f6 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h +++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
@@ -6,7 +6,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc index ba0a3f8..af32a7c5 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -6,7 +6,6 @@ #include "third_party/blink/renderer/core/css/css_property_names.h" #include "third_party/blink/renderer/core/frame/settings.h" -#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h" #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h" #include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" @@ -14,6 +13,7 @@ #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/shadow_list.h" #include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index ca62a033..d16c303 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2546,7 +2546,7 @@ if (!HasFilterThatMovesPixels()) return; PhysicalRect result = LocalBoundingBox(); - ExpandRectForStackingChildren( + ExpandRectForSelfPaintingDescendants( *this, result, kIncludeTransforms | kIncludeCompositedChildLayers); FloatRect reference_box = FloatRect(result); @@ -2666,6 +2666,13 @@ return rect; } +PhysicalRect PaintLayer::ClippedLocalBoundingBox( + const PaintLayer& ancestor_layer) const { + return Intersection(LocalBoundingBox(), + Clipper(GeometryMapperOption::kUseGeometryMapper) + .LocalClipRect(ancestor_layer)); +} + PhysicalRect PaintLayer::PhysicalBoundingBox( const PaintLayer* ancestor_layer) const { PhysicalOffset offset_from_root; @@ -2769,7 +2776,7 @@ // are composited or not. children_bounds.Unite(child_layer->BoundingBoxForCompositingInternal( *this, this, - kIncludeClips | kIncludeTransforms | + kIncludeAncestorClips | kIncludeTransforms | kIncludeCompositedChildLayers)); } if (!children_bounds.IsEmpty()) { @@ -2792,16 +2799,38 @@ return abs_bounds; } -void PaintLayer::ExpandRectForStackingChildren( +void PaintLayer::ExpandRectForSelfPaintingDescendants( const PaintLayer& composited_layer, PhysicalRect& result, unsigned options) const { - // If we're locked, th en the subtree does not contribute painted output. + // If we're locked, then the subtree does not contribute painted output. // Furthermore, we might not have up-to-date sizing and position information // in the subtree, so skip recursing into the subtree. if (GetLayoutObject().ChildPaintBlockedByDisplayLock()) return; + DCHECK_EQ(result, (options & kIncludeAncestorClips) + ? ClippedLocalBoundingBox(composited_layer) + : LocalBoundingBox()); + // The input |result| is based on LayoutObject::PhysicalVisualOverflowRect() + // which already includes bounds non-self-painting descendants. + if (!HasSelfPaintingLayerDescendant()) + return; + + if (const auto* box = GetLayoutBox()) { + // If the layer clips overflow and all descendants are contained, then no + // need to expand for children. Not checking kIncludeAncestorClips because + // the clip of the current layer is always applied. The doesn't check + // whether the non-contained descendants are actual descendants of this + // layer in paint order because it's not easy. + if (box->ShouldClipOverflowAlongBothAxis() && + !HasNonContainedAbsolutePositionDescendant() && + !(HasFixedPositionDescendant() && + !box->CanContainFixedPositionObjects())) { + return; + } + } + PaintLayerPaintOrderIterator iterator(*this, kAllChildren); while (PaintLayer* child_layer = iterator.Next()) { // Here we exclude both directly composited layers and squashing layers @@ -2819,7 +2848,8 @@ PhysicalRect PaintLayer::BoundingBoxForCompositing() const { return BoundingBoxForCompositingInternal( - *this, nullptr, kIncludeClips | kMaybeIncludeTransformForAncestorLayer); + *this, nullptr, + kIncludeAncestorClips | kMaybeIncludeTransformForAncestorLayer); } bool PaintLayer::ShouldApplyTransformToBoundingBox( @@ -2873,19 +2903,16 @@ return PhysicalRect(); PhysicalRect result; - if (options & kIncludeClips) { + if (options & kIncludeAncestorClips) { // If there is a clip applied by an ancestor to this PaintLayer but below or - // equal to |ancestorLayer|, apply that clip. This optimizes the size + // equal to |composited_layer|, apply that clip. This optimizes the size // of the composited layer to exclude clipped-out regions of descendants. - result = Clipper(GeometryMapperOption::kUseGeometryMapper) - .LocalClipRect(composited_layer); - - result.Intersect(LocalBoundingBox()); + result = ClippedLocalBoundingBox(composited_layer); } else { result = LocalBoundingBox(); } - ExpandRectForStackingChildren(composited_layer, result, options); + ExpandRectForSelfPaintingDescendants(composited_layer, result, options); // Only enlarge by the filter outsets if we know the filter is going to be // rendered in software. Accelerated filters will handle their own outsets.
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index c07d66b..47aaa24 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -463,7 +463,7 @@ enum CalculateBoundsOptions { // Include clips between this layer and its ancestor layer (inclusive). - kIncludeClips = 0x1, + kIncludeAncestorClips = 0x1, // Include transforms, irrespective of if they are applied via composition // or painting. kIncludeTransforms = 0x2, @@ -1160,6 +1160,7 @@ // Bounding box in the coordinates of this layer. PhysicalRect LocalBoundingBox() const; + PhysicalRect ClippedLocalBoundingBox(const PaintLayer& ancestor_layer) const; bool HasOverflowControls() const; @@ -1290,9 +1291,9 @@ bool IsTopMostNotAffectedByScrollOf(const PaintLayer* ancestor) const; - void ExpandRectForStackingChildren(const PaintLayer& composited_layer, - PhysicalRect& result, - unsigned options) const; + void ExpandRectForSelfPaintingDescendants(const PaintLayer& composited_layer, + PhysicalRect& result, + unsigned options) const; // The return value is in the space of |stackingParent|, if non-null, or // |this| otherwise.
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index 1c257da0..bdd7869 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -487,7 +487,9 @@ bool PrePaintTreeWalk::ContextRequiresTreeBuilderContext( const PrePaintTreeWalkContext& context) { return context.tree_builder_context && - context.tree_builder_context->force_subtree_update_reasons; + (context.tree_builder_context->force_subtree_update_reasons || + // PaintInvalidator forced subtree walk implies geometry update. + context.paint_invalidator_context.NeedsSubtreeWalk()); } #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc index 37d2599..a79d6a38 100644 --- a/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc +++ b/third_party/blink/renderer/core/scheduler_integration_tests/frame_throttling_test.cc
@@ -199,6 +199,8 @@ { GetDocument().GetFrame()->View()->SetTargetStateForTest( DocumentLifecycle::kPaintClean); + inner_frame_document->Lifecycle().EnsureStateAtMost( + DocumentLifecycle::kVisualUpdatePending); EXPECT_FALSE( inner_frame_document->View()->ShouldThrottleRenderingForTest()); GetDocument().GetFrame()->View()->SetTargetStateForTest( @@ -233,11 +235,12 @@ EXPECT_TRUE(inner_frame_document->View()->ShouldThrottleRenderingForTest()); EXPECT_FALSE(inner_view->NeedsLayout()); - EXPECT_TRUE(inner_frame_document->View() - ->GetLayoutView() - ->ShouldDoFullPaintInvalidation()); + EXPECT_LT(inner_frame_document->Lifecycle().GetState(), + DocumentLifecycle::kPaintClean); if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { - EXPECT_EQ(kCompositingUpdateRebuildTree, + // If IntersectionObserver is required to run, lifecycle will be updated + // through compositing. + EXPECT_EQ(kCompositingUpdateNone, inner_view->Compositor()->pending_update_type_); } EXPECT_TRUE(inner_view->Layer()->SelfNeedsRepaint()); @@ -357,6 +360,8 @@ { GetDocument().GetFrame()->View()->SetTargetStateForTest( DocumentLifecycle::kPaintClean); + frame_document->Lifecycle().EnsureStateAtMost( + DocumentLifecycle::kVisualUpdatePending); EXPECT_FALSE(frame_document->View()->ShouldThrottleRenderingForTest()); GetDocument().GetFrame()->View()->SetTargetStateForTest( DocumentLifecycle::kUninitialized); @@ -369,7 +374,7 @@ frame_document->View()->ScheduleAnimation(); frame_document->View()->GetLayoutView()->Layer()->SetNeedsRepaint(); CompositeFrame(); - EXPECT_EQ(DocumentLifecycle::kLayoutClean, + EXPECT_EQ(DocumentLifecycle::kCompositingAssignmentsClean, frame_document->Lifecycle().GetState()); EXPECT_TRUE(frame_document->View()->ShouldThrottleRenderingForTest()); }
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc index 2a1971c..0c2f9ab 100644 --- a/third_party/blink/renderer/core/script/script_loader.cc +++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -212,7 +212,7 @@ return true; } - if (type == "module") { + if (EqualIgnoringASCIICase(type, "module")) { // <spec step="7">... If the script block's type string is an ASCII // case-insensitive match for the string "module", the script's type is // "module". ...</spec>
diff --git a/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc b/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc index aae3cf2..50a7d2d 100644 --- a/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc +++ b/third_party/blink/renderer/core/testing/fake_remote_frame_host.cc
@@ -17,8 +17,8 @@ cc::TouchAction touch_action) {} void FakeRemoteFrameHost::UpdateRenderThrottlingStatus(bool is_throttled, - bool subtree_throttled) { -} + bool subtree_throttled, + bool display_locked) {} void FakeRemoteFrameHost::VisibilityChanged( mojom::blink::FrameVisibility visibility) {}
diff --git a/third_party/blink/renderer/core/testing/fake_remote_frame_host.h b/third_party/blink/renderer/core/testing/fake_remote_frame_host.h index 1f3917e..dd3b733 100644 --- a/third_party/blink/renderer/core/testing/fake_remote_frame_host.h +++ b/third_party/blink/renderer/core/testing/fake_remote_frame_host.h
@@ -27,7 +27,8 @@ void Init(blink::AssociatedInterfaceProvider* provider); void SetInheritedEffectiveTouchAction(cc::TouchAction touch_action) override; void UpdateRenderThrottlingStatus(bool is_throttled, - bool subtree_throttled) override; + bool subtree_throttled, + bool display_locked) override; void VisibilityChanged(mojom::blink::FrameVisibility visibility) override; void DidFocusFrame() override; void CheckCompleted() override;
diff --git a/third_party/blink/renderer/core/testing/mock_function_scope.cc b/third_party/blink/renderer/core/testing/mock_function_scope.cc new file mode 100644 index 0000000..998ac45 --- /dev/null +++ b/third_party/blink/renderer/core/testing/mock_function_scope.cc
@@ -0,0 +1,66 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" +#include "third_party/blink/renderer/bindings/core/v8/script_function.h" +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/bindings/v8_binding.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" + +namespace blink { + +MockFunctionScope::MockFunctionScope(ScriptState* script_state) + : script_state_(script_state) {} + +MockFunctionScope::~MockFunctionScope() { + v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate()); + for (MockFunction* mock_function : mock_functions_) { + testing::Mock::VerifyAndClearExpectations(mock_function); + } +} + +v8::Local<v8::Function> MockFunctionScope::ExpectCall(String* captor) { + mock_functions_.push_back( + MakeGarbageCollected<MockFunction>(script_state_, captor)); + EXPECT_CALL(*mock_functions_.back(), Call(testing::_)); + return mock_functions_.back()->Bind(); +} + +v8::Local<v8::Function> MockFunctionScope::ExpectCall() { + mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_)); + EXPECT_CALL(*mock_functions_.back(), Call(testing::_)); + return mock_functions_.back()->Bind(); +} + +v8::Local<v8::Function> MockFunctionScope::ExpectNoCall() { + mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_)); + EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0); + return mock_functions_.back()->Bind(); +} + +ACTION_P2(SaveValueIn, script_state, captor) { + *captor = ToCoreString( + arg0.V8Value()->ToString(script_state->GetContext()).ToLocalChecked()); +} + +MockFunctionScope::MockFunction::MockFunction(ScriptState* script_state) + : ScriptFunction(script_state) { + ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>()); +} + +MockFunctionScope::MockFunction::MockFunction(ScriptState* script_state, + String* captor) + : ScriptFunction(script_state) { + ON_CALL(*this, Call(testing::_)) + .WillByDefault( + testing::DoAll(SaveValueIn(WrapPersistent(script_state), captor), + testing::ReturnArg<0>())); +} + +v8::Local<v8::Function> MockFunctionScope::MockFunction::Bind() { + return BindToV8Function(); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/testing/mock_function_scope.h b/third_party/blink/renderer/core/testing/mock_function_scope.h new file mode 100644 index 0000000..e575c5c --- /dev/null +++ b/third_party/blink/renderer/core/testing/mock_function_scope.h
@@ -0,0 +1,46 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_ + +#include "testing/gmock/include/gmock/gmock.h" +#include "third_party/blink/renderer/bindings/core/v8/script_function.h" +#include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +class ScriptState; +class ScriptValue; + +class MockFunctionScope { + STACK_ALLOCATED(); + + public: + explicit MockFunctionScope(ScriptState*); + ~MockFunctionScope(); + + v8::Local<v8::Function> ExpectCall(); + v8::Local<v8::Function> ExpectCall(String* captor); + v8::Local<v8::Function> ExpectNoCall(); + + private: + class MockFunction : public ScriptFunction { + public: + explicit MockFunction(ScriptState*); + // TODO(http://crbug.com/1159794): add other convenience methods that allow + // the test case to capture non-String values. + MockFunction(ScriptState*, String* captor); + v8::Local<v8::Function> Bind(); + MOCK_METHOD1(Call, ScriptValue(ScriptValue)); + }; + + ScriptState* script_state_; + Vector<Persistent<MockFunction>> mock_functions_; +}; + +} // namespace blink +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TESTING_MOCK_FUNCTION_SCOPE_H_
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 0cd8f335..a90db0172 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -1464,12 +1464,9 @@ } // static -WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document, - bool update_layout_if_necessary) { - if (update_layout_if_necessary && - !MaybeUpdateLayoutAndCheckValidity(web_document)) { +WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document) { + if (!MaybeUpdateLayoutAndCheckValidity(web_document)) return WebAXObject(); - } const Document* document = web_document.ConstUnwrap<Document>(); auto* cache = To<AXObjectCacheImpl>(document->ExistingAXObjectCache()); return cache ? WebAXObject(cache->GetOrCreate(document->GetLayoutView()))
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl b/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl index df0834cd8..4897040 100644 --- a/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl +++ b/third_party/blink/renderer/modules/file_system_access/file_system_create_writer_options.idl
@@ -5,4 +5,5 @@ // https://wicg.github.io/native-file-system/#dictdef-filesystemcreatewriteroptions dictionary FileSystemCreateWriterOptions { boolean keepExistingData = false; + [RuntimeEnabled=FileSystemAccessAPIExperimental] boolean autoClose = false; };
diff --git a/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc b/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc index 5ec47c8..d758d00d6 100644 --- a/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc +++ b/third_party/blink/renderer/modules/file_system_access/native_file_system_file_handle.cc
@@ -45,7 +45,7 @@ ScriptPromise result = resolver->Promise(); mojo_ptr_->CreateFileWriter( - options->keepExistingData(), + options->keepExistingData(), options->autoClose(), WTF::Bind( [](ScriptPromiseResolver* resolver, mojom::blink::NativeFileSystemErrorPtr result,
diff --git a/third_party/blink/renderer/modules/payments/abort_test.cc b/third_party/blink/renderer/modules/payments/abort_test.cc index 0e1963d..b9ca0e39 100644 --- a/third_party/blink/renderer/modules/payments/abort_test.cc +++ b/third_party/blink/renderer/modules/payments/abort_test.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_request.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" @@ -45,7 +46,7 @@ // should not reject with exception. TEST(AbortTest, CanAbortAfterShow) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -59,7 +60,7 @@ // promise should be rejected. TEST(AbortTest, FailedAbortShouldRejectAbortPromise) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -76,7 +77,7 @@ // call should not be rejected, as it's not a duplicate request anymore. TEST(AbortTest, CanAbortAgainAfterFirstAbortRejected) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -93,7 +94,7 @@ // promise should be rejected, and request.abort() promise should be resolved. TEST(AbortTest, SuccessfulAbortShouldRejectShowPromiseAndResolveAbortPromise) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc index 96b539a..a1116185 100644 --- a/third_party/blink/renderer/modules/payments/can_make_payment_test.cc +++ b/third_party/blink/renderer/modules/payments/can_make_payment_test.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_request.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" @@ -20,7 +21,7 @@ TEST(HasEnrolledInstrumentTest, RejectPromiseOnUserCancel) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -34,7 +35,7 @@ TEST(HasEnrolledInstrumentTest, RejectPromiseOnUnknownError) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -60,7 +61,7 @@ TEST(HasEnrolledInstrumentTest, RejectQueryQuotaExceeded) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -74,7 +75,7 @@ TEST(HasEnrolledInstrumentTest, ReturnHasNoEnrolledInstrument) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -91,7 +92,7 @@ TEST(HasEnrolledInstrumentTest, ReturnHasEnrolledInstrument) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -108,7 +109,7 @@ TEST(CanMakePaymentTest, RejectPromiseOnUserCancel) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -123,7 +124,7 @@ TEST(CanMakePaymentTest, RejectPromiseOnUnknownError) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -149,7 +150,7 @@ TEST(CanMakePaymentTest, ReturnCannotMakePayment) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -166,7 +167,7 @@ TEST(CanMakePaymentTest, ReturnCanMakePayment) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/third_party/blink/renderer/modules/payments/complete_test.cc b/third_party/blink/renderer/modules/payments/complete_test.cc index 112020f7..9624f75 100644 --- a/third_party/blink/renderer/modules/payments/complete_test.cc +++ b/third_party/blink/renderer/modules/payments/complete_test.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_request.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" @@ -34,7 +35,7 @@ TEST(CompleteTest, ResolveCompletePromiseOnUnknownError) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -54,7 +55,7 @@ TEST(CompleteTest, ResolveCompletePromiseOnUserClosingUI) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -96,7 +97,7 @@ TEST(CompleteTest, ResolvePromiseOnComplete) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -116,7 +117,7 @@ TEST(CompleteTest, RejectCompletePromiseOnUpdateDetailsFailure) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -140,7 +141,7 @@ TEST(CompleteTest, RejectCompletePromiseAfterTimeout) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION);
diff --git a/third_party/blink/renderer/modules/payments/on_payment_response_test.cc b/third_party/blink/renderer/modules/payments/on_payment_response_test.cc index fd30e36..c9ba6191 100644 --- a/third_party/blink/renderer/modules/payments/on_payment_response_test.cc +++ b/third_party/blink/renderer/modules/payments/on_payment_response_test.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_function.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_response.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_address.h" #include "third_party/blink/renderer/modules/payments/payment_request.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" @@ -20,7 +21,7 @@ // provide the shipping option, reject the show() promise. TEST(OnPaymentResponseTest, RejectMissingShippingOption) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -42,7 +43,7 @@ // provide a shipping address, reject the show() promise. TEST(OnPaymentResponseTest, RejectMissingAddress) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -63,7 +64,7 @@ // reject the show() promise. TEST(OnPaymentResponseTest, RejectMissingName) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerName(true); PaymentRequest* request = PaymentRequest::Create( @@ -83,7 +84,7 @@ // it, reject the show() promise. TEST(OnPaymentResponseTest, RejectMissingEmail) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerEmail(true); PaymentRequest* request = PaymentRequest::Create( @@ -103,7 +104,7 @@ // reject the show() promise. TEST(OnPaymentResponseTest, RejectMissingPhone) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerPhone(true); PaymentRequest* request = PaymentRequest::Create( @@ -123,7 +124,7 @@ // empty string for shipping option, reject the show() promise. TEST(OnPaymentResponseTest, RejectEmptyShippingOption) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -146,7 +147,7 @@ // empty shipping address, reject the show() promise. TEST(OnPaymentResponseTest, RejectEmptyAddress) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -168,7 +169,7 @@ // string for name, reject the show() promise. TEST(OnPaymentResponseTest, RejectEmptyName) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerName(true); PaymentRequest* request = PaymentRequest::Create( @@ -189,7 +190,7 @@ // for email, reject the show() promise. TEST(OnPaymentResponseTest, RejectEmptyEmail) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerEmail(true); PaymentRequest* request = PaymentRequest::Create( @@ -210,7 +211,7 @@ // string for the phone number, reject the show() promise. TEST(OnPaymentResponseTest, RejectEmptyPhone) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerPhone(true); PaymentRequest* request = PaymentRequest::Create( @@ -231,7 +232,7 @@ // provides a shipping address, reject the show() promise. TEST(OnPaymentResponseTest, RejectNotRequestedAddress) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(false); PaymentRequest* request = PaymentRequest::Create( @@ -253,7 +254,7 @@ // provides a shipping option, reject the show() promise. TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(false); PaymentRequest* request = PaymentRequest::Create( @@ -274,7 +275,7 @@ // reject the show() promise. TEST(OnPaymentResponseTest, RejectNotRequestedName) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerName(false); PaymentRequest* request = PaymentRequest::Create( @@ -295,7 +296,7 @@ // reject the show() promise. TEST(OnPaymentResponseTest, RejectNotRequestedEmail) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerEmail(false); PaymentRequest* request = PaymentRequest::Create( @@ -316,7 +317,7 @@ // reject the show() promise. TEST(OnPaymentResponseTest, RejectNotRequestedPhone) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerPhone(false); PaymentRequest* request = PaymentRequest::Create( @@ -337,7 +338,7 @@ // invalid shipping address, reject the show() promise. TEST(OnPaymentResponseTest, RejectInvalidAddress) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -384,7 +385,7 @@ // should contain a shipping option and an address. TEST(OnPaymentResponseTest, CanRequestShippingInformation) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -413,7 +414,7 @@ // contain a payer name. TEST(OnPaymentResponseTest, CanRequestName) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerName(true); PaymentRequest* request = PaymentRequest::Create( @@ -441,7 +442,7 @@ // contain an email address. TEST(OnPaymentResponseTest, CanRequestEmail) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerEmail(true); PaymentRequest* request = PaymentRequest::Create( @@ -468,7 +469,7 @@ // contain a phone number. TEST(OnPaymentResponseTest, CanRequestPhone) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerPhone(true); PaymentRequest* request = PaymentRequest::Create( @@ -496,7 +497,7 @@ // promise should contain null shipping option and address. TEST(OnPaymentResponseTest, ShippingInformationNotRequired) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(false); PaymentRequest* request = PaymentRequest::Create( @@ -521,7 +522,7 @@ // should contain null phone number. TEST(OnPaymentResponseTest, PhoneNotRequred) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerPhone(false); PaymentRequest* request = PaymentRequest::Create( @@ -548,7 +549,7 @@ // should contain null payer name. TEST(OnPaymentResponseTest, NameNotRequired) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerName(false); PaymentRequest* request = PaymentRequest::Create( @@ -575,7 +576,7 @@ // promise should contain null email address. TEST(OnPaymentResponseTest, EmailNotRequired) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestPayerEmail(false); PaymentRequest* request = PaymentRequest::Create(
diff --git a/third_party/blink/renderer/modules/payments/payment_request_test.cc b/third_party/blink/renderer/modules/payments/payment_request_test.cc index 89bbf3a..d6e5c82 100644 --- a/third_party/blink/renderer/modules/payments/payment_request_test.cc +++ b/third_party/blink/renderer/modules/payments/payment_request_test.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/event_type_names.h" #include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" @@ -246,7 +247,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnInvalidShippingAddress) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -260,7 +261,7 @@ TEST(PaymentRequestTest, OnShippingOptionChange) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -274,7 +275,7 @@ TEST(PaymentRequestTest, CannotCallShowTwice) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -287,7 +288,7 @@ TEST(PaymentRequestTest, CannotShowAfterAborted) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -306,7 +307,7 @@ RuntimeEnabledFeatures::SetPaymentRequestShowConsumesUserActivationEnabled( true); PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -320,7 +321,7 @@ RuntimeEnabledFeatures::SetPaymentRequestShowConsumesUserActivationEnabled( true); PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -333,7 +334,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnErrorPaymentMethodNotSupported) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -353,7 +354,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnErrorCancelled) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -372,7 +373,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnUpdateDetailsFailure) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -391,7 +392,7 @@ TEST(PaymentRequestTest, IgnoreUpdatePaymentDetailsAfterShowPromiseResolved) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -406,7 +407,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnNonPaymentDetailsUpdate) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -422,7 +423,7 @@ TEST(PaymentRequestTest, RejectShowPromiseOnInvalidPaymentDetailsUpdate) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -442,7 +443,7 @@ TEST(PaymentRequestTest, ClearShippingOptionOnPaymentDetailsUpdateWithoutShippingOptions) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentDetailsInit* details = PaymentDetailsInit::Create(); details->setTotal(BuildPaymentItemForTest()); PaymentOptions* options = PaymentOptions::Create(); @@ -486,7 +487,7 @@ PaymentRequestTest, ClearShippingOptionOnPaymentDetailsUpdateWithMultipleUnselectedShippingOptions) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -513,7 +514,7 @@ TEST(PaymentRequestTest, UseTheSelectedShippingOptionFromPaymentDetailsUpdate) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentOptions* options = PaymentOptions::Create(); options->setRequestShipping(true); PaymentRequest* request = PaymentRequest::Create( @@ -542,7 +543,7 @@ TEST(PaymentRequestTest, NoExceptionWithErrorMessageInUpdate) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), ASSERT_NO_EXCEPTION); @@ -564,7 +565,7 @@ TEST(PaymentRequestTest, ShouldResolveWithExceptionIfIDsOfShippingOptionsAreDuplicated) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentDetailsInit* details = PaymentDetailsInit::Create(); details->setTotal(BuildPaymentItemForTest()); HeapVector<Member<PaymentShippingOption>> shipping_options(2);
diff --git a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc index 105d4e2..791252ca 100644 --- a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc +++ b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
@@ -12,6 +12,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/core/event_type_names.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/payments/payment_request.h" #include "third_party/blink/renderer/modules/payments/payment_request_delegate.h" #include "third_party/blink/renderer/modules/payments/payment_test_helper.h" @@ -134,7 +135,7 @@ TEST(PaymentRequestUpdateEventTest, AddressChangeUpdateWithTimeout) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), scope.GetExceptionState()); @@ -171,7 +172,7 @@ TEST(PaymentRequestUpdateEventTest, OptionChangeUpdateWithTimeout) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), scope.GetExceptionState()); @@ -208,7 +209,7 @@ TEST(PaymentRequestUpdateEventTest, AddressChangePromiseTimeout) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), scope.GetExceptionState()); @@ -242,7 +243,7 @@ TEST(PaymentRequestUpdateEventTest, OptionChangePromiseTimeout) { PaymentRequestV8TestingScope scope; - PaymentRequestMockFunctionScope funcs(scope.GetScriptState()); + MockFunctionScope funcs(scope.GetScriptState()); PaymentRequest* request = PaymentRequest::Create( scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), BuildPaymentDetailsInitForTest(), scope.GetExceptionState());
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.cc b/third_party/blink/renderer/modules/payments/payment_test_helper.cc index 8bcb545d..ab341c9 100644 --- a/third_party/blink/renderer/modules/payments/payment_test_helper.cc +++ b/third_party/blink/renderer/modules/payments/payment_test_helper.cc
@@ -8,9 +8,7 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_details_modifier.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_method_data.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" -#include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" -#include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink { @@ -217,60 +215,4 @@ PaymentRequestV8TestingScope::PaymentRequestV8TestingScope() : V8TestingScope(KURL("https://www.example.com/")) {} -PaymentRequestMockFunctionScope::PaymentRequestMockFunctionScope( - ScriptState* script_state) - : script_state_(script_state) {} - -PaymentRequestMockFunctionScope::~PaymentRequestMockFunctionScope() { - v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate()); - for (MockFunction* mock_function : mock_functions_) { - testing::Mock::VerifyAndClearExpectations(mock_function); - } -} - -v8::Local<v8::Function> PaymentRequestMockFunctionScope::ExpectCall( - String* captor) { - mock_functions_.push_back( - MakeGarbageCollected<MockFunction>(script_state_, captor)); - EXPECT_CALL(*mock_functions_.back(), Call(testing::_)); - return mock_functions_.back()->Bind(); -} - -v8::Local<v8::Function> PaymentRequestMockFunctionScope::ExpectCall() { - mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_)); - EXPECT_CALL(*mock_functions_.back(), Call(testing::_)); - return mock_functions_.back()->Bind(); -} - -v8::Local<v8::Function> PaymentRequestMockFunctionScope::ExpectNoCall() { - mock_functions_.push_back(MakeGarbageCollected<MockFunction>(script_state_)); - EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0); - return mock_functions_.back()->Bind(); -} - -ACTION_P2(SaveValueIn, script_state, captor) { - *captor = ToCoreString( - arg0.V8Value()->ToString(script_state->GetContext()).ToLocalChecked()); -} - -PaymentRequestMockFunctionScope::MockFunction::MockFunction( - ScriptState* script_state) - : ScriptFunction(script_state) { - ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>()); -} - -PaymentRequestMockFunctionScope::MockFunction::MockFunction( - ScriptState* script_state, - String* captor) - : ScriptFunction(script_state), value_(captor) { - ON_CALL(*this, Call(testing::_)) - .WillByDefault( - testing::DoAll(SaveValueIn(WrapPersistent(script_state), value_), - testing::ReturnArg<0>())); -} - -v8::Local<v8::Function> PaymentRequestMockFunctionScope::MockFunction::Bind() { - return BindToV8Function(); -} - } // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.h b/third_party/blink/renderer/modules/payments/payment_test_helper.h index 44933b8..ad09593 100644 --- a/third_party/blink/renderer/modules/payments/payment_test_helper.h +++ b/third_party/blink/renderer/modules/payments/payment_test_helper.h
@@ -23,8 +23,6 @@ namespace blink { class PaymentMethodData; -class ScriptState; -class ScriptValue; class V8TestingScope; enum PaymentTestDetailToChange { @@ -95,31 +93,6 @@ PaymentRequestV8TestingScope(); }; -class PaymentRequestMockFunctionScope { - STACK_ALLOCATED(); - - public: - explicit PaymentRequestMockFunctionScope(ScriptState*); - ~PaymentRequestMockFunctionScope(); - - v8::Local<v8::Function> ExpectCall(); - v8::Local<v8::Function> ExpectCall(String* captor); - v8::Local<v8::Function> ExpectNoCall(); - - private: - class MockFunction : public ScriptFunction { - public: - explicit MockFunction(ScriptState*); - MockFunction(ScriptState*, String* captor); - v8::Local<v8::Function> Bind(); - MOCK_METHOD1(Call, ScriptValue(ScriptValue)); - String* value_; - }; - - ScriptState* script_state_; - Vector<Persistent<MockFunction>> mock_functions_; -}; - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_TEST_HELPER_H_
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc b/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc index 3f3f49c4..5ead7a17 100644 --- a/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc +++ b/third_party/blink/renderer/modules/presentation/presentation_connection_callbacks_test.cc
@@ -8,21 +8,15 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" -#include "testing/gmock/include/gmock/gmock.h" // MockFunctionScope #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h" -#include "third_party/blink/renderer/bindings/core/v8/script_function.h" // MockFunctionScope #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/bindings/core/v8/script_value.h" // MockFunctionScope #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" +#include "third_party/blink/renderer/core/testing/mock_function_scope.h" #include "third_party/blink/renderer/modules/presentation/presentation_connection.h" #include "third_party/blink/renderer/modules/presentation/presentation_request.h" -#include "third_party/blink/renderer/platform/bindings/script_state.h" // MockFunctionScope #include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/persistent.h" // MockFunctionScope #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" -#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" // MockFunctionScope -#include "third_party/blink/renderer/platform/wtf/vector.h" // MockFunctionScope constexpr char kPresentationUrl[] = "https://example.com"; constexpr char kPresentationId[] = "xyzzy"; @@ -39,49 +33,6 @@ namespace { -// TODO(crbug.com/1120218): Consolidate with PaymentRequestMockFunctionScope and -// move to shared folder -class MockFunctionScope { - STACK_ALLOCATED(); - - public: - explicit MockFunctionScope(ScriptState* script_state) - : script_state_(script_state) {} - ~MockFunctionScope() { - v8::MicrotasksScope::PerformCheckpoint(script_state_->GetIsolate()); - for (MockFunction* mock_function : mock_functions_) - testing::Mock::VerifyAndClearExpectations(mock_function); - } - - v8::Local<v8::Function> ExpectCall() { - mock_functions_.push_back( - MakeGarbageCollected<MockFunction>(script_state_)); - EXPECT_CALL(*mock_functions_.back(), Call(testing::_)); - return mock_functions_.back()->Bind(); - } - - v8::Local<v8::Function> ExpectNoCall() { - mock_functions_.push_back( - MakeGarbageCollected<MockFunction>(script_state_)); - EXPECT_CALL(*mock_functions_.back(), Call(testing::_)).Times(0); - return mock_functions_.back()->Bind(); - } - - private: - class MockFunction : public ScriptFunction { - public: - explicit MockFunction(ScriptState* script_state) - : ScriptFunction(script_state) { - ON_CALL(*this, Call(testing::_)).WillByDefault(testing::ReturnArg<0>()); - } - v8::Local<v8::Function> Bind() { return BindToV8Function(); } - MOCK_METHOD1(Call, ScriptValue(ScriptValue)); - }; - - ScriptState* script_state_; - Vector<Persistent<MockFunction>> mock_functions_; -}; - static PresentationRequest* MakeRequest(V8TestingScope* scope) { PresentationRequest* request = PresentationRequest::Create(scope->GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc index 93b7484..1ff77a8 100644 --- a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc +++ b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl_test.cc
@@ -321,6 +321,28 @@ testing::Mock::VerifyAndClear(function); } +TEST_F(VideoFrameCallbackRequesterImplTest, + VerifyClearedMediaPlayerCancelsPendingExecution) { + V8TestingScope scope; + + auto* function = MockFunction::Create(scope.GetScriptState()); + + // Queue a request. + vfc_requester().requestVideoFrameCallback(GetCallback(function)); + SimulateFramePresented(); + + // The callback should be scheduled for execution, but not yet run. + EXPECT_CALL(*function, Call(_)).Times(0); + + // Simulate the HTMLVideoElement getting changing its WebMediaPlayer. + vfc_requester().OnWebMediaPlayerCleared(); + + // This should be a no-op, else we could get metadata for a null frame. + SimulateVideoFrameCallback(base::TimeTicks::Now()); + + testing::Mock::VerifyAndClear(function); +} + TEST_F(VideoFrameCallbackRequesterImplTest, VerifyParameters_WindowRaf) { auto timing = GetDocument().Loader()->GetTiming(); MetadataHelper::ReinitializeFields(timing.ReferenceMonotonicTime());
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc index df35448..abc7d89 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/memory/scoped_refptr.h" +#include "build/build_config.h" #include "components/viz/common/gpu/raster_context_provider.h" #include "components/viz/common/resources/single_release_callback.h" #include "gpu/command_buffer/client/shared_image_interface.h" @@ -412,6 +413,59 @@ return ScriptPromise(); } + // SharedImage optimization: create AcceleratedStaticBitmapImage directly. + // Disabled on Android because the hardware decode implementation may neuter + // frames, which would violate ImageBitmap requirements. + // TODO(sandersd): Handle YUV pixel formats. + // TODO(sandersd): Handle high bit depth formats. +#if !defined(OS_ANDROID) + if (local_frame->NumTextures() == 1 && + local_frame->mailbox_holder(0).mailbox.IsSharedImage() && + (local_frame->format() == media::PIXEL_FORMAT_ARGB || + local_frame->format() == media::PIXEL_FORMAT_XRGB || + local_frame->format() == media::PIXEL_FORMAT_ABGR || + local_frame->format() == media::PIXEL_FORMAT_XBGR || + local_frame->format() == media::PIXEL_FORMAT_BGRA)) { + // TODO(sandersd): Do we need to be able to handle limited-range RGB? It + // may never happen, and SkColorSpace doesn't know about it. + auto sk_color_space = + local_frame->ColorSpace().GetAsFullRangeRGB().ToSkColorSpace(); + if (!sk_color_space) + sk_color_space = SkColorSpace::MakeSRGB(); + + const SkImageInfo sk_image_info = SkImageInfo::Make( + local_frame->coded_size().width(), local_frame->coded_size().height(), + kN32_SkColorType, kUnpremul_SkAlphaType, std::move(sk_color_space)); + + // Hold a ref by storing it in the release callback. + auto release_callback = viz::SingleReleaseCallback::Create( + WTF::Bind([](scoped_refptr<media::VideoFrame> frame, + const gpu::SyncToken& sync_token, bool is_lost) {}, + local_frame)); + + scoped_refptr<StaticBitmapImage> image = + AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( + local_frame->mailbox_holder(0).mailbox, + local_frame->mailbox_holder(0).sync_token, 0u, sk_image_info, + local_frame->mailbox_holder(0).texture_target, true, + // Pass nullptr for |context_provider_wrapper|, because we don't + // know which context the mailbox came from. It is used only to + // detect when the mailbox is invalid due to context loss, and is + // ignored when |is_cross_thread|. + base::WeakPtr<WebGraphicsContext3DProviderWrapper>(), + // Pass null |context_thread_ref|, again because we don't know + // which context the mailbox came from. This should always trigger + // |is_cross_thread|. + base::PlatformThreadRef(), + // The task runner is only used for |release_callback|. + Thread::Current()->GetTaskRunner(), std::move(release_callback)); + ImageBitmap* image_bitmap = + MakeGarbageCollected<ImageBitmap>(image, crop_rect, options); + return ImageBitmapSource::FulfillImageBitmap(script_state, image_bitmap, + exception_state); + } +#endif // !defined(OS_ANDROID) + if ((local_frame->IsMappable() && (local_frame->format() == media::PIXEL_FORMAT_I420 || local_frame->format() == media::PIXEL_FORMAT_I420A)) ||
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc index a202c4ba..53f39f2 100644 --- a/third_party/blink/renderer/modules/xr/xr_system.cc +++ b/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -1436,6 +1436,7 @@ void XRSystem::OnRequestSessionReturned( PendingRequestSessionQuery* query, device::mojom::blink::RequestSessionResultPtr result) { + DVLOG(2) << __func__; // The session query has returned and we're about to resolve or reject the // promise, so remove it from our outstanding list. DCHECK(outstanding_request_queries_.Contains(query)); @@ -1473,13 +1474,8 @@ auto session_ptr = std::move(result->get_success()->session); auto metrics_recorder = std::move(result->get_success()->metrics_recorder); - bool environment_integration = - query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr; - // immersive sessions must supply display info. DCHECK(session_ptr->display_info); - DVLOG(2) << __func__ - << ": environment_integration=" << environment_integration; XRSessionFeatureSet enabled_features; for (const auto& feature : session_ptr->enabled_features) { @@ -1497,6 +1493,11 @@ if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveVr || query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { + const bool anchors_enabled = base::Contains( + enabled_features, device::mojom::XRSessionFeature::ANCHORS); + const bool hit_test_enabled = base::Contains( + enabled_features, device::mojom::XRSessionFeature::HIT_TEST); + const bool environment_integration = hit_test_enabled || anchors_enabled; if (environment_integration) { // See Task Sources spreadsheet for more information: // https://docs.google.com/spreadsheets/d/1b-dus1Ug3A8y0lX0blkmOjJILisUASdj8x9YN_XMwYc/view @@ -1511,7 +1512,9 @@ WrapWeakPersistent(this))); session->OnEnvironmentProviderCreated(); + } + if (query->mode() == device::mojom::blink::XRSessionMode::kImmersiveAr) { DCHECK(DomWindow()); if (query->HasFeature(device::mojom::XRSessionFeature::DOM_OVERLAY)) { DCHECK(query->DOMOverlayElement());
diff --git a/third_party/blink/renderer/platform/exported/web_url_response.cc b/third_party/blink/renderer/platform/exported/web_url_response.cc index 3f3efff7..743df4fc 100644 --- a/third_party/blink/renderer/platform/exported/web_url_response.cc +++ b/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -510,6 +510,13 @@ return resource_response_->FromArchive(); } +void WebURLResponse::SetDnsAliases(const WebVector<WebString>& aliases) { + Vector<String> dns_aliases(aliases.size()); + std::transform(aliases.begin(), aliases.end(), dns_aliases.begin(), + [](const WebString& h) { return WTF::String(h); }); + resource_response_->SetDnsAliases(std::move(dns_aliases)); +} + WebURLResponse::WebURLResponse(ResourceResponse& r) : resource_response_(&r) {} } // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_url_response_test.cc b/third_party/blink/renderer/platform/exported/web_url_response_test.cc index 5e2ce559..74174df 100644 --- a/third_party/blink/renderer/platform/exported/web_url_response_test.cc +++ b/third_party/blink/renderer/platform/exported/web_url_response_test.cc
@@ -30,8 +30,10 @@ #include "third_party/blink/public/platform/web_url_response.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" namespace blink { @@ -47,4 +49,15 @@ EXPECT_FALSE(instance.IsNull()); } +TEST(WebURLResponseTest, DnsAliasesCanBeAccessed) { + WebURLResponse instance; + instance.SetCurrentRequestUrl(KURL("http://localhost/")); + EXPECT_FALSE(instance.IsNull()); + EXPECT_TRUE(instance.ToResourceResponse().DnsAliases().IsEmpty()); + WebVector<WebString> aliases({"alias1", "alias2"}); + instance.SetDnsAliases(aliases); + EXPECT_THAT(instance.ToResourceResponse().DnsAliases(), + testing::ElementsAre("alias1", "alias2")); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/OWNERS b/third_party/blink/renderer/platform/fonts/OWNERS new file mode 100644 index 0000000..c0787f4 --- /dev/null +++ b/third_party/blink/renderer/platform/fonts/OWNERS
@@ -0,0 +1,2 @@ +per-file font_matching_metrics.cc=file://third_party/blink/public/common/privacy_budget/OWNERS +per-file font_matching_metrics.h=file://third_party/blink/public/common/privacy_budget/OWNERS \ No newline at end of file
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm index 1671d61..fb5629f 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm
@@ -140,16 +140,14 @@ font_data_to_substitute->PlatformData(); NSFont* ns_font = base::mac::CFToNSCast(platform_data.CtFont()); - NSString* string = - [[NSString alloc] initWithCharactersNoCopy:code_units - length:code_units_length - freeWhenDone:NO]; + NSString* string = [[[NSString alloc] + initWithCharacters:reinterpret_cast<UniChar*>(code_units) + length:code_units_length] autorelease]; NSFont* substitute_font = [NSFont findFontLike:ns_font forString:string withRange:NSMakeRange(0, code_units_length) inLanguage:nil]; - [string release]; // FIXME: Remove this SPI usage: http://crbug.com/255122 if (!substitute_font && code_units_length == 1)
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index b3117c6..6dde5c80 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "cc/document_transition/document_transition_request.h" #include "cc/layers/scrollbar_layer_base.h" #include "cc/paint/display_item_list.h" #include "cc/trees/effect_node.h" @@ -1102,7 +1103,9 @@ void PaintArtifactCompositor::Update( const Vector<PreCompositedLayerInfo>& pre_composited_layers, const ViewportProperties& viewport_properties, - const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes) { + const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes, + Vector<std::unique_ptr<cc::DocumentTransitionRequest>> + transition_requests) { DCHECK(scroll_translation_nodes.IsEmpty() || RuntimeEnabledFeatures::ScrollUnificationEnabled()); DCHECK(root_layer_); @@ -1114,6 +1117,9 @@ if (!host) return; + for (auto& request : transition_requests) + host->AddDocumentTransitionRequest(std::move(request)); + TRACE_EVENT0("blink", "PaintArtifactCompositor::Update"); host->property_trees()->scroll_tree.SetScrollCallbacks(scroll_callbacks_);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h index 81ca77a..16e8fd3 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -30,6 +30,7 @@ namespace cc { class ScrollbarLayerBase; +class DocumentTransitionRequest; } namespace blink { @@ -155,10 +156,11 @@ // noncomposited nodes, and is used for Scroll Unification to generate scroll // nodes for noncomposited scrollers to complete the compositor's scroll // property tree. - void Update(const Vector<PreCompositedLayerInfo>&, - const ViewportProperties& viewport_properties, - const Vector<const TransformPaintPropertyNode*>& - scroll_translation_nodes); + void Update( + const Vector<PreCompositedLayerInfo>&, + const ViewportProperties& viewport_properties, + const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes, + Vector<std::unique_ptr<cc::DocumentTransitionRequest>> requests); void UpdateRepaintedLayerProperties() const;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index 0e4e2515..82cc18e 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -10,6 +10,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "cc/document_transition/document_transition_request.h" #include "cc/input/main_thread_scrolling_reason.h" #include "cc/layers/layer.h" #include "cc/test/fake_impl_task_runner_provider.h" @@ -144,8 +145,9 @@ paint_artifact_compositor_->SetNeedsUpdate(); Vector<PreCompositedLayerInfo> pre_composited_layers = { {PaintChunkSubset(artifact)}}; - paint_artifact_compositor_->Update( - pre_composited_layers, viewport_properties, scroll_translation_nodes); + paint_artifact_compositor_->Update(pre_composited_layers, + viewport_properties, + scroll_translation_nodes, {}); layer_tree_->layer_tree_host()->LayoutAndUpdateLayers(); }
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_ref.cc b/third_party/blink/renderer/platform/graphics/mailbox_ref.cc index c926ce1..38dbfd51 100644 --- a/third_party/blink/renderer/platform/graphics/mailbox_ref.cc +++ b/third_party/blink/renderer/platform/graphics/mailbox_ref.cc
@@ -31,9 +31,7 @@ : sync_token_(sync_token), context_thread_ref_(context_thread_ref), context_task_runner_(std::move(context_task_runner)), - release_callback_(std::move(release_callback)) { - DCHECK(sync_token.HasData()); -} + release_callback_(std::move(release_callback)) {} MailboxRef::~MailboxRef() { if (context_thread_ref_ == base::PlatformThread::CurrentRef()) {
diff --git a/third_party/blink/renderer/platform/graphics/mailbox_ref.h b/third_party/blink/renderer/platform/graphics/mailbox_ref.h index ef9e2996..cd94537 100644 --- a/third_party/blink/renderer/platform/graphics/mailbox_ref.h +++ b/third_party/blink/renderer/platform/graphics/mailbox_ref.h
@@ -32,10 +32,7 @@ bool is_cross_thread() const { return base::PlatformThread::CurrentRef() != context_thread_ref_; } - void set_sync_token(gpu::SyncToken token) { - DCHECK(sync_token_.HasData()); - sync_token_ = token; - } + void set_sync_token(gpu::SyncToken token) { sync_token_ = token; } const gpu::SyncToken& sync_token() const { return sync_token_; } bool verified_flush() { return sync_token_.verified_flush(); }
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h index f4d380bd..8ebf65a2 100644 --- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h +++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -120,6 +120,19 @@ const { return ResourceRequestBlockedReason::kOther; } + // In derived classes, performs *only* a SubresourceFilter check for whether + // the request can go through or should be blocked. + virtual base::Optional<ResourceRequestBlockedReason> + CanRequestBasedOnSubresourceFilterOnly( + ResourceType, + const ResourceRequest&, + const KURL&, + const ResourceLoaderOptions&, + ReportingDisposition, + const base::Optional<ResourceRequest::RedirectInfo>& redirect_info) + const { + return ResourceRequestBlockedReason::kOther; + } virtual base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest( mojom::blink::RequestContextType, network::mojom::RequestDestination request_destination, @@ -151,9 +164,11 @@ virtual const FeaturePolicy* GetFeaturePolicy() const { return nullptr; } // Determine if the request is on behalf of an advertisement. If so, return - // true. + // true. Checks `resource_request.Url()` unless `alias_url` is non-null, in + // which case it checks the latter. virtual bool CalculateIfAdSubresource( - const ResourceRequest& resource_request, + const ResourceRequestHead& resource_request, + const base::Optional<KURL>& alias_url, ResourceType type, const FetchInitiatorInfo& initiator_info) { return false;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc index 9cb53a4..3dd56554 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -1200,4 +1200,8 @@ return !result.second; } +void Resource::SetIsAdResource() { + resource_request_.SetIsAdResource(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.h b/third_party/blink/renderer/platform/loader/fetch/resource.h index 61636da0..ffbfd46 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource.h
@@ -412,6 +412,9 @@ // already exists. bool AppendTopFrameSiteForMetrics(const SecurityOrigin& origin); + // Sets the ResourceRequest to be tagged as an ad. + void SetIsAdResource(); + protected: Resource(const ResourceRequestHead&, ResourceType,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index d5bef9fd..5ded2df8 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -949,8 +949,9 @@ reporting_disposition, resource_request.GetRedirectInfo()); - if (Context().CalculateIfAdSubresource(resource_request, resource_type, - options.initiator_info)) + if (Context().CalculateIfAdSubresource(resource_request, + base::nullopt /* alias_url */, + resource_type, options.initiator_info)) resource_request.SetIsAdResource(); if (blocked_reason)
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc index c2d0de5..00a5290 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -190,6 +190,28 @@ } } +void LogCnameAliasMetrics(const CnameAliasMetricInfo& info) { + UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.CnameAlias.Renderer.HadAliases", + info.has_aliases); + + if (info.has_aliases) { + UMA_HISTOGRAM_BOOLEAN( + "SubresourceFilter.CnameAlias.Renderer.WasAdTaggedBasedOnAlias", + info.was_ad_tagged_based_on_alias); + UMA_HISTOGRAM_BOOLEAN( + "SubresourceFilter.CnameAlias.Renderer.WasBlockedBasedOnAlias", + info.was_blocked_based_on_alias); + UMA_HISTOGRAM_COUNTS_1000( + "SubresourceFilter.CnameAlias.Renderer.ListLength", info.list_length); + UMA_HISTOGRAM_COUNTS_1000( + "SubresourceFilter.CnameAlias.Renderer.InvalidCount", + info.invalid_count); + UMA_HISTOGRAM_COUNTS_1000( + "SubresourceFilter.CnameAlias.Renderer.RedundantCount", + info.redundant_count); + } +} + } // namespace // CodeCacheRequest handles the requests to fetch data from code cache. @@ -786,8 +808,9 @@ reporting_disposition, new_request->GetRedirectInfo()); - if (Context().CalculateIfAdSubresource(*new_request, resource_type, - options.initiator_info)) + if (Context().CalculateIfAdSubresource( + *new_request, base::nullopt /* alias_url */, resource_type, + options.initiator_info)) new_request->SetIsAdResource(); if (blocked_reason) { @@ -957,6 +980,15 @@ return; } + // Redirect information for possible post-request checks below. + const base::Optional<ResourceRequest::RedirectInfo>& previous_redirect_info = + request.GetRedirectInfo(); + const KURL& original_url = previous_redirect_info + ? previous_redirect_info->original_url + : request.Url(); + const ResourceRequest::RedirectInfo redirect_info(original_url, + request.Url()); + if (response.WasFetchedViaServiceWorker()) { // Run post-request CSP checks. This is the "Should response to request be // blocked by Content Security Policy?" algorithm in the CSP specification: @@ -976,16 +1008,10 @@ // checks as a first-class concept instead of just reusing the functions for // pre-request checks, and consider running the checks regardless of service // worker interception. - const KURL& response_url = response.ResponseUrl(); - const base::Optional<ResourceRequest::RedirectInfo>& - previous_redirect_info = request.GetRedirectInfo(); - const KURL& original_url = previous_redirect_info - ? previous_redirect_info->original_url - : request.Url(); - const ResourceRequest::RedirectInfo redirect_info(original_url, - request.Url()); + // // CanRequest() below only checks enforced policies: check report-only // here to ensure violations are sent. + const KURL& response_url = response.ResponseUrl(); Context().CheckCSPForRequest( request_context, request_destination, response_url, options, ReportingDisposition::kReport, original_url, @@ -1002,6 +1028,18 @@ } } + if (base::FeatureList::IsEnabled( + features::kSendCnameAliasesToSubresourceFilterFromRenderer)) { + CnameAliasMetricInfo info; + bool should_block = ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck( + response.DnsAliases(), request.Url(), original_url, resource_type, + initial_request, options, redirect_info, &info); + LogCnameAliasMetrics(info); + + if (should_block) + return; + } + // A response should not serve partial content if it was not requested via a // Range header: https://fetch.spec.whatwg.org/#main-fetch if (response.GetType() == network::mojom::FetchResponseType::kOpaque && @@ -1504,4 +1542,73 @@ false /* should_report_corb_blocking */); } +bool ResourceLoader::ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck( + const Vector<String>& dns_aliases, + const KURL& request_url, + const KURL& original_url, + ResourceType resource_type, + const ResourceRequestHead& initial_request, + const ResourceLoaderOptions& options, + const ResourceRequest::RedirectInfo redirect_info, + CnameAliasMetricInfo* out_metric_info) { + DCHECK(out_metric_info); + + // Look for CNAME aliases, and if any are found, run SubresourceFilter + // checks on them to perform resource-blocking and ad-tagging based on the + // aliases: if any one of the aliases is on the denylist, then the + // request will be deemed on the denylist and treated accordingly (blocked + // and/or tagged). + out_metric_info->has_aliases = !dns_aliases.IsEmpty(); + out_metric_info->list_length = dns_aliases.size(); + + // If there are no aliases, we have no reason to block based on them. + if (!out_metric_info->has_aliases) + return false; + + // CNAME aliases were found, and so the SubresourceFilter must be + // consulted for each one. + // Create a copy of the request URL. We will swap out the host below. + KURL alias_url = request_url; + + for (const String& alias : dns_aliases) { + alias_url.SetHost(alias); + + // The SubresourceFilter only performs nontrivial matches for + // valid URLs. Skip sending this alias if it's invalid. + if (!alias_url.IsValid()) { + out_metric_info->invalid_count++; + continue; + } + + // Do not perform a SubresourceFilter check on an `alias_url` that matches + // the requested URL (or, inclusively, the original URL in the case of + // redirects). + if (alias_url == original_url || alias_url == request_url) { + out_metric_info->redundant_count++; + continue; + } + + base::Optional<ResourceRequestBlockedReason> blocked_reason = + Context().CanRequestBasedOnSubresourceFilterOnly( + resource_type, ResourceRequest(initial_request), alias_url, options, + ReportingDisposition::kReport, redirect_info); + if (blocked_reason) { + HandleError(ResourceError::CancelledDueToAccessCheckError( + alias_url, blocked_reason.value())); + out_metric_info->was_blocked_based_on_alias = true; + return true; + } + + if (!resource_->GetResourceRequest().IsAdResource() && + Context().CalculateIfAdSubresource(resource_->GetResourceRequest(), + alias_url, resource_type, + options.initiator_info)) { + resource_->SetIsAdResource(); + out_metric_info->was_ad_tagged_based_on_alias = true; + } + } + + return false; +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h index ed9188c2..bc6994b 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -31,6 +31,7 @@ #include <memory> #include "base/containers/span.h" +#include "base/feature_list.h" #include "base/gtest_prod_util.h" #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/base/big_buffer.h" @@ -58,6 +59,17 @@ class ResourceFetcher; class ResponseBodyLoader; +// Struct for keeping variables used in recording CNAME alias metrics bundled +// together. +struct CnameAliasMetricInfo { + bool has_aliases = false; + bool was_ad_tagged_based_on_alias = false; + bool was_blocked_based_on_alias = false; + int list_length = 0; + int invalid_count = 0; + int redundant_count = 0; +}; + // A ResourceLoader is created for each Resource by the ResourceFetcher when it // needs to load the specified resource. A ResourceLoader creates a // WebURLLoader and loads the resource using it. Any per-load logic should be @@ -204,6 +216,19 @@ // Processes Data URL in ResourceLoader instead of using |loader_|. void HandleDataUrl(); + // If enabled, performs SubresourceFilter checks for any DNS aliases found for + // the requested URL, which may result in ad-tagging the ResourceRequest. + // Returns true if the request should be blocked based on these checks. + bool ShouldBlockRequestBasedOnSubresourceFilterDnsAliasCheck( + const Vector<String>& dns_aliases, + const KURL& request_url, + const KURL& original_url, + ResourceType resource_type, + const ResourceRequestHead& initial_request, + const ResourceLoaderOptions& options, + const ResourceRequest::RedirectInfo redirect_info, + CnameAliasMetricInfo* out_metric_info); + std::unique_ptr<WebURLLoader> loader_; ResourceLoadScheduler::ClientId scheduler_client_id_; Member<ResourceFetcher> fetcher_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc index 615e434e..7a03e0f 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_test.cc
@@ -7,9 +7,12 @@ #include <string> #include <utility> +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "mojo/public/c/system/data_pipe.h" #include "services/network/public/mojom/fetch_api.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h" #include "third_party/blink/public/platform/web_url_loader.h" @@ -29,6 +32,19 @@ namespace blink { +const char kCnameAliasHadAliasesHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.HadAliases"; +const char kCnameAliasIsInvalidCountHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.InvalidCount"; +const char kCnameAliasIsRedundantCountHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.RedundantCount"; +const char kCnameAliasListLengthHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.ListLength"; +const char kCnameAliasWasAdTaggedHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.WasAdTaggedBasedOnAlias"; +const char kCnameAliasWasBlockedHistogram[] = + "SubresourceFilter.CnameAlias.Renderer.WasBlockedBasedOnAlias"; + class ResourceLoaderTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(ResourceLoaderTest); @@ -554,4 +570,289 @@ EXPECT_EQ(false, LoadAndCheckIsolatedCodeCache(response)); } +class ResourceLoaderSubresourceFilterCnameAliasTest + : public ResourceLoaderTest { + public: + ResourceLoaderSubresourceFilterCnameAliasTest() = default; + ~ResourceLoaderSubresourceFilterCnameAliasTest() override = default; + + void SetUp() override { + feature_list_.InitAndEnableFeature( + features::kSendCnameAliasesToSubresourceFilterFromRenderer); + ResourceLoaderTest::SetUp(); + } + + base::HistogramTester* histogram_tester() { return &histogram_tester_; } + + void SetMockSubresourceFilterBlockLists(Vector<String> blocked_urls, + Vector<String> tagged_urls) { + blocked_urls_ = blocked_urls; + tagged_urls_ = tagged_urls; + } + + Resource* CreateResource(ResourceRequest request) { + FetchParameters params = FetchParameters::CreateForTest(std::move(request)); + auto* fetcher = MakeResourceFetcherWithMockSubresourceFilter(); + return RawResource::Fetch(params, fetcher, nullptr); + } + + void GiveResponseToLoader(ResourceResponse response, ResourceLoader* loader) { + CreateMojoDataPipe(); + loader->DidReceiveResponse(WrappedResourceResponse(response)); + } + + protected: + FetchContext* MakeFetchContextWithMockSubresourceFilter( + Vector<String> blocked_urls, + Vector<String> tagged_urls) { + auto* context = MakeGarbageCollected<MockFetchContext>(); + context->set_blocked_urls(blocked_urls); + context->set_tagged_urls(tagged_urls); + return context; + } + + ResourceFetcher* MakeResourceFetcherWithMockSubresourceFilter() { + FetchContext* context = + MakeFetchContextWithMockSubresourceFilter(blocked_urls_, tagged_urls_); + auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>(); + return MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit( + properties->MakeDetachable(), context, CreateTaskRunner(), + CreateTaskRunner(), MakeGarbageCollected<NoopLoaderFactory>(), + MakeGarbageCollected<MockContextLifecycleNotifier>())); + } + + void CreateMojoDataPipe() { + mojo::ScopedDataPipeProducerHandle producer; + mojo::ScopedDataPipeConsumerHandle consumer; + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = 3; + + MojoResult result = CreateDataPipe(&options, &producer, &consumer); + ASSERT_EQ(result, MOJO_RESULT_OK); + } + + void ExpectHistogramsMatching(CnameAliasMetricInfo info) { + histogram_tester()->ExpectUniqueSample(kCnameAliasHadAliasesHistogram, + info.has_aliases, 1); + + if (info.has_aliases) { + histogram_tester()->ExpectUniqueSample(kCnameAliasWasAdTaggedHistogram, + info.was_ad_tagged_based_on_alias, + 1); + histogram_tester()->ExpectUniqueSample( + kCnameAliasWasBlockedHistogram, info.was_blocked_based_on_alias, 1); + histogram_tester()->ExpectUniqueSample(kCnameAliasListLengthHistogram, + info.list_length, 1); + histogram_tester()->ExpectUniqueSample(kCnameAliasIsInvalidCountHistogram, + info.invalid_count, 1); + histogram_tester()->ExpectUniqueSample( + kCnameAliasIsRedundantCountHistogram, info.redundant_count, 1); + } + } + + private: + base::test::ScopedFeatureList feature_list_; + base::HistogramTester histogram_tester_; + Vector<String> blocked_urls_; + Vector<String> tagged_urls_; +}; + +TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest, + DnsAliasesCheckedBySubresourceFilterDisallowed_TaggedAndBlocked) { + // Set the blocklists: the first for blocking, the second for ad-tagging. + Vector<String> blocked_urls = {"https://bad-ad.com/some_path.html"}; + Vector<String> tagged_urls = {"https://ad.com/some_path.html"}; + SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls); + + // Create the request. + KURL url("https://www.example.com/some_path.html"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::FETCH); + + // Create the resource and loader. + Resource* resource = CreateResource(std::move(request)); + ResourceLoader* loader = resource->Loader(); + + // Create the response. + ResourceResponse response(url); + response.SetHttpStatusCode(200); + + // Set the CNAME aliases. + Vector<String> aliases({"ad.com", "bad-ad.com", "alias3.com"}); + response.SetDnsAliases(aliases); + + // Give the response to the loader. + GiveResponseToLoader(response, loader); + + // Test the histograms to verify that the CNAME aliases were detected. + // Expect that the resource was tagged as a ad, due to first alias. + // Expect that the resource was blocked, due to second alias. + CnameAliasMetricInfo info = {.has_aliases = true, + .was_ad_tagged_based_on_alias = true, + .was_blocked_based_on_alias = true, + .list_length = 3, + .invalid_count = 0, + .redundant_count = 0}; + + ExpectHistogramsMatching(info); +} + +TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest, + DnsAliasesCheckedBySubresourceFilterDisallowed_BlockedOnly) { + // Set the blocklists: the first for blocking, the second for ad-tagging. + Vector<String> blocked_urls = {"https://bad-ad.com/some_path.html"}; + Vector<String> tagged_urls = {}; + SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls); + + // Create the request. + KURL url("https://www.example.com/some_path.html"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::FETCH); + + // Create the resource and loader. + Resource* resource = CreateResource(std::move(request)); + ResourceLoader* loader = resource->Loader(); + + // Create the response. + ResourceResponse response(url); + response.SetHttpStatusCode(200); + + // Set the CNAME aliases. + Vector<String> aliases({"ad.com", "bad-ad.com", "alias3.com"}); + response.SetDnsAliases(aliases); + + // Give the response to the loader. + GiveResponseToLoader(response, loader); + + // Test the histograms to verify that the CNAME aliases were detected. + // Expect that the resource was blocked, due to second alias. + CnameAliasMetricInfo info = {.has_aliases = true, + .was_ad_tagged_based_on_alias = false, + .was_blocked_based_on_alias = true, + .list_length = 3, + .invalid_count = 0, + .redundant_count = 0}; + + ExpectHistogramsMatching(info); +} + +TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest, + DnsAliasesCheckedBySubresourceFilterDisallowed_TaggedOnly) { + // Set the blocklists: the first for blocking, the second for ad-tagging. + Vector<String> blocked_urls = {}; + Vector<String> tagged_urls = {"https://bad-ad.com/some_path.html"}; + SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls); + + // Create the request. + KURL url("https://www.example.com/some_path.html"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::FETCH); + + // Create the resource and loader. + Resource* resource = CreateResource(std::move(request)); + ResourceLoader* loader = resource->Loader(); + + // Create the response. + ResourceResponse response(url); + response.SetHttpStatusCode(200); + + // Set the CNAME aliases. + Vector<String> aliases({"ad.com", "", "alias3.com", "bad-ad.com"}); + response.SetDnsAliases(aliases); + + // Give the response to the loader. + GiveResponseToLoader(response, loader); + + // Test the histograms to verify that the CNAME aliases were detected. + // Expect that the resource was tagged, due to fourth alias. + // Expect that the invalid empty alias is counted as such. + CnameAliasMetricInfo info = {.has_aliases = true, + .was_ad_tagged_based_on_alias = true, + .was_blocked_based_on_alias = false, + .list_length = 4, + .invalid_count = 1, + .redundant_count = 0}; + + ExpectHistogramsMatching(info); +} + +TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest, + DnsAliasesCheckedBySubresourceFilterAllowed_NotBlockedOrTagged) { + // Set the blocklists: the first for blocking, the second for ad-tagging. + Vector<String> blocked_urls = {}; + Vector<String> tagged_urls = {}; + SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls); + + // Create the request. + KURL url("https://www.example.com/some_path.html"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::FETCH); + + // Create the resource and loader. + Resource* resource = CreateResource(std::move(request)); + ResourceLoader* loader = resource->Loader(); + + // Create the response. + ResourceResponse response(url); + response.SetHttpStatusCode(200); + + // Set the CNAME aliases. + Vector<String> aliases( + {"non-ad.com", "?", "alias3.com", "not-an-ad.com", "www.example.com"}); + response.SetDnsAliases(aliases); + + // Give the response to the loader. + GiveResponseToLoader(response, loader); + + // Test the histograms to verify that the CNAME aliases were detected. + // Expect that the resource was neither tagged nor blocked. + // Expect that the invalid alias is counted as such. + // Expect that the redundant (i.e. matching the request URL) fifth alias to be + // counted as such. + CnameAliasMetricInfo info = {.has_aliases = true, + .was_ad_tagged_based_on_alias = false, + .was_blocked_based_on_alias = false, + .list_length = 5, + .invalid_count = 1, + .redundant_count = 1}; + + ExpectHistogramsMatching(info); +} + +TEST_F(ResourceLoaderSubresourceFilterCnameAliasTest, + DnsAliasesCheckedBySubresourceFilterNoAliases_NoneDetected) { + // Set the blocklists: the first for blocking, the second for ad-tagging. + Vector<String> blocked_urls = {}; + Vector<String> tagged_urls = {}; + SetMockSubresourceFilterBlockLists(blocked_urls, tagged_urls); + + // Create the request. + KURL url("https://www.example.com/some_path.html"); + ResourceRequest request(url); + request.SetRequestContext(mojom::blink::RequestContextType::FETCH); + + // Create the resource and loader. + Resource* resource = CreateResource(std::move(request)); + ResourceLoader* loader = resource->Loader(); + + // Create the response. + ResourceResponse response(url); + response.SetHttpStatusCode(200); + + // Set the CNAME aliases. + Vector<String> aliases; + response.SetDnsAliases(aliases); + + // Give the response to the loader. + GiveResponseToLoader(response, loader); + + // Test the histogram to verify that no aliases were detected. + CnameAliasMetricInfo info = {.has_aliases = false}; + + ExpectHistogramsMatching(info); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h index 5fadb1c..bf4ffc97 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -494,6 +494,12 @@ was_cookie_in_request_ = was_cookie_in_request; } + const Vector<String>& DnsAliases() const { return dns_aliases_; } + + void SetDnsAliases(Vector<String> aliases) { + dns_aliases_ = std::move(aliases); + } + network::mojom::CrossOriginEmbedderPolicyValue GetCrossOriginEmbedderPolicy() const; @@ -666,6 +672,11 @@ // cross-origin prefetch responses. It is used to pass the token along to // preload header requests from these responses. base::Optional<base::UnguessableToken> recursive_prefetch_token_; + + // Any DNS aliases for the requested URL, as read from CNAME records. + // The alias chain order is preserved in reverse, from canonical name (i.e. + // address record name) through to query name. + Vector<String> dns_aliases_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc index 1e2d919..ce3b6c5 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_response_test.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" @@ -102,4 +103,15 @@ EXPECT_EQ("a=1, b=2, c=3", response.HttpHeaderField("set-cookie")); } +TEST(ResourceResponseTest, DnsAliasesCanBeSetAndAccessed) { + ResourceResponse response(CreateTestResponse()); + + EXPECT_TRUE(response.DnsAliases().IsEmpty()); + + Vector<String> aliases({"alias1", "alias2"}); + response.SetDnsAliases(aliases); + + EXPECT_THAT(response.DnsAliases(), testing::ElementsAre("alias1", "alias2")); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc index 42a328f0..7bbd1ee9 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -435,5 +435,13 @@ EXPECT_EQ(resource->CalculateOverheadSizeForTest(), resource->OverheadSize()); } +TEST(ResourceTest, SetIsAdResource) { + const KURL url("http://127.0.0.1:8000/foo.html"); + auto* resource = MakeGarbageCollected<MockResource>(url); + EXPECT_FALSE(resource->GetResourceRequest().IsAdResource()); + resource->SetIsAdResource(); + EXPECT_TRUE(resource->GetResourceRequest().IsAdResource()); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h index 217da2c..4d5e3fd 100644 --- a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h +++ b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
@@ -38,6 +38,13 @@ uint64_t GetTransferSize() const { return transfer_size_; } + void set_blocked_urls(Vector<String> blocked_urls) { + blocked_urls_ = std::move(blocked_urls); + } + void set_tagged_urls(Vector<String> tagged_urls) { + tagged_urls_ = std::move(tagged_urls); + } + bool AllowImage(bool images_enabled, const KURL&) const override { return true; } @@ -51,6 +58,21 @@ const override { return base::nullopt; } + base::Optional<ResourceRequestBlockedReason> + CanRequestBasedOnSubresourceFilterOnly( + ResourceType type, + const ResourceRequest& resource_request, + const KURL& url, + const ResourceLoaderOptions& options, + ReportingDisposition reporting_disposition, + const base::Optional<ResourceRequest::RedirectInfo>& redirect_info) + const override { + if (blocked_urls_.Contains(url.GetString())) { + return ResourceRequestBlockedReason::kSubresourceFilter; + } + + return base::nullopt; + } base::Optional<ResourceRequestBlockedReason> CheckCSPForRequest( mojom::blink::RequestContextType, network::mojom::RequestDestination request_destination, @@ -79,6 +101,15 @@ weak_wrapper_resource_load_info_notifier_->AsWeakPtr()); } + bool CalculateIfAdSubresource( + const ResourceRequestHead& resource_request, + const base::Optional<KURL>& alias_url, + ResourceType type, + const FetchInitiatorInfo& initiator_info) override { + const KURL url = alias_url ? alias_url.value() : resource_request.Url(); + return tagged_urls_.Contains(url.GetString()); + } + void SetResourceLoadInfoNotifier( mojom::ResourceLoadInfoNotifier* resource_load_info_notifier) { resource_load_info_notifier_ = resource_load_info_notifier; @@ -89,6 +120,8 @@ mojom::ResourceLoadInfoNotifier* resource_load_info_notifier_ = nullptr; std::unique_ptr<WeakWrapperResourceLoadInfoNotifier> weak_wrapper_resource_load_info_notifier_; + Vector<String> blocked_urls_; + Vector<String> tagged_urls_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index e167fbc..7964433 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1016,7 +1016,7 @@ }, { name: "ImportMaps", - implied_by: ["ExperimentalProductivityFeatures"], + status: "stable" }, { name: "InertAttribute",
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc index ee190c9..c7cbe56 100644 --- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc +++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -106,7 +106,16 @@ } gfx::GpuMemoryBufferHandle TakeGpuMemoryBufferHandle() { +#if defined(OS_MAC) + // The same GpuMemoryBuffersHandles will be reused repeatedly by the + // unaccelerated macOS path. Each of these uses will call this function. + // Ensure that this function doesn't invalidate the GpuMemoryBufferHandle + // on macOS for this reason. + // https://crbug.com/1159722 + return gmb_resources_->gpu_memory_buffer_handle.Clone(); +#else return std::move(gmb_resources_->gpu_memory_buffer_handle); +#endif } void SetGpuMemoryBuffer( std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer) { @@ -660,7 +669,7 @@ // used by both hardware and software paths. // https://crbug.com/1125879 if (!gpu_factories_ || !media_task_runner_) { - frame = media::VideoFrame::WrapIOSurface( + frame = media::VideoFrame::WrapUnacceleratedIOSurface( buffer_context->TakeGpuMemoryBufferHandle(), gfx::Rect(info->visible_rect), info->timestamp); break;
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string.h b/third_party/blink/renderer/platform/wtf/text/atomic_string.h index 3dec4f7..77fa98e 100644 --- a/third_party/blink/renderer/platform/wtf/text/atomic_string.h +++ b/third_party/blink/renderer/platform/wtf/text/atomic_string.h
@@ -23,6 +23,7 @@ #include <cstring> #include <iosfwd> +#include <type_traits> #include "build/build_config.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -74,6 +75,10 @@ AtomicString(const LChar* chars, unsigned length); AtomicString(const UChar* chars, unsigned length); AtomicString(const UChar* chars); + // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t` + // on all platforms. + template <typename UCharT = UChar, + typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>> AtomicString(const char16_t* chars) : AtomicString(reinterpret_cast<const UChar*>(chars)) {}
diff --git a/third_party/blink/renderer/platform/wtf/text/string_mac.mm b/third_party/blink/renderer/platform/wtf/text/string_mac.mm index d1690b69..eda6594 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_mac.mm +++ b/third_party/blink/renderer/platform/wtf/text/string_mac.mm
@@ -45,7 +45,8 @@ Vector<UChar, 1024> uchar_buffer(size); CFStringGetCharacters(reinterpret_cast<CFStringRef>(str), - CFRangeMake(0, size), uchar_buffer.data()); + CFRangeMake(0, size), + reinterpret_cast<UniChar*>(uchar_buffer.data())); impl_ = StringImpl::Create(uchar_buffer.data(), size); } }
diff --git a/third_party/blink/renderer/platform/wtf/text/string_view.h b/third_party/blink/renderer/platform/wtf/text/string_view.h index 0178c7b0..b1276c8 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_view.h +++ b/third_party/blink/renderer/platform/wtf/text/string_view.h
@@ -11,6 +11,8 @@ #include "base/memory/scoped_refptr.h" #endif #include <cstring> +#include <type_traits> + #include "base/containers/span.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/string_impl.h" @@ -126,6 +128,10 @@ StringView(const UChar* chars, unsigned length) : impl_(StringImpl::empty16_bit_), bytes_(chars), length_(length) {} StringView(const UChar* chars); + // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t` + // on all platforms. + template <typename UCharT = UChar, + typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>> StringView(const char16_t* chars) : StringView(reinterpret_cast<const UChar*>(chars)) {}
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.h b/third_party/blink/renderer/platform/wtf/text/wtf_string.h index bea907ec..d56de32 100644 --- a/third_party/blink/renderer/platform/wtf/text/wtf_string.h +++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
@@ -27,6 +27,8 @@ // on systems without case-sensitive file systems. #include <iosfwd> +#include <type_traits> + #include "base/containers/span.h" #include "build/build_config.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -80,6 +82,10 @@ // Construct a string with UTF-16 data, from a null-terminated source. String(const UChar*); + // TODO(crbug.com/911896): Remove this constructor once `UChar` is `char16_t` + // on all platforms. + template <typename UCharT = UChar, + typename = std::enable_if_t<!std::is_same<UCharT, char16_t>::value>> String(const char16_t* chars) : String(reinterpret_cast<const UChar*>(chars)) {}
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index ec726cfbd..8b2ae57 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1028,7 +1028,7 @@ virtual/layout_ng_block_frag/fast/multicol/vertical-rl/nested-columns.html [ Pass ] ### Tests failing with LayoutNGBlockFragmentation enabled: -crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-break/block-end-aligned-abspos-nested.html [ Failure Crash ] +crbug.com/1079031 virtual/layout_ng_block_frag/external/wpt/css/css-break/block-end-aligned-abspos-nested.html [ Failure ] crbug.com/1113911 virtual/layout_ng_block_frag/external/wpt/css/css-break/fieldset-001.html [ Failure ] crbug.com/1154585 virtual/layout_ng_block_frag/external/wpt/css/css-break/ink-overflow-002.html [ Failure ] crbug.com/1146973 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-009.html [ Failure ] @@ -5890,10 +5890,6 @@ # Sheriff 2020-12-03 crbug.com/1154940 [ Win7 ] inspector-protocol/overlay/overlay-persistent-overlays-with-emulation.js [ Pass Failure ] -# Sheriff 2020-12-04 -# Failing on Webkit Linux Leak -crbug.com/1155771 [ Linux ] external/wpt/dom/events/AddEventListenerOptions-signal.any.html [ Pass Failure ] - # DevTools roll crbug.com/1144171 http/tests/devtools/report-API-errors.js [ Skip ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 1a8cabc..5b08fb4 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -639,7 +639,7 @@ { "prefix": "import-maps-disabled", "bases": ["external/wpt/import-maps/not-as-classic-script.html"], - "args": ["--disable-blink-features=ExperimentalProductivityFeatures"] + "args": ["--disable-blink-features=ImportMaps"] }, { "prefix": "overlay-scrollbar",
diff --git a/third_party/blink/web_tests/accessibility/aom-reparenting-crash.html b/third_party/blink/web_tests/accessibility/aom-reparenting-crash.html index 2ff73fd..49fd94e 100644 --- a/third_party/blink/web_tests/accessibility/aom-reparenting-crash.html +++ b/third_party/blink/web_tests/accessibility/aom-reparenting-crash.html
@@ -20,6 +20,6 @@ setTimeout(() => { let doc = document.implementation.createDocument("", null); doc.adoptNode(alert_atomic); -}); +}, 1); </script>
diff --git a/third_party/blink/web_tests/accessibility/aria-combo-box-with-delay-add.html b/third_party/blink/web_tests/accessibility/aria-combo-box-with-delay-add.html index 7229893..9109150 100644 --- a/third_party/blink/web_tests/accessibility/aria-combo-box-with-delay-add.html +++ b/third_party/blink/web_tests/accessibility/aria-combo-box-with-delay-add.html
@@ -35,6 +35,6 @@ assert_false(state2.isFocused, 'State2 should not be focused.'); t.done(); - }, 0); + }, 1); }, 'An option with an activedescendant pointing to it is selected.'); </script>
diff --git a/third_party/blink/web_tests/accessibility/notification-listeners.html b/third_party/blink/web_tests/accessibility/notification-listeners.html index 5ccc9f8d..9872129 100644 --- a/third_party/blink/web_tests/accessibility/notification-listeners.html +++ b/third_party/blink/web_tests/accessibility/notification-listeners.html
@@ -122,7 +122,7 @@ // This should trigger a "value changed" notification on the slider. document.getElementById("slider").setAttribute("aria-valuenow", "6"); - }, 0); + }, 1); window.setTimeout(t.step_func_done(() => { assert_unreached();
diff --git a/third_party/blink/web_tests/compositing/contents-opaque/filter-expected.txt b/third_party/blink/web_tests/compositing/contents-opaque/filter-expected.txt index 16b5c3b..e062f2d 100644 --- a/third_party/blink/web_tests/compositing/contents-opaque/filter-expected.txt +++ b/third_party/blink/web_tests/compositing/contents-opaque/filter-expected.txt
@@ -8,8 +8,7 @@ }, { "name": "LayoutNGBlockFlow DIV class='composited container-box'", - "position": [-28, -28], - "bounds": [157, 157], + "bounds": [100, 100], "transform": 1 }, {
diff --git a/third_party/blink/web_tests/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/compositing/overflow/mask-with-filter-expected.png deleted file mode 100644 index 2b12f00..0000000 --- a/third_party/blink/web_tests/compositing/overflow/mask-with-filter-expected.png +++ /dev/null Binary files differ
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 abfff766..6092084 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
@@ -6376,20 +6376,6 @@ ] }, "selectors": { - "focus-visible-006-manual.html": [ - "974abc0024e3153008e944ff706156efcb9948e2", - [ - null, - {} - ] - ], - "focus-visible-008-manual.html": [ - "53306a90bbcae67ca65feefce3e4d3758d1a4ecd", - [ - null, - {} - ] - ], "hover-001-manual.html": [ "87d7af91b6994371b72ff33923ea1cacc65c8b5b", [ @@ -53278,6 +53264,19 @@ ], {} ] + ], + "widows-orphans-018.html": [ + "80699c698d385b244cb58a79c108c6f28e733579", + [ + null, + [ + [ + "/css/css-break/reference/widows-orphans-009-ref.html", + "==" + ] + ], + {} + ] ] }, "css-cascade": { @@ -87874,6 +87873,19 @@ {} ] ], + "multicol-fill-balance-006.html": [ + "3dc2022a3dfcf80ff133c212237503a4b64a9fe1", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], "multicol-fill-balance-nested-000.html": [ "5e466df8077545b4d6474389d296bc26c5b28b86", [ @@ -117643,6 +117655,32 @@ ] }, "word-break": { + "break-boundary-2-chars-001.html": [ + "e207f474c75ad1f3e0dbb726826468763af2263d", + [ + null, + [ + [ + "/css/css-text/word-break/reference/break-boundary-2-chars-001-ref.html", + "==" + ] + ], + {} + ] + ], + "break-boundary-2-chars-002.html": [ + "67c4cb7310599337e6f6d801b029777934a1680a", + [ + null, + [ + [ + "/css/css-text/word-break/reference/break-boundary-2-chars-002-ref.html", + "==" + ] + ], + {} + ] + ], "word-break-break-all-000.html": [ "af21bedf4bdc3219b3c3b1225f76b55e127d3f13", [ @@ -173828,7 +173866,7 @@ [] ], "font.py": [ - "706ee022ef8ce7b4c08a0fed91b9415a8e5bd0f3", + "6e33dbbc35a6334586a83fe0762f6b6cb8112e21", [] ], "image.py": [ @@ -204948,6 +204986,14 @@ }, "word-break": { "reference": { + "break-boundary-2-chars-001-ref.html": [ + "e0702afce52b2cc3eadbdc200e91180239e8a6b1", + [] + ], + "break-boundary-2-chars-002-ref.html": [ + "cd3ed338f1c345a5d2903c2a9b01d280582cfd16", + [] + ], "word-break-break-all-010-ref.html": [ "0e0300a72dc920a5ffb54cda6fbe84a2f517d010", [] @@ -215412,18 +215458,6 @@ "dfa29a887db747cc5f1d34aa120b8860fa39a552", [] ], - "Event-dispatch-handlers-changed-expected.txt": [ - "4e26515bae7fe1400cec6129422902d1268de1e2", - [] - ], - "Event-dispatch-listener-order.window-expected.txt": [ - "65eec9685e2e5833faf2bf174efc9ea5a346617f", - [] - ], - "Event-dispatch-order-at-target-expected.txt": [ - "ad4f38095d000d51984168915439f1895e159cda", - [] - ], "EventListener-handleEvent-expected.txt": [ "bb076e74f458f8aa89855d42ef845b55b2ccb354", [] @@ -215440,10 +215474,6 @@ "dd683f6f65f89f097ca70594e4a02c2027fdb66b", [] ], - "EventTarget-dispatchEvent-expected.txt": [ - "0e719cd2366ad1ca6be239b3ad70f2b2ea9dc150", - [] - ], "event-global-extra.window-expected.txt": [ "beb0825558675758404ccb75e6ea4f6256d7d0a1", [] @@ -231491,7 +231521,7 @@ [] ], "404-response-with-actual-image-data.py": [ - "3e2d9917d90239148371a6c43b5f5d71b193355b", + "e98cf03cf530d1187cf41e71a940c93a42b3a248", [] ], "available-images-ref.html": [ @@ -245436,7 +245466,7 @@ [] ], "fetch-access-control.py": [ - "a6cc9b12ad1fab3babd088d1edde5bf27fa51dfb", + "8822f32b270d4cb3d11f83576ee0a72f25e97b4d", [] ], "fetch-canvas-tainting-double-write-worker.js": [ @@ -246521,10 +246551,6 @@ "8fb0a9b995d6289bb28582fa01e6bb092afa5dda", [] ], - "capturing-and-bubbling-event-listeners-across-shadow-trees-expected.txt": [ - "13b5ae9d5913bb93e3bb9e8d1bf750771330b138", - [] - ], "declarative": { "support": { "declarative-child-frame.html": [ @@ -255741,7 +255767,7 @@ [] ], "firefox.py": [ - "1fa0bceb17bd436d5463ebc5938e41d511009e38", + "9104fedb5f9f45b6c8e9640159315a62e93a37c7", [] ], "firefox_android.py": [ @@ -257195,7 +257221,7 @@ "urlpattern": { "resources": { "urlpatterntestdata.json": [ - "5a1a3ec01eb2d504c6dd76010c17a8a680e0dd67", + "fe38505ddf0f985772d356fd05a9d5652982c7cc", [] ] } @@ -258786,7 +258812,7 @@ [] ], "asserts.py": [ - "3c3d677c90ecfc90f864042ef0628fb99a57131c", + "7afa22fd3fb81a3f915fe5edb4aa2a57a8b2e108", [] ], "authentication.py": [ @@ -258832,7 +258858,7 @@ [] ], "image.py": [ - "6149ccccbe3252e5c1c2bc37ba3dd3103ffbf9b6", + "705f2668ea1fd2dff062dfdf3e3f6ae138f1581a", [] ], "inline.py": [ @@ -299921,6 +299947,13 @@ {} ] ], + "overflow-clip-margin-intersection-observer.html": [ + "dcc1e6e7edd7d14a96ea4037d459d2f16a1f706b", + [ + null, + {} + ] + ], "overflow-clip-scroll-size.html": [ "1f2c2236a412251a9c02b84d3fade4c2df8d0527", [ @@ -314725,6 +314758,15 @@ } ] ], + "focus-visible-006.html": [ + "4b034b2e27962810bd9357ff88e5fe4587e56d25", + [ + null, + { + "testdriver": true + } + ] + ], "focus-visible-007.html": [ "95a27006e62076909f63f9946e1f2d7f8331732a", [ @@ -314734,6 +314776,15 @@ } ] ], + "focus-visible-008.html": [ + "75f676f53f3319cb672195343c77cc7ebd94eee4", + [ + null, + { + "testdriver": true + } + ] + ], "focus-visible-009.html": [ "4dae6407adac3971db6064822643332cf7f1722d", [ @@ -316959,6 +317010,13 @@ {} ] ], + "Event-stopPropagation-cancel-bubbling.html": [ + "5c2c49f33826a94418a2bcb65ca781e246adbd4b", + [ + null, + {} + ] + ], "Event-subclasses-constructors.html": [ "08a5ded011635c66151d22a09330f9341eb48c91", [ @@ -337856,6 +337914,57 @@ } ] ], + "redirect-referrer-override.any.js": [ + "56e55d79e141fd90124c2d5ea4cef419ee8a9cbd", + [ + "fetch/api/redirect/redirect-referrer-override.any.html", + { + "script_metadata": [ + [ + "timeout", + "long" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "../resources/utils.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ] + ], + "timeout": "long" + } + ], + [ + "fetch/api/redirect/redirect-referrer-override.any.worker.html", + { + "script_metadata": [ + [ + "timeout", + "long" + ], + [ + "script", + "/common/utils.js" + ], + [ + "script", + "../resources/utils.js" + ], + [ + "script", + "/common/get-host-info.sub.js" + ] + ], + "timeout": "long" + } + ] + ], "redirect-referrer.any.js": [ "99fda42e69b29ff8bd12b7d987dbe00306059c5c", [ @@ -374194,6 +374303,24 @@ ] }, "the-input-element": { + "anchor-active-contenteditable.html": [ + "88a9a35cc57db82323725559d8b0e2a202b3d7b7", + [ + null, + { + "testdriver": true + } + ] + ], + "anchor-contenteditable-navigate.html": [ + "e958f10df8d2624b48d1d48f4bd361abe6710edd", + [ + null, + { + "testdriver": true + } + ] + ], "button.html": [ "3c826a9754f6fddcd0ace10525a645bbe7f26805", [ @@ -377761,6 +377888,13 @@ null, {} ] + ], + "type.html": [ + "5817ae4d435ed473b2f9cbcb798a48bc8318e12e", + [ + null, + {} + ] ] }, "moving-between-documents": { @@ -463915,14 +464049,14 @@ }, "print": { "printcmd.py": [ - "e043056dd12aa5a6863041e0c4c9b8f5ae0cac1c", + "ff3de4e0af9ccc83e5cafccccef352258b7dc803", [ null, {} ] ], "user_prompts.py": [ - "2022796774bf76b93b5f0f844991c557c79df383", + "dc8a32e22db25a3ed4b30a54d864f94a057adf1f", [ null, {
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/subresource/font.py b/third_party/blink/web_tests/external/wpt/common/security-features/subresource/font.py index 706ee02..6e33dbb 100644 --- a/third_party/blink/web_tests/external/wpt/common/security-features/subresource/font.py +++ b/third_party/blink/web_tests/external/wpt/common/security-features/subresource/font.py
@@ -1,58 +1,66 @@ import os, sys, base64 +import six + from wptserve.utils import isomorphic_decode import importlib subresource = importlib.import_module("common.security-features.subresource.subresource") + +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + def generate_payload(request, server_data): data = (u'{"headers": %(headers)s}') % server_data if b"id" in request.GET: request.server.stash.put(request.GET[b"id"], data) # Simple base64 encoded .tff font - return base64.decodestring(b"AAEAAAANAIAAAwBQRkZUTU6u6MkAAAXcAAAAHE9TLzJWYW" - b"QKAAABWAAAAFZjbWFwAA8D7wAAAcAAAAFCY3Z0IAAhAnkA" - b"AAMEAAAABGdhc3D//wADAAAF1AAAAAhnbHlmCC6aTwAAAx" - b"QAAACMaGVhZO8ooBcAAADcAAAANmhoZWEIkAV9AAABFAAA" - b"ACRobXR4EZQAhQAAAbAAAAAQbG9jYQBwAFQAAAMIAAAACm" - b"1heHAASQA9AAABOAAAACBuYW1lehAVOgAAA6AAAAIHcG9z" - b"dP+uADUAAAWoAAAAKgABAAAAAQAAMhPyuV8PPPUACwPoAA" - b"AAAMU4Lm0AAAAAxTgubQAh/5wFeAK8AAAACAACAAAAAAAA" - b"AAEAAAK8/5wAWgXcAAAAAAV4AAEAAAAAAAAAAAAAAAAAAA" - b"AEAAEAAAAEAAwAAwAAAAAAAgAAAAEAAQAAAEAALgAAAAAA" - b"AQXcAfQABQAAAooCvAAAAIwCigK8AAAB4AAxAQIAAAIABg" - b"kAAAAAAAAAAAABAAAAAAAAAAAAAAAAUGZFZABAAEEAQQMg" - b"/zgAWgK8AGQAAAABAAAAAAAABdwAIQAAAAAF3AAABdwAZA" - b"AAAAMAAAADAAAAHAABAAAAAAA8AAMAAQAAABwABAAgAAAA" - b"BAAEAAEAAABB//8AAABB////wgABAAAAAAAAAQYAAAEAAA" - b"AAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - b"AAAAAAAAAAAAAAAAAAAhAnkAAAAqACoAKgBGAAAAAgAhAA" - b"ABKgKaAAMABwAusQEALzyyBwQA7TKxBgXcPLIDAgDtMgCx" - b"AwAvPLIFBADtMrIHBgH8PLIBAgDtMjMRIREnMxEjIQEJ6M" - b"fHApr9ZiECWAAAAwBk/5wFeAK8AAMABwALAAABNSEVATUh" - b"FQE1IRUB9AH0/UQDhPu0BRQB9MjI/tTIyP7UyMgAAAAAAA" - b"4ArgABAAAAAAAAACYATgABAAAAAAABAAUAgQABAAAAAAAC" - b"AAYAlQABAAAAAAADACEA4AABAAAAAAAEAAUBDgABAAAAAA" - b"AFABABNgABAAAAAAAGAAUBUwADAAEECQAAAEwAAAADAAEE" - b"CQABAAoAdQADAAEECQACAAwAhwADAAEECQADAEIAnAADAA" - b"EECQAEAAoBAgADAAEECQAFACABFAADAAEECQAGAAoBRwBD" - b"AG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADAAOA" - b"AgAE0AbwB6AGkAbABsAGEAIABDAG8AcgBwAG8AcgBhAHQA" - b"aQBvAG4AAENvcHlyaWdodCAoYykgMjAwOCBNb3ppbGxhIE" - b"NvcnBvcmF0aW9uAABNAGEAcgBrAEEAAE1hcmtBAABNAGUA" - b"ZABpAHUAbQAATWVkaXVtAABGAG8AbgB0AEYAbwByAGcAZQ" - b"AgADIALgAwACAAOgAgAE0AYQByAGsAQQAgADoAIAA1AC0A" - b"MQAxAC0AMgAwADAAOAAARm9udEZvcmdlIDIuMCA6IE1hcm" - b"tBIDogNS0xMS0yMDA4AABNAGEAcgBrAEEAAE1hcmtBAABW" - b"AGUAcgBzAGkAbwBuACAAMAAwADEALgAwADAAMAAgAABWZX" - b"JzaW9uIDAwMS4wMDAgAABNAGEAcgBrAEEAAE1hcmtBAAAA" - b"AgAAAAAAAP+DADIAAAABAAAAAAAAAAAAAAAAAAAAAAAEAA" - b"AAAQACACQAAAAAAAH//wACAAAAAQAAAADEPovuAAAAAMU4" - b"Lm0AAAAAxTgubQ==") + return decodebytes(b"AAEAAAANAIAAAwBQRkZUTU6u6MkAAAXcAAAAHE9TLzJWYW" + b"QKAAABWAAAAFZjbWFwAA8D7wAAAcAAAAFCY3Z0IAAhAnkA" + b"AAMEAAAABGdhc3D//wADAAAF1AAAAAhnbHlmCC6aTwAAAx" + b"QAAACMaGVhZO8ooBcAAADcAAAANmhoZWEIkAV9AAABFAAA" + b"ACRobXR4EZQAhQAAAbAAAAAQbG9jYQBwAFQAAAMIAAAACm" + b"1heHAASQA9AAABOAAAACBuYW1lehAVOgAAA6AAAAIHcG9z" + b"dP+uADUAAAWoAAAAKgABAAAAAQAAMhPyuV8PPPUACwPoAA" + b"AAAMU4Lm0AAAAAxTgubQAh/5wFeAK8AAAACAACAAAAAAAA" + b"AAEAAAK8/5wAWgXcAAAAAAV4AAEAAAAAAAAAAAAAAAAAAA" + b"AEAAEAAAAEAAwAAwAAAAAAAgAAAAEAAQAAAEAALgAAAAAA" + b"AQXcAfQABQAAAooCvAAAAIwCigK8AAAB4AAxAQIAAAIABg" + b"kAAAAAAAAAAAABAAAAAAAAAAAAAAAAUGZFZABAAEEAQQMg" + b"/zgAWgK8AGQAAAABAAAAAAAABdwAIQAAAAAF3AAABdwAZA" + b"AAAAMAAAADAAAAHAABAAAAAAA8AAMAAQAAABwABAAgAAAA" + b"BAAEAAEAAABB//8AAABB////wgABAAAAAAAAAQYAAAEAAA" + b"AAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + b"AAAAAAAAAAAAAAAAAAAhAnkAAAAqACoAKgBGAAAAAgAhAA" + b"ABKgKaAAMABwAusQEALzyyBwQA7TKxBgXcPLIDAgDtMgCx" + b"AwAvPLIFBADtMrIHBgH8PLIBAgDtMjMRIREnMxEjIQEJ6M" + b"fHApr9ZiECWAAAAwBk/5wFeAK8AAMABwALAAABNSEVATUh" + b"FQE1IRUB9AH0/UQDhPu0BRQB9MjI/tTIyP7UyMgAAAAAAA" + b"4ArgABAAAAAAAAACYATgABAAAAAAABAAUAgQABAAAAAAAC" + b"AAYAlQABAAAAAAADACEA4AABAAAAAAAEAAUBDgABAAAAAA" + b"AFABABNgABAAAAAAAGAAUBUwADAAEECQAAAEwAAAADAAEE" + b"CQABAAoAdQADAAEECQACAAwAhwADAAEECQADAEIAnAADAA" + b"EECQAEAAoBAgADAAEECQAFACABFAADAAEECQAGAAoBRwBD" + b"AG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADAAOA" + b"AgAE0AbwB6AGkAbABsAGEAIABDAG8AcgBwAG8AcgBhAHQA" + b"aQBvAG4AAENvcHlyaWdodCAoYykgMjAwOCBNb3ppbGxhIE" + b"NvcnBvcmF0aW9uAABNAGEAcgBrAEEAAE1hcmtBAABNAGUA" + b"ZABpAHUAbQAATWVkaXVtAABGAG8AbgB0AEYAbwByAGcAZQ" + b"AgADIALgAwACAAOgAgAE0AYQByAGsAQQAgADoAIAA1AC0A" + b"MQAxAC0AMgAwADAAOAAARm9udEZvcmdlIDIuMCA6IE1hcm" + b"tBIDogNS0xMS0yMDA4AABNAGEAcgBrAEEAAE1hcmtBAABW" + b"AGUAcgBzAGkAbwBuACAAMAAwADEALgAwADAAMAAgAABWZX" + b"JzaW9uIDAwMS4wMDAgAABNAGEAcgBrAEEAAE1hcmtBAAAA" + b"AgAAAAAAAP+DADIAAAABAAAAAAAAAAAAAAAAAAAAAAAEAA" + b"AAAQACACQAAAAAAAH//wACAAAAAQAAAADEPovuAAAAAMU4" + b"Lm0AAAAAxTgubQ==") def generate_report_headers_payload(request, server_data): stashed_data = request.server.stash.take(request.GET[b"id"])
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/widows-orphans-018.html b/third_party/blink/web_tests/external/wpt/css/css-break/widows-orphans-018.html new file mode 100644 index 0000000..80699c6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/widows-orphans-018.html
@@ -0,0 +1,65 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Fragmentation level 3 Test: 'orphans', 'widows' and content distribution in columns</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-break-3/#widows-orphans"> + <link rel="match" href="reference/widows-orphans-009-ref.html"> + + <!-- + Date created: December 16th 2020 + Last modified: December 16th 2020 + --> + + <!-- + + Bug 137367: Implement orphans and widows + https://bugzilla.mozilla.org/show_bug.cgi?id=137367 + + --> + + <meta name="flags" content=""> + <meta name="assert" content="When column boxes are filled sequentially, their content should be distributed and fragmented in accordance with the 'orphans' and the 'widows' declarations. In this test, the 3rd column box is going to get only 1 line box which is insufficient to honor 'widows: 3'. If a class B break point would occur between the '6' and the '7' so that 3 line boxes would be at the top of the 3rd column box, then this would leave only 2 line boxes in the 2nd column box and this would violate the 'orphans: 3' constraint. For that reason, a class B break must not happen in the 2nd column between the '6' and the '7'. On the other hand, a class B break can occur between the '7' and the '8' in the 2nd column box and doing so does not violate the 'orphans: 3' constraint."> + + <style> + div + { + border: orange solid 4px; + font-size: 20px; + line-height: 1.3; /* computes to 26px */ + height: 104px; /* Therefore, exactly 4 line boxes */ + margin-bottom: 1em; + padding: 0.5em; /* computes to 10px */ + width: 460px; + + columns: 4 auto; + + column-fill: auto; + + column-gap: 1em; /* computes to 20px */ + + column-rule: blue solid 4px; + } + + div#test + { + orphans: 3; + widows: 3; + } + + div#reference + { + orphans: 1; + widows: 1; + } + </style> + + <p>Test passes if the digits inside both orange-bordered rectangles are <strong>distributed identically</strong>. + + <div id="test">1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9</div> + + <div id="reference">1<br>2<br>3<br>4<br>5<br>6<br>7<br><br>8<br>9</div> + + <!-- Same as div#test except 1 extra br here ^ -->
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-intersection-observer.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-intersection-observer.html new file mode 100644 index 0000000..dcc1e6e7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-clip-margin-intersection-observer.html
@@ -0,0 +1,55 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Overflow: intersection observer with overflow-clip-margin</title> +<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#propdef-overflow-clip-margin"> +<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #clipped_container { + overflow: clip; + width: 100px; + height: 100px; + border: solid; + overflow-clip-margin: 50px; + } + #big_green_div { + position: relative; + width: 1000px; + height: 1000px; + background: green; + left: -200px; + top: -200px; + } + /* These values ensure the element is vertically offscreen. */ + .spacer { width: 150px; height: calc(100vh + 10px); } +</style> +<div class="spacer"></div> +<div id="clipped_container"> + <div id="big_green_div"></div> +</div> + +<script> +let t = async_test("ParentWithOverflowClipMargin"); +let options = { + threshold: 0, + rootMargin: '0px' +} +// The 'big_green_div' is initially on screen due to +// overflow-clip-margin of the parent. Once the observer is notified, the +// overflow-clip-margin is reduced so that 'big_green_div' is no longer +// on screen, and the observer should again be notified. +let gotIntersects = false; +let intersectionObserver = new IntersectionObserver((entries, observer) => { + t.step(function() { assert_equals(1, entries.length); }); + let entry = entries[0]; + if (!gotIntersects) { + t.step(function() { assert_true(entry.isIntersecting); }); + gotIntersects = true; + document.getElementById('clipped_container').style.overflowClipMargin = "0px"; + } else { + t.step(function() { assert_false(entry.isIntersecting); }); + t.done(); + }}, options); +intersectionObserver.observe(document.getElementById('big_green_div')); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-001.html new file mode 100644 index 0000000..e207f47 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-001.html
@@ -0,0 +1,64 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text Test: soft wrap opportunity at boundary between two characters</title> + + <!-- + + CSS3 Text, §5.1 Line breaking details, 7th bullet, 2nd sentence + https://www.w3.org/TR/css-text-3/#line-break-details + + " + For soft wrap opportunities defined by the boundary between + two characters, the white-space property on the nearest + common ancestor of the two characters controls breaking + " + + --> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#word-break-property"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#line-break-details"> + <link rel="match" href="reference/break-boundary-2-chars-001-ref.html"> + + <meta content="" name="flags"> + <meta content="This test checks that the word-break property does not apply to a run of text that is styled with 'white-space: pre' because the word-break property has no rendering effect in cases where lines of text are not allowed to break. Between the 'c' and 'x' and between the 'z' and 'd', there must be a line break because the 'white-space' declaration in effect in the nearest common ancestor of each of these pairs of two characters allows text wrapping." name="assert"> + + <style> + div + { + display: inline-block; + font-size: 32px; + margin-right: 5ch; + width: 0; + word-break: break-all; + } + + span + { + white-space: pre; + } + + div#first-sub-test + { + white-space: normal; + } + + div#second-sub-test + { + white-space: pre-wrap; + } + + div#third-sub-test + { + white-space: break-spaces; + } + + div#fourth-sub-test + { + white-space: pre-line; + } + </style> + + <div id="first-sub-test">abc<span>xyz</span>def</div><div id="second-sub-test">abc<span>xyz</span>def</div><div id="third-sub-test">abc<span>xyz</span>def</div><div id="fourth-sub-test">abc<span>xyz</span>def</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-002.html new file mode 100644 index 0000000..67c4cb7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/break-boundary-2-chars-002.html
@@ -0,0 +1,49 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Text Test: soft wrap opportunity at boundary between two characters</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + <link rel="help" href="https://www.w3.org/TR/css-text-3/#word-break-property"> + <link rel="match" href="reference/break-boundary-2-chars-002-ref.html"> + + <meta content="" name="flags"> + <meta content="The word-break property can only apply when the 'white-space' value allow text wrapping, when line breaking opportunities are preserved. Therefore, 'word-break: break-all' must not cause any text wrapping in both cases of this test. There must be no wrapping between the 'c' and the 'x' and there must be no wrapping between the 'z' and the 'd'." name="assert"> + + <!-- + + white-space values that DISallow text wrapping: + { pre , nowrap } + + --> + + <style> + div + { + display: inline-block; + font-size: 32px; + margin-right: 10ch; + width: 0; + word-break: normal; + } + + span + { + word-break: break-all; + } + + div#first-sub-test + { + white-space: pre; + } + + div#second-sub-test + { + white-space: nowrap; + } + </style> + + <div id="first-sub-test">abc<span>xyz</span>def</div> + + <div id="second-sub-test">abc<span>xyz</span>def</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-001-ref.html new file mode 100644 index 0000000..e0702af --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-001-ref.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + display: inline-block; + font-size: 32px; + margin-right: 5ch; + white-space: pre; + width: 0; + } + </style> + + <div>a<br>b<br>c<br>xyz<br>d<br>e<br>f</div><div>a<br>b<br>c<br>xyz<br>d<br>e<br>f</div><div>a<br>b<br>c<br>xyz<br>d<br>e<br>f</div><div>a<br>b<br>c<br>xyz<br>d<br>e<br>f</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-002-ref.html new file mode 100644 index 0000000..cd3ed33 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/reference/break-boundary-2-chars-002-ref.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + display: inline-block; + font-size: 32px; + margin-right: 10ch; + white-space: normal; + width: 0; + } + + </style> + + <div>abcxyzdef</div> + + <div>abcxyzdef</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006-manual.html b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006.html similarity index 89% rename from third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006-manual.html rename to third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006.html index 974abc0..4b034b2 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006-manual.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-006.html
@@ -7,6 +7,9 @@ <link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" /> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> <style> span[contenteditable] { border: 1px solid black; @@ -42,6 +45,8 @@ assert_equals(getComputedStyle(el).outlineColor, "rgb(0, 100, 0)"); t.done(); })); + + test_driver.click(el); }, "Focus should always match :focus-visible on content editable divs"); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008-manual.html b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008.html similarity index 83% rename from third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008-manual.html rename to third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008.html index 53306a9..75f676f 100644 --- a/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008-manual.html +++ b/third_party/blink/web_tests/external/wpt/css/selectors/focus-visible-008.html
@@ -7,6 +7,9 @@ <link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo" /> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> <style> :focus-visible { outline: darkgreen auto 5px; @@ -44,6 +47,12 @@ el.focus(); }); } + + const tab_key = '\ue004'; + const enter_key = '\uE007'; + test_driver.send_keys(el, tab_key).then(() => { + test_driver.send_keys(el, enter_key); + }); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-referrer-override.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-referrer-override.any.js new file mode 100644 index 0000000..56e55d7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-referrer-override.any.js
@@ -0,0 +1,104 @@ +// META: timeout=long +// META: script=/common/utils.js +// META: script=../resources/utils.js +// META: script=/common/get-host-info.sub.js + +function getExpectation(expectations, init, initScenario, redirectPolicy, redirectScenario) { + let policies = [ + expectations[initPolicy][initScenario], + expectations[redirectPolicy][redirectScenario] + ]; + + if (policies.includes("omitted")) { + return null; + } else if (policies.includes("origin")) { + return referrerOrigin; + } else { + // "stripped-referrer" + return referrerUrl; + } +} + +function testReferrerAfterRedirection(desc, redirectUrl, redirectLocation, referrerPolicy, redirectReferrerPolicy, expectedReferrer) { + var url = redirectUrl; + var urlParameters = "?location=" + encodeURIComponent(redirectLocation); + var description = desc + ", " + referrerPolicy + " init, " + redirectReferrerPolicy + " redirect header "; + + if (redirectReferrerPolicy) + urlParameters += "&redirect_referrerpolicy=" + redirectReferrerPolicy; + + var requestInit = {"redirect": "follow", "referrerPolicy": referrerPolicy}; + promise_test(function(test) { + return fetch(url + urlParameters, requestInit).then(function(response) { + assert_equals(response.status, 200, "Inspect header response's status is 200"); + assert_equals(response.headers.get("x-request-referer"), expectedReferrer ? expectedReferrer : null, "Check referrer header"); + }); + }, description); +} + +var referrerOrigin = get_host_info().HTTP_ORIGIN + "/"; +var referrerUrl = location.href; + +var redirectUrl = RESOURCES_DIR + "redirect.py"; +var locationUrl = get_host_info().HTTP_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?headers=referer"; +var crossLocationUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=referer"; + +var expectations = { + "no-referrer": { + "same-origin": "omitted", + "cross-origin": "omitted" + }, + "no-referrer-when-downgrade": { + "same-origin": "stripped-referrer", + "cross-origin": "stripped-referrer" + }, + "origin": { + "same-origin": "origin", + "cross-origin": "origin" + }, + "origin-when-cross-origin": { + "same-origin": "stripped-referrer", + "cross-origin": "origin", + }, + "same-origin": { + "same-origin": "stripped-referrer", + "cross-origin": "omitted" + }, + "strict-origin": { + "same-origin": "origin", + "cross-origin": "origin" + }, + "strict-origin-when-cross-origin": { + "same-origin": "stripped-referrer", + "cross-origin": "origin" + }, + "unsafe-url": { + "same-origin": "stripped-referrer", + "cross-origin": "stripped-referrer" + } +}; + +for (var initPolicy in expectations) { + for (var redirectPolicy in expectations) { + + // Redirect to same-origin URL + testReferrerAfterRedirection( + "Same origin redirection", + redirectUrl, + locationUrl, + initPolicy, + redirectPolicy, + getExpectation(expectations, initPolicy, "same-origin", redirectPolicy, "same-origin")); + + // Redirect to cross-origin URL + testReferrerAfterRedirection( + "Cross origin redirection", + redirectUrl, + crossLocationUrl, + initPolicy, + redirectPolicy, + getExpectation(expectations, initPolicy, "same-origin", redirectPolicy, "cross-origin")); + } +} + +done();
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/404-response-with-actual-image-data.py b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/404-response-with-actual-image-data.py index 3e2d9917..e98cf03 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/404-response-with-actual-image-data.py +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/404-response-with-actual-image-data.py
@@ -1,3 +1,10 @@ import base64 +import six + +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + def main(req, res): - return 404, [(b'Content-Type', b'image/png')], base64.decodestring(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMGjBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=") + return 404, [(b'Content-Type', b'image/png')], decodebytes(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMGjBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=")
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-active-contenteditable.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-active-contenteditable.html new file mode 100644 index 0000000..88a9a35 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-active-contenteditable.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<link rel="help" href="http://crbug.com/1007941"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<!-- This behavior is not explicitly specified. --> + +<a id=anchorid href="nonexistant">anchor</a> + +<script> +anchorid.addEventListener('mousedown', () => { + anchorid.contentEditable = true; +}); + +promise_test(async () => { + await test_driver.click(anchorid); + assert_equals(document.querySelector(':active'), null); +}, 'Anchor elements should not stay :active when contentEditable is enabled.'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html new file mode 100644 index 0000000..e958f10 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/anchor-contenteditable-navigate.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<!-- This behavior is not explicitly specified. --> + +<a id=anchorid href="javascript:window.anchornavigated = true;">anchor</a> + +<script> +promise_test(async () => { + window.anchornavigated = false; + + anchorid.contentEditable = true; + await test_driver.click(anchorid); + + assert_false(window.anchornavigated, "Anchor's javascript: url was run."); + +}, 'Anchor elements should not be able to navigate if they have contentEditable.'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/type.html b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/type.html new file mode 100644 index 0000000..5817ae4d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/module/type.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<title>Type attribute of module scripts</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +window.t1 = async_test('type="module"'); +window.t2 = async_test('type="MODULE"'); +window.t3 = async_test('type="Module"'); +window.t4 = async_test('type="module "'); +window.t5 = async_test('type=" module"'); +</script> +<script type="module">window.t1.done();</script> +<script type="MODULE">window.t2.done();</script> +<script type="Module">window.t3.done();</script> +<script type="module ">window.t4.unreached_func('Unexpectedly evaluated');</script> +<script type=" module">window.t5.unreached_func('Unexpectedly evaluated');</script> +<script type="module"> +window.t1.unreached_func('Unexpectedly not evaluated')(); +window.t2.unreached_func('Unexpectedly not evaluated')(); +window.t3.unreached_func('Unexpectedly not evaluated')(); +window.t4.done(); +window.t5.done(); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py index a6cc9b12..8822f32 100644 --- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py +++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py
@@ -2,8 +2,15 @@ import json import os +import six + from wptserve.utils import isomorphic_decode, isomorphic_encode +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + def main(request, response): headers = [] headers.append((b'X-ServiceWorker-ServerHeader', b'SetInTheServer')) @@ -29,9 +36,9 @@ if b"PNGIMAGE" in request.GET: headers.append((b"Content-Type", b"image/png")) - body = base64.decodestring(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1B" - b"AACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMG" - b"jBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=") + body = decodebytes(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1B" + b"AACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMG" + b"jBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=") return headers, body if b"VIDEO" in request.GET:
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py index ca93004b..f68312f 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py
@@ -43,7 +43,7 @@ server_config['ports']['ws'] + server_config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(test_type, server_config, + executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, **kwargs) del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"]
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py index 27a09f5..3cde248b 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py
@@ -43,7 +43,7 @@ server_config['ports']['ws'] + server_config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(test_type, server_config, + executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, **kwargs) del executor_kwargs["capabilities"]["goog:chromeOptions"]["prefs"]
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py index 607b7835..d7e3e210 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py
@@ -44,7 +44,7 @@ server_config['ports']['ws'] + server_config['ports']['wss'] )) - executor_kwargs = chrome_executor_kwargs(test_type, server_config, + executor_kwargs = chrome_executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data, **kwargs) # Remove unsupported options on mobile.
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py index 1fa0bce..9104fed 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -189,7 +189,10 @@ "verify": kwargs["verify"], "headless": kwargs.get("headless", False) or "MOZ_HEADLESS" in os.environ, "sw-e10s": True, - "fission": kwargs.get("enable_fission") or get_bool_pref("fission.autostart")} + "fission": kwargs.get("enable_fission") or get_bool_pref("fission.autostart"), + "sessionHistoryInParent": (kwargs.get("enable_fission") or + get_bool_pref("fission.autostart") or + get_bool_pref("fission.sessionHistoryInParent"))} # The value of `sw-e10s` defaults to whether the "parent_intercept" # implementation is enabled for the current build. This value, however,
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/print/printcmd.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/print/printcmd.py index e043056d..ff3de4e 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/print/printcmd.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/print/printcmd.py
@@ -2,10 +2,14 @@ import pytest -from six import ensure_binary +import six from tests.support.asserts import assert_error, assert_success +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) def do_print(session, options): return session.transport.send( @@ -26,7 +30,7 @@ def test_no_browsing_context(session, closed_frame): response = do_print(session, {}) value = assert_success(response) - pdf = base64.decodestring(ensure_binary(value)) + pdf = decodebytes(six.ensure_binary(value)) assert_pdf(pdf) @@ -39,7 +43,7 @@ "shrinkToFit": False }) value = assert_success(response) - pdf = base64.decodestring(ensure_binary(value)) + pdf = decodebytes(six.ensure_binary(value)) # TODO: Test that the output is reasonable assert_pdf(pdf)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/print/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/print/user_prompts.py index 2022796..dc8a32e 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/print/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/print/user_prompts.py
@@ -3,12 +3,17 @@ import pytest -from six import ensure_binary +import six from tests.support.asserts import assert_dialog_handled, assert_error, assert_success from .printcmd import do_print, assert_pdf +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + @pytest.fixture def check_user_prompt_closed_without_exception(session, create_dialog, inline): def check_user_prompt_closed_without_exception(dialog_type, retval): @@ -19,7 +24,7 @@ response = do_print(session, {}) value = assert_success(response) - pdf = base64.decodestring(ensure_binary(value)) + pdf = decodebytes(six.ensure_binary(value)) assert_dialog_handled(session, expected_text=dialog_type, expected_retval=retval) assert_pdf(pdf)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/asserts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/asserts.py index 3c3d677..7afa22fd 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/asserts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/asserts.py
@@ -2,11 +2,16 @@ import imghdr import struct -from six import ensure_binary, text_type +import six from webdriver import Element, NoSuchAlertException, WebDriverException +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + # WebDriver specification ID: dfn-error-response-data errors = { "element click intercepted": 400, @@ -52,8 +57,8 @@ assert response.status == errors[error_code] assert "value" in response.body assert response.body["value"]["error"] == error_code - assert isinstance(response.body["value"]["message"], text_type) - assert isinstance(response.body["value"]["stacktrace"], text_type) + assert isinstance(response.body["value"]["message"], six.text_type) + assert isinstance(response.body["value"]["stacktrace"], six.text_type) assert_response_headers(response.headers) @@ -214,6 +219,6 @@ def assert_png(screenshot): """Test that screenshot is a Base64 encoded PNG file.""" - image = base64.decodestring(ensure_binary(screenshot)) + image = decodebytes(six.ensure_binary(screenshot)) mime_type = imghdr.what("", image) assert mime_type == "png", "Expected image to be PNG, but it was {}".format(mime_type)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/image.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/image.py index 6149ccc..705f266 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/image.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/image.py
@@ -2,13 +2,18 @@ import math import struct -from six import ensure_binary +import six from tests.support.asserts import assert_png +def decodebytes(s): + if six.PY3: + return base64.decodebytes(six.ensure_binary(s)) + return base64.decodestring(s) + def png_dimensions(screenshot): assert_png(screenshot) - image = base64.decodestring(ensure_binary(screenshot)) + image = decodebytes(six.ensure_binary(screenshot)) width, height = struct.unpack(">LL", image[16:24]) return int(width), int(height)
diff --git a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-006-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-006-manual-automation.js deleted file mode 100644 index 6e6fc92..0000000 --- a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-006-manual-automation.js +++ /dev/null
@@ -1,5 +0,0 @@ -importAutomationScript('/pointerevents/pointerevent_common_input.js'); - -function inject_input() { - return mouseClickInTarget("#el"); -};
diff --git a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-008-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-008-manual-automation.js deleted file mode 100644 index 154e9a9..0000000 --- a/third_party/blink/web_tests/external/wpt_automation/css/selectors/focus-visible-008-manual-automation.js +++ /dev/null
@@ -1,7 +0,0 @@ -importAutomationScript('/input-events/inputevent_common_input.js'); - -function inject_input() { - return keyDown("Tab").then(() => { - return keyDown("Enter"); - }); -};
diff --git a/third_party/blink/web_tests/fast/forms/calendar-picker/date-picker-input-change-events.html b/third_party/blink/web_tests/fast/forms/calendar-picker/date-picker-input-change-events.html index 115aaafa..9ec8c5f 100644 --- a/third_party/blink/web_tests/fast/forms/calendar-picker/date-picker-input-change-events.html +++ b/third_party/blink/web_tests/fast/forms/calendar-picker/date-picker-input-change-events.html
@@ -41,7 +41,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0); + }, 1); }); }); }, "Date picker: Test input and change event firing when popup value is modified"); @@ -76,7 +76,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 0, 'No change event should fire if popup was submitted with value still matching the original.'); resolve(); - }, 0); + }, 1); }); }); }, "Date picker: Test that change does not fire if popup value is modified and then restored to original value.");
diff --git a/third_party/blink/web_tests/fast/forms/color/color-picker-events-change.html b/third_party/blink/web_tests/fast/forms/color/color-picker-events-change.html index 4eb293f..cc12af8 100644 --- a/third_party/blink/web_tests/fast/forms/color/color-picker-events-change.html +++ b/third_party/blink/web_tests/fast/forms/color/color-picker-events-change.html
@@ -43,7 +43,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0) + }, 1) }); }); }, "Color picker: Test firing change and input events");
diff --git a/third_party/blink/web_tests/fast/forms/datetimelocal/datetimelocal-picker-input-change-events.html b/third_party/blink/web_tests/fast/forms/datetimelocal/datetimelocal-picker-input-change-events.html index d16be82..0b7b0984 100644 --- a/third_party/blink/web_tests/fast/forms/datetimelocal/datetimelocal-picker-input-change-events.html +++ b/third_party/blink/web_tests/fast/forms/datetimelocal/datetimelocal-picker-input-change-events.html
@@ -41,7 +41,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0); + }, 1); }); }); }, "Test input and change event firing when popup value is modified"); @@ -76,7 +76,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 0, 'No change event should fire if popup was submitted with value still matching the original.'); resolve(); - }, 0); + }, 1); }); }); }, "Test that change does not fire if popup value is modified and then restored to original value.");
diff --git a/third_party/blink/web_tests/fast/forms/month/month-picker-input-change-events.html b/third_party/blink/web_tests/fast/forms/month/month-picker-input-change-events.html index fc1990e38b..b84e25f2 100644 --- a/third_party/blink/web_tests/fast/forms/month/month-picker-input-change-events.html +++ b/third_party/blink/web_tests/fast/forms/month/month-picker-input-change-events.html
@@ -41,7 +41,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0); + }, 1); }); }); }, "Month picker: Test input and change event firing when popup value is modified"); @@ -76,7 +76,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 0, 'No change event should fire if popup was submitted with value still matching the original.'); resolve(); - }, 0); + }, 1); }); }); }, "Month picker: Test that change does not fire if popup value is modified and then restored to original value.");
diff --git a/third_party/blink/web_tests/fast/forms/time/time-picker-input-change-events.html b/third_party/blink/web_tests/fast/forms/time/time-picker-input-change-events.html index e80b56e..885a0ef 100644 --- a/third_party/blink/web_tests/fast/forms/time/time-picker-input-change-events.html +++ b/third_party/blink/web_tests/fast/forms/time/time-picker-input-change-events.html
@@ -41,7 +41,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0); + }, 1); }); }); }, "Test input and change event firing when popup value is modified"); @@ -76,7 +76,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 0, 'No change event should fire if popup was submitted with value still matching the original.'); resolve(); - }, 0); + }, 1); }); }); }, "Test that change does not fire if popup value is modified and then restored to original value.");
diff --git a/third_party/blink/web_tests/fast/forms/week/week-picker-input-change-events.html b/third_party/blink/web_tests/fast/forms/week/week-picker-input-change-events.html index b54b34b9..f26e3667 100644 --- a/third_party/blink/web_tests/fast/forms/week/week-picker-input-change-events.html +++ b/third_party/blink/web_tests/fast/forms/week/week-picker-input-change-events.html
@@ -41,7 +41,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 1, 'Change event should have fired (once) asynchronously after closing popup.'); resolve(); - }, 0); + }, 1); }); }); }, "Week picker: Test input and change event firing when popup value is modified"); @@ -76,7 +76,7 @@ window.setTimeout(() => { assert_equals(changeEventCount, 0, 'No change event should fire if popup was submitted with value still matching the original.'); resolve(); - }, 0); + }, 1); }); }); }, "Week picker: Test that change does not fire if popup value is modified and then restored to original value.");
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/contents-opaque/filter-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/contents-opaque/filter-expected.txt index 0b480a6..643a72f 100644 --- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/contents-opaque/filter-expected.txt +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/compositing/contents-opaque/filter-expected.txt
@@ -8,8 +8,7 @@ }, { "name": "LayoutBlockFlow DIV class='composited container-box'", - "position": [-28, -28], - "bounds": [157, 157], + "bounds": [100, 100], "transform": 1 }, {
diff --git a/third_party/blink/web_tests/http/tests/history/back-during-beforeunload.html b/third_party/blink/web_tests/http/tests/history/back-during-beforeunload.html index a39f1c5..fbc95760 100644 --- a/third_party/blink/web_tests/http/tests/history/back-during-beforeunload.html +++ b/third_party/blink/web_tests/http/tests/history/back-during-beforeunload.html
@@ -15,7 +15,7 @@ setTimeout(function() { history.pushState("", "", "#"); location = "we-wont-actually-go-here.html"; -}, 0); +}, 1); </script> Ensure we ignore back/forward navigations during beforeunload. </body>
diff --git a/third_party/blink/web_tests/http/tests/navigation/resources/frame-with-anchor-same-origin.html b/third_party/blink/web_tests/http/tests/navigation/resources/frame-with-anchor-same-origin.html index dd97c0c1..ed2a49c0 100644 --- a/third_party/blink/web_tests/http/tests/navigation/resources/frame-with-anchor-same-origin.html +++ b/third_party/blink/web_tests/http/tests/navigation/resources/frame-with-anchor-same-origin.html
@@ -11,7 +11,7 @@ shouldBeTrue('document.scrollingElement.scrollTop > 0'); shouldBeTrue('document.scrollingElement.scrollLeft > 0'); finishJSTest(); - }, 0); + }, 1); } var jsTestIsAsync = true; </script>
diff --git a/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js b/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js index ef6771b..8d18d26 100644 --- a/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js +++ b/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js
@@ -55,7 +55,7 @@ callback(); if (autoNotifyDone) testRunner.notifyDone(); - }, 0); + }, 1); }); }
diff --git a/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-insecure-plugin.html b/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-insecure-plugin.html index 5943f20..87b5c2b 100644 --- a/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-insecure-plugin.html +++ b/third_party/blink/web_tests/http/tests/security/mixedContent/resources/frame-with-insecure-plugin.html
@@ -5,7 +5,7 @@ internals.updateLayoutAndRunPostLayoutTasks(document); if (window.testRunner) testRunner.notifyDone(); - }, 0); + }, 1); } </script> <object name='plugin' type='application/x-blink-test-plugin'>
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/resources/fetch-event-async-add-test-worker.js b/third_party/blink/web_tests/http/tests/serviceworker/resources/fetch-event-async-add-test-worker.js index 2edf3e2..f7e3d0bc 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/resources/fetch-event-async-add-test-worker.js +++ b/third_party/blink/web_tests/http/tests/serviceworker/resources/fetch-event-async-add-test-worker.js
@@ -4,4 +4,4 @@ setTimeout(() => { self.addEventListener('fetch', eventHandler); -}, 0); +}, 1);
diff --git a/third_party/blink/web_tests/media/media-controls.js b/third_party/blink/web_tests/media/media-controls.js index 770a0cde..01ceaea 100644 --- a/third_party/blink/web_tests/media/media-controls.js +++ b/third_party/blink/web_tests/media/media-controls.js
@@ -481,7 +481,7 @@ function hoverMuteButton(video, func) { // Wait for hover timer fires - const delayedCallback = function() { setTimeout(func); }; + const delayedCallback = function() { setTimeout(func, 1); }; const muteBtn = muteButton(video); hoverOverControl(muteBtn, delayedCallback); }
diff --git a/third_party/blink/web_tests/platform/linux/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/platform/linux/compositing/overflow/mask-with-filter-expected.png deleted file mode 100644 index f1bbf44..0000000 --- a/third_party/blink/web_tests/platform/linux/compositing/overflow/mask-with-filter-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png deleted file mode 100644 index f1bbf44..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/platform/mac/compositing/overflow/mask-with-filter-expected.png new file mode 100644 index 0000000..571c514 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/compositing/overflow/mask-with-filter-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/platform/win/compositing/overflow/mask-with-filter-expected.png index 5ca2da0..bcbe48c 100644 --- a/third_party/blink/web_tests/platform/win/compositing/overflow/mask-with-filter-expected.png +++ b/third_party/blink/web_tests/platform/win/compositing/overflow/mask-with-filter-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png deleted file mode 100644 index 5ca2da0..0000000 --- a/third_party/blink/web_tests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/resources/run-after-layout-and-paint.js b/third_party/blink/web_tests/resources/run-after-layout-and-paint.js index ef6771b..8d18d26 100644 --- a/third_party/blink/web_tests/resources/run-after-layout-and-paint.js +++ b/third_party/blink/web_tests/resources/run-after-layout-and-paint.js
@@ -55,7 +55,7 @@ callback(); if (autoNotifyDone) testRunner.notifyDone(); - }, 0); + }, 1); }); }
diff --git a/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png b/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png deleted file mode 100644 index 2b12f00..0000000 --- a/third_party/blink/web_tests/virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium index 7bb37ec..f75c27f 100644 --- a/third_party/freetype/README.chromium +++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@ Name: FreeType URL: http://www.freetype.org/ -Version: VER-2-10-4-50-g84b3616c9 -Revision: 84b3616c94f48726c596ead4150218d4431b3412 +Version: VER-2-10-4-52-g7bdf386e7 +Revision: 7bdf386e758cb7c01392e625f4d723e5abb3f9a6 CPEPrefix: cpe:/a:freetype:freetype:2.10.1 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses"
diff --git a/third_party/glslang/DIR_METADATA b/third_party/glslang/DIR_METADATA deleted file mode 100644 index 348e542..0000000 --- a/third_party/glslang/DIR_METADATA +++ /dev/null
@@ -1,4 +0,0 @@ -monorail { - component: "Internals>GPU>Internals" -} -team_email: "graphics-dev@chromium.org"
diff --git a/third_party/glslang/LICENSE b/third_party/glslang/LICENSE deleted file mode 100644 index 8b2e821..0000000 --- a/third_party/glslang/LICENSE +++ /dev/null
@@ -1,25 +0,0 @@ -Copyright (c) 2015-2016 The Khronos Group Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. - -MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS -KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS -SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT - https://www.khronos.org/registry/ - -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/third_party/glslang/OWNERS b/third_party/glslang/OWNERS deleted file mode 100644 index ed07d05f..0000000 --- a/third_party/glslang/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -dsinclair@chromium.org -vmiura@chromium.org
diff --git a/third_party/glslang/README.chromium b/third_party/glslang/README.chromium deleted file mode 100644 index f22f536..0000000 --- a/third_party/glslang/README.chromium +++ /dev/null
@@ -1,15 +0,0 @@ -Name: Khronos reference front-end for GLSL and ESSL -Short Name: glslang -URL: https://github.com/KhronosGroup/glslang -Version: Unknown -Security Critical: yes -License: MIT -License File: LICENSE - -Description: -An OpenGL and OpenGL ES shader front end and validator. - -Local Modifications: -Added OWNERS, README.chromium. -Ported build rules from CMake to GN. -5/13/2016 - Updated GN build rules to include new files added in repository.
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 8bb3672..d9c57b2 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby-connections -Version: 03db3f121129434cd1298c098b6d14444e488c01 +Version: 183aed7f6cc2bc86c4deac1037b9873b567b4a52 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/spirv-cross/DIR_METADATA b/third_party/spirv-cross/DIR_METADATA deleted file mode 100644 index e353adf..0000000 --- a/third_party/spirv-cross/DIR_METADATA +++ /dev/null
@@ -1,4 +0,0 @@ -monorail: { - component: "Internals>GPU>Internals" -} -team_email: "graphics-dev@chromium.org"
diff --git a/third_party/spirv-cross/OWNERS b/third_party/spirv-cross/OWNERS deleted file mode 100644 index b375c58..0000000 --- a/third_party/spirv-cross/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -cwallez@chromium.org -dsinclair@chromium.org
diff --git a/third_party/spirv-cross/README.chromium b/third_party/spirv-cross/README.chromium deleted file mode 100644 index 4b96bf38..0000000 --- a/third_party/spirv-cross/README.chromium +++ /dev/null
@@ -1,12 +0,0 @@ -Name: SPIRV-Cross -Short Name: SPIRV-Cross -URL: https://github.com/KhronosGroup/SPIRV-Cross -Version: Unknown -Security Critical: yes -License: Apache 2.0 -License File: spirv-cross/LICENSE - -Description: -A translator from SPIR-V bytecode to other shading languages like GLSL, HLSL -and MSL. This project is not secure (yet!) and should only be used for -prototyping, and not shipped to users.
diff --git a/third_party/spirv-headers/DIR_METADATA b/third_party/spirv-headers/DIR_METADATA deleted file mode 100644 index e353adf..0000000 --- a/third_party/spirv-headers/DIR_METADATA +++ /dev/null
@@ -1,4 +0,0 @@ -monorail: { - component: "Internals>GPU>Internals" -} -team_email: "graphics-dev@chromium.org"
diff --git a/third_party/spirv-headers/LICENSE b/third_party/spirv-headers/LICENSE deleted file mode 100644 index d645695..0000000 --- a/third_party/spirv-headers/LICENSE +++ /dev/null
@@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.
diff --git a/third_party/spirv-headers/OWNERS b/third_party/spirv-headers/OWNERS deleted file mode 100644 index d417f07..0000000 --- a/third_party/spirv-headers/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -dsinclair@chromium.org
diff --git a/third_party/spirv-headers/README.chromium b/third_party/spirv-headers/README.chromium deleted file mode 100644 index f7df74e..0000000 --- a/third_party/spirv-headers/README.chromium +++ /dev/null
@@ -1,14 +0,0 @@ -Name: SPIR-V Headers -Short Name: spirv-headers -URL: https://github.com/KhronosGroup/SPIRV-Headers.git -Version: unknown -Security Critical: yes -License: MIT -License File: LICENSE - -Description: -This repository contains machine-readable files from the SPIR-V Registry. This includes: - -* Header files for various languages. -* JSON files describing the grammar for the SPIR-V core instruction set, and for the GLSL.std.450 extended instruction set. -* The XML registry file.
diff --git a/tools/clang/pylib/clang/compile_db.py b/tools/clang/pylib/clang/compile_db.py index 2502810c..2966ea9 100755 --- a/tools/clang/pylib/clang/compile_db.py +++ b/tools/clang/pylib/clang/compile_db.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -10,6 +10,7 @@ import re import sys import subprocess +import shutil _RSP_RE = re.compile(r' (@(.+?\.rsp)) ') @@ -140,8 +141,11 @@ # TODO(dcheng): Ensure that clang is enabled somehow. # First, generate the compile database. + ninja_path = GetNinjaPath() + if not os.path.exists(ninja_path): + ninja_path = shutil.which("ninja") json_compile_db = subprocess.check_output( - [GetNinjaPath(), '-C', path] + targets + + [ninja_path, '-C', path] + targets + ['-t', 'compdb', 'cc', 'cxx', 'objc', 'objcxx']) return json.loads(json_compile_db)
diff --git a/tools/clang/scripts/generate_compdb.py b/tools/clang/scripts/generate_compdb.py index f981c36a..d532953 100755 --- a/tools/clang/scripts/generate_compdb.py +++ b/tools/clang/scripts/generate_compdb.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index b393e06f..0712027b 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -226,7 +226,8 @@ "META": {"sizes": {"messages": [50]}, "join": 2}, # Relies on src-internal. "messages": [2015], }, - "chrome/browser/resources/bluetooth_internals/resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/bluetooth_internals/resources.grd": { + "META": {"sizes": {"includes": [30],}}, "includes": [2020], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog_resources.grd": {
diff --git a/tools/licenses.py b/tools/licenses.py index ef74fc6..c548ac8f 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -163,12 +163,6 @@ "URL": "http://code.google.com/p/angleproject/", "License": "BSD", }, - os.path.join('third_party', 'angle', 'third_party', 'vulkan-headers'): { - "Name": "Vulkan-Headers", - "URL": "https://github.com/KhronosGroup/Vulkan-Headers", - "License": "Apache 2.0", - "License File": "src/LICENSE.txt", - }, os.path.join('third_party', 'cros_system_api'): { "Name": "Chromium OS system API", "URL": "http://www.chromium.org/chromium-os",
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index d2f5be4..9ebb137d 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -875,6 +875,11 @@ args_contents = ReplaceImports(args_contents) args_dict = gn_helpers.FromGNArgs(args_contents) + # Re-add the quotes around strings so they show up as they would in the + # args.gn file. + for k, v in args_dict.items(): + if isinstance(v, str): + args_dict[k] = '"%s"' % v return ' '.join(['%s=%s' % (k, v) for (k, v) in args_dict.items()]) def Lookup(self):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 41bc465..87302c1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -41860,6 +41860,11 @@ <int value="3" label="Gaia ID mismatch"/> </enum> +<enum name="LocationPermissionsFirstRunModalIOSEnum"> + <int value="0" label="iOS native system location prompt shown"/> + <int value="1" label="No system prompt shown, modal dismissed"/> +</enum> + <enum name="LocationPermissionsIOSUI"> <int value="0" label="First Run Location Prompt Not Shown"/> <int value="1" label="First Run Location Permissions Modal Shown"/> @@ -42189,6 +42194,7 @@ <int value="-1972219399" label="NTPSaveToOffline:enabled"/> <int value="-1971086581" label="print-scaling"/> <int value="-1969636234" label="OmniboxRefinedFocusState:disabled"/> + <int value="-1966445414" label="StylusBatteryStatus:disabled"/> <int value="-1965587041" label="omnibox-tab-switch-suggestions"/> <int value="-1964261747" label="WebVrVsyncAlign:disabled"/> <int value="-1963838301" @@ -42570,6 +42576,7 @@ <int value="-1621963267" label="EnableAssistantLauncherUI:enabled"/> <int value="-1620804800" label="NoScriptPreviews:disabled"/> <int value="-1620568042" label="FeaturePolicy:disabled"/> + <int value="-1620230777" label="StylusBatteryStatus:enabled"/> <int value="-1620046590" label="UseMediaHistoryStore:enabled"/> <int value="-1619757314" label="touch-scrolling-mode"/> <int value="-1619146163" label="OverrideSitePrefsForHrefTranslate:disabled"/> @@ -46566,6 +46573,9 @@ <int value="0" label="No login"/> <int value="1" label="OAuth login"/> <int value="2" label="OAuth first time login flow"/> + <int value="3" label="Password entered login"/> + <int value="4" label="Preloaded password sites list"/> + <int value="5" label="Field trial logged-in site"/> </enum> <enum name="LoginFailureReason"> @@ -50777,6 +50787,19 @@ <int value="7" label="WiFiLAN error"/> </enum> +<enum name="NearbyShareTransferFinalStatus"> + <int value="0" label="Complete"/> + <int value="1" label="Unknown"/> + <int value="2" label="Awaiting remote acceptance failed"/> + <int value="3" label="Failed"/> + <int value="4" label="Rejected"/> + <int value="5" label="Cancelled"/> + <int value="6" label="Timed out"/> + <int value="7" label="Media unavailable"/> + <int value="8" label="Not enough space"/> + <int value="9" label="Unsupported attachment type"/> +</enum> + <enum name="NearbyShareTransferNotCompletedReason"> <int value="0" label="Unknown"/> <int value="1" label="Awaiting remote acceptance failed"/> @@ -57788,6 +57811,13 @@ <int value="3" label="Warning string with org name"/> </enum> +<enum name="PasswordProtectionReferringAppSource"> + <int value="0" label="Source unspecified"/> + <int value="1" label="Known app id"/> + <int value="2" label="Unknown app id"/> + <int value="3" label="Activity referrer"/> +</enum> + <enum name="PasswordProtectionRequestOutcome"> <int value="0" label="Unknown"/> <int value="1" label="Succeeded"/> @@ -66579,6 +66609,7 @@ <int value="5" label="SYNC_ADD_FAIL_OTHER_ERROR"/> <int value="6" label="SYNC_UPDATE_SUCCESS"/> <int value="7" label="SYNC_UPDATE_CONVERTED_TO_ADD"/> + <int value="8" label="MIGRATE_SAFE_FOR_AUTOREPLACE_PLAY_API_ENGINE"/> </enum> <enum name="SearchWidgetUseInfo">
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml index a7938fe..88ea3b2 100644 --- a/tools/metrics/histograms/histograms_xml/android/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -274,12 +274,13 @@ <owner>boliu@chromium.org</owner> <summary> Measures time from {type} child process starts to right before main. Only - recorded on Android N+. + recorded on Android N+. Zygote measurements are recorded on Q+. </summary> <token key="type"> - <variant name=".All" summary="all"/> + <variant name=".All" summary="all (excluding zygote)"/> <variant name=".Isolated" summary="isolated"/> <variant name=".NotIsolated" summary="non-isolated"/> + <variant name=".Zygote" summary="app zygote"/> </token> </histogram> @@ -509,6 +510,9 @@ <histogram name="Android.DefaultBrowserPromo.IntentReceivedFromDisambiguationSheet" enum="AndroidDefaultBrowserPromoOutcomeType" expires_after="2021-03-26"> + <obsolete> + Removed Dec 2020; experiment is done and the data isn't useful. + </obsolete> <owner>lazzzis@google.com</owner> <owner>twellington@chromium.org</owner> <owner>pavely@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml index 4470b0a..641220e 100644 --- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -418,6 +418,15 @@ </summary> </histogram> +<histogram name="IOS.LocationPermissions.FirstRunModal.Interaction" + enum="LocationPermissionsFirstRunModalIOSEnum" expires_after="2021-05-31"> + <owner>thegreenfrog@chromium.org</owner> + <owner>rohitrao@chromium.org</owner> + <summary> + The user engagement of the Location permissions first run modal. + </summary> +</histogram> + <histogram name="IOS.LocationPermissionsUI" enum="LocationPermissionsIOSUI" expires_after="2021-05-31"> <owner>thegreenfrog@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 322ecb3..7aa55e3 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -3105,6 +3105,18 @@ </summary> </histogram> +<histogram name="Conversions.Storage.ClearDataWithFilterDuration" units="ms" + expires_after="M95"> + <owner>johnidel@chromium.org</owner> + <owner>csharrison@chromium.org</owner> + <summary> + Records the time it took to do perform a clear operation on the database + when supplied an origin filter. Recorded when the conversion database + finishes performing a clear operation. Note that filters may vary in size + and computation complexity, skewing this metric aribtrarily. + </summary> +</histogram> + <histogram name="Conversions.TimeFromConversionToReportSend" units="hours" expires_after="M95"> <owner>johnidel@chromium.org</owner> @@ -10053,6 +10065,9 @@ <histogram name="Nearby.Share.Transfer.CompletionStatus.NotCompletedReason{Direction}{ShareTargetType}" enum="NearbyShareTransferNotCompletedReason" expires_after="2021-08-19"> + <obsolete> + Replaced 12/2020 with Nearby.Share.Transfer.FinalStatus[...]. + </obsolete> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -10082,6 +10097,9 @@ <histogram name="Nearby.Share.Transfer.CompletionStatus{Direction}{ShareTargetType}" enum="BooleanCompleted" expires_after="2021-08-19"> + <obsolete> + Replaced 12/2020 with Nearby.Share.Transfer.FinalStatus[...]. + </obsolete> <owner>nohle@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -10111,6 +10129,44 @@ </token> </histogram> +<histogram name="Nearby.Share.Transfer.FinalStatus" + enum="NearbyShareTransferFinalStatus" expires_after="2021-08-19"> + <owner>nohle@chromium.org</owner> + <owner>better-together-dev@google.com</owner> + <summary> + Records the final status of a Nearby Share transfer. Emitted when a transfer + completes successfully, fails, or was aborted by the user, for example, by + cancelling the transfer. + </summary> +</histogram> + +<histogram + name="Nearby.Share.Transfer.FinalStatus.{Direction}.{ShareTargetType}.{ContactStatus}" + enum="NearbyShareTransferFinalStatus" expires_after="2021-08-19"> + <owner>nohle@chromium.org</owner> + <owner>better-together-dev@google.com</owner> + <summary> + Records the final status of a Nearby Share {Direction} transfer with + {ShareTargetType} using {ContactStatus}. Emitted when a transfer completes + successfully, fails, or was aborted by the user, for example, by cancelling + the transfer. + </summary> + <token key="Direction"> + <variant name="Receive" summary="incoming (receive)"/> + <variant name="Send" summary="outgoing (send)"/> + </token> + <token key="ShareTargetType"> + <variant name="Laptop" summary="a laptop"/> + <variant name="Phone" summary="a phone"/> + <variant name="Tablet" summary="a tablet"/> + <variant name="UnknownDeviceType" summary="an unknown device type"/> + </token> + <token key="ContactStatus"> + <variant name="Contact" summary="contact-based sharing"/> + <variant name="NonContact" summary="non-contact-based sharing"/> + </token> +</histogram> + <histogram name="Nearby.Share.Transfer.NumAttachments{Type}" units="attachments" expires_after="2021-08-19"> <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml index 3c5f115..7cf195d 100644 --- a/tools/metrics/histograms/histograms_xml/password/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -2470,6 +2470,17 @@ </summary> </histogram> +<histogram name="PasswordProtection.RequestReferringAppSource" + enum="PasswordProtectionReferringAppSource" expires_after="2021-12-15"> + <owner>xinghuilu@chromium.org</owner> + <owner>chrome-safebrowsing-alerts@google.com</owner> + <summary> + Records the referring app source of the password protection request, + indicating the source of the referring app name in the request. This metric + is only logged on Android. + </summary> +</histogram> + <histogram name="PasswordProtection.SampleReportSent" units="Boolean" expires_after="2021-04-25"> <owner>bdea@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml index c55387b..9d88eda5e 100644 --- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -32,6 +32,86 @@ </summary> </histogram> +<histogram name="SubresourceFilter.CnameAlias.Renderer.HadAliases" + units="BooleanHadAliases" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Records whether or not a given ResourceLoader's ResourceRequest has a + nonempty vector of CNAME aliases. Only recorded if + features::kSendCnameAliasesToSubresourceFilterFromRenderer is enabled. + Recorded in a method called by + blink::ResourceLoader::DidReceiveResponseInternal. + </summary> +</histogram> + +<histogram name="SubresourceFilter.CnameAlias.Renderer.InvalidCount" + units="count" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Counts the number of invalid CNAME aliases encountered by the + ResourceLoader, as these are not sent to the SubResourceFilter. Only + recorded if features::kSendCnameAliasesToSubresourceFilterFromRenderer is + enabled and the request has a nonempty vector of CNAME aliases. Recorded in + a method called by blink::ResourceLoader::DidReceiveResponseInternal. + </summary> +</histogram> + +<histogram name="SubresourceFilter.CnameAlias.Renderer.ListLength" + units="length" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Records the length of the CNAME aliases vector passed to the ResourceLoader, + not including empty alias vectors. Only recorded if + features::kSendCnameAliasesToSubresourceFilterFromRenderer is enabled and + the request has a nonempty vector of CNAME aliases. Recorded in a method + called by blink::ResourceLoader::DidReceiveResponseInternal. + </summary> +</histogram> + +<histogram name="SubresourceFilter.CnameAlias.Renderer.RedundantCount" + units="count" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Counts the number of CNAME aliases encountered by the ResourceLoader that + match the host of the requested URL (as well as the number of any that the + match the host of the original URL in the case of redirects), as these + aliases are not sent to the SubResourceFilter. Only recorded if + features::kSendCnameAliasesToSubresourceFilterFromRenderer is enabled and + the request has a nonempty vector of CNAME aliases. Recorded in a method + called by blink::ResourceLoader::DidReceiveResponseInternal. + </summary> +</histogram> + +<histogram name="SubresourceFilter.CnameAlias.Renderer.WasAdTaggedBasedOnAlias" + units="BooleanTagged" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Records whether or not a given ResourceLoader's ResourceRequest has CNAME + alias for which the returned LoadPolicy was LoadPolicy::kWouldDisallow. Only + recorded if features::kSendCnameAliasesToSubresourceFilterFromRenderer is + enabled and the request has a nonempty vector of CNAME aliases. Recorded in + a method called by blink::ResourceLoader::DidReceiveResponseInternal. + </summary> +</histogram> + +<histogram name="SubresourceFilter.CnameAlias.Renderer.WasBlockedBasedOnAlias" + units="BooleanBlocked" expires_after="2021-06-18"> + <owner>cammie@chromium.org</owner> + <owner>chrome-ads-histograms@google.com</owner> + <summary> + Records whether or not a given ResourceLoader's ResourceRequest has CNAME + alias for which the returned LoadPolicy was LoadPolicy::kDisallow. Only + recorded if features::kSendCnameAliasesToSubresourceFilterFromRenderer is + enabled and the request has a nonempty vector of CNAME aliases. Recorded in + a method called by the destructor of blink::ResourceLoader. + </summary> +</histogram> + <histogram name="SubresourceFilter.DocumentLoad.Activation.CPUDuration" units="microseconds" expires_after="M77"> <owner>pkalinnikov@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 3a106dd..17b15d9 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@ { "trace_processor_shell": { "win": { - "hash": "27a43b7b55cde0d8bd64d76b6856d909664cfe82", - "remote_path": "perfetto_binaries/trace_processor_shell/win/0da7da798b33eb8624ed09f0b50d83cbec80e0cb/trace_processor_shell.exe" + "hash": "338c190945851de759c1aa74422592480695a218", + "remote_path": "perfetto_binaries/trace_processor_shell/win/0d23e521cc40b7a795ad98247a5d5b20121a5cf4/trace_processor_shell.exe" }, "mac": { - "hash": "7912bf71b35af9edfe3769e21c877ce7a7b2e461", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/0da7da798b33eb8624ed09f0b50d83cbec80e0cb/trace_processor_shell" + "hash": "607eed89d7285563dbfdddc37e6e3e2642b7eb8c", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/0d23e521cc40b7a795ad98247a5d5b20121a5cf4/trace_processor_shell" }, "linux": { - "hash": "aa33412242fe4b18678f566dfe34abdf5e889fa9", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/cc9b7694ce3d8fbcc20b3492313923c7d392ac54/trace_processor_shell" + "hash": "72c98fdee445bb652f16c2965bddc2d8cf1f0325", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/c65f224a7259d87bf1f980e7424d73fc0cfca795/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/page_sets/rendering/key_hit_test_cases.py b/tools/perf/page_sets/rendering/key_hit_test_cases.py index df0563b7..2085834 100644 --- a/tools/perf/page_sets/rendering/key_hit_test_cases.py +++ b/tools/perf/page_sets/rendering/key_hit_test_cases.py
@@ -42,7 +42,7 @@ 'window.__tapTarget != null') for _ in xrange(100): - self.TapButton(action_runner) + self.TapButton(action_runner) def TapButton(self, action_runner): with action_runner.CreateInteraction('Action_TapAction'):
diff --git a/tools/perf/page_sets/rendering/rendering_story.py b/tools/perf/page_sets/rendering/rendering_story.py index f96403f..31a0c922 100644 --- a/tools/perf/page_sets/rendering/rendering_story.py +++ b/tools/perf/page_sets/rendering/rendering_story.py
@@ -57,4 +57,5 @@ shared_page_state_class=shared_page_state_class, extra_browser_args=extra_browser_args, make_javascript_deterministic=make_javascript_deterministic, - base_dir=base_dir) + base_dir=base_dir, + perform_final_navigation=True)
diff --git a/tools/perf/page_sets/rendering/repaint_desktop.py b/tools/perf/page_sets/rendering/repaint_desktop.py index 3cdd127..1549975 100644 --- a/tools/perf/page_sets/rendering/repaint_desktop.py +++ b/tools/perf/page_sets/rendering/repaint_desktop.py
@@ -142,4 +142,3 @@ BASE_NAME = 'repaint_yahoo_homepage' YEAR = '2018' URL = 'http://vmiura.github.io/snapit-pages/snapit_yahoo_homepage.html' -
diff --git a/tools/perf/page_sets/rendering/top_real_world_desktop.py b/tools/perf/page_sets/rendering/top_real_world_desktop.py index 174f739..52c0940d 100644 --- a/tools/perf/page_sets/rendering/top_real_world_desktop.py +++ b/tools/perf/page_sets/rendering/top_real_world_desktop.py
@@ -26,13 +26,13 @@ extra_browser_args=extra_browser_args) def RunPageInteractions(self, action_runner): - action_runner.Wait(1) - with action_runner.CreateGestureInteraction('ScrollAction'): - action_runner.ScrollPage() - if self.story_set.scroll_forever: - while True: - action_runner.ScrollPage(direction='up') - action_runner.ScrollPage(direction='down') + action_runner.Wait(1) + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage() + if self.story_set.scroll_forever: + while True: + action_runner.ScrollPage(direction='up') + action_runner.ScrollPage(direction='down') class GoogleWebSearch2018Page(TopRealWorldDesktopPage):
diff --git a/tools/perf/page_sets/rendering/top_real_world_mobile.py b/tools/perf/page_sets/rendering/top_real_world_mobile.py index 0789aa5..f7c23ef 100644 --- a/tools/perf/page_sets/rendering/top_real_world_mobile.py +++ b/tools/perf/page_sets/rendering/top_real_world_mobile.py
@@ -194,8 +194,8 @@ shared_page_state_class=shared_page_state_class) def RunNavigateSteps(self, action_runner): - super(YahooAnswersMobile2018Page, self).RunNavigateSteps(action_runner) - action_runner.ScrollElement(selector='#page_scrollable') + super(YahooAnswersMobile2018Page, self).RunNavigateSteps(action_runner) + action_runner.ScrollElement(selector='#page_scrollable') class GoogleNewsMobile2018Page(TopRealWorldMobilePage):
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py index 4beeeb9..b7e1817 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -33,13 +33,12 @@ def RunPinchGesture(self, action_runner, left_anchor_ratio=0.5, top_anchor_ratio=0.5, scale_factor=None, speed_in_pixels_per_second=800): - with action_runner.CreateGestureInteraction('PinchAction', - repeatable=True): - action_runner.PinchPage( - left_anchor_ratio=left_anchor_ratio, - top_anchor_ratio=top_anchor_ratio, - scale_factor=scale_factor, - speed_in_pixels_per_second=speed_in_pixels_per_second) + with action_runner.CreateGestureInteraction('PinchAction', repeatable=True): + action_runner.PinchPage( + left_anchor_ratio=left_anchor_ratio, + top_anchor_ratio=top_anchor_ratio, + scale_factor=scale_factor, + speed_in_pixels_per_second=speed_in_pixels_per_second) def RunPageInteractions(self, action_runner): action_runner.tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py index c9056f4e..12f90a1 100644 --- a/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py +++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_mobile_cases.py
@@ -28,13 +28,12 @@ def RunPinchGesture(self, action_runner, left_anchor_ratio=0.5, top_anchor_ratio=0.5, scale_factor=None, speed_in_pixels_per_second=800): - with action_runner.CreateGestureInteraction('PinchAction', - repeatable=True): - action_runner.PinchPage( - left_anchor_ratio=left_anchor_ratio, - top_anchor_ratio=top_anchor_ratio, - scale_factor=scale_factor, - speed_in_pixels_per_second=speed_in_pixels_per_second) + with action_runner.CreateGestureInteraction('PinchAction', repeatable=True): + action_runner.PinchPage( + left_anchor_ratio=left_anchor_ratio, + top_anchor_ratio=top_anchor_ratio, + scale_factor=scale_factor, + speed_in_pixels_per_second=speed_in_pixels_per_second) def RunPageInteractions(self, action_runner): action_runner.tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index 3b9b4d2c..8b5adeca 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc
@@ -2435,6 +2435,14 @@ return has_pagination_support_; } +void AXTree::NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id) { + if (previous_tree_id == AXTreeIDUnknown()) + return; + + for (AXTreeObserver& observer : observers_) + observer.OnTreeManagerWillBeRemoved(previous_tree_id); +} + void AXTree::RecordError(std::string new_error) { if (!error_.empty()) error_ = error_ + "\n"; // Add visual separation between errors.
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h index a2d711f..9994e21 100644 --- a/ui/accessibility/ax_tree.h +++ b/ui/accessibility/ax_tree.h
@@ -175,6 +175,13 @@ return event_intents_; } + // Notify the delegate that the tree manager for |previous_tree_id| will be + // removed from the AXTreeManagerMap. Because we sometimes remove the tree + // manager after the tree's id has been modified, we need to pass the (old) + // tree id associated with the manager we are removing even though it is the + // same tree. + void NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id); + private: friend class AXTableInfoTest;
diff --git a/ui/accessibility/ax_tree_manager.h b/ui/accessibility/ax_tree_manager.h index 2e2d4d87..d462cfe 100644 --- a/ui/accessibility/ax_tree_manager.h +++ b/ui/accessibility/ax_tree_manager.h
@@ -44,6 +44,10 @@ // hosts the current tree. Returns nullptr if this tree doesn't have a parent // tree. virtual AXNode* GetParentNodeFromParentTreeAsAXNode() const = 0; + + // Called when the tree manager is about to be removed from the tree + // AXTreeManagerMap. + virtual void WillBeRemovedFromMap() {} }; } // namespace ui
diff --git a/ui/accessibility/ax_tree_manager_map.cc b/ui/accessibility/ax_tree_manager_map.cc index 8d2c73dc..5a0942b 100644 --- a/ui/accessibility/ax_tree_manager_map.cc +++ b/ui/accessibility/ax_tree_manager_map.cc
@@ -26,8 +26,10 @@ } void AXTreeManagerMap::RemoveTreeManager(AXTreeID tree_id) { - if (tree_id != AXTreeIDUnknown()) + if (auto* manager = GetManager(tree_id)) { + manager->WillBeRemovedFromMap(); map_.erase(tree_id); + } } AXTreeManager* AXTreeManagerMap::GetManager(AXTreeID tree_id) {
diff --git a/ui/accessibility/ax_tree_observer.h b/ui/accessibility/ax_tree_observer.h index c9517c6a..c99971cb 100644 --- a/ui/accessibility/ax_tree_observer.h +++ b/ui/accessibility/ax_tree_observer.h
@@ -8,6 +8,7 @@ #include "base/observer_list_types.h" #include "ui/accessibility/ax_enums.mojom-forward.h" #include "ui/accessibility/ax_export.h" +#include "ui/accessibility/ax_tree_id.h" namespace ui { @@ -126,6 +127,15 @@ // updating. virtual void OnNodeChanged(AXTree* tree, AXNode* node) {} + // Called just before a tree manager is removed from the AXTreeManagerMap. + // + // Why is this needed? + // In some cases, we update the tree id of an AXTree and need to update the + // map entry that corresponds to that tree. The observers maintained in the + // observers list of that AXTree might need to be notified of that change to + // remove themselves from the list, if needed. + virtual void OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) {} + enum ChangeType { NODE_CREATED, SUBTREE_CREATED,
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc index e055476..8b3ffde6 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -1543,4 +1543,12 @@ } } +void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints:: + OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) { + if (start_->tree_id() == previous_tree_id || + end_->tree_id() == previous_tree_id) { + RemoveObserver(previous_tree_id); + } +} + } // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h index 0d96071..5bd55bf 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -211,6 +211,7 @@ void AddObserver(const AXTreeID tree_id); void RemoveObserver(const AXTreeID tree_id); void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override; + void OnTreeManagerWillBeRemoved(AXTreeID previous_tree_id) override; private: AXPositionInstance start_;
diff --git a/ui/aura/window_targeter.cc b/ui/aura/window_targeter.cc index 1ded0d6..1e6c4c7 100644 --- a/ui/aura/window_targeter.cc +++ b/ui/aura/window_targeter.cc
@@ -273,35 +273,18 @@ bool WindowTargeter::EventLocationInsideBounds( Window* window, const ui::LocatedEvent& event) const { - gfx::Rect mouse_rect; - gfx::Rect touch_rect; - if (!GetHitTestRects(window, &mouse_rect, &touch_rect)) - return false; - const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin(); - mouse_rect.Offset(offset); - touch_rect.Offset(offset); gfx::Point point = event.location(); if (window->parent()) Window::ConvertPointToTarget(window->parent(), window, &point); - const bool point_in_rect = event.IsTouchEvent() || event.IsGestureEvent() - ? touch_rect.Contains(point) - : mouse_rect.Contains(point); - if (!point_in_rect) - return false; + BoundsType bounds_type = BoundsType::kMouse; + if (event.IsTouchEvent()) + bounds_type = BoundsType::kTouch; + else if (event.IsGestureEvent()) + bounds_type = BoundsType::kGesture; - auto shape_rects = GetExtraHitTestShapeRects(window); - if (!shape_rects) - return true; - - for (const gfx::Rect& shape_rect : *shape_rects) { - if (shape_rect.Contains(point)) { - return true; - } - } - - return false; + return PointInsideBounds(window, bounds_type, point); } bool WindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const { @@ -356,4 +339,63 @@ return root_window->CanAcceptEvent(*event) ? root_window : nullptr; } +bool WindowTargeter::PointInsideBounds(Window* window, + BoundsType bounds_type, + const gfx::Point& point) const { + gfx::Rect mouse_rect; + gfx::Rect touch_rect; + if (!GetHitTestRects(window, &mouse_rect, &touch_rect)) + return false; + + const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin(); + mouse_rect.Offset(offset); + touch_rect.Offset(offset); + + const bool point_in_rect = + bounds_type == BoundsType::kTouch || bounds_type == BoundsType::kGesture + ? touch_rect.Contains(point) + : mouse_rect.Contains(point); + if (point_in_rect) { + auto shape_rects = GetExtraHitTestShapeRects(window); + if (!shape_rects) + return true; + + for (const gfx::Rect& shape_rect : *shape_rects) { + if (shape_rect.Contains(point)) { + return true; + } + } + + return false; + } + + if (ShouldUseExtendedBounds(window) && + (!mouse_extend_.IsEmpty() || !touch_extend_.IsEmpty())) { + // Insets take priority over child traversal, otherwise it's possible to + // have a window that has a non-interactable region in the middle. + return false; + } + + if (window->layer()->GetMasksToBounds()) { + // If the layer masks to bounds, children are clipped and shouldn't receive + // input events. + return false; + } + + // Child windows are not always fully contained in the current window. + std::unique_ptr<ui::EventTargetIterator> iter = window->GetChildIterator(); + if (!iter) + return false; + + for (ui::EventTarget* child = iter->GetNextTarget(); child; + child = iter->GetNextTarget()) { + auto* child_window = static_cast<Window*>(child); + gfx::Point child_point(point); + Window::ConvertPointToTarget(window, child_window, &child_point); + if (PointInsideBounds(child_window, bounds_type, child_point)) + return true; + } + return false; +} + } // namespace aura
diff --git a/ui/aura/window_targeter.h b/ui/aura/window_targeter.h index e0485413..7fdf3f4 100644 --- a/ui/aura/window_targeter.h +++ b/ui/aura/window_targeter.h
@@ -14,6 +14,7 @@ #include "ui/gfx/geometry/insets.h" namespace gfx { +class Point; class Rect; } @@ -130,10 +131,22 @@ // To call OnInstalled(). friend class Window; + enum class BoundsType { + kMouse, + kTouch, + kGesture, + }; + Window* FindTargetForNonKeyEvent(Window* root_window, ui::Event* event); Window* FindTargetForLocatedEventRecursively(Window* root_window, ui::LocatedEvent* event); + // Whether |point| is inside |window| or its descendents using |bounds_type| + // as a rect source. |point| should be relative to |window|. + bool PointInsideBounds(Window* window, + BoundsType bounds_type, + const gfx::Point& point) const; + // The Window this WindowTargeter is installed on. Null if not attached to a // Window. aura::Window* window_ = nullptr;
diff --git a/ui/aura/window_targeter_unittest.cc b/ui/aura/window_targeter_unittest.cc index 9ab8a23..f4e6b465 100644 --- a/ui/aura/window_targeter_unittest.cc +++ b/ui/aura/window_targeter_unittest.cc
@@ -288,6 +288,43 @@ EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &third)); } +TEST_F(WindowTargeterTest, NonFullyContainedBounds) { + test::TestWindowDelegate delegate; + std::unique_ptr<Window> parent( + CreateNormalWindow(1, root_window(), &delegate)); + std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate)); + + parent->SetBounds(gfx::Rect(0, 0, 30, 30)); + child->SetBounds(gfx::Rect(15, 15, 5, 100)); + + auto* targeter = + static_cast<ui::EventTarget*>(root_window())->GetEventTargeter(); + + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75), + gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE, + ui::EF_NONE); + EXPECT_EQ(child.get(), targeter->FindTargetForEvent(root_window(), &mouse)); +} + +TEST_F(WindowTargeterTest, NonFullyContainedBoundsWithMasksToBounds) { + test::TestWindowDelegate delegate; + std::unique_ptr<Window> parent( + CreateNormalWindow(1, root_window(), &delegate)); + std::unique_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate)); + + parent->SetBounds(gfx::Rect(0, 0, 30, 30)); + parent->layer()->SetMasksToBounds(true); + child->SetBounds(gfx::Rect(15, 15, 5, 100)); + + auto* targeter = + static_cast<ui::EventTarget*>(root_window())->GetEventTargeter(); + + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(17, 75), + gfx::Point(17, 75), ui::EventTimeForNow(), ui::EF_NONE, + ui::EF_NONE); + EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_window(), &mouse)); +} + class IgnoreWindowTargeter : public WindowTargeter { public: IgnoreWindowTargeter() {}
diff --git a/ui/base/models/list_selection_model.cc b/ui/base/models/list_selection_model.cc index e4fc907..cee62e62 100644 --- a/ui/base/models/list_selection_model.cc +++ b/ui/base/models/list_selection_model.cc
@@ -79,43 +79,59 @@ for (auto i = selected_indices_.begin(); i != selected_indices_.end(); ++i) { IncrementFromImpl(index, &(*i)); } + reset_index_set(); IncrementFromImpl(index, &anchor_); IncrementFromImpl(index, &active_); } void ListSelectionModel::DecrementFrom(int index) { for (auto i = selected_indices_.begin(); i != selected_indices_.end();) { - if (DecrementFromImpl(index, &(*i))) + if (DecrementFromImpl(index, &(*i))) { i = selected_indices_.erase(i); - else + } else { ++i; + } } + reset_index_set(); DecrementFromImpl(index, &anchor_); DecrementFromImpl(index, &active_); } void ListSelectionModel::SetSelectedIndex(int index) { anchor_ = active_ = index; - selected_indices_.clear(); + clear_indices(); if (index != kUnselectedIndex) - selected_indices_.push_back(index); + add_index(index); } bool ListSelectionModel::IsSelected(int index) const { - return base::Contains(selected_indices_, index); + return base::Contains(selected_indices_set_, index); } void ListSelectionModel::AddIndexToSelection(int index) { if (!IsSelected(index)) { - selected_indices_.push_back(index); + add_index(index); std::sort(selected_indices_.begin(), selected_indices_.end()); } } +void ListSelectionModel::AddIndexRangeToSelection(int index_start, + int index_end) { + DCHECK_LT(index_start, index_end); + + for (int i = index_start; i <= index_end; ++i) { + if (!IsSelected(i)) + add_index(i); + } + std::sort(selected_indices_.begin(), selected_indices_.end()); +} + void ListSelectionModel::RemoveIndexFromSelection(int index) { auto i = std::find(selected_indices_.begin(), selected_indices_.end(), index); - if (i != selected_indices_.end()) + if (i != selected_indices_.end()) { selected_indices_.erase(i); + selected_indices_set_.erase(index); + } } void ListSelectionModel::SetSelectionFromAnchorTo(int index) { @@ -127,6 +143,7 @@ for (int i = 0, min = std::min(index, anchor_); i <= delta; ++i) new_selection[i] = i + min; selected_indices_.swap(new_selection); + reset_index_set(); active_ = index; } } @@ -138,7 +155,7 @@ for (int i = std::min(index, anchor_), end = std::max(index, anchor_); i <= end; ++i) { if (!IsSelected(i)) - selected_indices_.push_back(i); + add_index(i); } std::sort(selected_indices_.begin(), selected_indices_.end()); active_ = index; @@ -156,6 +173,7 @@ // by 2. if (new_index > old_index) { Move(old_index + length, old_index, new_index - old_index); + reset_index_set(); return; } @@ -196,12 +214,28 @@ // [low, middle), and an upper bound for [middle, high). std::rotate(low, middle, high); DCHECK(std::is_sorted(selected_indices_.begin(), selected_indices_.end())); + reset_index_set(); } void ListSelectionModel::Clear() { anchor_ = active_ = kUnselectedIndex; - SelectedIndices empty_selection; - selected_indices_.swap(empty_selection); + clear_indices(); +} + +void ListSelectionModel::add_index(int index) { + selected_indices_.push_back(index); + selected_indices_set_.insert(index); +} + +void ListSelectionModel::reset_index_set() { + auto set = + SelectedIndicesSet(selected_indices_.begin(), selected_indices_.end()); + selected_indices_set_.swap(set); +} + +void ListSelectionModel::clear_indices() { + selected_indices_.clear(); + selected_indices_set_.clear(); } } // namespace ui
diff --git a/ui/base/models/list_selection_model.h b/ui/base/models/list_selection_model.h index 4c98ae9f..44850db 100644 --- a/ui/base/models/list_selection_model.h +++ b/ui/base/models/list_selection_model.h
@@ -7,6 +7,7 @@ #include <stddef.h> +#include <set> #include <vector> #include "base/component_export.h" @@ -28,6 +29,7 @@ class COMPONENT_EXPORT(UI_BASE) ListSelectionModel { public: using SelectedIndices = std::vector<int>; + using SelectedIndicesSet = std::set<int>; // Used to identify no selection. static constexpr int kUnselectedIndex = -1; @@ -80,6 +82,10 @@ // indices. void AddIndexToSelection(int index); + // Adds indices between |index_start| and |index_end|, inclusive. + // This does not change the active or anchor indices. + void AddIndexRangeToSelection(int index_start, int index_end); + // Removes |index| from the selection. This does not change the active or // anchor indices. void RemoveIndexFromSelection(int index); @@ -110,7 +116,13 @@ const SelectedIndices& selected_indices() const { return selected_indices_; } private: + void add_index(int index); + void reset_index_set(); + void clear_indices(); + // TODO(crbug.com/1159585): Refactor to only use one backing store for + // selections. SelectedIndices selected_indices_; + SelectedIndicesSet selected_indices_set_; int active_ = kUnselectedIndex;
diff --git a/ui/base/models/list_selection_model_unittest.cc b/ui/base/models/list_selection_model_unittest.cc index 8c52ba11..bafbafb 100644 --- a/ui/base/models/list_selection_model_unittest.cc +++ b/ui/base/models/list_selection_model_unittest.cc
@@ -98,6 +98,15 @@ EXPECT_EQ("active=-1 anchor=-1 selection=2 4", StateAsString(model)); } +TEST_F(ListSelectionModelTest, AddIndexRangeToSelected) { + ListSelectionModel model; + model.AddIndexRangeToSelection(2, 3); + EXPECT_EQ("active=-1 anchor=-1 selection=2 3", StateAsString(model)); + + model.AddIndexRangeToSelection(4, 5); + EXPECT_EQ("active=-1 anchor=-1 selection=2 3 4 5", StateAsString(model)); +} + TEST_F(ListSelectionModelTest, RemoveIndexFromSelection) { ListSelectionModel model; model.SetSelectedIndex(2);
diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc index 02fcf068..d2014c4d 100644 --- a/ui/base/x/selection_requestor.cc +++ b/ui/base/x/selection_requestor.cc
@@ -15,6 +15,7 @@ #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/xproto.h" +#include "ui/gfx/x/xproto_util.h" namespace ui { @@ -126,7 +127,7 @@ request->target != selection.target) { // ICCCM requires us to delete the property passed into SelectionNotify. if (event_property != x11::Atom::None) - ui::DeleteProperty(x_window_, event_property); + x11::DeleteProperty(x_window_, event_property); return; } @@ -141,7 +142,7 @@ } } if (event_property != x11::Atom::None) - ui::DeleteProperty(x_window_, event_property); + x11::DeleteProperty(x_window_, event_property); if (request->out_type == x11::GetAtom(kIncr)) { request->data_sent_incrementally = true; @@ -184,7 +185,7 @@ request->out_type = out_type; // Delete the property to tell the selection owner to send the next chunk. - ui::DeleteProperty(x_window_, x_property_); + x11::DeleteProperty(x_window_, x_property_); request->timeout = base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(kRequestTimeoutMs); @@ -256,7 +257,7 @@ // shutdown and the X11EventSource has already been destroyed. auto* conn = x11::Connection::Get(); while (!request->completed && request->timeout > base::TimeTicks::Now()) - conn->Dispatch(); + conn->DispatchAll(); } }
diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc index 7f06900..155cfc70 100644 --- a/ui/base/x/selection_utils.cc +++ b/ui/base/x/selection_utils.cc
@@ -197,8 +197,8 @@ // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is // UTF-16, otherwise assume UTF-8. - if (size >= 2 && reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { - markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, + if (size >= 2 && reinterpret_cast<const base::char16*>(data)[0] == 0xFEFF) { + markup.assign(reinterpret_cast<const base::char16*>(data) + 1, (size / 2) - 1); } else { base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
diff --git a/ui/base/x/x11_drag_drop_client.cc b/ui/base/x/x11_drag_drop_client.cc index 00c224e..9e9e219 100644 --- a/ui/base/x/x11_drag_drop_client.cc +++ b/ui/base/x/x11_drag_drop_client.cc
@@ -443,7 +443,7 @@ // ICCCM requires us to delete the property passed into SelectionNotify. if (xselection.property != x11::Atom::None) - ui::DeleteProperty(xwindow_, xselection.property); + x11::DeleteProperty(xwindow_, xselection.property); } void XDragDropClient::InitDrag(int operation, const OSExchangeData* data) { @@ -471,8 +471,8 @@ void XDragDropClient::CleanupDrag() { source_provider_ = nullptr; - ui::DeleteProperty(xwindow_, x11::GetAtom(kXdndActionList)); - ui::DeleteProperty(xwindow_, x11::GetAtom(kXdndDirectSave0)); + x11::DeleteProperty(xwindow_, x11::GetAtom(kXdndActionList)); + x11::DeleteProperty(xwindow_, x11::GetAtom(kXdndDirectSave0)); } void XDragDropClient::UpdateModifierState(int flags) {
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index a77b10e..d98e1bb 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc
@@ -168,13 +168,6 @@ } // namespace -void DeleteProperty(x11::Window window, x11::Atom name) { - x11::Connection::Get()->DeleteProperty({ - .window = static_cast<x11::Window>(window), - .property = name, - }); -} - bool GetWmNormalHints(x11::Window window, SizeHints* hints) { std::vector<uint32_t> hints32; if (!GetArrayProperty(window, x11::GetAtom("WM_NORMAL_HINTS"), &hints32)) @@ -646,9 +639,9 @@ void SetWindowRole(x11::Window window, const std::string& role) { x11::Atom prop = x11::GetAtom("WM_WINDOW_ROLE"); if (role.empty()) - DeleteProperty(window, prop); + x11::DeleteProperty(window, prop); else - SetStringProperty(window, prop, x11::Atom::STRING, role); + x11::SetStringProperty(window, prop, x11::Atom::STRING, role); } void SetWMSpecState(x11::Window window,
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 613a10d..19f89803 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h
@@ -125,9 +125,6 @@ // the UI thread. Thus, they don't support multiple displays. COMPONENT_EXPORT(UI_BASE_X) -void DeleteProperty(x11::Window window, x11::Atom name); - -COMPONENT_EXPORT(UI_BASE_X) bool GetWmNormalHints(x11::Window window, SizeHints* hints); COMPONENT_EXPORT(UI_BASE_X)
diff --git a/ui/base/x/x11_window.cc b/ui/base/x/x11_window.cc index 760d38b4..0459e6e 100644 --- a/ui/base/x/x11_window.cc +++ b/ui/base/x/x11_window.cc
@@ -454,7 +454,7 @@ UpdateMinAndMaxSize(); if (window_properties_.empty()) { - DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_STATE")); + x11::DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_STATE")); } else { SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM", std::vector<x11::Atom>(std::begin(window_properties_), @@ -763,7 +763,7 @@ uint32_t cardinality = opacity_8bit * channel_multiplier; if (cardinality == 0xffffffff) { - DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_OPACITY")); + x11::DeleteProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_OPACITY")); } else { SetProperty(xwindow_, x11::GetAtom("_NET_WM_WINDOW_OPACITY"), x11::Atom::CARDINAL, cardinality);
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp index fcc709b..e83d58a 100644 --- a/ui/chromeos/file_manager_strings.grdp +++ b/ui/chromeos/file_manager_strings.grdp
@@ -1274,6 +1274,9 @@ <message name="IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT" desc="In the Holding Space welcome banner, text of the welcome message."> Right-click a file, and select "Pin to shelf" for quick access to your files in shelf. </message> + <message name="IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE" desc="In the Holding Space welcome banner, text of the welcome message in tablet mode."> + Touch & hold a file and tap <ph name="ICON">$1</ph>, and select "Pin to shelf" for quick access to your files in shelf. + </message> <message name="IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_DISMISS" desc="In the Holding Space welcome banner, text on the button to dismiss the banner."> Got it </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE.png.sha1 new file mode 100644 index 0000000..f62a595d --- /dev/null +++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE.png.sha1
@@ -0,0 +1 @@ +a2a3f984125a40b15227ed0a101dae31a5e5f418 \ No newline at end of file
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc index 8f5d2ce..ad6b27e 100644 --- a/ui/events/platform/x11/x11_event_source.cc +++ b/ui/events/platform/x11/x11_event_source.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #include <algorithm> #include <memory> #include <type_traits> @@ -151,8 +150,10 @@ void X11EventSource::DispatchXEvents() { continue_stream_ = true; - while (connection_->Dispatch() && continue_stream_) { - } + do { + connection_->Flush(); + connection_->ReadResponses(); + } while (connection_->Dispatch() && continue_stream_); } x11::Time X11EventSource::GetCurrentServerTime() {
diff --git a/ui/file_manager/file_manager/foreground/css/holding_space_welcome.css b/ui/file_manager/file_manager/foreground/css/holding_space_welcome.css index 68c82e1..1ac2b49 100644 --- a/ui/file_manager/file_manager/foreground/css/holding_space_welcome.css +++ b/ui/file_manager/file_manager/foreground/css/holding_space_welcome.css
@@ -54,7 +54,25 @@ } .holding-space-welcome .holding-space-welcome-text { - display: inline; + align-items: center; + display: inline-flex; +} + +.holding-space-welcome .holding-space-welcome-text span.icon { + -webkit-mask-image: url(../images/files/ui/menu_ng.svg); + -webkit-mask-position: center; + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 100%; + background-color: var(--cros-text-color-primary); + display: inline-block; + flex: 0 0 auto; + height: 13px; + width: 13px; +} + +/* TODO(crbug.com/1154347): Handle tablet mode enabled. */ +.holding-space-welcome-text.tablet-mode-enabled { + display: none; } .holding-space-welcome .text-button {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js index a51a38f..f9f75df 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/banners.js +++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -321,10 +321,16 @@ util.createChild(message, 'holding-space-welcome-title headline2'); title.textContent = str('HOLDING_SPACE_WELCOME_TITLE'); - // TODO(crbug.com/1154347): Use different `text` string in tablet mode. + // NOTE: Only one of either `text` or `textInTabletMode` will be displayed + // at a time depending on whether or not tablet mode is enabled. const body = util.createChild(message, 'body2-primary'); const text = util.createChild(body, 'holding-space-welcome-text'); + const textInTabletMode = util.createChild( + body, 'holding-space-welcome-text tablet-mode-enabled'); text.textContent = str('HOLDING_SPACE_WELCOME_TEXT'); + textInTabletMode.innerHTML = strf( + 'HOLDING_SPACE_WELCOME_TEXT_IN_TABLET_MODE', + '<span class="icon"> </span>'); const buttonGroup = util.createChild(wrapper, 'button-group', 'div'); const dismiss = util.createChild(buttonGroup, 'text-button', 'cr-button');
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc index aa97a53..787dba9 100644 --- a/ui/gfx/x/connection.cc +++ b/ui/gfx/x/connection.cc
@@ -405,9 +405,6 @@ bool Connection::Dispatch() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - Flush(); - ReadResponses(); - if (HasNextResponse() && !events_.empty()) { auto next_response_sequence = first_request_id_; auto next_event_sequence = events_.front().sequence(); @@ -430,8 +427,10 @@ } void Connection::DispatchAll() { - while (Dispatch()) { - } + do { + Flush(); + ReadResponses(); + } while (Dispatch()); } void Connection::DispatchEvent(const Event& event) {
diff --git a/ui/gfx/x/connection.h b/ui/gfx/x/connection.h index e450e6a..83e3a1cb 100644 --- a/ui/gfx/x/connection.h +++ b/ui/gfx/x/connection.h
@@ -155,10 +155,12 @@ bool HasPendingResponses(); // Dispatches one event, reply, or error from the server; or returns false - // if there's none available. + // if there's none available. This function doesn't read or write any data on + // the socket. bool Dispatch(); - // Dispatches all available events, replies, and errors. + // Dispatches all available events, replies, and errors. This function + // ensures the read and write buffers on the socket are empty upon returning. void DispatchAll(); // Directly dispatch an event, bypassing the event queue.
diff --git a/ui/gfx/x/property_cache.cc b/ui/gfx/x/property_cache.cc index 5fe2860..2f318a2 100644 --- a/ui/gfx/x/property_cache.cc +++ b/ui/gfx/x/property_cache.cc
@@ -32,7 +32,7 @@ connection_->RemoveEventObserver(this); } -const GetPropertyResponse& PropertyCache::GetProperty(Atom atom) { +const GetPropertyResponse& PropertyCache::Get(Atom atom) { auto it = properties_.find(atom); DCHECK(it != properties_.end()); @@ -52,7 +52,16 @@ auto it = properties_.find(prop->atom); if (it == properties_.end()) return; - FetchProperty(it->first, &it->second); + if (prop->state == Property::NewValue) { + FetchProperty(it->first, &it->second); + } else { + DCHECK_EQ(prop->state, Property::Delete); + // When the property is deleted, a GetPropertyRequest will result in a + // zeroed GetPropertyReply, so set the reply state now to avoid making an + // unnecessary request. + it->second.response = + GetPropertyResponse{std::make_unique<GetPropertyReply>(), nullptr}; + } } void PropertyCache::FetchProperty(Atom property, PropertyValue* value) {
diff --git a/ui/gfx/x/property_cache.h b/ui/gfx/x/property_cache.h index a3b8fdb..2ab765a 100644 --- a/ui/gfx/x/property_cache.h +++ b/ui/gfx/x/property_cache.h
@@ -32,9 +32,25 @@ ~PropertyCache() override; - const GetPropertyResponse& GetProperty(Atom atom); + const GetPropertyResponse& Get(Atom atom); + + template <typename T> + const T* GetAs(Atom atom, size_t* size = nullptr) { + auto& response = Get(atom); + if (size) + *size = 0; + if (!response || response->format != CHAR_BIT * sizeof(T) || + !response->value_len) { + return nullptr; + } + if (size) + *size = response->value_len; + return response->value->front_as<T>(); + } private: + friend class PropertyCacheTest; + struct PropertyValue { PropertyValue();
diff --git a/ui/gfx/x/property_cache_unittest.cc b/ui/gfx/x/property_cache_unittest.cc index 01a96ee..ffc39d6 100644 --- a/ui/gfx/x/property_cache_unittest.cc +++ b/ui/gfx/x/property_cache_unittest.cc
@@ -4,6 +4,8 @@ #include "ui/gfx/x/property_cache.h" +#include <memory> + #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/xproto.h" @@ -11,20 +13,161 @@ namespace x11 { -TEST(X11PropertyCacheTest, Basic) { - Connection connection; - auto window = CreateDummyWindow("", &connection); - auto atom = x11::GetAtom("DUMMY ATOM"); - SetProperty(window, atom, Atom::ATOM, atom, &connection).Sync(); +class PropertyCacheTest : public testing::Test { + public: + ~PropertyCacheTest() override = default; - PropertyCache cache(&connection, window, {atom}); - auto& response = cache.GetProperty(atom); + protected: + base::flat_map<Atom, PropertyCache::PropertyValue>& GetProperties( + PropertyCache* property_cache) { + return property_cache->properties_; + } + + Connection* connection() { return connection_; } + + Window window() { return window_; } + + private: + void SetUp() override { + connection_ = Connection::Get(); + window_ = CreateDummyWindow(""); + } + + void TearDown() override { + connection_->DestroyWindow({window_}).Sync(); + window_ = Window::None; + connection_ = nullptr; + } + + Connection* connection_ = nullptr; + Window window_ = Window::None; +}; + +TEST_F(PropertyCacheTest, GetSync) { + auto atom = x11::GetAtom("DUMMY ATOM"); + SetProperty(window(), atom, Atom::CARDINAL, 1234); + + PropertyCache cache(connection(), window(), {atom}); + + // The cache should Sync() on getting the value. + EXPECT_FALSE(GetProperties(&cache)[atom].response.has_value()); + auto* value = cache.GetAs<uint32_t>(atom); + EXPECT_TRUE(GetProperties(&cache)[atom].response.has_value()); + + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); +} + +TEST_F(PropertyCacheTest, GetAsync) { + auto atom = x11::GetAtom("DUMMY ATOM"); + SetProperty(window(), atom, Atom::CARDINAL, 1234); + + PropertyCache cache(connection(), window(), {atom}); + + // The cache should not Sync() unnecessarily. + EXPECT_FALSE(GetProperties(&cache)[atom].response.has_value()); + connection()->Sync(); + connection()->DispatchAll(); + EXPECT_TRUE(GetProperties(&cache)[atom].response.has_value()); + + auto* value = cache.GetAs<uint32_t>(atom); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); +} + +TEST_F(PropertyCacheTest, Event) { + auto atom = x11::GetAtom("DUMMY ATOM"); + SetProperty(window(), atom, Atom::CARDINAL, 1234); + + PropertyCache cache(connection(), window(), {atom}); + + auto* value = cache.GetAs<uint32_t>(atom); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); + + // Change the property and sync to ensure the PropertyNotify event is ready to + // be dispatched. + SetProperty(window(), atom, Atom::CARDINAL, 5678); + connection()->Sync(); + connection()->ReadResponses(); + + // Dispatch the PropertyNotify event, which will cause the PropertyCache to + // send another GetPropertyRequest. Calling DispatchAll() would introduce a + // race condition where we could get the GetPropertyResponse early if the 2 + // round trips are completed fast enough. To avoid this, we use Dispatch(), + // which doesn't read or write on the socket. + while (connection()->Dispatch()) { + } + + // We don't have the new GetPropertyResponse yet, so the old value should + // still be there. + value = cache.GetAs<uint32_t>(atom); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); + + // Complete the second round trip to acquire the new property value. + connection()->Sync(); + connection()->DispatchAll(); + + // Now the cache should have the new value. + value = cache.GetAs<uint32_t>(atom); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 5678u); +} + +TEST_F(PropertyCacheTest, GetAs) { + auto atom = x11::GetAtom("DUMMY ATOM"); + SetProperty(window(), atom, Atom::CARDINAL, 1234); + + PropertyCache cache(connection(), window(), {atom}); + + // Get() should return the correct property value. + auto& response = cache.Get(atom); ASSERT_TRUE(response); EXPECT_EQ(response->bytes_after, 0u); EXPECT_EQ(response->format, 32); - EXPECT_EQ(response->type, Atom::ATOM); - EXPECT_EQ(*response->value->front_as<Atom>(), atom); + EXPECT_EQ(response->type, Atom::CARDINAL); + EXPECT_EQ(*response->value->front_as<uint32_t>(), 1234u); EXPECT_EQ(response->value_len, 1u); + + // GetAs() should do the same thing as Get(). + size_t size = 0; + auto* value = cache.GetAs<uint32_t>(atom, &size); + EXPECT_EQ(size, 1u); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); + + // GetAs() should allow a nullptr size. + value = cache.GetAs<uint32_t>(atom /* size is defaulted to nullptr */); + ASSERT_TRUE(value); + EXPECT_EQ(*value, 1234u); + + // The below checks make requests and requires event dispatching, so + // synchronize all requests to avoid verbosity from Sync()ing everywhere. + connection()->SynchronizeForTest(true); + + // GetAs() should return nullptr if the type's size is mismatched. + SetProperty(window(), atom, Atom::CARDINAL, static_cast<uint8_t>(123)); + connection()->DispatchAll(); + value = cache.GetAs<uint32_t>(atom, &size); + EXPECT_EQ(size, 0u); + EXPECT_FALSE(value); + + // GetAs() should return nullptr if the property has no elements. + SetArrayProperty(window(), atom, Atom::CARDINAL, std::vector<uint32_t>()); + connection()->DispatchAll(); + value = cache.GetAs<uint32_t>(atom, &size); + EXPECT_EQ(size, 0u); + EXPECT_FALSE(value); + + // GetAs() should return nullptr if the property is deleted. + DeleteProperty(window(), atom); + connection()->DispatchAll(); + value = cache.GetAs<uint32_t>(atom, &size); + EXPECT_EQ(size, 0u); + EXPECT_FALSE(value); + + connection()->SynchronizeForTest(true); } } // namespace x11
diff --git a/ui/gfx/x/xproto_types.h b/ui/gfx/x/xproto_types.h index 754442df..196f7a0a 100644 --- a/ui/gfx/x/xproto_types.h +++ b/ui/gfx/x/xproto_types.h
@@ -110,18 +110,15 @@ template <typename Reply> struct Response { + Response(std::unique_ptr<Reply> reply, std::unique_ptr<Error> error) + : reply(std::move(reply)), error(std::move(error)) {} + operator bool() const { return reply.get(); } const Reply* operator->() const { return reply.get(); } Reply* operator->() { return reply.get(); } std::unique_ptr<Reply> reply; std::unique_ptr<Error> error; - - private: - friend class Future<Reply>; - - Response(std::unique_ptr<Reply> reply, std::unique_ptr<Error> error) - : reply(std::move(reply)), error(std::move(error)) {} }; template <>
diff --git a/ui/gfx/x/xproto_util.cc b/ui/gfx/x/xproto_util.cc index 95b83d21..6662b12 100644 --- a/ui/gfx/x/xproto_util.cc +++ b/ui/gfx/x/xproto_util.cc
@@ -6,6 +6,13 @@ namespace x11 { +void DeleteProperty(x11::Window window, x11::Atom name) { + x11::Connection::Get()->DeleteProperty({ + .window = static_cast<x11::Window>(window), + .property = name, + }); +} + void SetStringProperty(Window window, Atom property, Atom type,
diff --git a/ui/gfx/x/xproto_util.h b/ui/gfx/x/xproto_util.h index 86ba572b..fc140e5f 100644 --- a/ui/gfx/x/xproto_util.h +++ b/ui/gfx/x/xproto_util.h
@@ -111,6 +111,9 @@ } COMPONENT_EXPORT(X11) +void DeleteProperty(x11::Window window, x11::Atom name); + +COMPONENT_EXPORT(X11) void SetStringProperty(Window window, Atom property, Atom type,
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc index 5909170..cc8adf0 100644 --- a/ui/gl/gl_context.cc +++ b/ui/gl/gl_context.cc
@@ -281,17 +281,10 @@ void GLContext::FlushForDriverCrashWorkaround() { // If running on Apple silicon, regardless of the architecture, disable this - // workaround. - // https://crbug.com/1131312 - switch (base::mac::GetCPUType()) { - case base::mac::CPUType::kArm: - case base::mac::CPUType::kTranslatedIntel: - return; - default: - break; - } - - if (!IsCurrent(nullptr)) + // workaround. See https://crbug.com/1131312. + static const bool needs_flush = + base::mac::GetCPUType() == base::mac::CPUType::kIntel; + if (!needs_flush || !IsCurrent(nullptr)) return; TRACE_EVENT0("gpu", "GLContext::FlushForDriverCrashWorkaround"); glFlush();
diff --git a/ui/gl/init/create_gr_gl_interface.cc b/ui/gl/init/create_gr_gl_interface.cc index f46b73da..bc07a546 100644 --- a/ui/gl/init/create_gr_gl_interface.cc +++ b/ui/gl/init/create_gr_gl_interface.cc
@@ -13,6 +13,10 @@ #include "ui/gl/gl_version_info.h" #include "ui/gl/progress_reporter.h" +#if defined(OS_APPLE) +#include "base/mac/mac_util.h" +#endif + namespace gl { namespace init { @@ -159,13 +163,17 @@ // Conditional may be optimized out because droppable_call is set at compile // time. if (!droppable_call || !HasInitializedNullDrawGLBindings()) { - { + // If running on Apple silicon, regardless of the architecture, disable + // this workaround. See https://crbug.com/1131312. + static const bool needs_flush = + base::mac::GetCPUType() == base::mac::CPUType::kIntel; + if (needs_flush) { TRACE_EVENT0( "gpu", "CreateGrGLInterface - bind_with_flush_on_mac - beforefunc") glFlush(); } func(args...); - { + if (needs_flush) { TRACE_EVENT0("gpu", "CreateGrGLInterface - bind_with_flush_on_mac - afterfunc") glFlush();
diff --git a/ui/gtk/gtk_ui_delegate.h b/ui/gtk/gtk_ui_delegate.h index 9daed0a8..1bab2590 100644 --- a/ui/gtk/gtk_ui_delegate.h +++ b/ui/gtk/gtk_ui_delegate.h
@@ -55,6 +55,9 @@ // Presents |window|, doing all the necessary platform-specific operations // needed, if any. virtual void ShowGtkWindow(GtkWindow* window) = 0; + + // Get the current keyboard modifier state. + virtual int GetGdkKeyState() = 0; }; } // namespace ui
diff --git a/ui/gtk/gtk_util.cc b/ui/gtk/gtk_util.cc index 6cd7e64..b5c93b6 100644 --- a/ui/gtk/gtk_util.cc +++ b/ui/gtk/gtk_util.cc
@@ -83,35 +83,23 @@ << ui::kPropertyKeyboardIBusFlagOffset); } -GdkModifierType ExtractGdkEventStateFromKeyEvent( - const ui::KeyEvent& key_event) { - auto event_flags = static_cast<ui::EventFlags>(key_event.flags()); - static const struct { - ui::EventFlags event_flag; - GdkModifierType gdk_modifier; - } mapping[] = { - {ui::EF_SHIFT_DOWN, GDK_SHIFT_MASK}, - {ui::EF_CAPS_LOCK_ON, GDK_LOCK_MASK}, - {ui::EF_CONTROL_DOWN, GDK_CONTROL_MASK}, - {ui::EF_ALT_DOWN, GDK_MOD1_MASK}, - {ui::EF_NUM_LOCK_ON, GDK_MOD2_MASK}, - {ui::EF_MOD3_DOWN, GDK_MOD3_MASK}, - {ui::EF_COMMAND_DOWN, GDK_MOD4_MASK}, - {ui::EF_ALTGR_DOWN, GDK_MOD5_MASK}, - {ui::EF_LEFT_MOUSE_BUTTON, GDK_BUTTON1_MASK}, - {ui::EF_MIDDLE_MOUSE_BUTTON, GDK_BUTTON2_MASK}, - {ui::EF_RIGHT_MOUSE_BUTTON, GDK_BUTTON3_MASK}, - {ui::EF_BACK_MOUSE_BUTTON, GDK_BUTTON4_MASK}, - {ui::EF_FORWARD_MOUSE_BUTTON, GDK_BUTTON5_MASK}, - }; - unsigned int gdk_modifier_type = 0; - for (const auto& map : mapping) { - if (event_flags & map.event_flag) { - gdk_modifier_type = gdk_modifier_type | map.gdk_modifier; - } +GdkModifierType GetGdkKeyEventState(ui::KeyEvent key_event) { + // ui::KeyEvent uses a normalized modifier state which is not respected by + // Gtk, so we need to get the state from the display backend. Gtk instead + // follows the X11 spec in which the state of a key event is expected to be + // the mask of modifier keys _prior_ to this event. Some IMEs rely on this + // behavior. See https://crbug.com/1086946#c11. + + GdkModifierType state = GetIbusFlags(key_event); + if (key_event.key_code() != ui::VKEY_PROCESSKEY) { + // This is an synthetized event when |key_code| is VKEY_PROCESSKEY. + // In such a case there is no event being dispatching in the display + // backend. + state = static_cast<GdkModifierType>( + state | ui::GtkUiDelegate::instance()->GetGdkKeyState()); } - return static_cast<GdkModifierType>(gdk_modifier_type | - GetIbusFlags(key_event)); + + return state; } int GetKeyEventProperty(const ui::KeyEvent& key_event, @@ -590,7 +578,7 @@ GdkKeymap* keymap = GtkUi::GetDelegate()->GetGdkKeymap(); // Get keyval and state - GdkModifierType state = ExtractGdkEventStateFromKeyEvent(key_event); + GdkModifierType state = GetGdkKeyEventState(key_event); guint keyval = GDK_KEY_VoidSymbol; GdkModifierType consumed; gdk_keymap_translate_keyboard_state(keymap, hw_code, state, group, &keyval,
diff --git a/ui/gtk/x/gtk_ui_delegate_x11.cc b/ui/gtk/x/gtk_ui_delegate_x11.cc index ae1eacc..32101e56 100644 --- a/ui/gtk/x/gtk_ui_delegate_x11.cc +++ b/ui/gtk/x/gtk_ui_delegate_x11.cc
@@ -104,4 +104,16 @@ static_cast<uint32_t>(X11EventSource::GetInstance()->GetTimestamp())); } +int GtkUiDelegateX11::GetGdkKeyState() { + auto* xevent = + X11EventSource::GetInstance()->connection()->dispatching_event(); + + if (!xevent) + return ui::EF_NONE; + + auto* key_xevent = xevent->As<x11::KeyEvent>(); + DCHECK(key_xevent); + return static_cast<int>(key_xevent->state); +} + } // namespace ui
diff --git a/ui/gtk/x/gtk_ui_delegate_x11.h b/ui/gtk/x/gtk_ui_delegate_x11.h index 730af74..e92f9a3c 100644 --- a/ui/gtk/x/gtk_ui_delegate_x11.h +++ b/ui/gtk/x/gtk_ui_delegate_x11.h
@@ -34,6 +34,7 @@ gfx::AcceleratedWidget parent) override; void ClearTransientFor(gfx::AcceleratedWidget parent) override; void ShowGtkWindow(GtkWindow* window) override; + int GetGdkKeyState() override; private: GdkDisplay* GetGdkDisplay();
diff --git a/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc b/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc index 8d581a9..c6acaab 100644 --- a/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc +++ b/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.cc
@@ -14,6 +14,7 @@ #include "base/logging.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_event_source.h" #include "ui/ozone/platform/wayland/host/wayland_surface.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/ozone/platform/wayland/host/wayland_window_manager.h" @@ -86,6 +87,11 @@ gtk_window_present(window); } +int GtkUiDelegateWayland::GetGdkKeyState() { + // TODO(crbug/1159460): Test fcitx unikey IME on ozone/wayland. + return connection_->event_source()->keyboard_modifiers(); +} + void GtkUiDelegateWayland::OnHandle(GdkWindow* window, const std::string& handle) { gdk_wayland_window_set_transient_for_exported(
diff --git a/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h b/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h index e5e23ae..d198057b 100644 --- a/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h +++ b/ui/ozone/platform/wayland/host/gtk_ui_delegate_wayland.h
@@ -30,6 +30,7 @@ gfx::AcceleratedWidget parent) override; void ClearTransientFor(gfx::AcceleratedWidget parent) override; void ShowGtkWindow(GtkWindow* window) override; + int GetGdkKeyState() override; private: // Called when xdg-foreign exports a parent window passed in
diff --git a/ui/ozone/platform/x11/x11_clipboard_ozone.cc b/ui/ozone/platform/x11/x11_clipboard_ozone.cc index 50e1999..df3c22e 100644 --- a/ui/ozone/platform/x11/x11_clipboard_ozone.cc +++ b/ui/ozone/platform/x11/x11_clipboard_ozone.cc
@@ -226,7 +226,7 @@ x11::Atom type; std::vector<uint8_t> data; x11::GetArrayProperty(x_window_, x_property_, &data, &type); - ui::DeleteProperty(x_window_, x_property_); + x11::DeleteProperty(x_window_, x_property_); if (type != x11::Atom::None) selection_state.data = scoped_refptr<base::RefCountedBytes>( base::RefCountedBytes::TakeVector(&data));
diff --git a/ui/touch_selection/BUILD.gn b/ui/touch_selection/BUILD.gn index 64dbda0f..5e7fdba 100644 --- a/ui/touch_selection/BUILD.gn +++ b/ui/touch_selection/BUILD.gn
@@ -95,7 +95,10 @@ if (is_android) { java_cpp_enum("ui_touch_selection_enums_srcjar") { - sources = [ "selection_event_type.h" ] + sources = [ + "selection_event_type.h", + "touch_selection_draggable.h", + ] } java_cpp_enum("ui_touch_handle_orientation_srcjar") { sources = [ "touch_handle_orientation.h" ]
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc index ebbeacf34..6f7ae84b 100644 --- a/ui/touch_selection/touch_selection_controller.cc +++ b/ui/touch_selection/touch_selection_controller.cc
@@ -446,11 +446,20 @@ else client_->MoveRangeSelectionExtent(line_position); - // We use the bound middle point to restrict the ability to move up and down, - // but let user move it more freely in horizontal direction. - if (&draggable != &longpress_drag_selector_) { - float y = GetActiveHandleMiddleY(); - client_->OnDragUpdate(gfx::PointF(drag_position.x(), y)); + // We use the bound middle point to restrict the ability to move up and + // down, but let user move it more freely in horizontal direction. + if (&draggable == &longpress_drag_selector_) { + // Show magnifier at the selection edge. + const gfx::SelectionBound* bound = + anchor_drag_to_selection_start_ ? &start_ : &end_; + const float x = bound->edge_start().x(); + const float y = (bound->edge_start().y() + bound->edge_end().y()) / 2.f; + client_->OnDragUpdate(TouchSelectionDraggable::Type::kLongpress, + gfx::PointF(x, y)); + } else { + const float y = GetActiveHandleMiddleY(); + client_->OnDragUpdate(TouchSelectionDraggable::Type::kTouchHandle, + gfx::PointF(drag_position.x(), y)); } }
diff --git a/ui/touch_selection/touch_selection_controller.h b/ui/touch_selection/touch_selection_controller.h index 56ae7ff..4e203ab6 100644 --- a/ui/touch_selection/touch_selection_controller.h +++ b/ui/touch_selection/touch_selection_controller.h
@@ -34,7 +34,8 @@ virtual void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) = 0; virtual void OnSelectionEvent(SelectionEventType event) = 0; - virtual void OnDragUpdate(const gfx::PointF& position) = 0; + virtual void OnDragUpdate(const TouchSelectionDraggable::Type type, + const gfx::PointF& position) = 0; virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0; virtual void DidScroll() = 0; virtual void ShowTouchSelectionContextMenu(const gfx::Point& location) {}
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc index a29c06e..58c9fefd 100644 --- a/ui/touch_selection/touch_selection_controller_unittest.cc +++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -105,7 +105,8 @@ last_event_bounds_rect_ = controller_->GetRectBetweenBounds(); } - void OnDragUpdate(const gfx::PointF& position) override { + void OnDragUpdate(const TouchSelectionDraggable::Type type, + const gfx::PointF& position) override { last_drag_update_position_ = position; } @@ -1514,6 +1515,49 @@ EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); } +TEST_F(TouchSelectionControllerTest, LongpressDragSelectorUpdageDragPosition) { + EnableLongPressDragSelection(); + float line_height = 10.f; + gfx::RectF start_rect(-40, 0, 0, line_height); + gfx::RectF end_rect(50, 0, 0, line_height); + bool visible = true; + + // Start a touch sequence. + MockMotionEvent event; + EXPECT_FALSE(controller().WillHandleTouchEvent(event.PressPoint(0, 0))); + + // Activate a longpress-triggered selection + OnLongPressEvent(); + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN)); + EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart()); + + EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 0, 0))); + EXPECT_THAT(GetAndResetEvents(), IsEmpty()); + + // Move within tap slop, move haven't started yet. + EXPECT_TRUE( + controller().WillHandleTouchEvent(event.MovePoint(0, 0, kDefaulTapSlop))); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); + EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastDragUpdatePosition()); + + // Movement after the start of drag will be relative to the moved endpoint, + // the actual selection change offset is not necessary equal to the event + // moving distance. + end_rect.Offset(6, 0); + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 5, 0))); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_EQ(gfx::PointF(56.f, 5.f), GetLastDragUpdatePosition()); + + // Vertical move + end_rect.Offset(0, 10); + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_TRUE(controller().WillHandleTouchEvent(event.MovePoint(0, 5, 10))); + EXPECT_TRUE(GetAndResetSelectionMoved()); + EXPECT_EQ(gfx::PointF(56.f, 15.f), GetLastDragUpdatePosition()); +} + TEST_F(TouchSelectionControllerTest, NoHideActiveInsertionHandle) { SetHideActiveHandle(false); TouchSelectionControllerTestApi test_controller(&controller());
diff --git a/ui/touch_selection/touch_selection_draggable.h b/ui/touch_selection/touch_selection_draggable.h index 0bd9a70..2c72174 100644 --- a/ui/touch_selection/touch_selection_draggable.h +++ b/ui/touch_selection/touch_selection_draggable.h
@@ -27,6 +27,15 @@ // Generic interface for entities that manipulate the selection via dragging. class UI_TOUCH_SELECTION_EXPORT TouchSelectionDraggable { + public: + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.touch_selection + // GENERATED_JAVA_CLASS_NAME_OVERRIDE: TouchSelectionDraggableType + enum class Type { + kNone, + kTouchHandle, + kLongpress, + }; + protected: virtual ~TouchSelectionDraggable() {}
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc index 1911f19..2dcbd0c 100644 --- a/ui/views/controls/scroll_view.cc +++ b/ui/views/controls/scroll_view.cc
@@ -994,18 +994,10 @@ void ScrollView::ScrollToOffset(const gfx::ScrollOffset& offset) { if (ScrollsWithLayers()) { contents_->layer()->SetScrollOffset(offset); - - // TODO(tapted): Remove this call to OnLayerScrolled(). It's unnecessary, - // but will only be invoked (asynchronously) when a Compositor is present - // and commits a frame, which isn't true in some tests. - // See http://crbug.com/637521. - OnLayerScrolled(offset, contents_->layer()->element_id()); } else { contents_->SetPosition(gfx::Point(-offset.x(), -offset.y())); - ScrollHeader(); } - UpdateOverflowIndicatorVisibility(offset); - UpdateScrollBarPositions(); + OnScrolled(offset); } bool ScrollView::ScrollsWithLayers() const { @@ -1051,8 +1043,13 @@ UpdateBackground(); } -void ScrollView::OnLayerScrolled(const gfx::ScrollOffset&, +void ScrollView::OnLayerScrolled(const gfx::ScrollOffset& current_offset, const cc::ElementId&) { + OnScrolled(current_offset); +} + +void ScrollView::OnScrolled(const gfx::ScrollOffset& offset) { + UpdateOverflowIndicatorVisibility(offset); UpdateScrollBarPositions(); ScrollHeader(); }
diff --git a/ui/views/controls/scroll_view.h b/ui/views/controls/scroll_view.h index ec20b21..6b9c664 100644 --- a/ui/views/controls/scroll_view.h +++ b/ui/views/controls/scroll_view.h
@@ -244,6 +244,9 @@ // Callback entrypoint when hosted Layers are scrolled by the Compositor. void OnLayerScrolled(const gfx::ScrollOffset&, const cc::ElementId&); + // Updates accessory elements when |contents_| is scrolled. + void OnScrolled(const gfx::ScrollOffset& offset); + // Horizontally scrolls the header (if any) to match the contents. void ScrollHeader();
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc index 1b254a0..d5aaeaf 100644 --- a/ui/views/controls/table/table_view.cc +++ b/ui/views/controls/table/table_view.cc
@@ -251,6 +251,21 @@ SelectByViewIndex(model_row == -1 ? -1 : ModelToView(model_row)); } +void TableView::SetSelectionAll(bool select) { + if (!GetRowCount()) + return; + + ui::ListSelectionModel selection_model; + + if (select) + selection_model.AddIndexRangeToSelection(0, GetRowCount() - 1); + + selection_model.set_anchor(selection_model_.anchor()); + selection_model.set_active(selection_model_.active()); + + SetSelectionModel(std::move(selection_model)); +} + int TableView::GetFirstSelectedRow() const { return selection_model_.empty() ? -1 : selection_model_.selected_indices()[0]; } @@ -470,11 +485,7 @@ case ui::VKEY_A: // control-a selects all. if (IsCmdOrCtrl(event) && !single_selection_ && GetRowCount()) { - ui::ListSelectionModel selection_model; - selection_model.SetSelectedIndex(selection_model_.active()); - for (int i = 0; i < GetRowCount(); ++i) - selection_model.AddIndexToSelection(i); - SetSelectionModel(std::move(selection_model)); + SetSelectionAll(/*select=*/true); return true; } break;
diff --git a/ui/views/controls/table/table_view.h b/ui/views/controls/table/table_view.h index 42589aa..962cc76 100644 --- a/ui/views/controls/table/table_view.h +++ b/ui/views/controls/table/table_view.h
@@ -138,6 +138,9 @@ // Selects the specified item, making sure it's visible. void Select(int model_row); + // Selects all items. + void SetSelectionAll(bool select); + // Returns the first selected row in terms of the model. int GetFirstSelectedRow() const;
diff --git a/ui/views/controls/table/table_view_unittest.cc b/ui/views/controls/table/table_view_unittest.cc index dfa2affc..3445cbcd 100644 --- a/ui/views/controls/table/table_view_unittest.cc +++ b/ui/views/controls/table/table_view_unittest.cc
@@ -1295,6 +1295,29 @@ table_->set_observer(nullptr); } +TEST_P(TableViewTest, SelectAll) { + TableViewObserverImpl observer; + table_->set_observer(&observer); + + // Initially no selection. + EXPECT_EQ("active=-1 anchor=-1 selection=", SelectionStateAsString()); + + table_->SetSelectionAll(/*select=*/true); + EXPECT_EQ(1, observer.GetChangedCountAndClear()); + EXPECT_EQ("active=-1 anchor=-1 selection=0 1 2 3", SelectionStateAsString()); + + table_->Select(2); + EXPECT_EQ(1, observer.GetChangedCountAndClear()); + EXPECT_EQ("active=2 anchor=2 selection=2", SelectionStateAsString()); + + table_->SetSelectionAll(/*select=*/true); + EXPECT_EQ(1, observer.GetChangedCountAndClear()); + EXPECT_EQ("active=2 anchor=2 selection=0 1 2 3", SelectionStateAsString()); + + table_->SetSelectionAll(/*select=*/false); + EXPECT_EQ("active=2 anchor=2 selection=", SelectionStateAsString()); +} + TEST_P(TableViewTest, RemoveUnselectedRows) { TableViewObserverImpl observer; table_->set_observer(&observer);
diff --git a/ui/views/style/platform_style_mac.mm b/ui/views/style/platform_style_mac.mm index 8fd57c7e..6572f9f3 100644 --- a/ui/views/style/platform_style_mac.mm +++ b/ui/views/style/platform_style_mac.mm
@@ -70,9 +70,9 @@ if (cursor_position == 0) return gfx::Range(); - base::ScopedCFTypeRef<CFStringRef> cf_string( - CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, text.data(), - text.size(), kCFAllocatorNull)); + base::ScopedCFTypeRef<CFStringRef> cf_string(CFStringCreateWithCharacters( + kCFAllocatorDefault, reinterpret_cast<const UniChar*>(text.data()), + text.size())); CFRange range_to_delete = CFStringGetRangeOfCharacterClusterAtIndex( cf_string, cursor_position - 1, kCFStringBackwardDeletionCluster);
diff --git a/ui/webui/resources/cr_components/customize_themes/customize_themes.html b/ui/webui/resources/cr_components/customize_themes/customize_themes.html index 523376fa..6ff12c4 100644 --- a/ui/webui/resources/cr_components/customize_themes/customize_themes.html +++ b/ui/webui/resources/cr_components/customize_themes/customize_themes.html
@@ -144,7 +144,8 @@ </div> </div> <cr-grid id="themesContainer" columns="6"> - <div id="autogeneratedThemeContainer" aria-label="[[i18n('colorPickerLabel')]]" + <div id="autogeneratedThemeContainer" + aria-label="[[i18n('colorPickerLabel')]]" tabindex="0" on-click="onAutogeneratedThemeClick_"> <cr-theme-icon id="autogeneratedTheme" selected$="[[isThemeIconSelected_('autogenerated', selectedTheme)]]"> @@ -152,31 +153,31 @@ <div id="colorPickerIcon"></div> <input id="colorPicker" type="color" on-change="onCustomFrameColorChange_"> </input> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[i18n('colorPickerLabel')]] + </paper-tooltip> </div> - <paper-tooltip for="autogeneratedThemeContainer" offset="0" - fit-to-visible-bounds> - [[i18n('colorPickerLabel')]] - </paper-tooltip> - <cr-theme-icon id="defaultTheme" aria-label="[[i18n('defaultThemeLabel')]]" - on-click="onDefaultThemeClick_" tabindex="0" - selected$="[[isThemeIconSelected_('default', selectedTheme)]]"> - </cr-theme-icon> - <paper-tooltip for="defaultTheme" offset="0" fit-to-visible-bounds> - [[i18n('defaultThemeLabel')]] - </paper-tooltip> - <template is="dom-repeat" id="themes" items="[[chromeThemes_]]"> - <cr-theme-icon aria-label="[[item.label]]" on-click="onChromeThemeClick_" - id="[[getThemeIconId_(index)]]" - style="--cr-theme-icon-frame-color: - [[skColorToRgba_(item.colors.frame)]]; - --cr-theme-icon-active-tab-color: - [[skColorToRgba_(item.colors.activeTab)]];" - tabindex="0" - selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]"> + <div aria-label="[[i18n('defaultThemeLabel')]]" tabindex="0"> + <cr-theme-icon id="defaultTheme" + on-click="onDefaultThemeClick_" + selected$="[[isThemeIconSelected_('default', selectedTheme)]]"> </cr-theme-icon> - <paper-tooltip for="[[getThemeIconId_(index)]]" - offset="0" fit-to-visible-bounds> - [[item.label]] - </paper-tooltip> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[i18n('defaultThemeLabel')]] + </paper-tooltip> + </div> + <template is="dom-repeat" id="themes" items="[[chromeThemes_]]"> + <div aria-label="[[item.label]]" tabindex="0" class="chrome-theme-wrapper"> + <cr-theme-icon on-click="onChromeThemeClick_" + style="--cr-theme-icon-frame-color: + [[skColorToRgba_(item.colors.frame)]]; + --cr-theme-icon-active-tab-color: + [[skColorToRgba_(item.colors.activeTab)]];" + selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]"> + </cr-theme-icon> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[item.label]] + </paper-tooltip> + </div> </template> </cr-grid>
diff --git a/ui/webui/resources/cr_components/customize_themes/customize_themes.js b/ui/webui/resources/cr_components/customize_themes/customize_themes.js index 0f23727..f648129 100644 --- a/ui/webui/resources/cr_components/customize_themes/customize_themes.js +++ b/ui/webui/resources/cr_components/customize_themes/customize_themes.js
@@ -213,15 +213,6 @@ skColorToRgba_(skColor) { return skColorToRgba(skColor); } - - /** - * @param {number} index - * @return {string} - * @private - */ - getThemeIconId_(index) { - return 'themeIconId' + index; - } } customElements.define(CustomizeThemesElement.is, CustomizeThemesElement);