diff --git a/BUILD.gn b/BUILD.gn index 917a2429d..a7a198d 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -109,27 +109,18 @@ deps += [ "//third_party/abseil-cpp:absl_tests" ] } - if (!is_android && !is_chromecast) { + if (enable_js_type_check) { + deps += [ ":webui_closure_compile" ] + } + + if (!is_android && !is_castos) { deps += [ "//crypto:crypto_unittests", "//google_apis/gcm:gcm_unit_tests", ] } - if (enable_js_type_check) { - deps += [ ":webui_closure_compile" ] - } - - if (!is_ios && !is_android && !is_chromecast) { - deps += [ - "//ui/accessibility:accessibility_perftests", - "//ui/accessibility:accessibility_unittests", - "//ui/accessibility/extensions:extension_tests", - "//ui/accessibility/extensions:extensions", - ] - } - - if (!is_ios && !is_android && !is_chromecast) { + if (!is_ios && !is_android && !is_castos) { deps += [ "//chrome", "//chrome/browser/ui/color:dump_colors", @@ -148,6 +139,10 @@ "//tools/perf/clear_system_cache", "//tools/polymer:polymer_tools_python_unittests", "//tools/privacy_budget:privacy_budget_tools", + "//ui/accessibility:accessibility_perftests", + "//ui/accessibility:accessibility_unittests", + "//ui/accessibility/extensions:extension_tests", + "//ui/accessibility/extensions:extensions", ] } @@ -254,7 +249,7 @@ ] } - if (is_fuchsia && !is_chromecast) { + if (is_fuchsia) { # Add targets that only exist on Fuchsia. deps += [ ":d8_fuchsia", @@ -403,7 +398,7 @@ ] } - if (!is_chromecast) { + if (!is_cast_android) { deps += [ "//android_webview:empty_group", "//android_webview/test", @@ -609,26 +604,26 @@ "//third_party/breakpad:minidump_dump($host_toolchain)", "//third_party/breakpad:minidump_stackwalk($host_toolchain)", ] + } - if (!is_android) { - deps += [ - "//chrome/test:chrome_app_unittests", - "//gpu/khronos_glcts_support:khronos_glcts_test", - "//media/cast:cast_benchmarks", - "//media/cast:tap_proxy", - "//skia:filter_fuzz_stub", - "//skia:image_operations_bench", - "//ui/snapshot:snapshot_unittests", - ] + if (is_linux || is_chromeos_lacros) { + deps += [ + "//chrome/test:chrome_app_unittests", + "//gpu/khronos_glcts_support:khronos_glcts_test", + "//media/cast:cast_benchmarks", + "//media/cast:tap_proxy", + "//skia:filter_fuzz_stub", + "//skia:image_operations_bench", + "//ui/snapshot:snapshot_unittests", + ] - if (!is_debug && !is_component_build) { - deps += [ "//chrome/tools/service_discovery_sniffer" ] - } + if (!is_debug && !is_component_build) { + deps += [ "//chrome/tools/service_discovery_sniffer" ] } + } - if (ozone_platform_x11 && !is_chromecast && target_cpu != "arm") { - deps += [ "//gpu/tools/compositor_model_bench" ] - } + if (ozone_platform_x11 && !is_castos && target_cpu != "arm") { + deps += [ "//gpu/tools/compositor_model_bench" ] } if (is_mac) { @@ -683,18 +678,19 @@ deps += [ "//third_party/breakpad:symupload($host_toolchain)" ] } - if (is_chromecast) { + # TODO(crbug.com/1330636): Remove the Fuchsia `is_chromecast` condition. + if (is_cast_android || is_castos || (is_fuchsia && is_chromecast)) { deps += [ "//chromecast:cast_test_lists" ] + } - if (!is_fuchsia) { - deps += [ - "//chromecast:cast_shell", - "//chromecast/cast_core:core_runtime_simple", - ] + if (is_cast_android || is_castos) { + deps += [ + "//chromecast:cast_shell", + "//chromecast/cast_core:core_runtime_simple", + ] - if (enable_extensions && use_aura) { - deps += [ "//chrome/browser/resources/chromeos/accessibility:build" ] - } + if (enable_extensions && use_aura) { + deps += [ "//chrome/browser/resources/chromeos/accessibility:build" ] } } @@ -726,14 +722,15 @@ deps += [ "//third_party/sqlite:sqlite_shell" ] } - if ((is_linux && !is_chromecast) || is_chromeos_lacros || is_fuchsia) { - # TODO(https://crbug.com/1329673): Figure out if this should be in gn_all and how cross-platform this is. + if ((is_linux && !is_castos) || is_chromeos_lacros || is_fuchsia) { + # TODO(https://crbug.com/1329673): Figure out if this should be in gn_all + # and how cross-platform this is. deps += [ "//components/services/filesystem:filesystem_service_unittests" ] } - if ((is_linux && !is_chromecast) || is_chromeos_lacros) { - # TODO(https://crbug.com/1329673): Figure out if any of these should be in gn_all - # and figure out how cross-platform they are + if ((is_linux && !is_castos) || is_chromeos_lacros) { + # TODO(https://crbug.com/1329673): Figure out if any of these should be in + # gn_all and figure out how cross-platform they are. deps += [ "//chrome/installer/util:strings", "//chrome/tools/convert_dict", @@ -768,8 +765,8 @@ } } - if (((is_linux || is_chromeos) && !is_chromecast) || - (is_win && use_libfuzzer) || (use_libfuzzer && is_mac)) { + if ((is_linux && !is_castos) || is_chromeos || + ((is_win || is_mac) && use_libfuzzer)) { deps += [ "//testing/libfuzzer/fuzzers", "//third_party/freetype-testing:fuzzers", @@ -832,9 +829,9 @@ if (build_dawn_tests) { deps += [ + "//third_party/dawn/src/dawn/fuzzers:fuzzers", "//third_party/dawn/src/dawn/tests:dawn_end2end_tests", "//third_party/dawn/src/dawn/tests:dawn_unittests", - "//third_party/dawn/src/fuzzers/dawn:dawn_fuzzers", "//third_party/dawn/src/tint/fuzzers", "//third_party/dawn/test/tint:tint_unittests", ] @@ -1055,13 +1052,13 @@ testonly = true if (is_fuchsia || is_android) { - # On Fuchsia/Android, ChromeDriver runs on the host, not the device. - if (!is_chromecast) { + # On Fuchsia and non-Cast Android, ChromeDriver runs on the host, not the + # device. + if (!is_cast_android) { deps = [ "//chrome/test/chromedriver:chromedriver($host_toolchain)" ] - - if (is_android) { - deps += [ "//chrome/test/chromedriver/test/webview_shell:chromedriver_webview_shell_apk" ] - } + } + if (is_android && !is_cast_android) { + deps += [ "//chrome/test/chromedriver/test/webview_shell:chromedriver_webview_shell_apk" ] } } else { deps = [ @@ -1556,7 +1553,7 @@ group("chromium_builder_perf") { testonly = true - if (!is_ios && !is_android && !is_chromecast) { + if (!is_ios && !is_android && !is_castos) { data_deps = [ "//cc:cc_perftests", "//chrome/test:load_library_perf_tests", @@ -1568,47 +1565,44 @@ "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", ] - if (is_android) { - data += [ "//third_party/android_sdk/public/platform-tools/adb" ] - } - if (!is_chromeos_ash) { data_deps += [ "//chrome/test:performance_browser_tests" ] } - if (is_linux || is_chromeos_lacros) { - if (is_official_build) { - # In GN builds, this is controlled by the 'linux_dump_symbols' - # flag, which defaults to 1 for official builds. For now, - # we skip the separate flag and just key off of is_official_build. - data_deps += [ "//chrome:linux_symbols" ] - } - data_deps += [ "//tools/perf/clear_system_cache" ] - } - - if (is_win) { - data_deps += [ "//chrome/installer/mini_installer:mini_installer" ] - } else { + if (!is_win) { data_deps += [ "//third_party/breakpad:minidump_stackwalk($host_toolchain)" ] } - if (is_win || is_android) { - data_deps += [ - "//components:components_perftests", - "//third_party/angle/src/tests:angle_perftests", - ] + } + + if ((is_linux && !is_castos) || is_chromeos_lacros) { + if (is_official_build) { + # In GN builds, this is controlled by the 'linux_dump_symbols' + # flag, which defaults to 1 for official builds. For now, + # we skip the separate flag and just key off of is_official_build. + data_deps += [ "//chrome:linux_symbols" ] } - # An `if (is_fuchsia)` condition in //chrome/test/BUILD.gn prevents this - # target from being defined. - # TODO(crbug.com/1310086): Resolve that and remove this exception. - if (is_fuchsia) { - data_deps -= [ "//chrome/test:performance_test_suite" ] - } + data_deps += [ "//tools/perf/clear_system_cache" ] + } + + if (is_win) { + data_deps += [ + "//chrome/installer/mini_installer:mini_installer", + "//components:components_perftests", + "//third_party/angle/src/tests:angle_perftests", + ] + } + + # An `if (is_fuchsia)` condition in //chrome/test/BUILD.gn prevents this + # target from being defined. + # TODO(crbug.com/1310086): Resolve that and remove this exception. + if (is_fuchsia) { + data_deps -= [ "//chrome/test:performance_test_suite" ] } } -if (!is_ios && !is_android && !is_chromecast) { +if (!is_ios && !is_android && !is_castos) { group("chromium_builder_asan") { testonly = true @@ -1671,7 +1665,6 @@ "chrome/test:closure_compile", "components/neterror/resources:closure_compile", "components/security_interstitials:closure_compile", - "components/sync/driver/resources:closure_compile", "mojo/public/tools/bindings/generators/js_templates/lite/test:closure_compile", "ui/webui/resources:closure_compile", ]
diff --git a/DEPS b/DEPS index fe41c656..1c0ca03 100644 --- a/DEPS +++ b/DEPS
@@ -280,11 +280,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': '854c5109541ff35d9927a423c14bed0d48538dda', + 'skia_revision': '8b21825fa22f1eaf90210d75040b0709f19c6a4b', # 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': '183c13946307edeeb383706d79615d928395894d', + 'v8_revision': 'a55b91fbdb006f991fa7cae31bec25636025bdb0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -296,7 +296,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '1ab810ed60e5b5f2e2423adc7dfc67f5d0e9069d', + 'pdfium_revision': '057b3d331dbf564f59bdbf24b2c9407f00d3fd47', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -351,7 +351,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': '483ed69769f24729dc176668a697994ff8704090', + 'catapult_revision': 'b83d69ffe9f3785ceef6f4e0e918ec71ddc14bfb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -359,7 +359,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': '349521cc1d85de84c44e480b04538c4c6e28d843', + 'devtools_frontend_revision': '591021cc31e57e105e9e8e8d2335874d0e8d5bcc', # 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. @@ -617,7 +617,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chrome_mac_universal', - 'version': '3UoNd4X57YAONz6mhQPapIUoO1Ds6K5AIHTAZxNmLUUC', + 'version': 'vE_TO22Lykmt0Fiz5G8bN3pDSBCf9SDzn4a5HTyh_osC', }, ], }, @@ -760,12 +760,12 @@ }, 'src/ios/third_party/earl_grey2/src': { - 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '0422eb059adf0d32c194cfc95eabf4eacc61ecf1', + 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'a800009e44fe22dd527c36462cef25962ef3b6a6', 'condition': 'checkout_ios', }, 'src/ios/third_party/edo/src': { - 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '80e7a3c5cce7a9a68dc5a5e4d54e8fa164cec0e4', + 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '3e49e0e9664d7af8268eee9db7ab0a05671643e2', 'condition': 'checkout_ios', }, @@ -1093,7 +1093,7 @@ }, 'src/third_party/cast_core/public/src': - Var('chromium_git') + '/cast_core/public' + '@' + '6c053df4fe5aea168ca651e2d95dc5dc40ebe059', + Var('chromium_git') + '/cast_core/public' + '@' + '73f0f19136b7617bb893a98e7dd6d17893ff55ba', 'src/third_party/catapult': Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), @@ -1145,7 +1145,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6cebde7ca21a66cbf42f17102e01da2dee5191f8', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9a3c4bc67c6ee06993e295d957681452f829577d', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1434,7 +1434,7 @@ Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da', 'src/third_party/libyuv': - Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '30f9b280487be412da346aecce7834275020976e', + Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'e906ba9fe9df1cdc32307dbb1dcb1223d41bfd56', 'src/third_party/lighttpd': { 'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'), @@ -1673,7 +1673,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@8b44f9a34e1f561d6a91bc80eed34f505eaf8a41', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4ede36c4734b36032b0b0c64c7f4cb63c9d35293', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1712,7 +1712,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f8000b0ea82de00b3cc7d337e7521d1e94fed587', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'f87cb8182033c7ae2f8aa161255673c09f280a84', + Var('webrtc_git') + '/src.git' + '@' + '74fca5ae3a2a4911328d569a12cc95389340ce59', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1785,7 +1785,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@432e93b46201384fcc99943f39094099a8ab3bbc', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0cab979b6c47c39b30d5b95a55e00b774f9c8690', 'condition': 'checkout_src_internal', },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 99c0f518..9b1ade02 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -5877,7 +5877,7 @@ 'IsMainFrame', ] concerning_blink_frame_methods = [ - 'IsCrossOriginToMainFrame', + 'IsCrossOriginToNearestMainFrame', ] concerning_method_pattern = input_api.re.compile(r'(' + r'|'.join( item for sublist in [
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index 078450c4..9381b541 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -339,6 +339,9 @@ + " same value as before."), Flag.baseFeature(BlinkFeatures.THREADED_PRELOAD_SCANNER, "If enabled, the HTMLPreloadScanner will run on a worker thread."), + Flag.baseFeature(BlinkFeatures.TIMED_HTML_PARSER_BUDGET, + "If enabled, the HTMLDocumentParser will use a budget based on elapsed time" + + " rather than token count."), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc index f72c645..0243366 100644 --- a/ash/app_list/views/folder_header_view.cc +++ b/ash/app_list/views/folder_header_view.cc
@@ -99,6 +99,7 @@ kFolderNameBorderThickness)); AppListColorProvider* color_provider = AppListColorProvider::Get(); + set_placeholder_text_color(color_provider->GetFolderHintTextColor()); const SkColor text_color = color_provider->GetFolderTitleTextColor(); SetTextColor(text_color); SetSelectionTextColor(text_color);
diff --git a/ash/webui/personalization_app/resources/common/slideshow.png b/ash/webui/personalization_app/resources/common/slideshow.png index 239ed6e..1abeb7a 100644 --- a/ash/webui/personalization_app/resources/common/slideshow.png +++ b/ash/webui/personalization_app/resources/common/slideshow.png Binary files differ
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html index fd3db03..27433c0e 100644 --- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html +++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html
@@ -102,7 +102,11 @@ } #imageContainer img.disabled { - opacity: var(--cros-disabled-opacity); + /** + * Use 50% for image instead of default cros-disabled-opacity. + * TODO(b/236415314) get this into design system as a semantic value. + */ + opacity: 50%; } :host(:not([main-page])) #collageContainer,
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h index e3f3f7a..205c8ff 100644 --- a/base/allocator/partition_allocator/partition_root.h +++ b/base/allocator/partition_allocator/partition_root.h
@@ -83,6 +83,14 @@ namespace partition_alloc::internal { +// This type trait verifies a type can be used as a pointer offset. +// +// We support pointer offsets in signed (ptrdiff_t) or unsigned (size_t) values. +// Smaller types are also allowed. +template <typename Z> +static constexpr bool offset_type = + std::is_integral_v<Z> && sizeof(Z) <= sizeof(ptrdiff_t); + static constexpr size_t kAllocInfoSize = 1 << 20; struct AllocInfo { @@ -972,8 +980,9 @@ // // This isn't a general purpose function. The caller is responsible for ensuring // that the ref-count is in place for this allocation. +template <typename Z, typename = std::enable_if_t<offset_type<Z>, void>> PA_ALWAYS_INLINE bool PartitionAllocIsValidPtrDelta(uintptr_t address, - ptrdiff_t delta_in_bytes) { + Z delta_in_bytes) { // Required for pointers right past an allocation. See // |PartitionAllocGetSlotStartInBRPPool()|. uintptr_t adjusted_address = address - kPartitionPastAllocationAdjustment;
diff --git a/base/big_endian.cc b/base/big_endian.cc index c4f4443..0563e46 100644 --- a/base/big_endian.cc +++ b/base/big_endian.cc
@@ -113,7 +113,7 @@ bool BigEndianWriter::Skip(size_t len) { if (len > remaining()) return false; - ptr_ += static_cast<ptrdiff_t>(len); + ptr_ += len; return true; } @@ -121,7 +121,7 @@ if (len > remaining()) return false; memcpy(ptr_, buf, len); - ptr_ += static_cast<ptrdiff_t>(len); + ptr_ += len; return true; }
diff --git a/base/memory/raw_ptr.cc b/base/memory/raw_ptr.cc index cf1052b..cbe10c6 100644 --- a/base/memory/raw_ptr.cc +++ b/base/memory/raw_ptr.cc
@@ -58,8 +58,16 @@ } template <bool AllowDangling> -bool BackupRefPtrImpl<AllowDangling>::IsValidDelta(uintptr_t address, - ptrdiff_t delta_in_bytes) { +bool BackupRefPtrImpl<AllowDangling>::IsValidSignedDelta( + uintptr_t address, + ptrdiff_t delta_in_bytes) { + return PartitionAllocIsValidPtrDelta(address, delta_in_bytes); +} + +template <bool AllowDangling> +bool BackupRefPtrImpl<AllowDangling>::IsValidUnsignedDelta( + uintptr_t address, + size_t delta_in_bytes) { return PartitionAllocIsValidPtrDelta(address, delta_in_bytes); }
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h index 75571e2f..98f54580 100644 --- a/base/memory/raw_ptr.h +++ b/base/memory/raw_ptr.h
@@ -62,6 +62,14 @@ // These classes/structures are part of the raw_ptr implementation. // DO NOT USE THESE CLASSES DIRECTLY YOURSELF. +// This type trait verifies a type can be used as a pointer offset. +// +// We support pointer offsets in signed (ptrdiff_t) or unsigned (size_t) values. +// Smaller types are also allowed. +template <typename Z> +static constexpr bool offset_type = + std::is_integral_v<Z> && sizeof(Z) <= sizeof(ptrdiff_t); + struct RawPtrNoOpImpl { // Wraps a pointer. template <typename T> @@ -105,8 +113,10 @@ } // Advance the wrapped pointer by `delta_elems`. - template <typename T> - static ALWAYS_INLINE T* Advance(T* wrapped_ptr, ptrdiff_t delta_elems) { + template <typename T, + typename Z, + typename = std::enable_if_t<offset_type<Z>, void>> + static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr + delta_elems; } @@ -246,8 +256,10 @@ } // Advance the wrapped pointer by `delta_elems`. - template <typename T> - static ALWAYS_INLINE T* Advance(T* wrapped_ptr, ptrdiff_t delta_elems) { + template <typename T, + typename Z, + typename = std::enable_if_t<offset_type<Z>, void>> + static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr + delta_elems; } @@ -423,8 +435,10 @@ } // Advance the wrapped pointer by `delta_elems`. - template <typename T> - static ALWAYS_INLINE T* Advance(T* wrapped_ptr, ptrdiff_t delta_elems) { + template <typename T, + typename Z, + typename = std::enable_if_t<offset_type<Z>, void>> + static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { #if DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS) uintptr_t address = reinterpret_cast<uintptr_t>(wrapped_ptr); if (IsSupportedAndNotNull(address)) @@ -457,8 +471,17 @@ static BASE_EXPORT NOINLINE void AcquireInternal(uintptr_t address); static BASE_EXPORT NOINLINE void ReleaseInternal(uintptr_t address); static BASE_EXPORT NOINLINE bool IsPointeeAlive(uintptr_t address); - static BASE_EXPORT NOINLINE bool IsValidDelta(uintptr_t address, - ptrdiff_t delta_in_bytes); + template <typename Z, typename = std::enable_if_t<offset_type<Z>, void>> + static ALWAYS_INLINE bool IsValidDelta(uintptr_t address, Z delta_in_bytes) { + if constexpr (std::is_signed_v<Z>) + return IsValidSignedDelta(address, ptrdiff_t{delta_in_bytes}); + else + return IsValidUnsignedDelta(address, size_t{delta_in_bytes}); + } + static BASE_EXPORT NOINLINE bool IsValidSignedDelta(uintptr_t address, + ptrdiff_t delta_in_bytes); + static BASE_EXPORT NOINLINE bool IsValidUnsignedDelta(uintptr_t address, + size_t delta_in_bytes); }; #endif // BUILDFLAG(USE_BACKUP_REF_PTR) @@ -510,8 +533,10 @@ } // Advance the wrapped pointer by `delta_elems`. - template <typename T> - static ALWAYS_INLINE T* Advance(T* wrapped_ptr, ptrdiff_t delta_elems) { + template <typename T, + typename Z, + typename = std::enable_if_t<offset_type<Z>, void>> + static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) { return wrapped_ptr + delta_elems; } @@ -847,11 +872,15 @@ --(*this); return result; } - ALWAYS_INLINE raw_ptr& operator+=(ptrdiff_t delta_elems) { + template <typename Z, + typename = std::enable_if_t<internal::offset_type<Z>, void>> + ALWAYS_INLINE raw_ptr& operator+=(Z delta_elems) { wrapped_ptr_ = Impl::Advance(wrapped_ptr_, delta_elems); return *this; } - ALWAYS_INLINE raw_ptr& operator-=(ptrdiff_t delta_elems) { + template <typename Z, + typename = std::enable_if_t<internal::offset_type<Z>, void>> + ALWAYS_INLINE raw_ptr& operator-=(Z delta_elems) { return *this += -delta_elems; }
diff --git a/base/memory/raw_ptr_unittest.cc b/base/memory/raw_ptr_unittest.cc index dae6b2b..719ff96 100644 --- a/base/memory/raw_ptr_unittest.cc +++ b/base/memory/raw_ptr_unittest.cc
@@ -767,6 +767,20 @@ EXPECT_EQ(g_get_for_dereference_cnt, 2); } +TEST_F(RawPtrTest, PlusEqualOperatorTypes) { + int foo[] = {42, 43, 44, 45}; + CountingRawPtr<int> ptr = foo; + ASSERT_EQ(*ptr, 42); + ptr += 2; // Positive literal. + ASSERT_EQ(*ptr, 44); + ptr -= 2; // Negative literal. + ASSERT_EQ(*ptr, 42); + ptr += ptrdiff_t{1}; // ptrdiff_t. + ASSERT_EQ(*ptr, 43); + ptr += size_t{2}; // size_t. + ASSERT_EQ(*ptr, 45); +} + TEST_F(RawPtrTest, MinusEqualOperator) { int foo[] = {42, 43, 44, 45}; CountingRawPtr<int> ptr = &foo[3]; @@ -778,6 +792,20 @@ EXPECT_EQ(g_get_for_dereference_cnt, 2); } +TEST_F(RawPtrTest, MinusEqualOperatorTypes) { + int foo[] = {42, 43, 44, 45}; + CountingRawPtr<int> ptr = &foo[3]; + ASSERT_EQ(*ptr, 45); + ptr -= 2; // Positive literal. + ASSERT_EQ(*ptr, 43); + ptr -= -2; // Negative literal. + ASSERT_EQ(*ptr, 45); + ptr -= ptrdiff_t{2}; // ptrdiff_t. + ASSERT_EQ(*ptr, 43); + ptr -= size_t{1}; // size_t. + ASSERT_EQ(*ptr, 42); +} + TEST_F(RawPtrTest, AdvanceString) { const char kChars[] = "Hello"; std::string str = kChars;
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index 510684c..73948b2c 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -1209,6 +1209,21 @@ has_batch_limit = self._test_instance.test_launcher_batch_limit is not None return is_tryjob and has_filter and has_batch_limit + def _IsFlakeEndorserRun(self): + """Checks whether this test run is part of the flake endorser. + + Returns: + True iff this is being run on a trybot and the current step is part of the + flake endorser. + """ + is_tryjob = self._test_instance.skia_gold_properties.IsTryjobRun() + # Flake endorser shards automatically pass in --gtest_repeat, + # --gtest_filter, and --test-launcher-retry-limit. This is similar to retry + # without patch steps, but does NOT include --test-launcher-batch-limit. + has_filter = bool(self._test_instance.test_filter) + has_batch_limit = self._test_instance.test_launcher_batch_limit is not None + return is_tryjob and has_filter and not has_batch_limit + def _ProcessSkiaGoldRenderTestResults(self, device, results): gold_dir = posixpath.join(self._render_tests_device_output_dir, _DEVICE_GOLD_DIR) @@ -1286,6 +1301,16 @@ gold_session = self._skia_gold_session_manager.GetSkiaGoldSession( keys_input=json_path) + # Both retry without patch steps and flake endorser runs run into an + # issue where they can clobber untriaged results we care about with + # previously triaged (usually good) results. So, run those in dryrun + # mode. In the case of a flake endorser run, we want to re-run the + # comparison without dryrun if the dryrun fails so that the image that + # needs triaging is uploaded. + should_force_dryrun = (self._IsRetryWithoutPatch() + or self._IsFlakeEndorserRun()) + should_redo_on_failed_dryrun = self._IsFlakeEndorserRun() + try: status, error = gold_session.RunComparison( name=render_name, @@ -1293,11 +1318,23 @@ output_manager=self._env.output_manager, use_luci=use_luci, optional_keys=optional_dict, - force_dryrun=self._IsRetryWithoutPatch()) + force_dryrun=should_force_dryrun) except Exception as e: # pylint: disable=broad-except + error = e + if should_redo_on_failed_dryrun: + try: + status, error = gold_session.RunComparison( + name=render_name, + png_file=image_path, + output_manager=self._env.output_manager, + use_luci=use_luci, + optional_keys=optional_dict, + force_dryrun=False) + except Exception as inner_e: # pylint: disable=broad-except + error = inner_e _FailTestIfNecessary(results, full_test_name) _AppendToLog(results, full_test_name, - 'Skia Gold comparison raised exception: %s' % e) + 'Skia Gold comparison raised exception: %s' % error) continue if not status:
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 6f64c7b..fc50bdd 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -8.20220617.1.1 +8.20220617.3.1
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 45c3ff8..a2669bb 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1327,6 +1327,7 @@ sources = [ "javatests/src/org/chromium/chrome/browser/IntentFilterUnitTest.java", "javatests/src/org/chromium/chrome/browser/IntentHandlerUnitTest.java", + "javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRowTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtilsTest.java", @@ -1377,6 +1378,7 @@ "//chrome/browser/ui/android/toolbar:java", "//chrome/browser/ui/messages/android:java", "//chrome/test/android:chrome_java_unit_test_support", + "//components/autofill/android:main_autofill_java", "//components/bookmarks/common/android:bookmarks_java", "//components/browser_ui/notifications/android:java", "//components/browser_ui/settings/android:java", @@ -1454,6 +1456,7 @@ "//chrome/android/features/tab_ui:java", "//chrome/android/features/tab_ui:java_resources", "//chrome/android/features/tab_ui:tab_suggestions_java", + "//chrome/android/features/tab_ui:test_support_javalib", "//chrome/android/webapk/libs/client:client_java", "//chrome/android/webapk/libs/common:common_java", "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java", @@ -1557,7 +1560,6 @@ "//chrome/browser/ui/android/multiwindow:javatests", "//chrome/browser/ui/android/native_page:java", "//chrome/browser/ui/android/night_mode:java", - "//chrome/browser/ui/android/night_mode:javatests", "//chrome/browser/ui/android/night_mode:night_mode_java_test_support", "//chrome/browser/ui/android/omnibox:java", "//chrome/browser/ui/android/page_info:java", @@ -3181,6 +3183,7 @@ "//chrome/browser/signin/services/android:unit_device_javatests", "//chrome/browser/thumbnail/generator:unit_device_javatests", "//chrome/browser/ui/android/appmenu/internal:unit_device_javatests", + "//chrome/browser/ui/android/night_mode:unit_device_javatests", "//chrome/browser/ui/android/omnibox:unit_device_javatests", "//chrome/browser/ui/android/searchactivityutils:unit_device_javatests", "//chrome/browser/ui/messages/android:unit_device_javatests",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 655b8b5..326c6fa 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -58,7 +58,6 @@ "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillSnackbarControllerTest.java", - "javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java", "javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java",
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java index ae830628b0..293b120 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java
@@ -42,6 +42,7 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.UserActionTester; @@ -84,6 +85,7 @@ @Restriction( {UiRestriction.RESTRICTION_TYPE_PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) +@DoNotBatch(reason = "StartSurface*Test tests startup behaviours and thus can't be batched.") @CommandLineFlags. Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"}) public class StartSurfaceBackButtonTest { @@ -164,8 +166,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); // Case 1: // Launches the first site in mv tiles, and press back button. @@ -226,7 +227,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting( allOf(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_container), isDisplayed())); @@ -288,8 +289,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); // Taps on the "Recent tabs" menu item. @@ -306,7 +306,7 @@ // Tap the back on the "Recent tabs" should take us back to the start surface homepage, and // the Tab should be deleted. StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); } @@ -321,8 +321,8 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); + UserActionTester actionTester = new UserActionTester(); // Open a MV tile and back. @@ -333,7 +333,7 @@ StartSurfaceTestUtils.pressBack(mActivityTestRule); // Back gesture on the tab should take us back to the start surface homepage. StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); Assert.assertTrue( actionTester.getActions().contains("StartSurface.ShownFromBackNavigation.FromTab")); } @@ -370,8 +370,8 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); + StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); Assert.assertEquals("The launched tab should have the launch type FROM_START_SURFACE", TabLaunchType.FROM_START_SURFACE, @@ -381,7 +381,7 @@ // Back gesture on the tab should take us back to the start surface homepage. StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); } @Test @@ -394,8 +394,7 @@ Assume.assumeTrue(mImmediateReturn && !mUseInstantStart); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.logo)); // Open an incognito tab from Start. @@ -408,7 +407,7 @@ // Go back to Start homepage. TestThreadUtils.runOnUiThreadBlocking(() -> cta.getTabCreator(false).launchNTP()); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); // Open an incognito tab from Start again. mvTilesLayout = mActivityTestRule.getActivity().findViewById( @@ -419,7 +418,7 @@ // Press back button and Start homepage should show. StartSurfaceTestUtils.pressBack(mActivityTestRule); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 1); onViewWaiting( allOf(withId(org.chromium.chrome.tab_ui.R.id.mv_tiles_layout), isDisplayed())); @@ -442,8 +441,8 @@ // work with a single event. Assume.assumeFalse(mImmediateReturn); StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, + mCurrentlyActiveLayout, mActivityTestRule.getActivity()); StartSurfaceTestUtils.gestureNavigateBack(mActivityTestRule);
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java index 41a898b1..e70e900 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java
@@ -38,6 +38,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; @@ -79,6 +80,7 @@ @Restriction( {UiRestriction.RESTRICTION_TYPE_PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) +@DoNotBatch(reason = "StartSurface*Test tests startup behaviours and thus can't be batched.") @CommandLineFlags. Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"}) public class StartSurfaceMVTilesTest { @@ -154,10 +156,9 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - StartSurfaceTestUtils.waitForTabModel(cta); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); StartSurfaceTestUtils.launchFirstMVTile(cta, /* currentTabCount = */ 1); if (isInstantReturn()) { // TODO(crbug.com/1076274): fix toolbar to avoid wrongly focusing on the toolbar @@ -178,10 +179,10 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); StartSurfaceCoordinator startSurfaceCoordinator = StartSurfaceTestUtils.getStartSurfaceFromUIThread(cta); + TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); TestThreadUtils.runOnUiThreadBlocking(() -> { Assert.assertFalse(startSurfaceCoordinator.isMVTilesCleanedUpForTesting()); }); @@ -204,8 +205,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); StartSurfaceCoordinator startSurfaceCoordinator = StartSurfaceTestUtils.getStartSurfaceFromUIThread(cta); @@ -237,9 +237,8 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(mActivityTestRule.getActivity()); + StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, + mCurrentlyActiveLayout, mActivityTestRule.getActivity()); SiteSuggestion siteToDismiss = mMostVisitedSites.getCurrentSites().get(1); final View tileView = getTileViewFor(siteToDismiss); @@ -270,10 +269,9 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - StartSurfaceTestUtils.waitForTabModel(cta); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); SiteSuggestion siteToOpen = mMostVisitedSites.getCurrentSites().get(1); final View tileView = getTileViewFor(siteToOpen); @@ -296,10 +294,9 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - StartSurfaceTestUtils.waitForTabModel(cta); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); SiteSuggestion siteToOpen = mMostVisitedSites.getCurrentSites().get(1); final View tileView = getTileViewFor(siteToOpen);
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java index 179c3747e..e01cfa46 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -40,6 +40,7 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; @@ -69,6 +70,7 @@ @Restriction( {UiRestriction.RESTRICTION_TYPE_PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) +@DoNotBatch(reason = "StartSurface*Test tests startup behaviours and thus can't be batched.") @CommandLineFlags. Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"}) public class StartSurfaceNoTabsTest {
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java index ea0c1ba..e2fc48d 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTabSwitcherTest.java
@@ -47,6 +47,7 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.DoNotBatch; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.base.test.util.Restriction; @@ -79,6 +80,7 @@ @Restriction( {UiRestriction.RESTRICTION_TYPE_PHONE, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @EnableFeatures({ChromeFeatureList.START_SURFACE_ANDROID + "<Study"}) +@DoNotBatch(reason = "StartSurface*Test tests startup behaviours and thus can't be batched.") @CommandLineFlags. Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "force-fieldtrials=Study/Group"}) public class StartSurfaceTabSwitcherTest { @@ -146,9 +148,8 @@ @CommandLineFlags.Add({START_SURFACE_TEST_BASE_PARAMS}) public void testShow_SingleAsTabSwitcher() { if (mImmediateReturn) { - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(mActivityTestRule.getActivity()); + StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, + mCurrentlyActiveLayout, mActivityTestRule.getActivity()); if (isInstantReturn()) { // TODO(crbug.com/1076274): fix toolbar to avoid wrongly focusing on the toolbar // omnibox. @@ -181,8 +182,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); assertEquals(cta.findViewById(R.id.tab_switcher_title).getVisibility(), View.VISIBLE); @@ -270,10 +270,8 @@ } ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - CriteriaHelper.pollUiThread(() - -> cta.getLayoutManager() != null - && cta.getLayoutManager().isLayoutVisible(LayoutType.TAB_SWITCHER)); - StartSurfaceTestUtils.waitForTabModel(cta); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.logo)); Tab tab1 = cta.getCurrentTabModel().getTabAt(0); @@ -382,8 +380,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); StartSurfaceCoordinator startSurfaceCoordinator = StartSurfaceTestUtils.getStartSurfaceFromUIThread(cta);
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index d95252b3..e34f3e7 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -18,10 +18,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; -import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -109,8 +107,7 @@ /** * Integration tests of the {@link StartSurface} for cases with tabs. See {@link * StartSurfaceNoTabsTest} for test that have no tabs. See {@link StartSurfaceTabSwitcherTest}, - * {@link StartSurfaceMVTilesTest}, {@link StartSurfaceBackButtonTest}, {@link - * StartSurfaceFinaleTest} for more tests. + * {@link StartSurfaceMVTilesTest}, {@link StartSurfaceBackButtonTest} for more tests. */ @RunWith(ParameterizedRunner.class) @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) @@ -196,8 +193,7 @@ } ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.primary_tasks_surface_view)); onViewWaiting(withId(R.id.search_box_text)).check(matches(isDisplayed())); @@ -229,8 +225,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.primary_tasks_surface_view)); onViewWaiting(withId(R.id.search_box_text)); @@ -276,9 +271,9 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.primary_tasks_surface_view)); onViewWaiting(withId(R.id.search_box_text)); @@ -324,9 +319,9 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.primary_tasks_surface_view)); onViewWaiting(withId(R.id.search_box_text)); @@ -394,7 +389,7 @@ assertTrue(cta.getTabModelSelector().getCurrentModel().isIncognito()); if (mImmediateReturn) { StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.secondary_tasks_surface_view)); } else { int container_id = ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_NTP_REVAMP) @@ -412,11 +407,10 @@ if (!mImmediateReturn) { StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - StartSurfaceTestUtils.waitForTabModel(cta); - assertThat(cta.getTabModelSelector().getCurrentModel().getCount(), equalTo(1)); + StartSurfaceTestUtils.waitForOverviewVisible( + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); + TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); onViewWaiting(withId(R.id.search_box_text)).perform(replaceText("about:blank")); CriteriaHelper.pollInstrumentationThread( @@ -428,7 +422,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> cta.getTabCreator(false).launchNTP()); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(withId(R.id.primary_tasks_surface_view)); TextView urlBar = cta.findViewById(R.id.url_bar); @@ -546,8 +540,8 @@ Assert.assertEquals("single", StartSurfaceConfiguration.START_SURFACE_VARIATION.getValue()); Assert.assertEquals(isSingleTabSwitcher, StartSurfaceConfiguration.START_SURFACE_LAST_ACTIVE_TAB_ONLY.getValue()); - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, + mCurrentlyActiveLayout, mActivityTestRule.getActivity()); mActivityTestRule.waitForActivityNativeInitializationComplete(); StartSurfaceTestUtils.waitForDeferredStartup(mActivityTestRule); @@ -610,9 +604,8 @@ StartSurfaceTestUtils.pressHomePageButton(mActivityTestRule.getActivity()); } - StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(mActivityTestRule.getActivity()); + StartSurfaceTestUtils.waitForOverviewVisible(mLayoutChangedCallbackHelper, + mCurrentlyActiveLayout, mActivityTestRule.getActivity()); onViewWaiting(withId(R.id.primary_tasks_surface_view)); onView(withId(R.id.search_box_text)).check(matches(isDisplayed())); @@ -632,8 +625,7 @@ BottomSheetTestSupport bottomSheetTestSupport = new BottomSheetTestSupport( cta.getRootUiCoordinatorForTesting().getBottomSheetController()); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); assertFalse(bottomSheetTestSupport.hasSuppressionTokens()); @@ -679,8 +671,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); // Scroll the toolbar. @@ -712,7 +703,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); onViewWaiting(allOf(withId(R.id.mv_tiles_container), isDisplayed())); // Launches the first site in mv tiles. @@ -776,8 +767,9 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); + TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); + TestThreadUtils.runOnUiThreadBlocking( () -> { cta.getTabModelSelector().getModel(false).closeAllTabs(); }); TabUiTestHelper.verifyTabModelTabCount(cta, 0, 0); @@ -995,8 +987,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); if (!mImmediateReturn) StartSurfaceTestUtils.pressHomePageButton(cta); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -1065,8 +1056,7 @@ ChromeTabbedActivity cta = mActivityTestRule.getActivity(); StartSurfaceTestUtils.waitForOverviewVisible( - mLayoutChangedCallbackHelper, mCurrentlyActiveLayout); - StartSurfaceTestUtils.waitForTabModel(cta); + mLayoutChangedCallbackHelper, mCurrentlyActiveLayout, cta); TabUiTestHelper.verifyTabModelTabCount(cta, 1, 0); Assert.assertEquals(0, RenderProcessHostUtils.getCurrentRenderProcessCount());
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java index c001b24..eff6aecd 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java
@@ -194,12 +194,17 @@ * @param layoutChangedCallbackHelper The call back function to help check whether layout is * changed. * @param currentlyActiveLayout The current active layout. + * @param cta The ChromeTabbedActivity under test. */ - public static void waitForOverviewVisible( - CallbackHelper layoutChangedCallbackHelper, @LayoutType int currentlyActiveLayout) { - if (currentlyActiveLayout == LayoutType.TAB_SWITCHER) return; + public static void waitForOverviewVisible(CallbackHelper layoutChangedCallbackHelper, + @LayoutType int currentlyActiveLayout, ChromeTabbedActivity cta) { + if (currentlyActiveLayout == LayoutType.TAB_SWITCHER) { + StartSurfaceTestUtils.waitForTabModel(cta); + return; + } try { layoutChangedCallbackHelper.waitForNext(30L, TimeUnit.SECONDS); + StartSurfaceTestUtils.waitForTabModel(cta); } catch (TimeoutException ex) { assert false : "Timeout waiting for browser to enter tab switcher / start surface."; }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java index 698eedc2..ddaab17 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java
@@ -13,7 +13,6 @@ import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; import static androidx.test.espresso.matcher.RootMatchers.withDecorView; import static androidx.test.espresso.matcher.ViewMatchers.Visibility.VISIBLE; -import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -43,11 +42,9 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount; import static org.chromium.components.embedder_support.util.UrlConstants.NTP_URL; import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; -import static org.chromium.ui.test.util.ViewUtils.waitForView; import android.content.res.Configuration; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Build.VERSION_CODES; import android.support.test.InstrumentationRegistry; @@ -90,7 +87,6 @@ import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.compositor.layouts.Layout; -import org.chromium.chrome.browser.compositor.layouts.StaticLayout; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.flags.CachedFeatureFlags; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -98,17 +94,11 @@ import org.chromium.chrome.browser.layouts.LayoutTestUtils; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils; -import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLaunchType; -import org.chromium.chrome.browser.tab.TabStateExtractor; import org.chromium.chrome.browser.tab.TabUtils; -import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver; -import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; -import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabGridThumbnailView; import org.chromium.chrome.browser.tasks.tab_management.TabProperties; @@ -131,7 +121,6 @@ import org.chromium.chrome.test.util.MenuUtils; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; -import org.chromium.components.browser_ui.widget.chips.ChipView; import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -141,7 +130,6 @@ import org.chromium.ui.test.util.DisableAnimationsTestRule; import org.chromium.ui.test.util.UiRestriction; import org.chromium.ui.util.ColorUtils; -import org.chromium.ui.widget.ChromeImageView; import org.chromium.ui.widget.ViewLookupCachingFrameLayout; import java.io.FileOutputStream; @@ -152,8 +140,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; // clang-format off /** Tests for the {@link TabSwitcherAndStartSurfaceLayout} */ @@ -1560,169 +1546,6 @@ } } - private void waitForLastSearchTerm(Tab tab, String expected) { - CriteriaHelper.pollUiThread(() -> { - Criteria.checkThat( - TabAttributeCache.getLastSearchTerm(tab.getId()), Matchers.is(expected)); - }); - } - - @Test - @MediumTest - // Disable TAB_TO_GTS_ANIMATION to make it less flaky. - @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION) - @CommandLineFlags.Add({BASE_PARAMS + "/enable_search_term_chip/true"}) - public void testSearchTermChip_noChip() throws InterruptedException { - assertTrue(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()); - prepareTabs(1, 0, mUrl); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(allOf(withId(R.id.page_info_button), - isDescendantOfA(withId(R.id.compositor_view_holder)))) - .check(matches(not(isDisplayed()))); - } - - @Test - @MediumTest - // Disable TAB_TO_GTS_ANIMATION to make it less flaky. - @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION) - @CommandLineFlags.Add({BASE_PARAMS + "/enable_search_term_chip/true"}) - @DisabledTest(message = "http://crbug/1120822 - Flaky on bots.") - public void testSearchTermChip_withChip() throws InterruptedException { - assertTrue(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()); - // Make sure we support RTL and CJKV languages. - String searchTermWithSpecialCodePoints = "a\n ئۇيغۇرچە\u200Eæ¼¢å—"; - // Special code points like new line (\n) and left-to-right marker (\u200E) should - // be stripped out. See TabAttributeCache#removeEscapedCodePoints for more details. - String expectedTerm = "a ئۇيغۇرچە漢å—"; - - String anotherTerm = "hello world"; - - // Do search, and verify the chip is still not shown. - AtomicReference<String> searchUrl = new AtomicReference<>(); - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - Tab currentTab = cta.getTabModelSelector().getCurrentTab(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - TemplateUrlServiceFactory.get().setSearchEngine("google.com"); - searchUrl.set(TemplateUrlServiceFactory.get().getUrlForSearchQuery( - searchTermWithSpecialCodePoints)); - currentTab.loadUrl(new LoadUrlParams(searchUrl.get())); - }); - ChromeTabUtils.waitForTabPageLoaded(currentTab, null); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(withId(R.id.page_info_button)).check(matches(not(isDisplayed()))); - Espresso.pressBack(); - - // Navigate, and verify the chip is shown. - mActivityTestRule.loadUrl(mUrl); - waitForLastSearchTerm(currentTab, expectedTerm); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(withId(R.id.page_info_button)) - .check(waitForView(allOf(withText(expectedTerm), isDisplayed()))); - Espresso.pressBack(); - - // Do another search, and verify the chip is gone. - AtomicReference<String> searchUrl2 = new AtomicReference<>(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - TemplateUrlServiceFactory.get().setSearchEngine("google.com"); - searchUrl2.set(TemplateUrlServiceFactory.get().getUrlForSearchQuery(anotherTerm)); - currentTab.loadUrl(new LoadUrlParams(searchUrl2.get())); - }); - ChromeTabUtils.waitForTabPageLoaded(currentTab, null); - waitForLastSearchTerm(currentTab, null); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(withId(R.id.page_info_button)).check(matches(not(isDisplayed()))); - Espresso.pressBack(); - - // Back to previous page, and verify the chip is back. - Espresso.pressBack(); - waitForLastSearchTerm(currentTab, expectedTerm); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(withId(R.id.page_info_button)) - .check(waitForView(allOf(withText(expectedTerm), isDisplayed()))); - - // Click the chip and check the tab navigates back to the search result page. - assertEquals(mUrl, ChromeTabUtils.getUrlStringOnUiThread(currentTab)); - onView(withId(R.id.page_info_button)) - .check(waitForView(allOf(withText(expectedTerm), isDisplayed()))); - onView(withId(R.id.page_info_button)).perform(click()); - LayoutTestUtils.waitForLayout(cta.getLayoutManager(), LayoutType.BROWSING); - ChromeTabUtils.waitForTabPageLoaded(currentTab, searchUrl.get()); - - // Verify the chip is gone. - waitForLastSearchTerm(currentTab, null); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(withId(R.id.page_info_button)).check(matches(not(isDisplayed()))); - } - - @Test - @MediumTest - @FlakyTest(message = "crbug.com/1324021") - // clang-format off - // Disable TAB_TO_GTS_ANIMATION to make it less flaky. - @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION) - @CommandLineFlags.Add({BASE_PARAMS + - "/enable_search_term_chip/true/enable_search_term_chip_adaptive_icon/true"}) - public void testSearchTermChip_adaptiveIcon() throws InterruptedException { - // clang-format on - assertTrue(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP.getValue()); - assertTrue(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP_ADAPTIVE.getValue()); - String searchTerm = "hello world"; - - // Do search, and verify the chip is still not shown. - AtomicReference<String> searchUrl = new AtomicReference<>(); - ChromeTabbedActivity cta = mActivityTestRule.getActivity(); - Tab currentTab = cta.getTabModelSelector().getCurrentTab(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - TemplateUrlServiceFactory.get().setSearchEngine("google.com"); - searchUrl.set(TemplateUrlServiceFactory.get().getUrlForSearchQuery(searchTerm)); - currentTab.loadUrl(new LoadUrlParams(searchUrl.get())); - }); - ChromeTabUtils.waitForTabPageLoaded(currentTab, null); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(allOf(withId(R.id.page_info_button), - isDescendantOfA(withId(R.id.compositor_view_holder)))) - .check(matches(not(isDisplayed()))); - Espresso.pressBack(); - - // Navigate, and verify the chip is shown. - mActivityTestRule.loadUrl(mUrl); - waitForLastSearchTerm(currentTab, searchTerm); - enterTabSwitcher(mActivityTestRule.getActivity()); - - onView(tabSwitcherViewMatcher()).check(TabCountAssertion.havingTabCount(1)); - onView(allOf(withId(R.id.page_info_button), - isDescendantOfA(withId(R.id.compositor_view_holder)))) - .check(waitForView(allOf(withText(searchTerm), isDisplayed()))); - - // Switch the default search engine from google.com to yahoo.com, the search chip icon - // should change. - RecyclerView tabListRecyclerView = cta.findViewById(R.id.tab_list_view); - ChipView chipView = - tabListRecyclerView.findViewHolderForAdapterPosition(0).itemView.findViewById( - R.id.page_info_button); - ChromeImageView iconImageView = (ChromeImageView) chipView.getChildAt(0); - Drawable googleDrawable = iconImageView.getDrawable(); - - TestThreadUtils.runOnUiThreadBlocking( - () -> TemplateUrlServiceFactory.get().setSearchEngine("yahoo.com")); - - assertNotEquals(googleDrawable, iconImageView.getDrawable()); - } - @Test @MediumTest @EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID}) @@ -1893,98 +1716,6 @@ () -> GarbageCollectionTestUtils.canBeGarbageCollected(activityRef)); } - /** - * This test is to simulate closing all incognito tabs during the activity recreation stage. - * This is a regression test for crbug.com/1044557. The test ensures all incognito tabs closed, - * which leads to a TabModel switching event, before the first normal tab is restored. - */ - @Test - @MediumTest - @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION) - // clang-format off - @DisabledTest(message = "crbug.com/1044557 This regression test fails deterministically with" + - " the bot, but passes with local emulator. Disable the test for now.") - public void - closeAllIncognitoTabsBeforeRestoreCompleted() { - // clang-format on - prepareTabs(3, 1, "about:blank"); - - assertTrue(mActivityTestRule.getActivity().getCurrentTabModel().isIncognito()); - - // Need to wait for contentsState to be initialized for the tab to restore correctly. - CriteriaHelper.pollUiThread( - () - -> TabStateExtractor.from(mActivityTestRule.getActivity().getActivityTab()) - .contentsState - != null, - "Incognito tab contentsState is null"); - - ChromeTabUtils.newTabFromMenu(InstrumentationRegistry.getInstrumentation(), - mActivityTestRule.getActivity(), true, false); - - mActivityTestRule.loadUrl("about:blank"); - - // Need to wait for contentsState to be initialized for the tab to restore correctly. - CriteriaHelper.pollUiThread( - () - -> TabStateExtractor.from(mActivityTestRule.getActivity().getActivityTab()) - .contentsState - != null, - "Incognito tab contentsState is null"); - - PseudoTab.clearForTesting(); - - AtomicBoolean tabModelRestoreCompleted = new AtomicBoolean(false); - AtomicBoolean normalModelIsEmpty = new AtomicBoolean(true); - - mActivityTestRule.recreateActivity(); - ChromeTabbedActivity newActivity = mActivityTestRule.getActivity(); - - new TabModelSelectorTabModelObserver(newActivity.getTabModelSelector()) { - @Override - public void restoreCompleted() { - tabModelRestoreCompleted.set(true); - } - - @Override - public void willAddTab(Tab tab, int type) { - if (tab.isIncognito() || !normalModelIsEmpty.get()) return; - - // Ensure normal tab model is active before its first tab restores. - CriteriaHelper.pollUiThread( - () - -> !newActivity.getCurrentTabModel().isIncognito(), - "Had not switched to Normal TabModel before the first normal Tab restored"); - } - - @Override - public void didAddTab(Tab tab, int type, int creationState) { - if (tab.isIncognito()) return; - normalModelIsEmpty.set(false); - } - }; - - CriteriaHelper.pollUiThread(() - -> newActivity.didFinishNativeInitialization(), - "New Activity has not finished initialized yet"); - CriteriaHelper.pollUiThread(() - -> newActivity.getCurrentTabModel().isIncognito(), - "New Activity current TabModel is not incognito"); - TestThreadUtils.runOnUiThreadBlocking(IncognitoTabHostUtils::closeAllIncognitoTabs); - - assertTrue("Deferred startup never completed", mActivityTestRule.waitForDeferredStartup()); - - CriteriaHelper.pollUiThread(() - -> tabModelRestoreCompleted.get(), - "New Activity normal TabModel has never restored"); - - assertFalse(newActivity.getCurrentTabModel().isIncognito()); - assertNotNull(newActivity.getTabModelSelector().getCurrentTab()); - // With the fix, StaticLayout guarantees to be shown. Otherwise, StartSurfaceLayout could be - // shown, not guaranteed. - assertTrue(newActivity.getLayoutManager().getActiveLayout() instanceof StaticLayout); - } - @Test @MediumTest // clang-format off
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn index 4d3a61a..222234e 100644 --- a/chrome/android/features/tab_ui/BUILD.gn +++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -240,30 +240,52 @@ testonly = true sources = [ "javatests/src/org/chromium/chrome/browser/tasks/tab_management/LargeMessageCardViewBinderTest.java", + "javatests/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderTest.java", "javatests/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardViewBinderTest.java", + "javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceCardViewTest.java", "javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiViewBinderTest.java", + "javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java", "javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorLayoutBinderTest.java", ] deps = [ ":java", ":java_resources", + ":test_support_javalib", + "//base:base_java", "//base:base_java_test_support", + "//base/test:test_support_java", "//chrome/android/features/tab_ui:java", + "//chrome/android/features/tab_ui:tab_suggestions_java", + "//chrome/browser/commerce/price_tracking/android:java", + "//chrome/browser/flags:java", + "//chrome/browser/optimization_guide/android:java", + "//chrome/browser/profiles/android:java", "//chrome/browser/tab:java", + "//chrome/test/android:chrome_java_integration_only_test_support", "//chrome/test/android:chrome_java_test_support_common", "//components/browser_ui/styles/android:java", "//components/browser_ui/widget/android:java", + "//components/commerce/core:proto_java", + "//components/embedder_support/android:util_java", + "//components/optimization_guide/proto:optimization_guide_proto_java", + "//components/payments/content/android:full_java", + "//content/public/android:content_full_java", "//content/public/test/android:content_java_test_support", + "//third_party/android_deps:espresso_java", + "//third_party/android_deps:protobuf_lite_runtime_java", "//third_party/android_sdk:android_test_base_java", "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//third_party/androidx:androidx_recyclerview_recyclerview_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/hamcrest:hamcrest_core_java", "//third_party/junit:junit", + "//third_party/mockito:mockito_java", "//ui/android:ui_java_test_support", "//ui/android:ui_java_test_support", "//ui/android:ui_no_recycler_view_java", + "//ui/android:ui_recycler_view_java", + "//url:gurl_java", ] } @@ -288,6 +310,35 @@ ] } +android_library("test_support_javalib") { + testonly = true + sources = [ "javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java" ] + + deps = [ + ":java", + "//base:base_java", + "//base:base_java_test_support", + "//chrome/android:chrome_java", + "//chrome/browser/tab:java", + "//chrome/browser/tab_group:java", + "//chrome/browser/tabmodel:java", + "//chrome/browser/ui/android/layouts:java", + "//chrome/browser/ui/android/layouts/test:java", + "//chrome/test/android:chrome_java_integration_only_test_support", + "//components/browser_ui/widget/android:test_support_java", + "//content/public/android:content_full_java", + "//content/public/android:content_main_dex_java", + "//content/public/test/android:content_java_test_support", + "//third_party/android_deps:espresso_java", + "//third_party/android_support_test_runner:runner_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_core_core_java", + "//third_party/androidx:androidx_recyclerview_recyclerview_java", + "//third_party/hamcrest:hamcrest_library_java", + "//third_party/junit:junit", + ] +} + module_desc_java("module_desc_java") { module_name = "tab_management" }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuCoordinator.java index 44a5c4e..88f9124 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuCoordinator.java
@@ -92,7 +92,7 @@ // clang-format off adapter.registerType(ListItemType.MENU_ITEM, new LayoutViewBuilder(R.layout.list_menu_item), - TabGridDialogMenuItemBinder::binder); + TabGridDialogMenuItemBinder::bind); // clang-format on listView.setOnItemClickListener((p, v, pos, id) -> { if (mOnItemClickedCallback != null) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinder.java index d45b1e70..5d8ef8d 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinder.java
@@ -15,7 +15,7 @@ * ViewBinder for menu item in tab grid dialog menu. */ public class TabGridDialogMenuItemBinder { - public static void binder(PropertyModel model, View view, PropertyKey propertyKey) { + public static void bind(PropertyModel model, View view, PropertyKey propertyKey) { if (propertyKey == TabGridDialogMenuItemProperties.TITLE) { TextView textView = view.findViewById(R.id.menu_item_text); textView.setText(model.get(TabGridDialogMenuItemProperties.TITLE));
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java index 086bde8..631e0034 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
@@ -585,7 +585,6 @@ @Test @MediumTest - @FlakyTest(message = "https://crbug.com/1237367") // clang-format off @EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID + "<Study"}) @CommandLineFlags.Add({"force-fieldtrials=Study/Group",
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinderUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinderUnitTest.java new file mode 100644 index 0000000..77d76f9 --- /dev/null +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinderUnitTest.java
@@ -0,0 +1,60 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.tasks.tab_management; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.widget.TextView; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.tab_ui.R; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; + +/** + * Tests for {@link TabGridDialogMenuItemBinder}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class TabGridDialogMenuItemBinderUnitTest { + @Mock + private TextView mMockTextView; + + @Mock + private TextView mMockRootView; + + private static final String FAKE_ITEM_TITLE_TEXT = "FAKE TITLE"; + private PropertyModel mModel; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mModel = new PropertyModel(TabGridDialogMenuItemProperties.ALL_KEYS); + PropertyModelChangeProcessor.create( + mModel, mMockRootView, TabGridDialogMenuItemBinder::bind); + + when(mMockRootView.findViewById(R.id.menu_item_text)).thenReturn(mMockTextView); + } + + @Test + @SmallTest + public void updateTitleText() { + mModel.set(TabGridDialogMenuItemProperties.TITLE, FAKE_ITEM_TITLE_TEXT); + verify(mMockTextView, times(1)).setText(FAKE_ITEM_TITLE_TEXT); + + mModel.set(TabGridDialogMenuItemProperties.TITLE, null); + verify(mMockTextView, times(1)).setText(null); + } +}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni index 363a8472..96f0046 100644 --- a/chrome/android/features/tab_ui/tab_management_java_sources.gni +++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -23,9 +23,7 @@ tab_management_test_java_sources = [ "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/CloseAllTabsDialogTest.java", - "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceAlertsMessageCardTest.java", - "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceCardViewTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/PriceTrackingDialogTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/RecyclerViewMatcherUtils.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridAccessibilityHelperTest.java", @@ -35,14 +33,12 @@ "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerViewBinderTest.java", - "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTestingRobot.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherThumbnailTest.java", - "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java", ] @@ -57,6 +53,7 @@ "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageServiceUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java", + "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemBinderUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinderUnitTest.java", "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupTitleEditorUnitTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java index e3cdc957..70e0d51 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -160,8 +160,7 @@ this::isInOverviewMode, this::isWarmOnResume, /* appMenuDelegate= */ this, /* statusBarColorProvider= */ this, getIntentRequestTracker(), () -> mToolbarCoordinator, () -> mNavigationController, () -> mIntentDataProvider, - () -> mDelegateFactory.getEphemeralTabCoordinator(), - getMultiWindowModeStateDispatcher()); + () -> mDelegateFactory.getEphemeralTabCoordinator()); // clang-format on return mBaseCustomTabRootUiCoordinator; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java index 5f3c0e6..5bed26e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -34,7 +34,6 @@ import org.chromium.chrome.browser.fullscreen.BrowserControlsManager; import org.chromium.chrome.browser.fullscreen.FullscreenManager; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.reengagement.ReengagementNotificationController; import org.chromium.chrome.browser.share.ShareDelegate; @@ -58,7 +57,6 @@ private final Supplier<CustomTabToolbarCoordinator> mToolbarCoordinator; private final Supplier<CustomTabActivityNavigationController> mNavigationController; private final Supplier<BrowserServicesIntentDataProvider> mIntentDataProvider; - private final MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher; private CustomTabHeightStrategy mCustomTabHeightStrategy; @@ -96,7 +94,6 @@ * @param customTabToolbarCoordinator Coordinates the custom tab toolbar. * @param customTabNavigationController Controls the custom tab navigation. * @param intentDataProvider Contains intent information used to start the Activity. - * @param multiWindowModeStateDispatcher Required to register for multi-window mode changes. */ public BaseCustomTabRootUiCoordinator(@NonNull AppCompatActivity activity, @NonNull ObservableSupplier<ShareDelegate> shareDelegateSupplier, @@ -129,8 +126,7 @@ @NonNull Supplier<CustomTabToolbarCoordinator> customTabToolbarCoordinator, @NonNull Supplier<CustomTabActivityNavigationController> customTabNavigationController, @NonNull Supplier<BrowserServicesIntentDataProvider> intentDataProvider, - @NonNull Supplier<EphemeralTabCoordinator> ephemeralTabCoordinatorSupplier, - @NonNull MultiWindowModeStateDispatcher multiWindowModeStateDispatcher) { + @NonNull Supplier<EphemeralTabCoordinator> ephemeralTabCoordinatorSupplier) { // clang-format off super(activity, null, shareDelegateSupplier, tabProvider, profileSupplier, bookmarkBridgeSupplier, tabBookmarkerSupplier, @@ -151,7 +147,6 @@ mToolbarCoordinator = customTabToolbarCoordinator; mNavigationController = customTabNavigationController; mIntentDataProvider = intentDataProvider; - mMultiWindowModeStateDispatcher = multiWindowModeStateDispatcher; } @Override @@ -203,7 +198,7 @@ != null : "IntentDataProvider needs to be non-null after preInflationStartup"; mCustomTabHeightStrategy = CustomTabHeightStrategy.createStrategy(mActivity, - intentDataProvider.getInitialActivityHeight(), mMultiWindowModeStateDispatcher, + intentDataProvider.getInitialActivityHeight(), intentDataProvider.getColorProvider().getNavigationBarColor(), intentDataProvider.getColorProvider().getNavigationBarDividerColor(), CustomTabsConnection.getInstance(), intentDataProvider.getSession(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java index f819ab5..9d15aa6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java
@@ -13,14 +13,12 @@ import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; /** * The default strategy for setting the height of the custom tab. */ public class CustomTabHeightStrategy { public static CustomTabHeightStrategy createStrategy(Activity activity, @Px int initialHeight, - MultiWindowModeStateDispatcher multiWindowModeStateDispatcher, Integer navigationBarColor, Integer navigationBarDividerColor, CustomTabsConnection connection, @Nullable CustomTabsSessionToken session, ActivityLifecycleDispatcher lifecycleDispatcher) { @@ -28,8 +26,8 @@ return new CustomTabHeightStrategy(); } - return new PartialCustomTabHeightStrategy(activity, initialHeight, - multiWindowModeStateDispatcher, navigationBarColor, navigationBarDividerColor, + return new PartialCustomTabHeightStrategy(activity, initialHeight, navigationBarColor, + navigationBarDividerColor, size -> connection.onResized(session, size), lifecycleDispatcher); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java index 89fd504..06f74612 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -50,7 +50,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; -import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; +import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.ui.util.ColorUtils; import java.lang.annotation.Retention; @@ -61,8 +61,7 @@ * owned by the CustomTabActivity. */ public class PartialCustomTabHeightStrategy extends CustomTabHeightStrategy - implements ConfigurationChangedObserver, ValueAnimator.AnimatorUpdateListener, - MultiWindowModeStateDispatcher.MultiWindowModeObserver { + implements ConfigurationChangedObserver, ValueAnimator.AnimatorUpdateListener { /** * Minimal height the bottom sheet CCT should show is half of the display height. */ @@ -98,6 +97,7 @@ private ValueAnimator mAnimator; private int mShadowOffset; private boolean mDrawOutlineShadow; + private @Px int mDisplayHeight; // ContentFrame + CoordinatorLayout - CompositorViewHolder // + NavigationBar @@ -156,13 +156,7 @@ @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) { - return false; - } - if (mIsInMultiWindowMode) { - return false; - } - return mGestureDetector.onTouchEvent(event); + return isFullHeight() ? false : mGestureDetector.onTouchEvent(event); } @Override @@ -178,10 +172,7 @@ // We will get events directly even when onInterceptTouchEvent() didn't return true, // because the sub View tree might not want this event, so check orientation and // multi-window flags here again. - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) { - return true; - } - if (mIsInMultiWindowMode) { + if (isFullHeight()) { return true; } @@ -263,13 +254,13 @@ } public PartialCustomTabHeightStrategy(Activity activity, @Px int initialHeight, - MultiWindowModeStateDispatcher multiWindowModeStateDispatcher, Integer navigationBarColor, Integer navigationBarDividerColor, OnResizedCallback onResizedCallback, ActivityLifecycleDispatcher lifecycleDispatcher) { mActivity = activity; mMaxHeight = getMaximumPossibleHeight(); mInitialHeight = MathUtils.clamp( initialHeight, mMaxHeight, (int) (mMaxHeight * MINIMAL_HEIGHT_RATIO)); + mDisplayHeight = getDisplayHeight(); mOnResizedCallback = onResizedCallback; // When the flag is enabled, we make the max snap point 10% shorter, so it will only occupy // 90% of the height. @@ -291,10 +282,8 @@ lifecycleDispatcher.register(this); - multiWindowModeStateDispatcher.addObserver(this); - mOrientation = mActivity.getResources().getConfiguration().orientation; - mIsInMultiWindowMode = multiWindowModeStateDispatcher.isInMultiWindowMode(); + mIsInMultiWindowMode = MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity); mNavigationBarColor = navigationBarColor; mNavigationBarDividerColor = navigationBarDividerColor; mDrawOutlineShadow = SysUtils.isLowEndDevice(); @@ -353,9 +342,7 @@ initializeHeight(); updateShadowOffset(); - // When the navigation bar on the right side (not at the bottom), no need to - // set contents height since it is fixed to the max height. - if (mNavbarHeight != 0) setContentsHeight(); + setContentsHeight(); updateNavbarVisibility(true); } @@ -371,7 +358,7 @@ // was to get it from a resource definition('navigation_bar_height') but it fails on some // vendor-customized devices. A workaround here is to subtract the app-usable height // (client view height + status bar height) from the whole display height. - return getDisplayHeight() - getAppUsableScreenHeight(); + return mDisplayHeight - getAppUsableScreenHeight(); } private int getAppUsableScreenHeight() { @@ -391,18 +378,19 @@ toolbar.setHandleStrategy(new PartialCustomTabHandleStrategy(mActivity)); } - // MultiWindowMOdeObserver implementation - @Override - public void onMultiWindowModeChanged(boolean isInMultiWindowMode) { - mIsInMultiWindowMode = isInMultiWindowMode; - } - // ConfigurationChangedObserver implementation. @Override public void onConfigurationChanged(Configuration newConfig) { - if (newConfig.orientation != mOrientation) { - mOrientation = newConfig.orientation; - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) { + boolean isInMultiWindow = MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity); + int orientation = newConfig.orientation; + int displayHeight = getDisplayHeight(); + + if (isInMultiWindow != mIsInMultiWindowMode || orientation != mOrientation + || displayHeight != mDisplayHeight) { + mIsInMultiWindowMode = isInMultiWindow; + mOrientation = orientation; + mDisplayHeight = displayHeight; + if (isFullHeight()) { // We should update CCT position before Window#FLAG_LAYOUT_NO_LIMITS is set, // otherwise it is not possible to get the correct content height. mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); @@ -461,14 +449,13 @@ mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); mNavbarHeight = getNavbarHeight(); - int maxHeight = getDisplayHeight(); int maxExpandedY = getFullyExpandedYCoordinate(); final @Px int height; - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) { + if (isFullHeight()) { // Resizing by user dragging is not supported in landscape mode; no need to set // the status here. - height = maxHeight - maxExpandedY; + height = mDisplayHeight - maxExpandedY; mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } else { height = mInitialHeight; @@ -483,13 +470,12 @@ // We do not resize Window but just translate its vertical offset, and resize Coordinator- // LayoutForPointer instead. This helps us work around the round-corner bug in Android S. // See b/223536648. - attributes.y = Math.max(maxExpandedY, maxHeight - height - mNavbarHeight); + attributes.y = Math.max(maxExpandedY, mDisplayHeight - height - mNavbarHeight); mActivity.getWindow().setAttributes(attributes); } private void updateShadowOffset() { - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE || mDrawOutlineShadow) { - // Shadow is not necessary as CCT will be always of full-height in landscape mode. + if (isFullHeight() || mDrawOutlineShadow) { mShadowOffset = 0; } else { mShadowOffset = mActivity.getResources().getDimensionPixelSize( @@ -507,6 +493,10 @@ mToolbarCoordinator.requestLayout(); } + private boolean isFullHeight() { + return mOrientation == Configuration.ORIENTATION_LANDSCAPE || mIsInMultiWindowMode; + } + private void updateWindowPos(@Px int y) { // Do not allow the Window to go down below the initial position or above the minimum // threshold capped by the status bar and (optionally) the 90%-height adjustment. @@ -595,7 +585,7 @@ // TODO(jinsukkim): // - Remove the shadow when in full-height so there won't be a gap beneath the status bar. int windowPos = mActivity.getWindow().getAttributes().y; - lp.height = getDisplayHeight() - windowPos - mHandleHeight - mShadowOffset - mNavbarHeight; + lp.height = mDisplayHeight - windowPos - mHandleHeight - mShadowOffset - mNavbarHeight; mCoordinatorLayout.setLayoutParams(lp); if (oldHeight >= 0 && lp.height != oldHeight) mOnResizedCallback.onResized(lp.height); } @@ -634,7 +624,7 @@ * one that can handle the API |setNavigationBarColor()|. */ private boolean shouldShowSystemNavbar() { - return mNavbarHeight == 0 || mOrientation == Configuration.ORIENTATION_LANDSCAPE; + return mNavbarHeight == 0 || isFullHeight(); } // Position our own navbar where the system navigation bar which is obscured by WebContents @@ -772,10 +762,10 @@ mFinishRunnable = finishRunnable; int start = mActivity.getWindow().getAttributes().y; - int end = getDisplayHeight() - mNavbarHeight; + int end = mDisplayHeight - mNavbarHeight; mInitialHeight = 0; - if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) { + if (isFullHeight()) { mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } mAnimator.setDuration(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/homepage/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/homepage/OWNERS index cc92f624..7d9a4ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/homepage/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/homepage/OWNERS
@@ -1 +1,3 @@ -file://chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/OWNERS +file://chrome/browser/partnercustomizations/OWNERS + +wenyufu@chromium.org
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java index 078e905a..d291aae9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -238,7 +238,6 @@ @Test @MediumTest @Feature({"Navigation"}) - @DisabledTest(message = "crbug.com/879153") public void testRequestDesktopSiteSettingPers() throws Exception { String url1 = mTestServer.getURL("/chrome/test/data/android/google.html"); String url2 = mTestServer.getURL("/chrome/test/data/android/about.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java index 57ba5140..1182df47 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -6,10 +6,13 @@ import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; import static org.chromium.ui.test.util.ViewUtils.createMotionEvent; +import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; import android.content.pm.ActivityInfo; import android.graphics.Point; @@ -18,6 +21,7 @@ import android.util.DisplayMetrics; import android.view.View; +import androidx.test.espresso.Espresso; import androidx.test.filters.LargeTest; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; @@ -26,19 +30,19 @@ import org.junit.After; import org.junit.Assert; 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.task.PostTask; import org.chromium.base.test.util.ApplicationTestUtils; +import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; 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.Feature; -import org.chromium.base.test.util.FlakyTest; import org.chromium.base.test.util.Manual; import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.UrlUtils; @@ -66,6 +70,7 @@ import org.chromium.chrome.browser.tabpersistence.TabStateFileManager; 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.MenuUtils; import org.chromium.chrome.test.util.NewTabPageTestUtils; @@ -82,7 +87,6 @@ import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.content_public.browser.test.util.UiUtils; import org.chromium.content_public.common.ContentSwitches; -import org.chromium.net.test.EmbeddedTestServer; import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.test.util.UiRestriction; @@ -93,7 +97,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** @@ -101,16 +104,20 @@ */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +@Batch(Batch.PER_CLASS) public class TabsTest { + @ClassRule + public static ChromeTabbedActivityTestRule sActivityTestRule = + new ChromeTabbedActivityTestRule(); + @Rule - public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + public BlankCTATabInitialStateRule mBlankCTATabInitialStateRule = + new BlankCTATabInitialStateRule(sActivityTestRule, false); private static final String TEST_FILE_PATH = "/chrome/test/data/android/tabstest/tabs_test.html"; private static final String TEST_PAGE_FILE_PATH = "/chrome/test/data/google/google.html"; - private EmbeddedTestServer mTestServer; - private float mPxToDp = 1.0f; private float mTabsViewHeightDp; private float mTabsViewWidthDp; @@ -154,26 +161,17 @@ .density; mPxToDp = 1.0f / dpToPx; - // Exclude the tests that can launch directly to a page other than the NTP. - if (mActivityTestRule.getName().equals("testOpenAndCloseNewTabButton") - || mActivityTestRule.getName().equals("testSwitchToTabThatDoesNotHaveThumbnail") - || mActivityTestRule.getName().equals("testCloseTabPortrait") - || mActivityTestRule.getName().equals("testCloseTabLandscape") - || mActivityTestRule.getName().equals("testTabsAreDestroyedOnModelDestruction") - || mActivityTestRule.getName().equals("testIncognitoTabsNotRestoredAfterSwipe")) { - return; - } - mActivityTestRule.startMainActivityOnBlankPage(); CompositorAnimationHandler.setTestingMode(true); } @After public void tearDown() { - mActivityTestRule.getActivity().setRequestedOrientation( + sActivityTestRule.getActivity().setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - if (mTestServer != null) { - mTestServer.stopAndDestroyServer(); - } + } + + private String getUrl(String filePath) { + return sActivityTestRule.getTestServer().getURL(filePath); } /** @@ -184,13 +182,11 @@ @Feature({"Navigation"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) @CommandLineFlags.Add(ContentSwitches.DISABLE_POPUP_BLOCKING) - @DisabledTest(message = "https://crbug.com/1269010") public void testSpawnPopupOnBackgroundTab() { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.loadUrl(mTestServer.getURL(TEST_FILE_PATH)); - final Tab tab = mActivityTestRule.getActivity().getActivityTab(); + sActivityTestRule.loadUrl(getUrl(TEST_FILE_PATH)); + final Tab tab = sActivityTestRule.getActivity().getActivityTab(); - mActivityTestRule.newIncognitoTabFromMenu(); + sActivityTestRule.newIncognitoTabFromMenu(); TestThreadUtils.runOnUiThreadBlocking( () -> tab.getWebContents().evaluateJavaScriptForTests("(function() {" @@ -199,7 +195,7 @@ null)); CriteriaHelper.pollUiThread(() -> { - int tabCount = mActivityTestRule.getActivity() + int tabCount = sActivityTestRule.getActivity() .getTabModelSelector() .getModel(false) .getCount(); @@ -210,10 +206,9 @@ @Test @MediumTest public void testAlertDialogDoesNotChangeActiveModel() { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.newIncognitoTabFromMenu(); - mActivityTestRule.loadUrl(mTestServer.getURL(TEST_FILE_PATH)); - final Tab tab = mActivityTestRule.getActivity().getActivityTab(); + sActivityTestRule.newIncognitoTabFromMenu(); + sActivityTestRule.loadUrl(getUrl(TEST_FILE_PATH)); + final Tab tab = sActivityTestRule.getActivity().getActivityTab(); TestThreadUtils.runOnUiThreadBlocking( () -> tab.getWebContents().evaluateJavaScriptForTests("(function() {" + " alert('hi');" @@ -235,61 +230,61 @@ () -> Criteria.checkThat(getCurrentAlertDialog(), Matchers.nullValue())); Assert.assertTrue("Incognito model was not selected", - mActivityTestRule.getActivity().getTabModelSelector().isIncognitoSelected()); + sActivityTestRule.getActivity().getTabModelSelector().isIncognitoSelected()); } /** * Verify New Tab Open and Close Event not from the context menu. - * @LargeTest - * @Feature({"Android-TabSwitcher"}) - * @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) */ @Test - @DisabledTest(message = "crbug.com/490473") + @LargeTest + @Feature({"Android-TabSwitcher"}) + @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) public void testOpenAndCloseNewTabButton() { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_FILE_PATH)); + sActivityTestRule.loadUrl(getUrl(TEST_FILE_PATH)); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { String title = - mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0).getTitle(); + sActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0).getTitle(); Assert.assertEquals("Data file for TabsTest", title); }); - final int tabCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount(); + final int tabCount = sActivityTestRule.getActivity().getCurrentTabModel().getCount(); View tabSwitcherButton = - mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button); + sActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button); Assert.assertNotNull("'tab_switcher_button' view is not found", tabSwitcherButton); TouchCommon.singleClickView(tabSwitcherButton); LayoutTestUtils.waitForLayout( - mActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER); + sActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER); - View newTabButton = mActivityTestRule.getActivity().findViewById(R.id.new_tab_button); + View newTabButton = sActivityTestRule.getActivity().findViewById(R.id.new_tab_button); Assert.assertNotNull("'new_tab_button' view is not found", newTabButton); TouchCommon.singleClickView(newTabButton); LayoutTestUtils.waitForLayout( - mActivityTestRule.getActivity().getLayoutManager(), LayoutType.BROWSING); + sActivityTestRule.getActivity().getLayoutManager(), LayoutType.BROWSING); InstrumentationRegistry.getInstrumentation().runOnMainSync( - () -> Assert.assertEquals("The tab count is wrong", tabCount + 1, - mActivityTestRule.getActivity().getCurrentTabModel().getCount())); + () + -> Assert.assertEquals("The tab count is wrong", tabCount + 1, + sActivityTestRule.getActivity().getCurrentTabModel().getCount())); CriteriaHelper.pollUiThread(() -> { - Tab tab = mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(1); + Tab tab = sActivityTestRule.getActivity().getCurrentTabModel().getTabAt(1); String title = tab.getTitle().toLowerCase(Locale.US); String expectedTitle = "new tab"; Criteria.checkThat(title, Matchers.startsWith(expectedTitle)); }); ChromeTabUtils.closeCurrentTab( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); InstrumentationRegistry.getInstrumentation().runOnMainSync( - () -> Assert.assertEquals(tabCount, - mActivityTestRule.getActivity().getCurrentTabModel().getCount())); + () + -> Assert.assertEquals(tabCount, + sActivityTestRule.getActivity().getCurrentTabModel().getCount())); } private void assertWaitForKeyboardStatus(final boolean show) { CriteriaHelper.pollUiThread(() -> { - boolean isKeyboardShowing = mActivityTestRule.getKeyboardDelegate().isKeyboardShowing( - mActivityTestRule.getActivity(), mActivityTestRule.getActivity().getTabsView()); + boolean isKeyboardShowing = sActivityTestRule.getKeyboardDelegate().isKeyboardShowing( + sActivityTestRule.getActivity(), sActivityTestRule.getActivity().getTabsView()); Criteria.checkThat(isKeyboardShowing, Matchers.is(show)); }); } @@ -303,63 +298,57 @@ @Restriction(UiRestriction.RESTRICTION_TYPE_TABLET) @Feature({"Android-TabSwitcher"}) public void testHideKeyboard() throws Exception { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - // Open a new tab(The 1st tab) and click node. - ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(), - mActivityTestRule.getActivity(), mTestServer.getURL(TEST_FILE_PATH), false); + sActivityTestRule.loadUrlInNewTab(getUrl(TEST_FILE_PATH), false); Assert.assertEquals("Failed to click node.", true, - DOMUtils.clickNode(mActivityTestRule.getWebContents(), "input_text")); + DOMUtils.clickNode(sActivityTestRule.getWebContents(), "input_text")); assertWaitForKeyboardStatus(true); // Open a new tab(the 2nd tab). - ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(), - mActivityTestRule.getActivity(), mTestServer.getURL(TEST_FILE_PATH), false); + sActivityTestRule.loadUrlInNewTab(getUrl(TEST_FILE_PATH), false); assertWaitForKeyboardStatus(false); // Click node in the 2nd tab. - DOMUtils.clickNode(mActivityTestRule.getWebContents(), "input_text"); + DOMUtils.clickNode(sActivityTestRule.getWebContents(), "input_text"); assertWaitForKeyboardStatus(true); // Switch to the 1st tab. - ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), 1); + ChromeTabUtils.switchTabInCurrentTabModel(sActivityTestRule.getActivity(), 1); assertWaitForKeyboardStatus(false); // Click node in the 1st tab. - DOMUtils.clickNode(mActivityTestRule.getWebContents(), "input_text"); + DOMUtils.clickNode(sActivityTestRule.getWebContents(), "input_text"); assertWaitForKeyboardStatus(true); // Close current tab(the 1st tab). ChromeTabUtils.closeCurrentTab( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); assertWaitForKeyboardStatus(false); } /** * Verify that opening a new window hides keyboard. */ - @DisabledTest(message = "crbug.com/766735") @Test @MediumTest @Feature({"Android-TabSwitcher"}) public void testHideKeyboardWhenOpeningWindow() throws Exception { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); // Open a new tab and click an editable node. ChromeTabUtils.fullyLoadUrlInNewTab(InstrumentationRegistry.getInstrumentation(), - mActivityTestRule.getActivity(), mTestServer.getURL(TEST_FILE_PATH), false); + sActivityTestRule.getActivity(), getUrl(TEST_FILE_PATH), false); Assert.assertEquals("Failed to click textarea.", true, - DOMUtils.clickNode(mActivityTestRule.getWebContents(), "textarea")); + DOMUtils.clickNode(sActivityTestRule.getWebContents(), "textarea")); assertWaitForKeyboardStatus(true); // Click the button to open a new window. Assert.assertEquals("Failed to click button.", true, - DOMUtils.clickNode(mActivityTestRule.getWebContents(), "button")); + DOMUtils.clickNode(sActivityTestRule.getWebContents(), "button")); assertWaitForKeyboardStatus(false); } private void assertWaitForSelectedText(final String text) { CriteriaHelper.pollUiThread(() -> { - WebContents webContents = mActivityTestRule.getWebContents(); + WebContents webContents = sActivityTestRule.getWebContents(); SelectionPopupController controller = SelectionPopupController.fromWebContents(webContents); final String actualText = controller.getSelectedText(); @@ -373,12 +362,12 @@ */ private void fling(float startX, float startY, float endX, float endY, int stepCount) { Point size = new Point(); - mActivityTestRule.getActivity().getWindowManager().getDefaultDisplay().getSize(size); + sActivityTestRule.getActivity().getWindowManager().getDefaultDisplay().getSize(size); float dragStartX = size.x * startX; float dragEndX = size.x * endX; float dragStartY = size.y * startY; float dragEndY = size.y * endY; - TouchCommon.performDrag(mActivityTestRule.getActivity(), dragStartX, dragEndX, dragStartY, + TouchCommon.performDrag(sActivityTestRule.getActivity(), dragStartX, dragEndX, dragStartY, dragEndY, stepCount, 250); } @@ -395,9 +384,8 @@ @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) @Feature({"Android-TabSwitcher"}) public void testTabSwitcherCollapseSelection() throws Exception { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.loadUrlInNewTab(mTestServer.getURL(TEST_FILE_PATH), false); - DOMUtils.longPressNode(mActivityTestRule.getWebContents(), "textarea"); + sActivityTestRule.loadUrlInNewTab(getUrl(TEST_FILE_PATH), false); + DOMUtils.longPressNode(sActivityTestRule.getWebContents(), "textarea"); assertWaitForSelectedText("helloworld"); // Switch to tab-switcher mode, switch back, and scroll page. @@ -416,20 +404,20 @@ @SmallTest public void testNewTabSetsContentViewSize() throws TimeoutException { ChromeTabUtils.newTabFromMenu( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // Make sure we're on the NTP - Tab tab = mActivityTestRule.getActivity().getActivityTab(); + Tab tab = sActivityTestRule.getActivity().getActivityTab(); NewTabPageTestUtils.waitForNtpLoaded(tab); - mActivityTestRule.loadUrl(INITIAL_SIZE_TEST_URL); + sActivityTestRule.loadUrl(INITIAL_SIZE_TEST_URL); final WebContents webContents = tab.getWebContents(); String innerText = JavaScriptUtils.executeJavaScriptAndWaitForResult( webContents, "document.body.innerText").replace("\"", ""); - DisplayMetrics metrics = mActivityTestRule.getActivity().getResources().getDisplayMetrics(); + DisplayMetrics metrics = sActivityTestRule.getActivity().getResources().getDisplayMetrics(); // For non-integer pixel ratios like the N7v1 (1.333...), the layout system will actually // ceil the width. @@ -452,22 +440,17 @@ * This is a LargeTest but because we're doing it "slowly", we need to further scale * the timeout for adb am instrument and the various events. */ - /* - * @EnormousTest - * @TimeoutScale(10) - * @Feature({"Android-TabSwitcher"}) - * Bug crbug.com/166208 - */ @Test - @DisabledTest(message = "crbug.com/575816") + @Manual(message = "Slow test") + @Feature({"Android-TabSwitcher"}) public void testOpenManyTabsSlowly() { - int startCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount(); + int startCount = sActivityTestRule.getActivity().getCurrentTabModel().getCount(); for (int i = 1; i <= STRESSFUL_TAB_COUNT; ++i) { ChromeTabUtils.newTabFromMenu( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); Assert.assertEquals(startCount + i, - mActivityTestRule.getActivity().getCurrentTabModel().getCount()); + sActivityTestRule.getActivity().getCurrentTabModel().getCount()); } } @@ -479,12 +462,12 @@ @Manual(message = "Slow test") @Feature({"Android-TabSwitcher"}) public void testOpenManyTabsQuickly() { - int startCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount(); + int startCount = sActivityTestRule.getActivity().getCurrentTabModel().getCount(); for (int i = 1; i <= STRESSFUL_TAB_COUNT; ++i) { MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), - mActivityTestRule.getActivity(), R.id.new_tab_menu_id); + sActivityTestRule.getActivity(), R.id.new_tab_menu_id); Assert.assertEquals(startCount + i, - mActivityTestRule.getActivity().getCurrentTabModel().getCount()); + sActivityTestRule.getActivity().getCurrentTabModel().getCount()); } } @@ -496,14 +479,13 @@ @Manual(message = "Slow test") @Feature({"Navigation"}) public void testOpenManyTabsInBursts() throws TimeoutException { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); final int burstSize = 5; - final String url = mTestServer.getURL(TEST_PAGE_FILE_PATH); - final int startCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount(); + final String url = getUrl(TEST_PAGE_FILE_PATH); + final int startCount = sActivityTestRule.getActivity().getCurrentTabModel().getCount(); for (int tabCount = startCount; tabCount < STRESSFUL_TAB_COUNT; tabCount += burstSize) { loadUrlInManyNewTabs(url, burstSize); Assert.assertEquals(tabCount + burstSize, - mActivityTestRule.getActivity().getCurrentTabModel().getCount()); + sActivityTestRule.getActivity().getCurrentTabModel().getCount()); } } @@ -522,24 +504,23 @@ * tab loads when selected. */ private void openAndVerifyManyTestTabs(final int num) throws TimeoutException { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - final String url = mTestServer.getURL(TEST_PAGE_FILE_PATH); - int startCount = mActivityTestRule.getActivity().getCurrentTabModel().getCount(); + final String url = getUrl(TEST_PAGE_FILE_PATH); + int startCount = sActivityTestRule.getActivity().getCurrentTabModel().getCount(); loadUrlInManyNewTabs(url, num); Assert.assertEquals( - startCount + num, mActivityTestRule.getActivity().getCurrentTabModel().getCount()); + startCount + num, sActivityTestRule.getActivity().getCurrentTabModel().getCount()); } /** Enters the tab switcher without animation.*/ private void showOverviewWithNoAnimation() { LayoutTestUtils.startShowingAndWaitForLayout( - mActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER, false); + sActivityTestRule.getActivity().getLayoutManager(), LayoutType.TAB_SWITCHER, false); } /** Exits the tab switcher without animation. */ private void hideOverviewWithNoAnimation() { LayoutTestUtils.startShowingAndWaitForLayout( - mActivityTestRule.getActivity().getLayoutManager(), LayoutType.BROWSING, false); + sActivityTestRule.getActivity().getLayoutManager(), LayoutType.BROWSING, false); } /** @@ -549,7 +530,7 @@ * @return The new number of tabs in the model. */ private int openTabs(final int targetTabCount, boolean waitToLoad) { - final ChromeTabbedActivity activity = mActivityTestRule.getActivity(); + final ChromeTabbedActivity activity = sActivityTestRule.getActivity(); Callable<Integer> countOnUi = () -> { return activity.getCurrentTabModel().getCount(); }; @@ -569,10 +550,10 @@ } 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(); } /** @@ -582,44 +563,48 @@ @SmallTest @Feature({"Android-TabSwitcher"}) public void testCloseTabDuringFling() { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.loadUrlInNewTab( - mTestServer.getURL("/chrome/test/data/android/tabstest/text_page.html")); + sActivityTestRule.loadUrlInNewTab( + getUrl("/chrome/test/data/android/tabstest/text_page.html")); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - WebContents webContents = mActivityTestRule.getWebContents(); + WebContents webContents = sActivityTestRule.getWebContents(); webContents.getEventForwarder().startFling( SystemClock.uptimeMillis(), 0, -2000, false, true); }); ChromeTabUtils.closeCurrentTab( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); } @Test - @FlakyTest(message = "Flaky on instrumentation-yakju-clankium-ics - https://crbug.com/431296") + @MediumTest + @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) public void testQuickSwitchBetweenTabAndSwitcherMode() { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - final String[] urls = { - mTestServer.getURL("/chrome/test/data/android/navigate/one.html"), - mTestServer.getURL("/chrome/test/data/android/navigate/two.html"), - mTestServer.getURL("/chrome/test/data/android/navigate/three.html")}; + final String[] urls = {getUrl("/chrome/test/data/android/navigate/one.html"), + getUrl("/chrome/test/data/android/navigate/two.html"), + getUrl("/chrome/test/data/android/navigate/three.html")}; for (String url : urls) { - mActivityTestRule.loadUrlInNewTab(url); + sActivityTestRule.loadUrlInNewTab(url, false); } - int lastUrlIndex = urls.length - 1; + final int lastUrlIndex = urls.length - 1; - View button = mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button); + View button = sActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button); Assert.assertNotNull("Could not find 'tab_switcher_button'", button); for (int i = 0; i < 15; i++) { TouchCommon.singleClickView(button); + + // Wait for UI to show so the back press will apply to the switcher not the tab. + onViewWaiting(withId(org.chromium.chrome.test.R.id.tab_switcher_toolbar)) + .check(matches(isDisplayed())); + // Switch back to the tab view from the tab-switcher mode. - TouchCommon.singleClickView(button); + Espresso.pressBack(); Assert.assertEquals("URL mismatch after switching back to the tab from tab-switch mode", urls[lastUrlIndex], - mActivityTestRule.getActivity().getActivityTab().getUrl().getSpec()); + ChromeTabUtils.getUrlStringOnUiThread( + sActivityTestRule.getActivity().getActivityTab())); } } @@ -630,10 +615,10 @@ @MediumTest @Feature({"Android-TabSwitcher"}) public void testOpenIncognitoTab() { - mActivityTestRule.newIncognitoTabFromMenu(); + sActivityTestRule.newIncognitoTabFromMenu(); Assert.assertTrue("Current Tab should be an incognito tab.", - mActivityTestRule.getActivity().getActivityTab().isIncognito()); + sActivityTestRule.getActivity().getActivityTab().isIncognito()); } @Test @@ -692,7 +677,7 @@ runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, true); final TabModel tabModel = - mActivityTestRule.getActivity().getTabModelSelector().getModel(false); + sActivityTestRule.getActivity().getTabModelSelector().getModel(false); Assert.assertEquals("Incorrect tab index after first swipe.", 1, tabModel.index()); runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, true); @@ -708,7 +693,7 @@ runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.LEFT, 1, true); final TabModel tabModel = - mActivityTestRule.getActivity().getTabModelSelector().getModel(true); + sActivityTestRule.getActivity().getTabModelSelector().getModel(true); Assert.assertEquals("Incorrect tab index after first swipe.", 1, tabModel.index()); runToolbarSideSwipeTestOnCurrentModel(ScrollDirection.RIGHT, 0, true); @@ -724,22 +709,22 @@ private void initToolbarSwipeTest(boolean useTwoTabs, int selectedTab, boolean incognito) { if (incognito) { // If incognito, there is no default tab, so open a new one and switch to it. - mActivityTestRule.loadUrlInNewTab(generateSolidColorUrl("#00ff00"), true); - mActivityTestRule.getActivity().getTabModelSelector().selectModel(true); + sActivityTestRule.loadUrlInNewTab(generateSolidColorUrl("#00ff00"), true); + sActivityTestRule.getActivity().getTabModelSelector().selectModel(true); } else { // If not incognito, use the tab the test started on. - mActivityTestRule.loadUrl(generateSolidColorUrl("#00ff00")); + sActivityTestRule.loadUrl(generateSolidColorUrl("#00ff00")); } if (useTwoTabs) { - mActivityTestRule.loadUrlInNewTab(generateSolidColorUrl("#0000ff"), incognito); + sActivityTestRule.loadUrlInNewTab(generateSolidColorUrl("#0000ff"), incognito); } - ChromeTabUtils.switchTabInCurrentTabModel(mActivityTestRule.getActivity(), selectedTab); + ChromeTabUtils.switchTabInCurrentTabModel(sActivityTestRule.getActivity(), selectedTab); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); final TabModelSelector tabModelSelector = - mActivityTestRule.getActivity().getTabModelSelector(); + sActivityTestRule.getActivity().getTabModelSelector(); final TabModel tabModel = tabModelSelector.getModel(incognito); Assert.assertEquals("Incorrect model selected.", incognito, @@ -751,7 +736,7 @@ private void runToolbarSideSwipeTestOnCurrentModel(@ScrollDirection int direction, int finalIndex, boolean expectsSelection) throws TimeoutException { final CallbackHelper selectCallback = new CallbackHelper(); - final ChromeTabbedActivity activity = mActivityTestRule.getActivity(); + final ChromeTabbedActivity activity = sActivityTestRule.getActivity(); final int id = activity.getCurrentTabModel().getTabAt(finalIndex).getId(); final TabModelSelectorTabModelObserver observer = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { @@ -796,7 +781,7 @@ private void performToolbarSideSwipe(@ScrollDirection int direction) { Assert.assertTrue("Unexpected direction for side swipe " + direction, direction == ScrollDirection.LEFT || direction == ScrollDirection.RIGHT); - final View toolbar = mActivityTestRule.getActivity().findViewById(R.id.toolbar); + final View toolbar = sActivityTestRule.getActivity().findViewById(R.id.toolbar); int[] toolbarPos = new int[2]; toolbar.getLocationOnScreen(toolbarPos); @@ -809,7 +794,7 @@ final int stepCount = 25; final long duration = 500; - View toolbarRoot = mActivityTestRule.getActivity() + View toolbarRoot = sActivityTestRule.getActivity() .getRootUiCoordinatorForTesting() .getToolbarManager() .getContainerViewForTesting(); @@ -824,7 +809,7 @@ @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @Feature({"Android-TabSwitcher"}) public void testOSKIsNotShownDuringSwipe() throws InterruptedException { - final View urlBar = mActivityTestRule.getActivity().findViewById(R.id.url_bar); + final View urlBar = sActivityTestRule.getActivity().findViewById(R.id.url_bar); final LayoutManagerChrome layoutManager = updateTabsViewSize(); final SwipeHandler swipeHandler = layoutManager.getToolbarSwipeHandler(); @@ -835,12 +820,12 @@ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> urlBar.clearFocus()); UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation()); ChromeTabUtils.newTabFromMenu( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation()); Assert.assertFalse("Keyboard somehow got shown", - mActivityTestRule.getKeyboardDelegate().isKeyboardShowing( - mActivityTestRule.getActivity(), urlBar)); + sActivityTestRule.getKeyboardDelegate().isKeyboardShowing( + sActivityTestRule.getActivity(), urlBar)); PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { swipeHandler.onSwipeStarted(ScrollDirection.RIGHT, createMotionEvent(0, 0)); @@ -850,7 +835,7 @@ }); CriteriaHelper.pollUiThread(() -> { - return !mActivityTestRule.getActivity() + return !sActivityTestRule.getActivity() .getLayoutManager() .getActiveLayout() .shouldDisplayContentOverlay(); @@ -858,19 +843,19 @@ PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { Assert.assertFalse("Keyboard should be hidden while swiping", - mActivityTestRule.getKeyboardDelegate().isKeyboardShowing( - mActivityTestRule.getActivity(), urlBar)); + sActivityTestRule.getKeyboardDelegate().isKeyboardShowing( + sActivityTestRule.getActivity(), urlBar)); swipeHandler.onSwipeFinished(); }); CriteriaHelper.pollUiThread(() -> { - LayoutManagerImpl driver = mActivityTestRule.getActivity().getLayoutManager(); + LayoutManagerImpl driver = sActivityTestRule.getActivity().getLayoutManager(); return driver.getActiveLayout().shouldDisplayContentOverlay(); }, "Layout not requesting Tab Android view be attached"); Assert.assertFalse("Keyboard should not be shown", - mActivityTestRule.getKeyboardDelegate().isKeyboardShowing( - mActivityTestRule.getActivity(), urlBar)); + sActivityTestRule.getKeyboardDelegate().isKeyboardShowing( + sActivityTestRule.getActivity(), urlBar)); } /** @@ -882,16 +867,16 @@ @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) public void testOrientationChangeCausesLiveTabReflowInNormalView() throws InterruptedException, TimeoutException { - mActivityTestRule.getActivity().setRequestedOrientation( + sActivityTestRule.getActivity().setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); ChromeTabUtils.newTabFromMenu( - InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity()); - mActivityTestRule.loadUrl(RESIZE_TEST_URL); - final WebContents webContents = mActivityTestRule.getWebContents(); + InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity()); + sActivityTestRule.loadUrl(RESIZE_TEST_URL); + final WebContents webContents = sActivityTestRule.getWebContents(); JavaScriptUtils.executeJavaScriptAndWaitForResult( - mActivityTestRule.getWebContents(), "resizeHappened = false;"); - mActivityTestRule.getActivity().setRequestedOrientation( + sActivityTestRule.getWebContents(), "resizeHappened = false;"); + sActivityTestRule.getActivity().setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation()); Assert.assertEquals("onresize event wasn't received by the tab (normal view)", "true", @@ -904,7 +889,7 @@ @Feature({"Android-TabSwitcher"}) public void testLastClosedUndoableTabGetsHidden() { final TabModel model = - mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel(); + sActivityTestRule.getActivity().getTabModelSelector().getCurrentModel(); final Tab tab = TabModelUtils.getCurrentTab(model); Assert.assertEquals("Too many tabs at startup", 1, model.getCount()); @@ -923,9 +908,9 @@ @Feature({"Android-TabSwitcher"}) public void testLastClosedTabTriggersNotifyChangedCall() { final TabModel model = - mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel(); + sActivityTestRule.getActivity().getTabModelSelector().getCurrentModel(); final Tab tab = TabModelUtils.getCurrentTab(model); - final TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector(); + final TabModelSelector selector = sActivityTestRule.getActivity().getTabModelSelector(); mNotifyChangedCalled = false; TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -946,62 +931,56 @@ } @Test - @DisabledTest(message = "Flaky: http://crbug.com/901986") @MediumTest @Feature({"Android-TabSwitcher"}) - public void testTabsAreDestroyedOnModelDestruction() throws InterruptedException { - mActivityTestRule.startMainActivityOnBlankPage(); + public void testTabsAreDestroyedOnModelDestruction() throws Exception { final TabModelSelectorImpl selector = - (TabModelSelectorImpl) mActivityTestRule.getActivity().getTabModelSelector(); - final Tab tab = mActivityTestRule.getActivity().getActivityTab(); + (TabModelSelectorImpl) sActivityTestRule.getActivity().getTabModelSelector(); + final Tab tab = sActivityTestRule.getActivity().getActivityTab(); - final AtomicBoolean webContentsDestroyCalled = new AtomicBoolean(); + final CallbackHelper webContentsDestroyed = new CallbackHelper(); - TestThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - @SuppressWarnings("unused") // Avoid GC of observer - WebContentsObserver observer = new WebContentsObserver(tab.getWebContents()) { - @Override - public void destroy() { - super.destroy(); - webContentsDestroyCalled.set(true); - } - }; + TestThreadUtils.runOnUiThreadBlocking(() -> { + @SuppressWarnings("unused") // Avoid GC of observer + WebContentsObserver observer = new WebContentsObserver(tab.getWebContents()) { + @Override + public void destroy() { + super.destroy(); + webContentsDestroyed.notifyCalled(); + } + }; - Assert.assertNotNull("No initial tab at startup", tab); - Assert.assertNotNull("Tab does not have a web contents", tab.getWebContents()); - Assert.assertTrue("Tab is destroyed", tab.isInitialized()); - - selector.destroy(); - - Assert.assertNull("Tab still has a web contents", tab.getWebContents()); - Assert.assertFalse("Tab was not destroyed", tab.isInitialized()); - } + Assert.assertNotNull("No initial tab at startup", tab); + Assert.assertNotNull("Tab does not have a web contents", tab.getWebContents()); + Assert.assertTrue("Tab is destroyed", tab.isInitialized()); }); - Assert.assertTrue( - "WebContentsObserver was never destroyed", webContentsDestroyCalled.get()); + ApplicationTestUtils.finishActivity(sActivityTestRule.getActivity()); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertNull("Tab still has a web contents", tab.getWebContents()); + Assert.assertFalse("Tab was not destroyed", tab.isInitialized()); + }); + + webContentsDestroyed.waitForFirst(); } @Test - @DisabledTest(message = "Flaky - http://crbug.com/649429") @MediumTest @Feature({"Android-TabSwitcher"}) public void testIncognitoTabsNotRestoredAfterSwipe() throws Exception { - mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); - mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PAGE_FILE_PATH)); + sActivityTestRule.loadUrl(getUrl(TEST_PAGE_FILE_PATH)); - mActivityTestRule.newIncognitoTabFromMenu(); + sActivityTestRule.newIncognitoTabFromMenu(); // Tab states are not saved for empty NTP tabs, so navigate to any page to trigger a file // to be saved. - mActivityTestRule.loadUrl(mTestServer.getURL(TEST_PAGE_FILE_PATH)); + sActivityTestRule.loadUrl(getUrl(TEST_PAGE_FILE_PATH)); File tabStateDir = TabStateDirectory.getOrCreateTabbedModeStateDirectory(); TabModel normalModel = - mActivityTestRule.getActivity().getTabModelSelector().getModel(false); + sActivityTestRule.getActivity().getTabModelSelector().getModel(false); TabModel incognitoModel = - mActivityTestRule.getActivity().getTabModelSelector().getModel(true); + sActivityTestRule.getActivity().getTabModelSelector().getModel(true); File normalTabFile = new File(tabStateDir, TabStateFileManager.getTabStateFilename( normalModel.getTabAt(normalModel.getCount() - 1).getId(), false)); @@ -1013,10 +992,10 @@ // Although we're destroying the activity, the Application will still live on since its in // the same process as this test. - ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); + ApplicationTestUtils.finishActivity(sActivityTestRule.getActivity()); // Activity will be started without a savedInstanceState. - mActivityTestRule.startMainActivityOnBlankPage(); + sActivityTestRule.startMainActivityOnBlankPage(); assertFileExists(normalTabFile, true); assertFileExists(incognitoTabFile, false); } @@ -1054,7 +1033,7 @@ @Override public void run() { Tab currentTab = - mActivityTestRule.getActivity().getCurrentTabCreator().launchUrl( + sActivityTestRule.getActivity().getCurrentTabCreator().launchUrl( url, TabLaunchType.FROM_LINK); final CallbackHelper pageLoadCallback = new CallbackHelper(); pageLoadedCallbacks[index] = pageLoadCallback; @@ -1072,7 +1051,7 @@ // When opening many tabs some may be frozen due to memory pressure and won't send // PAGE_LOAD_FINISHED events. Iterate over the newly opened tabs and wait for each to load. for (int i = 0; i < numTabs; ++i) { - final TabModel tabModel = mActivityTestRule.getActivity().getCurrentTabModel(); + final TabModel tabModel = sActivityTestRule.getActivity().getCurrentTabModel(); final Tab tab = TabModelUtils.getTabById(tabModel, tabIds[i]); InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override @@ -1086,7 +1065,7 @@ private JavascriptTabModalDialog getCurrentAlertDialog() { return (JavascriptTabModalDialog) TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - PropertyModel dialogModel = mActivityTestRule.getActivity() + PropertyModel dialogModel = sActivityTestRule.getActivity() .getModalDialogManager() .getCurrentDialogForTest(); return dialogModel != null ? dialogModel.get(ModalDialogProperties.CONTROLLER) : null;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java similarity index 81% rename from chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java rename to chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java index 912902b3..b33e4d08 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUnitTest.java
@@ -11,21 +11,17 @@ import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.test.BaseJUnit4ClassRunner; 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; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.components.autofill.AutofillDelegate; import org.chromium.components.autofill.AutofillPopup; import org.chromium.components.autofill.AutofillSuggestion; @@ -33,6 +29,7 @@ import org.chromium.content_public.browser.test.util.TouchCommon; import org.chromium.ui.DropdownItem; import org.chromium.ui.base.ViewAndroidDelegate; +import org.chromium.ui.test.util.BlankUiTestActivity; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,33 +37,33 @@ * Tests the Autofill's java code for creating the AutofillPopup object, opening and selecting * popups. */ -@RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@Batch(Batch.PER_CLASS) -public class AutofillTest { +@RunWith(BaseJUnit4ClassRunner.class) +@Batch(Batch.UNIT_TESTS) +public class AutofillUnitTest { @ClassRule - public static final ChromeTabbedActivityTestRule sActivityTestRule = - new ChromeTabbedActivityTestRule(); - - @Rule - public final BlankCTATabInitialStateRule mInitialStateRule = - new BlankCTATabInitialStateRule(sActivityTestRule, false); + public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule = + new BaseActivityTestRule<>(BlankUiTestActivity.class); private AutofillPopup mAutofillPopup; private MockAutofillCallback mMockAutofillCallback; + @BeforeClass + public static void setupSuite() { + sActivityTestRule.launchActivity(null); + } + @Before public void setUp() throws Exception { mMockAutofillCallback = new MockAutofillCallback(); - final ChromeActivity activity = sActivityTestRule.getActivity(); - final ViewAndroidDelegate viewDelegate = - ViewAndroidDelegate.createBasicDelegate(activity.getActivityTab().getContentView()); + final ViewAndroidDelegate viewDelegate = ViewAndroidDelegate.createBasicDelegate( + sActivityTestRule.getActivity().findViewById(android.R.id.content)); TestThreadUtils.runOnUiThreadBlocking(() -> { View anchorView = viewDelegate.acquireView(); viewDelegate.setViewPosition(anchorView, 50f, 500f, 500f, 500f, 10, 10); - mAutofillPopup = new AutofillPopup(activity, anchorView, mMockAutofillCallback); + mAutofillPopup = new AutofillPopup( + sActivityTestRule.getActivity(), anchorView, mMockAutofillCallback); mAutofillPopup.filterAndShow( new AutofillSuggestion[0], /* isRtl= */ false, /* isRefresh= */ false); }); @@ -87,8 +84,7 @@ } @Override - public void deleteSuggestion(int listIndex) { - } + public void deleteSuggestion(int listIndex) {} public void waitForCallback() { CriteriaHelper.pollInstrumentationThread( @@ -96,12 +92,10 @@ } @Override - public void dismissed() { - } + public void dismissed() {} @Override - public void accessibilityFocusCleared() { - } + public void accessibilityFocusCleared() {} } private AutofillSuggestion[] createTwoAutofillSuggestionArray() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java index 15b7fd42..6d879d0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java
@@ -21,7 +21,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisableIf; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -330,7 +329,6 @@ * Tests that chained searches load correctly. */ @Test - @DisabledTest(message = "crbug.com/549805") @SmallTest @Feature({"ContextualSearch"}) @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) @@ -357,7 +355,7 @@ waitToPreventDoubleTapRecognition(); // Now simulate a non-resolve search, leaving the Panel peeking. - simulateNonResolveSearch("resolution"); + simulateNonResolveSearchByLongPress("resolution"); // Expanding the Panel should load and display the new search. expandPanelAndAssert(); @@ -380,11 +378,7 @@ @Test @SmallTest @Feature({"ContextualSearch"}) - // Previously flaky and disabled 4/2021. https://crbug.com/1192285 - @DisabledTest( - message = "TODO:donnd fix and reeenable once expanding resolve works for base tests.") - public void - testChainedSearchContentVisibility() throws Exception { + public void testChainedSearchContentVisibility() throws Exception { // Chained searches are tap-triggered very close to existing tap-triggered searches. FeatureList.setTestFeatures(ENABLE_NONE); @@ -397,7 +391,7 @@ waitToPreventDoubleTapRecognition(); // Now simulate a non-resolve search, leaving the Panel peeking. - simulateNonResolveSearch("resolution"); + simulateNonResolveSearchByLongPress("resolution"); assertNeverCalledWebContentsOnShow(); Assert.assertEquals(1, mFakeServer.getLoadedUrlCount());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 16f8340..64b27cb2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -84,6 +84,12 @@ void triggerResolve(String nodeId) throws TimeoutException; /** + * Simulates a long press trigger on the given node and waits for the panel to peek. + * @param nodeId A string containing the node ID. + */ + void triggerLongPress(String nodeId) throws TimeoutException; + + /** * Waits for the selected text string to be the given string, and asserts. * @param text The string to wait for the selection to become. */ @@ -166,6 +172,14 @@ public abstract void simulate() throws InterruptedException, TimeoutException; /** + * Simulates a fake search by long press. + * + * @throws InterruptedException + * @throws TimeoutException + */ + public abstract void simulateLongPress() throws InterruptedException, TimeoutException; + + /** * @return The search term that will be used in the contextual search. */ public abstract String getSearchTerm(); @@ -206,6 +220,15 @@ } @Override + public void simulateLongPress() throws InterruptedException, TimeoutException { + boolean previousOptedInState = mPolicy.overrideDecidedStateForTesting(false); + + mTestHost.triggerLongPress(getNodeId()); + mTestHost.waitForSelectionToBe(mSearchTerm); + mPolicy.overrideDecidedStateForTesting(previousOptedInState); + } + + @Override public String getSearchTerm() { return mSearchTerm; } @@ -290,6 +313,35 @@ } @Override + public void simulateLongPress() throws InterruptedException, TimeoutException { + mActiveResolveSearch = this; + + // When a resolution is needed, the simulation does not start until the system + // requests one, and it does not finish until the simulated resolution happens. + mDidStartResolution = false; + mDidFinishResolution = false; + + boolean previousOptedInState = + mPolicy.overrideDecidedStateForTesting(mPolicy.shouldPreviousGestureResolve()); + mTestHost.triggerLongPress(getNodeId()); + mTestHost.waitForSelectionToBe(getSearchTerm()); + mPolicy.overrideDecidedStateForTesting(previousOptedInState); + + if (mPolicy.shouldPreviousGestureResolve()) { + // Now wait for the Search Term Resolution to start. + mTestHost.waitForSearchTermResolutionToStart(this); + + // Simulate a Search Term Resolution. + simulateSearchTermResolution(); + + // Now wait for the simulated Search Term Resolution to finish. + mTestHost.waitForSearchTermResolutionToFinish(this); + } else { + mDidFinishResolution = true; + } + } + + @Override public String getSearchTerm() { return mResolvedSearchTerm.searchTerm(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java index 09269e3..6c022ecb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java
@@ -525,6 +525,11 @@ } @Override + public void triggerLongPress(String nodeId) throws TimeoutException { + longPressNode(nodeId); + } + + @Override public void waitForSelectionToBe(final String text) { CriteriaHelper.pollInstrumentationThread(() -> { Criteria.checkThat(getSelectedText(), Matchers.is(text)); @@ -647,6 +652,14 @@ } /** + * Simulates a long press trigger on the given node and waits for the panel to peek. + * @param nodeId A string containing the node ID. + */ + protected void triggerLongPress(String nodeId) throws TimeoutException { + mTestHost.triggerLongPress(nodeId); + } + + /** * Waits for the selected text string to be the given string, and asserts. * @param text The string to wait for the selection to become. */ @@ -753,6 +766,19 @@ } /** + * Simulates a non-resolving search by long press. + * + * @param nodeId The id of the node to be triggered. + */ + protected void simulateNonResolveSearchByLongPress(String nodeId) + throws InterruptedException, TimeoutException { + ContextualSearchFakeServer.FakeNonResolveSearch search = + mFakeServer.getFakeNonResolveSearch(nodeId); + search.simulateLongPress(); + waitForPanelToPeek(); + } + + /** * Simulates a resolve-triggering search. * * @param nodeId The id of the node to be tapped.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTriggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTriggerTest.java index e7dab4f..a7ac57d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTriggerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTriggerTest.java
@@ -180,13 +180,10 @@ Assert.assertNull(mSelectionController.getSelectedText()); } - /** - * Tests that a Tap gesture followed by tapping a non-text character doesn't select. - * @SmallTest - * @Feature({"ContextualSearch"}) - * crbug.com/665633 - */ + /** Tests that a Tap gesture followed by tapping a non-text element doesn't select. */ @Test + @SmallTest + @Feature({"ContextualSearch"}) @DisabledTest(message = "crbug.com/662104") public void testTapGestureFollowedByNonTextTap() throws Exception { FeatureList.setTestFeatures(ENABLE_NONE); @@ -229,7 +226,7 @@ @Test @SmallTest @Feature({"ContextualSearch"}) - @DisabledTest(message = "https://crbug.com/1075895") + // Previously disabled at https://crbug.com/1075895 public void testTapGesturesNearbyKeepSelecting() throws Exception { FeatureList.setTestFeatures(ENABLE_NONE); @@ -379,12 +376,11 @@ @Test @SmallTest @Feature({"ContextualSearch"}) - // Previously flaky, disabled 4/2021. https://crbug.com/1192285 - @DisabledTest(message = "https://crbug.com/1291558") + // Previously flaky, disabled 4/2021. https://crbug.com/1192285, https://crbug.com/1291558 public void testPreventHandlingCurrentSelectionModification() throws Exception { FeatureList.setTestFeatures(ENABLE_NONE); - simulateNonResolveSearch("search"); + longPressNode("search"); // Dismiss the Contextual Search panel. closePanel(); @@ -403,7 +399,7 @@ assertPanelClosedOrUndefined(); // Select a different word and assert that the panel has appeared. - simulateNonResolveSearch("resolution"); + longPressNode("resolution"); // The simulateNonResolveSearch call will verify that the panel peeks. }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/OWNERS new file mode 100644 index 0000000..ff42f2c --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/OWNERS
@@ -0,0 +1 @@ +file://chrome/android/java/src/org/chromium/chrome/browser/homepage/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java index fd4450c..9dd4e0f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
@@ -37,6 +37,7 @@ import androidx.swiperefreshlayout.widget.CircularProgressDrawable; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -54,7 +55,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; +import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.test.util.browser.Features; import java.util.ArrayList; @@ -101,8 +102,6 @@ @Mock private PartialCustomTabHeightStrategy.OnResizedCallback mOnResizedCallback; @Mock - private MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher; - @Mock private ActivityLifecycleDispatcher mActivityLifecycleDispatcher; @Mock private LinearLayout mNavbar; @@ -183,10 +182,15 @@ .getRealMetrics(any(DisplayMetrics.class)); } + @After + public void tearDown() { + // Reset the multi-window mode. + MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(false); + } + private PartialCustomTabHeightStrategy createPcctAtHeight(int heightPx) { - PartialCustomTabHeightStrategy pcct = new PartialCustomTabHeightStrategy(mActivity, - heightPx, mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback, - mActivityLifecycleDispatcher); + PartialCustomTabHeightStrategy pcct = new PartialCustomTabHeightStrategy( + mActivity, heightPx, null, null, mOnResizedCallback, mActivityLifecycleDispatcher); pcct.setMockViewForTesting( mNavbar, mSpinnerView, mSpinner, mToolbarView, mToolbarCoordinator); return pcct; @@ -288,7 +292,7 @@ @Test public void moveUp_multiwindowModeUnresizable() { - when(mMultiWindowModeStateDispatcher.isInMultiWindowMode()).thenReturn(true); + MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true); PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800); // Pass null because we have a mock Activity and we don't depend on the GestureDetector @@ -344,7 +348,8 @@ PartialCustomTabHeightStrategy.PartialCustomTabHandleStrategy handleStrategy = strategy.new PartialCustomTabHandleStrategy(null); - strategy.onMultiWindowModeChanged(true); + MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true); + strategy.onConfigurationChanged(mConfiguration); // action down assertFalse(handleStrategy.onInterceptTouchEvent(
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 040850c..122383c2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -10190,6 +10190,9 @@ <message name="IDS_TRANSLATE_BUBBLE_ADVANCED_SOURCE" desc="Text to show as the title in the advanced source language view for TAB UI"> Page language to translate </message> + <message name="IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE" desc="Text to show for the partial translate bubble button to start a full page translation"> + Translate full page + </message> </if> <if expr="use_titlecase"> <message name="IDS_TRANSLATE_BUBBLE_ADVANCED_BUTTON" desc="In Title Case: Text to show for the translate bubble button to jump to the advanced panel."> @@ -10246,6 +10249,9 @@ <message name="IDS_TRANSLATE_BUBBLE_ADVANCED_SOURCE" desc="In Title Case: Text to show as the title in the advanced source language view for TAB UI"> Page Language to Translate </message> + <message name="IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE" desc="Text to show for the partial translate bubble button to start a full page translation"> + Translate Full Page + </message> </if> <message name="IDS_TRANSLATE_BUBBLE_RESET" desc="Text to show for the language combobox to revert to its original state in the advanced view under TAB UI"> Reset
diff --git a/chrome/app/generated_resources_grd/IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE.png.sha1 new file mode 100644 index 0000000..0386f66 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE.png.sha1
@@ -0,0 +1 @@ +284678c818bfd6db16ad6a8bdd68ebc543600b66 \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 0e4cbbd..e30bffd 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -5438,11 +5438,6 @@ kTabScrollingVariations, "TabScrolling")}, - {"scrollable-tabstrip-buttons", - flag_descriptions::kScrollableTabStripButtonsName, - flag_descriptions::kScrollableTabStripButtonsDescription, kOsDesktop, - FEATURE_VALUE_TYPE(features::kScrollableTabStripButtons)}, - {"side-panel-improved-clobbering", flag_descriptions::kSidePanelImprovedClobberingName, flag_descriptions::kSidePanelImprovedClobberingDescription, kOsDesktop, @@ -6108,13 +6103,6 @@ flag_descriptions::kDisableQuickAnswersV2TranslationDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kDisableQuickAnswersV2Translation)}, - {"quick-answers-always-trigger-for-single-word", - flag_descriptions::kQuickAnswersAlwaysTriggerForSingleWordName, - flag_descriptions::kQuickAnswersAlwaysTriggerForSingleWordDescription, - kOsCrOS, - FEATURE_VALUE_TYPE( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord)}, - {"quick-answers-for-more-locales", flag_descriptions::kQuickAnswersForMoreLocalesName, flag_descriptions::kQuickAnswersForMoreLocalesDescription, kOsCrOS,
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc index 17be82e..639389fd 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
@@ -20,6 +20,7 @@ #include "base/gtest_prod_util.h" #include "base/json/json_writer.h" #include "base/memory/singleton.h" +#include "base/scoped_observation.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -253,6 +254,10 @@ // automatically unregisters a callback when it's destructed. base::CallbackListSubscription default_zoom_level_subscription_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Name of the default network. Used to keep track of whether the default // network has changed. std::string default_network_name_; @@ -427,8 +432,8 @@ TimezoneSettings::GetInstance()->AddObserver(this); - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + network_state_handler_observer_.Observe( + chromeos::NetworkHandler::Get()->network_state_handler()); } void ArcSettingsServiceImpl::StopObservingSettingsChanges() { @@ -437,8 +442,7 @@ reporting_consent_subscription_ = {}; TimezoneSettings::GetInstance()->RemoveObserver(this); - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); + network_state_handler_observer_.Reset(); } void ArcSettingsServiceImpl::SyncInitialSettings() const {
diff --git a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.cc b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.cc index 7edeea2c..2eadf2c 100644 --- a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.cc +++ b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.cc
@@ -30,7 +30,6 @@ #include "chromeos/ash/components/dbus/authpolicy/authpolicy_client.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "chromeos/ui/vector_icons/vector_icons.h" #include "components/account_manager_core/account.h" #include "components/account_manager_core/chromeos/account_manager.h" @@ -226,7 +225,8 @@ if (is_observing_network_) return; is_observing_network_ = true; - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); } void AuthPolicyCredentialsManager::StopObserveNetwork() { @@ -234,8 +234,7 @@ return; DCHECK(NetworkHandler::IsInitialized()); is_observing_network_ = false; - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); + network_state_handler_observer_.Reset(); } void AuthPolicyCredentialsManager::UpdateDisplayAndGivenName(
diff --git a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h index 05c9a5cf..eebc9f5 100644 --- a/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h +++ b/chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h
@@ -10,8 +10,10 @@ #include "base/cancelable_callback.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "chrome/browser/ash/authpolicy/kerberos_files_handler.h" #include "chromeos/ash/components/dbus/authpolicy/active_directory_info.pb.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/account_id/account_id.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" @@ -114,6 +116,10 @@ bool is_observing_network_ = false; KerberosFilesHandler kerberos_files_handler_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Stores message ids of shown notifications. Each notification is shown at // most once. std::set<int> shown_notifications_;
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc index 39ed9351..bcae6a2 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc
@@ -152,17 +152,13 @@ scoped_platform_keys_service_observation_.Observe(platform_keys_service_); - network_state_handler_->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(network_state_handler_); ScheduleInitialUpdate(); ScheduleDailyUpdate(); } -CertProvisioningSchedulerImpl::~CertProvisioningSchedulerImpl() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - network_state_handler_->RemoveObserver(this, FROM_HERE); -} +CertProvisioningSchedulerImpl::~CertProvisioningSchedulerImpl() = default; void CertProvisioningSchedulerImpl::ScheduleInitialUpdate() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h index 111c881..c8d1c94 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h
@@ -219,6 +219,10 @@ // |platform_keys_service_| can be nullptr if it has been shut down. platform_keys::PlatformKeysService* platform_keys_service_ = nullptr; NetworkStateHandler* network_state_handler_ = nullptr; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + PrefChangeRegistrar pref_change_registrar_; WorkerMap workers_; // Contains cert profile ids that will be renewed before next daily update.
diff --git a/chrome/browser/ash/crosapi/network_settings_service_ash.cc b/chrome/browser/ash/crosapi/network_settings_service_ash.cc index 6763eeee..84a9f2c 100644 --- a/chrome/browser/ash/crosapi/network_settings_service_ash.cc +++ b/chrome/browser/ash/crosapi/network_settings_service_ash.cc
@@ -16,7 +16,6 @@ #include "chromeos/ash/components/network/proxy/proxy_config_service_impl.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -52,19 +51,14 @@ } // Uninitialized in unit_tests. if (chromeos::NetworkHandler::IsInitialized()) { - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + network_state_handler_observer_.Observe( + chromeos::NetworkHandler::Get()->network_state_handler()); } observers_.set_disconnect_handler(base::BindRepeating( &NetworkSettingsServiceAsh::OnDisconnect, base::Unretained(this))); } NetworkSettingsServiceAsh::~NetworkSettingsServiceAsh() { - // Uninitialized in unit_tests. - if (chromeos::NetworkHandler::IsInitialized()) { - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); - } if (profile_manager_) { profile_manager_->RemoveObserver(this); }
diff --git a/chrome/browser/ash/crosapi/network_settings_service_ash.h b/chrome/browser/ash/crosapi/network_settings_service_ash.h index c8ed959..c8d75d0 100644 --- a/chrome/browser/ash/crosapi/network_settings_service_ash.h +++ b/chrome/browser/ash/crosapi/network_settings_service_ash.h
@@ -5,8 +5,10 @@ #ifndef CHROME_BROWSER_ASH_CROSAPI_NETWORK_SETTINGS_SERVICE_ASH_H_ #define CHROME_BROWSER_ASH_CROSAPI_NETWORK_SETTINGS_SERVICE_ASH_H_ +#include "base/scoped_observation.h" #include "chrome/browser/profiles/profile_manager_observer.h" #include "chromeos/crosapi/mojom/network_settings_service.mojom.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -95,6 +97,10 @@ PrefService* local_state_; ProfileManager* profile_manager_ = nullptr; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Support any number of connections. mojo::ReceiverSet<mojom::NetworkSettingsService> receivers_; // Support any number of observers.
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc index 510fa4f..c01aa24 100644 --- a/chrome/browser/ash/crostini/crostini_manager.cc +++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -1233,8 +1233,8 @@ chromeos::AnomalyDetectorClient::Get()->AddObserver(this); } if (chromeos::NetworkHandler::IsInitialized()) { - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, ::base::Location::Current()); + network_state_handler_observer_.Observe( + chromeos::NetworkHandler::Get()->network_state_handler()); } if (chromeos::PowerManagerClient::Get()) { chromeos::PowerManagerClient::Get()->AddObserver(this); @@ -1262,10 +1262,6 @@ CrostiniManager::~CrostiniManager() { RemoveDBusObservers(); - if (chromeos::NetworkHandler::IsInitialized()) { - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, ::base::Location::Current()); - } } base::WeakPtr<CrostiniManager> CrostiniManager::GetWeakPtr() { @@ -3886,6 +3882,10 @@ } } +void CrostiniManager::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void CrostiniManager::SuspendImminent( power_manager::SuspendImminent::Reason reason) { auto info = GetContainerInfo(DefaultContainerId());
diff --git a/chrome/browser/ash/crostini/crostini_manager.h b/chrome/browser/ash/crostini/crostini_manager.h index 87c404f0..d76d985 100644 --- a/chrome/browser/ash/crostini/crostini_manager.h +++ b/chrome/browser/ash/crostini/crostini_manager.h
@@ -14,6 +14,7 @@ #include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/unguessable_token.h" #include "chrome/browser/ash/crostini/crostini_low_disk_notification.h" @@ -33,6 +34,7 @@ #include "chromeos/dbus/anomaly_detector/anomaly_detector_client.h" #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -571,6 +573,7 @@ // chromeos::NetworkStateHandlerObserver overrides: void ActiveNetworksChanged(const std::vector<const chromeos::NetworkState*>& active_networks) override; + void OnShuttingDown() override; // chromeos::PowerManagerClient::Observer overrides: void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; @@ -970,6 +973,10 @@ guest_os::GuestOsTerminalProviderRegistry::Id> terminal_provider_ids_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_{this};
diff --git a/chrome/browser/ash/login/screens/network_screen.cc b/chrome/browser/ash/login/screens/network_screen.cc index 031aa8b..2a89796 100644 --- a/chrome/browser/ash/login/screens/network_screen.cc +++ b/chrome/browser/ash/login/screens/network_screen.cc
@@ -17,7 +17,6 @@ #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chromeos/network/network_handler.h" -#include "chromeos/network/network_state_handler.h" #include "ui/base/l10n/l10n_util.h" namespace ash { @@ -133,16 +132,15 @@ void NetworkScreen::SubscribeNetworkNotification() { if (!is_network_subscribed_) { is_network_subscribed_ = true; - NetworkHandler::Get()->network_state_handler()->AddObserver(this, - FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); } } void NetworkScreen::UnsubscribeNetworkNotification() { if (is_network_subscribed_) { is_network_subscribed_ = false; - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); + network_state_handler_observer_.Reset(); } }
diff --git a/chrome/browser/ash/login/screens/network_screen.h b/chrome/browser/ash/login/screens/network_screen.h index 38a90b4..52bb73a5 100644 --- a/chrome/browser/ash/login/screens/network_screen.h +++ b/chrome/browser/ash/login/screens/network_screen.h
@@ -11,10 +11,12 @@ #include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/timer/timer.h" // TODO(https://crbug.com/1164001): move to forward declaration. #include "chrome/browser/ash/login/helper.h" #include "chrome/browser/ash/login/screens/base_screen.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" // TODO(https://crbug.com/1164001): move to forward declaration. #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h" @@ -152,6 +154,10 @@ ScreenExitCallback exit_callback_; std::unique_ptr<login::NetworkStateHelper> network_state_helper_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::WeakPtrFactory<NetworkScreen> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/login/screens/update_required_screen.cc b/chrome/browser/ash/login/screens/update_required_screen.cc index 218ad030..d5d2df8 100644 --- a/chrome/browser/ash/login/screens/update_required_screen.cc +++ b/chrome/browser/ash/login/screens/update_required_screen.cc
@@ -24,7 +24,6 @@ #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h" #include "chromeos/network/network_handler.h" -#include "chromeos/network/network_state_handler.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "ui/chromeos/devicetype_utils.h" @@ -246,16 +245,15 @@ void UpdateRequiredScreen::ObserveNetworkState() { if (!is_network_subscribed_) { is_network_subscribed_ = true; - NetworkHandler::Get()->network_state_handler()->AddObserver(this, - FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); } } void UpdateRequiredScreen::StopObservingNetworkState() { if (is_network_subscribed_) { is_network_subscribed_ = false; - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); + network_state_handler_observer_.Reset(); } }
diff --git a/chrome/browser/ash/login/screens/update_required_screen.h b/chrome/browser/ash/login/screens/update_required_screen.h index 16951f48..efc60cbb 100644 --- a/chrome/browser/ash/login/screens/update_required_screen.h +++ b/chrome/browser/ash/login/screens/update_required_screen.h
@@ -11,7 +11,10 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/time/time.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_state_handler_observer.h" // TODO(https://crbug.com/1164001): move to forward declaration. #include "chrome/browser/ash/login/error_screens_histogram_helper.h" #include "chrome/browser/ash/login/screens/base_screen.h" @@ -122,6 +125,10 @@ base::RepeatingClosure exit_callback_; std::unique_ptr<ErrorScreensHistogramHelper> histogram_helper_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Whether the screen is shown. bool is_shown_ = false;
diff --git a/chrome/browser/ash/mobile/mobile_activator.cc b/chrome/browser/ash/mobile/mobile_activator.cc index 1901804..859db4a 100644 --- a/chrome/browser/ash/mobile/mobile_activator.cc +++ b/chrome/browser/ash/mobile/mobile_activator.cc
@@ -29,7 +29,6 @@ #include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_handler_callbacks.h" -#include "chromeos/network/network_state_handler.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -86,10 +85,8 @@ continue_reconnect_timer_.Stop(); reconnect_timeout_timer_.Stop(); - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); - } + network_state_handler_observer_.Reset(); + meid_.clear(); iccid_.clear(); service_path_.clear(); @@ -131,6 +128,10 @@ EvaluateCellularNetwork(network); } +void MobileActivator::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void MobileActivator::AddObserver(MobileActivator::Observer* observer) { DCHECK_CURRENTLY_ON(BrowserThread::UI); observers_.AddObserver(observer); @@ -273,7 +274,8 @@ } // Start monitoring network property changes. - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); if (network->activation_type() == shill::kActivationTypeNonCellular) { StartActivationOverNonCellularNetwork(); @@ -742,8 +744,7 @@ void MobileActivator::CompleteActivation() { // Remove observers, we are done with this page. - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); + network_state_handler_observer_.Reset(); } bool MobileActivator::RunningActivation() const {
diff --git a/chrome/browser/ash/mobile/mobile_activator.h b/chrome/browser/ash/mobile/mobile_activator.h index 174e49d..cbaf95a7 100644 --- a/chrome/browser/ash/mobile/mobile_activator.h +++ b/chrome/browser/ash/mobile/mobile_activator.h
@@ -12,12 +12,14 @@ #include "base/memory/singleton.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chromeos/network/network_handler_callbacks.h" // TODO(https://crbug.com/1164001): restore network_state.h as forward // declaration after it is moved to ash. #include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" namespace base { @@ -138,9 +140,7 @@ protected: // For unit tests. - void set_state_for_test(PlanActivationState state) { - state_ = state; - } + void set_state_for_test(PlanActivationState state) { state_ = state; } virtual const NetworkState* GetNetworkState(const std::string& service_path); virtual const NetworkState* GetDefaultNetwork(); @@ -155,6 +155,7 @@ // NetworkStateHandlerObserver overrides. void DefaultNetworkChanged(const NetworkState* network) override; void NetworkPropertiesUpdated(const NetworkState* network) override; + void OnShuttingDown() override; void GetPropertiesFailure(const std::string& error_name, std::unique_ptr<base::DictionaryValue> error_data); @@ -256,6 +257,10 @@ // Cellular plan payment time. base::Time cellular_plan_payment_time_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::ObserverList<Observer>::Unchecked observers_; base::WeakPtrFactory<MobileActivator> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/net/network_portal_detector_impl.cc b/chrome/browser/ash/net/network_portal_detector_impl.cc index 90e4437..f2d3976 100644 --- a/chrome/browser/ash/net/network_portal_detector_impl.cc +++ b/chrome/browser/ash/net/network_portal_detector_impl.cc
@@ -21,7 +21,6 @@ #include "chromeos/login/login_state/login_state.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "content/public/browser/notification_service.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -96,7 +95,8 @@ registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, content::NotificationService::AllSources()); - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); StartPortalDetection(); } @@ -110,10 +110,6 @@ captive_portal_detector_->Cancel(); captive_portal_detector_.reset(); observers_.Clear(); - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); - } for (auto& observer : observers_) observer.OnShutdown(); } @@ -252,6 +248,10 @@ } } +void NetworkPortalDetectorImpl::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + int NetworkPortalDetectorImpl::NoResponseResultCount() { return no_response_result_count_; }
diff --git a/chrome/browser/ash/net/network_portal_detector_impl.h b/chrome/browser/ash/net/network_portal_detector_impl.h index 5c20c6f..7f3eee7 100644 --- a/chrome/browser/ash/net/network_portal_detector_impl.h +++ b/chrome/browser/ash/net/network_portal_detector_impl.h
@@ -15,12 +15,14 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "base/sequence_checker.h" #include "base/time/time.h" #include "chromeos/ash/components/network/portal_detector/network_portal_detector.h" #include "chromeos/ash/components/network/portal_detector/network_portal_detector_strategy.h" // TODO(https://crbug.com/1164001): move to forward declaration. #include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/captive_portal/core/captive_portal_detector.h" #include "components/captive_portal/core/captive_portal_types.h" @@ -106,6 +108,7 @@ // NetworkStateHandlerObserver implementation: void DefaultNetworkChanged(const NetworkState* network) override; + void OnShuttingDown() override; // PortalDetectorStrategy::Delegate implementation: int NoResponseResultCount() override; @@ -226,6 +229,10 @@ content::NotificationRegistrar registrar_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // Test time ticks used by unit tests. base::TimeTicks time_ticks_for_testing_;
diff --git a/chrome/browser/ash/net/system_proxy_manager.cc b/chrome/browser/ash/net/system_proxy_manager.cc index c51ae0f..dd39f0b 100644 --- a/chrome/browser/ash/net/system_proxy_manager.cc +++ b/chrome/browser/ash/net/system_proxy_manager.cc
@@ -30,7 +30,6 @@ #include "chromeos/login/login_state/login_state.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -125,7 +124,8 @@ base::BindRepeating(&SystemProxyManager::OnKerberosEnabledChanged, weak_factory_.GetWeakPtr())); DCHECK(NetworkHandler::IsInitialized()); - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); system_proxy_state_ = DetermineSystemProxyState(/*policy_enabled=*/false); @@ -142,8 +142,6 @@ SendShutDownRequest(system_proxy::TrafficOrigin::ALL); } DCHECK(NetworkHandler::IsInitialized()); - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); } // static
diff --git a/chrome/browser/ash/net/system_proxy_manager.h b/chrome/browser/ash/net/system_proxy_manager.h index f499bae..39c07fe 100644 --- a/chrome/browser/ash/net/system_proxy_manager.h +++ b/chrome/browser/ash/net/system_proxy_manager.h
@@ -12,8 +12,10 @@ #include "base/callback_forward.h" #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "chrome/browser/extensions/api/settings_private/prefs_util.h" #include "chromeos/ash/components/dbus/system_proxy/system_proxy_service.pb.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/content_browser_client.h" @@ -275,6 +277,10 @@ std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> profile_pref_change_registrar_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::RepeatingClosure send_auth_details_closure_for_test_; base::WeakPtrFactory<SystemProxyManager> weak_factory_{this};
diff --git a/chrome/browser/ash/network_change_manager_client.cc b/chrome/browser/ash/network_change_manager_client.cc index f96b319..e61f7126 100644 --- a/chrome/browser/ash/network_change_manager_client.cc +++ b/chrome/browser/ash/network_change_manager_client.cc
@@ -8,7 +8,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "content/public/browser/network_service_instance.h" #include "content/public/common/network_service_util.h" #include "net/base/network_change_notifier.h" @@ -23,7 +22,9 @@ connection_subtype_(net::NetworkChangeNotifier::GetConnectionSubtype()), network_change_notifier_(network_change_notifier) { PowerManagerClient::Get()->AddObserver(this); - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); if (content::IsOutOfProcessNetworkService()) ConnectToNetworkChangeManager(); @@ -34,8 +35,6 @@ } NetworkChangeManagerClient::~NetworkChangeManagerClient() { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); PowerManagerClient::Get()->RemoveObserver(this); }
diff --git a/chrome/browser/ash/network_change_manager_client.h b/chrome/browser/ash/network_change_manager_client.h index 4f083ab..ea90d32 100644 --- a/chrome/browser/ash/network_change_manager_client.h +++ b/chrome/browser/ash/network_change_manager_client.h
@@ -8,7 +8,9 @@ #include <string> #include "base/gtest_prod_util.h" +#include "base/scoped_observation.h" #include "chromeos/dbus/power/power_manager_client.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/network_change_notifier.h" @@ -91,6 +93,10 @@ // Service path for the current default network. std::string service_path_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + net::NetworkChangeNotifierPosix* network_change_notifier_; mojo::Remote<network::mojom::NetworkChangeManager> network_change_manager_; };
diff --git a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc index ccdd12f..7f57cd5 100644 --- a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc +++ b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.cc
@@ -59,19 +59,15 @@ base::BindRepeating( &DeviceNamePolicyHandlerImpl::OnDeviceHostnamePropertyChanged, weak_factory_.GetWeakPtr())); - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + + network_state_handler_observer_.Observe( + chromeos::NetworkHandler::Get()->network_state_handler()); // Fire it once so we're sure we get an invocation on startup. OnDeviceHostnamePropertyChanged(); } -DeviceNamePolicyHandlerImpl::~DeviceNamePolicyHandlerImpl() { - if (chromeos::NetworkHandler::IsInitialized()) { - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); - } -} +DeviceNamePolicyHandlerImpl::~DeviceNamePolicyHandlerImpl() = default; DeviceNamePolicyHandler::DeviceNamePolicy DeviceNamePolicyHandlerImpl::GetDeviceNamePolicy() const { @@ -91,6 +87,10 @@ OnDeviceHostnamePropertyChanged(); } +void DeviceNamePolicyHandlerImpl::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void DeviceNamePolicyHandlerImpl::OnDeviceHostnamePropertyChanged() { ash::CrosSettingsProvider::TrustedStatus status = cros_settings_->PrepareTrustedValues(base::BindOnce(
diff --git a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h index 11d25708..f5b8a61 100644 --- a/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h +++ b/chrome/browser/ash/policy/handlers/device_name_policy_handler_impl.h
@@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "chrome/browser/ash/policy/handlers/device_name_policy_handler.h" #include "chrome/browser/ash/settings/cros_settings.h" #include "chromeos/network/network_handler.h" @@ -49,6 +50,7 @@ // NetworkStateHandlerObserver overrides void DefaultNetworkChanged(const chromeos::NetworkState* network) override; + void OnShuttingDown() override; void OnDeviceHostnamePropertyChanged(); @@ -71,6 +73,10 @@ ash::CrosSettings* cros_settings_; chromeos::system::StatisticsProvider* statistics_provider_; chromeos::NetworkStateHandler* handler_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + DeviceNamePolicy device_name_policy_; base::CallbackListSubscription template_policy_subscription_;
diff --git a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc index 1075ade..17441a9b 100644 --- a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc +++ b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.cc
@@ -32,7 +32,6 @@ #include "chrome/common/pref_names.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/network_handler.h" -#include "chromeos/network/network_state_handler.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "ui/chromeos/devicetype_utils.h" @@ -521,7 +520,7 @@ chromeos::NetworkStateHandler* network_state_handler = chromeos::NetworkHandler::Get()->network_state_handler(); if (!network_state_handler->HasObserver(this)) - network_state_handler->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(network_state_handler); } } @@ -582,12 +581,12 @@ } } +void MinimumVersionPolicyHandler::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void MinimumVersionPolicyHandler::StopObservingNetwork() { - if (!chromeos::NetworkHandler::IsInitialized()) - return; - chromeos::NetworkStateHandler* network_state_handler = - chromeos::NetworkHandler::Get()->network_state_handler(); - network_state_handler->RemoveObserver(this, FROM_HERE); + network_state_handler_observer_.Reset(); } void MinimumVersionPolicyHandler::UpdateOverMeteredPermssionGranted() {
diff --git a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h index 822c17d..b9c7bf7 100644 --- a/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h +++ b/chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h
@@ -9,12 +9,14 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/wall_clock_timer.h" #include "base/version.h" #include "chrome/browser/ash/settings/cros_settings.h" #include "chrome/browser/upgrade_detector/build_state_observer.h" #include "chromeos/dbus/update_engine/update_engine_client.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" class PrefRegistrySimple; @@ -145,6 +147,7 @@ // NetworkStateHandlerObserver: void DefaultNetworkChanged(const chromeos::NetworkState* network) override; + void OnShuttingDown() override; // UpdateEngineClient::Observer: void UpdateStatusChanged(const update_engine::StatusResult& status) override; @@ -312,6 +315,10 @@ // current network and time to reach the deadline. std::unique_ptr<ash::UpdateRequiredNotification> notification_handler_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + // List of registered observers. base::ObserverList<Observer>::Unchecked observers_;
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc index e6c3b49..b097a38 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc +++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.cc
@@ -56,7 +56,7 @@ FROM_HERE, update_checker_internal::kWaitForNetworkTimeout, base::BindOnce(&OsAndPoliciesUpdateChecker::OnNetworkWaitTimeout, base::Unretained(this))); - network_state_handler_->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(network_state_handler_); return; } @@ -81,7 +81,7 @@ return; wait_for_network_timer_.Stop(); - network_state_handler_->RemoveObserver(this, FROM_HERE); + network_state_handler_observer_.Reset(); ScheduleUpdateCheck(); } @@ -226,7 +226,7 @@ void OsAndPoliciesUpdateChecker::ResetState() { weak_factory_.InvalidateWeakPtrs(); update_engine_client_->RemoveObserver(this); - network_state_handler_->RemoveObserver(this, FROM_HERE); + network_state_handler_observer_.Reset(); update_check_task_executor_.Stop(); ignore_idle_status_ = true; is_running_ = false;
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h index 71b5b0c..46cc01c 100644 --- a/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h +++ b/chrome/browser/ash/policy/scheduled_task_handler/os_and_policies_update_checker.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_ASH_POLICY_SCHEDULED_TASK_HANDLER_OS_AND_POLICIES_UPDATE_CHECKER_H_ #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/ash/policy/scheduled_task_handler/task_executor_with_retries.h" @@ -118,6 +119,9 @@ // Not owned. chromeos::NetworkStateHandler* const network_state_handler_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; // Scheduled and retries |StartUpdateCheck|. TaskExecutorWithRetries update_check_task_executor_;
diff --git a/chrome/browser/ash/tether/tether_service.cc b/chrome/browser/ash/tether/tether_service.cc index 7b1082c4..7a9b0965 100644 --- a/chrome/browser/ash/tether/tether_service.cc +++ b/chrome/browser/ash/tether/tether_service.cc
@@ -117,7 +117,7 @@ timer_(std::make_unique<base::OneShotTimer>()) { tether_host_fetcher_->AddObserver(this); power_manager_client_->AddObserver(this); - network_state_handler_->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(network_state_handler_); device_sync_client_->AddObserver(this); multidevice_setup_client_->AddObserver(this); @@ -227,7 +227,7 @@ // calls to UpdateTetherTechnologyState() will be triggered. tether_host_fetcher_->RemoveObserver(this); power_manager_client_->RemoveObserver(this); - network_state_handler_->RemoveObserver(this, FROM_HERE); + network_state_handler_observer_.Reset(); device_sync_client_->RemoveObserver(this); multidevice_setup_client_->RemoveObserver(this);
diff --git a/chrome/browser/ash/tether/tether_service.h b/chrome/browser/ash/tether/tether_service.h index 8ed4255..fa767a8 100644 --- a/chrome/browser/ash/tether/tether_service.h +++ b/chrome/browser/ash/tether/tether_service.h
@@ -13,6 +13,7 @@ #include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h" #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/timer/timer.h" #include "chromeos/dbus/power/power_manager_client.h" #include "chromeos/network/network_state_handler.h" @@ -271,6 +272,9 @@ secure_channel::SecureChannelClient* secure_channel_client_; multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client_; chromeos::NetworkStateHandler* network_state_handler_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; session_manager::SessionManager* session_manager_; std::unique_ptr<NotificationPresenter> notification_presenter_; std::unique_ptr<GmsCoreNotificationsStateTrackerImpl>
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 44971bed..41d8ebb 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -5182,11 +5182,6 @@ "expiry_milestone": 120 }, { - "name": "quick-answers-always-trigger-for-single-word", - "owners": [ "croissant-eng", "updowndota" ], - "expiry_milestone": 120 - }, - { "name": "quick-answers-for-more-locales", "owners": [ "croissant-eng", "updowndota" ], "expiry_milestone": 120 @@ -5403,12 +5398,7 @@ { "name": "scrollable-tabstrip", "owners": [ "chrome-desktop-ui-sea@google.com", "tbergquist" ], - "expiry_milestone": 105 - }, - { - "name": "scrollable-tabstrip-buttons", - "owners": [ "chrome-desktop-ui-sea@google.com", "tbergquist" ], - "expiry_milestone": 105 + "expiry_milestone": 115 }, { "name": "sct-auditing", @@ -6385,7 +6375,7 @@ "yuhengh", "tluk" ], - "expiry_milestone": 106 + "expiry_milestone": 110 }, { "name" : "webui-tab-strip-context-menu-after-tap", @@ -6393,7 +6383,7 @@ "yuhengh", "tluk" ], - "expiry_milestone": 106 + "expiry_milestone": 110 }, { "name": "webui-tab-strip-ntb-in-tab-strip", @@ -6401,7 +6391,7 @@ "yuhengh", "tluk" ], - "expiry_milestone": 106 + "expiry_milestone": 110 }, { "name": "webui-tab-strip-tab-drag-integration", @@ -6409,7 +6399,7 @@ "yuhengh", "tluk" ], - "expiry_milestone": 106 + "expiry_milestone": 110 }, { "name": "webxr-incubations",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index b226c8e..6a45d38 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2327,11 +2327,6 @@ const char kScrollableTabStripDescription[] = "Enables tab strip to scroll left and right when full."; -const char kScrollableTabStripButtonsName[] = "Tab Scrolling Buttons"; -const char kScrollableTabStripButtonsDescription[] = - "When the scrollable-tabstrip flag is enabled, this enables buttons to " - "permanently appear on the tabstrip."; - const char kScrollUnificationName[] = "Scroll Unification"; const char kScrollUnificationDescription[] = "Refactoring project that eliminates scroll handling code from Blink. " @@ -4860,11 +4855,6 @@ const char kDisableQuickAnswersV2TranslationDescription[] = "Disable translation services of the Quick Answers."; -const char kQuickAnswersAlwaysTriggerForSingleWordName[] = - "Enable Quick Answers always trigger for single word"; -const char kQuickAnswersAlwaysTriggerForSingleWordDescription[] = - "Enable Quick Answers always trigger for single word selection."; - const char kQuickAnswersForMoreLocalesName[] = "Enable Quick Answers for more locales"; const char kQuickAnswersForMoreLocalesDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index e99435a..782b4651 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1308,9 +1308,6 @@ extern const char kScrollableTabStripName[]; extern const char kScrollableTabStripDescription[]; -extern const char kScrollableTabStripButtonsName[]; -extern const char kScrollableTabStripButtonsDescription[]; - extern const char kScrollUnificationName[]; extern const char kScrollUnificationDescription[]; @@ -2770,9 +2767,6 @@ extern const char kDisableQuickAnswersV2TranslationName[]; extern const char kDisableQuickAnswersV2TranslationDescription[]; -extern const char kQuickAnswersAlwaysTriggerForSingleWordName[]; -extern const char kQuickAnswersAlwaysTriggerForSingleWordDescription[]; - extern const char kQuickAnswersForMoreLocalesName[]; extern const char kQuickAnswersForMoreLocalesDescription[];
diff --git a/chrome/browser/net/stub_resolver_config_reader_browsertest.cc b/chrome/browser/net/stub_resolver_config_reader_browsertest.cc index 660f3311..805081e 100644 --- a/chrome/browser/net/stub_resolver_config_reader_browsertest.cc +++ b/chrome/browser/net/stub_resolver_config_reader_browsertest.cc
@@ -95,11 +95,6 @@ policy_provider_.UpdateChromePolicy(policy_map_); } - void ClearPolicies() { - policy_map_.Clear(); - policy_provider_.UpdateChromePolicy(policy_map_); - } - policy::PolicyMap policy_map_; testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_; @@ -214,17 +209,15 @@ EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); } -// Set various policies and ensure the correct prefs. -IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, ConfigFromPolicy) { +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, + DefaultNonSetPolicies) { bool async_dns_feature_enabled = GetParam(); - // Mark as not enterprise managed. #if BUILDFLAG(IS_WIN) base::win::ScopedDomainStateForTesting scoped_domain(false); EXPECT_FALSE(base::IsEnterpriseDevice()); #endif - // Start with default non-set policies. SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(async_dns_feature_enabled, @@ -235,49 +228,82 @@ EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kOff); } EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); +} - // ChromeOS includes its own special functionality to set default policies if - // any policies are set. This function is not declared and cannot be invoked - // in non-CrOS builds. Expect these enterprise user defaults to disable DoH. +// ChromeOS includes its own special functionality to set default policies if +// any policies are set. This function is not declared and cannot be invoked +// in non-CrOS builds. Expect these enterprise user defaults to disable DoH. #if BUILDFLAG(IS_CHROMEOS) +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, SpecialPolicies) { // Applies the special ChromeOS defaults to `policy_map_`. policy::SetEnterpriseUsersDefaults(&policy_map_); // Send the PolicyMap to the mock policy provider. policy_provider_.UpdateChromePolicy(policy_map_); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kOff); EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); +} #endif // BUILDFLAG(IS_CHROMEOS) - // Disable DoH by policy - ClearPolicies(); +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, + DisableDohByPolicy) { +// Mark as not enterprise managed. +#if BUILDFLAG(IS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain(false); + EXPECT_FALSE(base::IsEnterpriseDevice()); +#endif + SetSecureDnsModePolicy("off"); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kOff); EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); +} - // Automatic mode by policy +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, + AutomaticModeByPolicy) { +// Mark as not enterprise managed. +#if BUILDFLAG(IS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain(false); + EXPECT_FALSE(base::IsEnterpriseDevice()); +#endif + SetSecureDnsModePolicy("automatic"); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kAutomatic); EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); +} - // Secure mode by policy +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, + SecureModeByPolicy) { +// Mark as not enterprise managed. +#if BUILDFLAG(IS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain(false); + EXPECT_FALSE(base::IsEnterpriseDevice()); +#endif + SetSecureDnsModePolicy("secure"); SetDohTemplatesPolicy("https://doh.test/"); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kSecure); EXPECT_EQ(*net::DnsOverHttpsConfig::FromString("https://doh.test/"), secure_dns_config.doh_servers()); +} - // Invalid template policy +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, + InvalidTemplatePolicy) { +// Mark as not enterprise managed. +#if BUILDFLAG(IS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain(false); + EXPECT_FALSE(base::IsEnterpriseDevice()); +#endif + SetSecureDnsModePolicy("secure"); SetDohTemplatesPolicy("invalid template"); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kSecure); EXPECT_THAT(secure_dns_config.doh_servers().servers(), testing::IsEmpty()); @@ -287,11 +313,18 @@ ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("foo.example", "/"))); +} - // Invalid mode policy +IN_PROC_BROWSER_TEST_P(StubResolverConfigReaderBrowsertest, InvalidModePolicy) { +// Mark as not enterprise managed. +#if BUILDFLAG(IS_WIN) + base::win::ScopedDomainStateForTesting scoped_domain(false); + EXPECT_FALSE(base::IsEnterpriseDevice()); +#endif + SetSecureDnsModePolicy("invalid"); SetDohTemplatesPolicy("https://doh.test/"); - secure_dns_config = config_reader_->GetSecureDnsConfiguration( + SecureDnsConfig secure_dns_config = config_reader_->GetSecureDnsConfiguration( /*force_check_parental_controls_for_automatic_mode=*/false); EXPECT_EQ(secure_dns_config.mode(), net::SecureDnsMode::kOff); // Expect empty templates if mode policy is invalid.
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 3e19cfac..5ae176d 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -2133,10 +2133,17 @@ resource_id = IDS_CONTENT_CONTEXT_LENS_REGION_SEARCH_ALT1; } else if (lens::features::UseRegionSearchMenuItemAltText2()) { resource_id = IDS_CONTENT_CONTEXT_LENS_REGION_SEARCH_ALT2; - } else if (lens::features::UseRegionSearchMenuItemAltText3() || - lens::features::IsLensFullscreenSearchEnabled()) { - // Default text for fullscreen search when enabled. Uses `Google` instead of - // `Google Lens` like the first alternative string. + } else if (lens::features::UseRegionSearchMenuItemAltText3()) { + // Uses `Google` instead of `Google Lens` like the first alternative string. + resource_id = IDS_CONTENT_CONTEXT_LENS_REGION_SEARCH_ALT1; + provider_name = std::u16string(kGoogle); + } else if (lens::features::UseRegionSearchMenuItemAltText4()) { + // This string is the same as currently launched but uses `Google` instead + // of `Google Lens` as the provider name. + provider_name = std::u16string(kGoogle); + } else if (lens::features::IsLensFullscreenSearchEnabled()) { + // Default text for fullscreen search when enabled. This is the same string + // as the third alternative text option. resource_id = IDS_CONTENT_CONTEXT_LENS_REGION_SEARCH_ALT1; provider_name = std::u16string(kGoogle); }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_node_menu_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_node_menu_background.js index dda0cac..23c659c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_node_menu_background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_node_menu_background.js
@@ -7,6 +7,7 @@ * panel. */ import {ChromeVoxState} from '/chromevox/background/chromevox_state.js'; +import {Output} from '/chromevox/background/output/output.js'; const AutomationNode = chrome.automation.AutomationNode;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js index e74c8559..01b848a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
@@ -199,7 +199,7 @@ await this.runWithLoadedTree(this.internationalButtonDoc); // Turn on language switching and set available voice list. localStorage['languageSwitching'] = 'true'; - this.getPanelWindow().LocaleOutputHelper.instance.availableVoices_ = + LocaleOutputHelper.instance.availableVoices_ = [{'lang': 'en-US'}, {'lang': 'es-ES'}]; CommandHandlerInterface.instance.onCommand('showFormsList'); await this.waitForMenu('panel_menu_form_controls');
diff --git a/chrome/browser/resources/chromeos/accessibility/common/automation_util_test.js b/chrome/browser/resources/chromeos/accessibility/common/automation_util_test.js index a693382..b64b01e 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/automation_util_test.js +++ b/chrome/browser/resources/chromeos/accessibility/common/automation_util_test.js
@@ -66,12 +66,12 @@ TEST_F( 'AccessibilityExtensionAutomationUtilE2ETest', 'GetAncestors', async function() { - const root = await this.runWithLoadedTree(this.basicDoc()); + let current = await this.runWithLoadedTree(this.basicDoc()); let expectedLength = 1; - while (root) { - const ancestors = getNonDesktopAncestors(root); + while (current) { + const ancestors = getNonDesktopAncestors(current); assertEquals(expectedLength++, ancestors.length); - root = root.firstChild; + current = current.firstChild; } });
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js index 62071f2e..e51490e2 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js
@@ -387,17 +387,6 @@ const website = `<input type="text" id="testinput"></input><button>ok</button>`; const rootWebArea = await this.runWithLoadedTree(website); - // SA initially focuses this node in Ash Chrome; wait for it first. - await new Promise(resolve => { - chrome.commandLinePrivate.hasSwitch( - 'lacros-chrome-path', async hasLacrosChromePath => { - if (!hasLacrosChromePath) { - await this.untilFocusIs( - {className: 'BrowserNonClientFrameViewChromeOS'}); - } - resolve(); - }); - }); // Move to the text field. Navigator.byItem.moveTo_(this.findNodeById('testinput')); @@ -420,9 +409,9 @@ // Wait for the keyboard to become invisible and the ok button to be // focused by automation. - await new Promise(resolve => { - okButton.addEventListener(chrome.automation.EventType.FOCUS, resolve); - }); + await new Promise( + resolve => okButton.addEventListener( + chrome.automation.EventType.FOCUS, resolve)); await new Promise(resolve => { keyboard.automationNode.addEventListener( chrome.automation.EventType.STATE_CHANGED, event => {
diff --git a/chrome/browser/resources/discards/BUILD.gn b/chrome/browser/resources/discards/BUILD.gn index 5b24af59..3066297 100644 --- a/chrome/browser/resources/discards/BUILD.gn +++ b/chrome/browser/resources/discards/BUILD.gn
@@ -95,6 +95,7 @@ ts_library("build_ts") { root_dir = "$target_gen_dir/$preprocess_folder" out_dir = "$target_gen_dir/$tsc_folder" + composite = true tsconfig_base = "tsconfig_base.json" manifest_excludes = [ "graph_doc.ts",
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java index 8509097..945630f 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
@@ -52,9 +52,10 @@ import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleMetricsHelper.LinkToggleMetricsDetails; import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.test.ChromeBrowserTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.chrome.test.util.browser.Features.DisableFeatures; +import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.share.ShareParams; import org.chromium.components.feature_engagement.Tracker; @@ -62,6 +63,7 @@ import org.chromium.components.user_prefs.UserPrefs; import org.chromium.components.user_prefs.UserPrefsJni; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.test.util.BlankUiTestActivity; @@ -71,14 +73,16 @@ import java.util.List; /** - * Tests {@link ChromeProvidedSharingOptionsProvider}. + * Unit tests {@link ChromeProvidedSharingOptionsProvider}. */ @RunWith(ChromeJUnit4ClassRunner.class) +@EnableFeatures( + {ChromeFeatureList.CHROME_SHARE_LONG_SCREENSHOT, ChromeFeatureList.WEBNOTES_STYLIZE}) +@DisableFeatures( + {ChromeFeatureList.LIGHTWEIGHT_REACTIONS, ChromeFeatureList.UPCOMING_SHARING_FEATURES, + ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO}) public class ChromeProvidedSharingOptionsProviderTest { @Rule - public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule(); - - @Rule public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = new BaseActivityTestRule<>(BlankUiTestActivity.class); @@ -123,6 +127,7 @@ @Before public void setUp() { Looper.prepare(); + NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); MockitoAnnotations.initMocks(this); mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsNatives); mJniMocker.mock(
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java index 92909c3c..13149e7 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java
@@ -40,7 +40,6 @@ import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType; -import org.chromium.chrome.test.ChromeBrowserTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.browser_ui.share.ShareParams; import org.chromium.components.favicon.IconType; @@ -49,6 +48,7 @@ import org.chromium.components.feature_engagement.Tracker; import org.chromium.components.feature_engagement.TriggerDetails; import org.chromium.components.url_formatter.UrlFormatter; +import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.test.util.BlankUiTestActivity; import org.chromium.url.GURL; @@ -56,14 +56,11 @@ import java.util.ArrayList; /** - * Tests {@link ShareSheetBottomSheetContent}. + * Unit tests {@link ShareSheetBottomSheetContent}. */ @RunWith(ChromeJUnit4ClassRunner.class) public final class ShareSheetBottomSheetContentTest { @Rule - public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule(); - - @Rule public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = new BaseActivityTestRule<>(BlankUiTestActivity.class); @@ -86,6 +83,7 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); + NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); mActivityTestRule.launchActivity(null); mActivity = mActivityTestRule.getActivity();
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java index 17c6046..d71a830 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
@@ -38,10 +38,10 @@ import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration; import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType; -import org.chromium.chrome.test.ChromeBrowserTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.browser_ui.share.ShareParams; +import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.test.util.BlankUiTestActivity; @@ -49,15 +49,12 @@ import java.util.List; /** - * Tests {@link ShareSheetPropertyModelBuilder}. + * Unit tests {@link ShareSheetPropertyModelBuilder}. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public final class ShareSheetPropertyModelBuilderTest { @Rule - public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule(); - - @Rule public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = new BaseActivityTestRule<>(BlankUiTestActivity.class); @@ -91,6 +88,7 @@ @Before public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); + NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); mActivityTestRule.launchActivity(null); mActivity = mActivityTestRule.getActivity(); mPropertyModelBuilder = new ShareSheetPropertyModelBuilder(null, mPackageManager, mProfile);
diff --git a/chrome/browser/share/android/test_java_sources.gni b/chrome/browser/share/android/test_java_sources.gni index 7d9a77cd..1ca6e50 100644 --- a/chrome/browser/share/android/test_java_sources.gni +++ b/chrome/browser/share/android/test_java_sources.gni
@@ -12,13 +12,15 @@ "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/scroll_capture/ScrollCaptureCallbackRenderTest.java", "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfBottomSheetRenderTest.java", "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java", - "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java", - "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java", - "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java", "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetTest.java", ] -share_unit_device_javatest_java_sources = [ "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java" ] +share_unit_device_javatest_java_sources = [ + "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetViewTest.java", + "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java", + "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java", + "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java", +] share_junit_test_java_sources = [ "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinatorTest.java", @@ -39,8 +41,16 @@ "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinatorTest.java", ] -share_unit_device_javatest_java_deps = - [ "//chrome/browser/share/android:java_resources" ] +share_unit_device_javatest_java_deps = [ + "//chrome/browser/feature_engagement:java", + "//chrome/browser/share:java", + "//chrome/browser/share/android:java_resources", + "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/share/android:java", + "//components/feature_engagement/public:public_java", + "//components/url_formatter/android:url_formatter_java", + "//components/user_prefs/android:java", +] share_junit_test_java_deps = [ "//chrome/browser/paint_preview/android:java",
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_webauthn_credential_item_modern.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_webauthn_credential_item_modern.xml index d355466..2011467 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_webauthn_credential_item_modern.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_webauthn_credential_item_modern.xml
@@ -28,7 +28,7 @@ android:layout_weight="1" android:orientation="vertical"> <TextView - android:id="@+id/diplay_name" + android:id="@+id/display_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minHeight="20dp"
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java index ea10814..c9386ec 100644 --- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java +++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
@@ -36,13 +36,11 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.ScalableTimeout; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.touch_to_fill.data.Credential; import org.chromium.chrome.browser.touch_to_fill.data.WebAuthnCredential; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; @@ -118,7 +116,6 @@ @Test @MediumTest - @DisableFeatures({ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ANDROID}) public void testClickingWebAuthnCredentialTriggersCallback() { runOnUiThreadBlocking(() -> { mTouchToFill.showCredentials(sExampleUrl, true, Collections.singletonList(sAna),
diff --git a/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc b/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc index 5f49ce19..4007968 100644 --- a/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc +++ b/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc
@@ -334,8 +334,14 @@ void SaveCardMessageControllerAndroid::ResetInternal() { message_.reset(); reprompt_required_ = false; + is_dialog_shown_ = false; + is_link_clicked_ = false; web_contents_ = nullptr; save_card_message_confirm_controller_.reset(); + + is_name_confirmed_for_testing_ = false; + is_date_confirmed_for_testing_ = false; + is_save_card_confirmed_for_testing_ = false; } } // namespace autofill
diff --git a/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc b/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc index fa652c2..6e3abf4 100644 --- a/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc +++ b/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc
@@ -533,6 +533,63 @@ 1); } +TEST_F(SaveCardMessageControllerAndroidTest, + DismissOnPromoDismissedUploadRecordedPreperly) { + // Decline dialog first. + base::MockOnceCallback<void(AutofillClient::SaveCardOfferUserDecision, + const AutofillClient::UserProvidedCardDetails&)> + mock_upload_callback_receiver; + base::HistogramTester histogram_tester; + EnqueueMessage(mock_upload_callback_receiver.Get(), {}, {}); + EXPECT_CALL( + mock_upload_callback_receiver, + Run(AutofillClient::SaveCardOfferUserDecision::kIgnored, testing::_)); + TriggerPrimaryButtonClick(); + // Triggering dialog will dismiss the message. + DismissMessage(messages::DismissReason::PRIMARY_ACTION); + OnConfirmationDialogDismissed(); + EXPECT_EQ(nullptr, GetMessageWrapper()); + histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kShown, 1); + histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kIgnored, + 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo"}), + MessageDialogPromptMetrics::kIgnored, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo", ".DidClickLinks"}), + MessageDialogPromptMetrics::kIgnored, 0); + histogram_tester.ExpectBucketCount( + kServerResultPrefix, SaveCreditCardPromptResult::kInteractedAndIgnored, + 1); + + // Trigger another message and dismiss it to test that no more dialog + // related metric is record. + base::MockOnceCallback<void(AutofillClient::SaveCardOfferUserDecision, + const AutofillClient::UserProvidedCardDetails&)> + mock_upload_callback_receiver2; + EnqueueMessage(mock_upload_callback_receiver2.Get(), {}, {}); + EXPECT_CALL( + mock_upload_callback_receiver2, + Run(AutofillClient::SaveCardOfferUserDecision::kIgnored, testing::_)); + DismissMessage(messages::DismissReason::TIMER); + EXPECT_EQ(nullptr, GetMessageWrapper()); + histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kShown, 2); + histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kIgnored, + 2); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo"}), + MessageDialogPromptMetrics::kIgnored, 1); // expect no change. + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo", ".DidClickLinks"}), + MessageDialogPromptMetrics::kIgnored, 0); // expect no change. + histogram_tester.ExpectBucketCount( + kServerResultPrefix, SaveCreditCardPromptResult::kInteractedAndIgnored, + 1); // expect no change. + histogram_tester.ExpectBucketCount(kServerResultPrefix, + SaveCreditCardPromptResult::kIgnored, + 1); // new change. +} + // -- Others -- TEST_F(SaveCardMessageControllerAndroidTest, DialogRestoredOnTabSwitching) { base::MockOnceCallback<void(AutofillClient::SaveCardOfferUserDecision,
diff --git a/chrome/browser/ui/android/night_mode/BUILD.gn b/chrome/browser/ui/android/night_mode/BUILD.gn index b181f48b..479f9949 100644 --- a/chrome/browser/ui/android/night_mode/BUILD.gn +++ b/chrome/browser/ui/android/night_mode/BUILD.gn
@@ -75,7 +75,7 @@ ] } -android_library("javatests") { +android_library("unit_device_javatests") { testonly = true sources = [ "java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java" ] @@ -85,14 +85,16 @@ ":night_mode_java_test_support", "//base:base_java", "//base:base_java_test_support", + "//chrome/browser/feature_engagement:java", "//chrome/browser/flags:java", "//chrome/browser/preferences:java", - "//chrome/browser/settings:java", - "//chrome/browser/settings:test_support_java", - "//chrome/test/android:chrome_java_integration_test_support", + "//chrome/browser/profiles/android:java", + "//chrome/test/android:chrome_java_test_support_common", + "//components/browser_ui/settings/android:test_support_java", "//components/browser_ui/site_settings/android:java", "//components/browser_ui/widget/android:java", "//components/content_settings/android:content_settings_enums_java", + "//components/feature_engagement/public:public_java", "//content/public/android:content_full_java", "//content/public/test/android:content_java_test_support", "//third_party/androidx:androidx_test_runner_java",
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java index f6ef5b4..57907ea 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java
@@ -6,6 +6,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.chromium.chrome.browser.flags.ChromeFeatureList.DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING; @@ -18,48 +19,68 @@ import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.metrics.UmaRecorder; +import org.chromium.base.metrics.UmaRecorderHolder; +import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.night_mode.NightModeMetrics.ThemeSettingsEntry; import org.chromium.chrome.browser.night_mode.NightModeUtils; import org.chromium.chrome.browser.night_mode.R; import org.chromium.chrome.browser.night_mode.ThemeType; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.chrome.browser.settings.SettingsActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.components.browser_ui.settings.BlankUiTestActivitySettingsTestRule; import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge; import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni; import org.chromium.components.browser_ui.widget.RadioButtonWithDescription; import org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout; import org.chromium.components.content_settings.ContentSettingsType; +import org.chromium.components.feature_engagement.Tracker; import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivityTestCase; +import org.chromium.ui.test.util.DisableAnimationsTestRule; /** * Tests for ThemeSettingsFragment. */ -// clang-format off -@RunWith(ChromeJUnit4ClassRunner.class) -public class ThemeSettingsFragmentTest extends BlankUiTestActivityTestCase { - // clang-format on +@RunWith(BaseJUnit4ClassRunner.class) +@Features.DisableFeatures(DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING) +public class ThemeSettingsFragmentTest { + @ClassRule + public static final DisableAnimationsTestRule disableAnimationsRule = + new DisableAnimationsTestRule(); + @Rule - public SettingsActivityTestRule<ThemeSettingsFragment> mSettingsActivityTestRule = - new SettingsActivityTestRule<>(ThemeSettingsFragment.class); + public BlankUiTestActivitySettingsTestRule mSettingsTestRule = + new BlankUiTestActivitySettingsTestRule(); @Rule public JniMocker mMocker = new JniMocker(); + @Rule + public Features.JUnitProcessor processor = new Features.JUnitProcessor(); + @Mock public WebsitePreferenceBridge.Natives mMockWebsitePreferenceBridgeJni; + @Mock + public Profile mProfile; + @Mock + public Tracker mTracker; + @Mock + public UmaRecorder mUmaRecorder; private ThemeSettingsFragment mFragment; private RadioButtonGroupThemePreference mPreference; @@ -67,9 +88,8 @@ // Boolean used for web content auto dark mode. private boolean mForceDarkModeEnabled; - @Override - public void setUpTest() throws Exception { - super.setUpTest(); + @Before + public void setUp() { // For some reason MockitoRule does not work with JniMocker (seems like an order issue), and // RuleChain cannot be applied to MockitoRule since it is not a TestRule. MockitoAnnotations.initMocks(this); @@ -77,6 +97,10 @@ mMocker.mock(WebsitePreferenceBridgeJni.TEST_HOOKS, mMockWebsitePreferenceBridgeJni); + Profile.setLastUsedProfileForTesting(mProfile); + TrackerFactory.setTrackerForTests(mTracker); + UmaRecorderHolder.setNonNativeDelegate(mUmaRecorder); + // Default value for feature DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING. mForceDarkModeEnabled = true; Mockito.doAnswer(invocation -> mForceDarkModeEnabled) @@ -91,12 +115,14 @@ any(), eq(ContentSettingsType.AUTO_DARK_WEB_CONTENT), anyBoolean()); } - @Override - public void tearDownTest() throws Exception { + @After + public void tearDown() throws Exception { TestThreadUtils.runOnUiThreadBlocking(() -> { SharedPreferencesManager.getInstance().removeKey(UI_THEME_SETTING); + Profile.setLastUsedProfileForTesting(null); + TrackerFactory.setTrackerForTests(null); + UmaRecorderHolder.resetForTesting(); }); - super.tearDownTest(); } @Test @@ -226,9 +252,9 @@ private void launchThemeSettings(@ThemeSettingsEntry Integer settingsEntry) { Bundle args = new Bundle(); args.putInt(ThemeSettingsFragment.KEY_THEME_SETTINGS_ENTRY, settingsEntry); - mSettingsActivityTestRule.startSettingsActivity(args); + mSettingsTestRule.launchPreference(ThemeSettingsFragment.class, args); - mFragment = mSettingsActivityTestRule.getFragment(); + mFragment = (ThemeSettingsFragment) mSettingsTestRule.getPreferenceFragment(); mPreference = (RadioButtonGroupThemePreference) mFragment.findPreference( ThemeSettingsFragment.PREF_UI_THEME_PREF); assertThemeSettingsEntryRecorded(settingsEntry); @@ -258,14 +284,10 @@ } private void assertThemeSettingsEntryRecorded(int sample) { - Assert.assertEquals("<Android.DarkTheme.ThemeSettingsEntry> should be recorded once.", 1, - RecordHistogram.getHistogramTotalCountForTesting( - "Android.DarkTheme.ThemeSettingsEntry")); - Assert.assertEquals( - "<Android.DarkTheme.ThemeSettingsEntry> should be recorded once for sample <" - + sample + ">.", - 1, - RecordHistogram.getHistogramValueCountForTesting( - "Android.DarkTheme.ThemeSettingsEntry", sample)); + ArgumentCaptor<Integer> sampleCaptor = ArgumentCaptor.forClass(Integer.class); + Mockito.verify(mUmaRecorder, Mockito.times(1)) + .recordLinearHistogram(eq("Android.DarkTheme.ThemeSettingsEntry"), + sampleCaptor.capture(), anyInt(), anyInt(), anyInt()); + Assert.assertEquals(sample, sampleCaptor.getValue().intValue()); } }
diff --git a/chrome/browser/ui/ash/network/mobile_data_notifications.cc b/chrome/browser/ui/ash/network/mobile_data_notifications.cc index eec6149..bf241346 100644 --- a/chrome/browser/ui/ash/network/mobile_data_notifications.cc +++ b/chrome/browser/ui/ash/network/mobile_data_notifications.cc
@@ -20,7 +20,6 @@ #include "chromeos/login/login_state/login_state.h" #include "chromeos/network/network_connection_handler.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_type_pattern.h" #include "components/prefs/pref_service.h" #include "components/session_manager/core/session_manager.h" @@ -51,7 +50,8 @@ // MobileDataNotifications MobileDataNotifications::MobileDataNotifications() { - NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); NetworkHandler::Get()->network_connection_handler()->AddObserver(this); UserManager::Get()->AddSessionStateObserver(this); SessionManager::Get()->AddObserver(this); @@ -59,8 +59,6 @@ MobileDataNotifications::~MobileDataNotifications() { if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); NetworkHandler::Get()->network_connection_handler()->RemoveObserver(this); } UserManager::Get()->RemoveSessionStateObserver(this); @@ -74,6 +72,10 @@ ShowOptionalMobileDataNotificationImpl(active_networks); } +void MobileDataNotifications::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void MobileDataNotifications::ConnectSucceeded( const std::string& service_path) { // We delay because it might take some time before the default network
diff --git a/chrome/browser/ui/ash/network/mobile_data_notifications.h b/chrome/browser/ui/ash/network/mobile_data_notifications.h index fdf816fa..86bee78 100644 --- a/chrome/browser/ui/ash/network/mobile_data_notifications.h +++ b/chrome/browser/ui/ash/network/mobile_data_notifications.h
@@ -9,8 +9,10 @@ #include <vector> #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/timer/timer.h" #include "chromeos/network/network_connection_observer.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/session_manager/core/session_manager_observer.h" #include "components/user_manager/user_manager.h" @@ -44,6 +46,7 @@ // NetworkStateHandlerObserver: void ActiveNetworksChanged(const std::vector<const chromeos::NetworkState*>& active_networks) override; + void OnShuttingDown() override; // NetworkConnectionObserver: void ConnectSucceeded(const std::string& service_path) override; @@ -79,6 +82,10 @@ base::OneShotTimer one_shot_notification_check_delay_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::WeakPtrFactory<MobileDataNotifications> weak_factory_{this}; };
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc index 648b785..ceb9b51 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.cc +++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -23,7 +23,6 @@ #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_name_util.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "chromeos/network/shill_property_util.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/l10n/l10n_util.h" @@ -172,7 +171,7 @@ if (!NetworkHandler::IsInitialized()) return; NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - handler->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(handler); NetworkStateHandler::NetworkStateList active_networks; handler->GetActiveNetworkListByType(NetworkTypePattern::Default(), &active_networks); @@ -183,8 +182,6 @@ NetworkStateNotifier::~NetworkStateNotifier() { if (!NetworkHandler::IsInitialized()) return; - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); NetworkHandler::Get()->network_connection_handler()->RemoveObserver(this); } @@ -222,6 +219,10 @@ connect_error_notification_network_guid_ = new_guid; } +void NetworkStateNotifier::OnShuttingDown() { + network_state_handler_observer_.Reset(); +} + void NetworkStateNotifier::ConnectSucceeded(const std::string& service_path) { RemoveConnectNotification(); }
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.h b/chrome/browser/ui/ash/network/network_state_notifier.h index 11157a7..34ef79db3 100644 --- a/chrome/browser/ui/ash/network/network_state_notifier.h +++ b/chrome/browser/ui/ash/network/network_state_notifier.h
@@ -11,9 +11,11 @@ #include <vector> #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/time/time.h" #include "base/values.h" #include "chromeos/network/network_connection_observer.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -89,6 +91,7 @@ const std::string& new_service_path, const std::string& old_guid, const std::string& new_guid) override; + void OnShuttingDown() override; void OnConnectErrorGetProperties( const std::string& error_name, @@ -139,6 +142,10 @@ // Tracks GUIDs of activating cellular networks for activation notification. std::set<std::string> cellular_activating_guids_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::WeakPtrFactory<NetworkStateNotifier> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/translate/partial_translate_bubble_model.h b/chrome/browser/ui/translate/partial_translate_bubble_model.h index 46c584b..ee3ccf2 100644 --- a/chrome/browser/ui/translate/partial_translate_bubble_model.h +++ b/chrome/browser/ui/translate/partial_translate_bubble_model.h
@@ -11,6 +11,7 @@ #include "chrome/browser/ui/translate/translate_language_list_model.h" #include "components/translate/core/browser/translate_ui_delegate.h" #include "components/translate/core/common/translate_errors.h" +#include "content/public/browser/web_contents.h" // The model for the Partial Translate bubble UX. This manages the user's // manipulation of the bubble and offers the data to show on the bubble. @@ -72,6 +73,10 @@ // Returns true if the current text selection is translated in the currently // selected source and target language. virtual bool IsCurrentSelectionTranslated() const = 0; + + // Closes the Partial Translate bubble, then immediately opens the Full Page + // Translate bubble and starts a translation. + virtual void TranslateFullPage(content::WebContents* web_contents) = 0; }; #endif // CHROME_BROWSER_UI_TRANSLATE_PARTIAL_TRANSLATE_BUBBLE_MODEL_H_
diff --git a/chrome/browser/ui/translate/partial_translate_bubble_model_impl.cc b/chrome/browser/ui/translate/partial_translate_bubble_model_impl.cc index ed81b010..1aa73d7 100644 --- a/chrome/browser/ui/translate/partial_translate_bubble_model_impl.cc +++ b/chrome/browser/ui/translate/partial_translate_bubble_model_impl.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/translate/chrome_translate_client.h" #include "components/translate/core/browser/language_state.h" +#include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_ui_delegate.h" // TODO(crbug/1314825): When the PartialTranslateManager is added it will @@ -106,3 +107,10 @@ // LanguageState. return false; } + +void PartialTranslateBubbleModelImpl::TranslateFullPage( + content::WebContents* web_contents) { + translate::TranslateManager* translate_manager = + ChromeTranslateClient::GetManagerFromWebContents(web_contents); + translate_manager->ShowTranslateUI(true); +}
diff --git a/chrome/browser/ui/translate/partial_translate_bubble_model_impl.h b/chrome/browser/ui/translate/partial_translate_bubble_model_impl.h index 2d38ccf0..00c6247e 100644 --- a/chrome/browser/ui/translate/partial_translate_bubble_model_impl.h +++ b/chrome/browser/ui/translate/partial_translate_bubble_model_impl.h
@@ -35,6 +35,7 @@ void Translate() override; void RevertTranslation() override; bool IsCurrentSelectionTranslated() const override; + void TranslateFullPage(content::WebContents* web_contents) override; private: std::unique_ptr<translate::TranslateUIDelegate> ui_delegate_;
diff --git a/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.cc b/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.cc index d4813fe7..fd9b434 100644 --- a/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.cc +++ b/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.cc
@@ -11,7 +11,7 @@ void ReportPartialTranslateBubbleUiAction( translate::PartialTranslateBubbleUiEvent action) { UMA_HISTOGRAM_ENUMERATION( - "Translate.PartialTranslateBubbleUiEvent", action, + kPartialTranslateBubbleUiEventHistogramName, action, translate::PartialTranslateBubbleUiEvent::kMaxValue); }
diff --git a/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.h b/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.h index ca2883d..f09a28b 100644 --- a/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.h +++ b/chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.h
@@ -7,6 +7,11 @@ namespace translate { +// Histogram for recording the UI events related to the Partial Translate +// bubble. +constexpr char kPartialTranslateBubbleUiEventHistogramName[] = + "Translate.PartialTranslateBubbleUiEvent"; + enum class PartialTranslateBubbleUiEvent { // Update PartialTranslateBubbleUiEvent in enums.xml when making changes. // The partial translate bubble was shown to the user.
diff --git a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc index 8b9561f..eb2ad27 100644 --- a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc +++ b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc
@@ -11,7 +11,7 @@ void ReportTranslateBubbleUiAction(translate::TranslateBubbleUiEvent action) { UMA_HISTOGRAM_ENUMERATION( - "Translate.BubbleUiEvent", action, + kTranslateBubbleUiEventHistogramName, action, translate::TranslateBubbleUiEvent::TRANSLATE_BUBBLE_UI_EVENT_MAX); }
diff --git a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h index 3cbca4f..4880062 100644 --- a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h +++ b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h
@@ -7,6 +7,11 @@ namespace translate { +// Histogram for recording the UI events related to the Translate +// bubble. +constexpr char kTranslateBubbleUiEventHistogramName[] = + "Translate.BubbleUiEvent"; + enum class TranslateBubbleUiEvent { // Update TranslateBubbleUiEvent in enums.xml when making changes. // Start with 1 to match existing UMA values: see http://crbug.com/612558
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 2a257c5..5eedc39 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -142,11 +142,6 @@ base::FEATURE_DISABLED_BY_DEFAULT}; const char kMinimumTabWidthFeatureParameterName[] = "minTabWidth"; -// Enables buttons to permanently appear on the tabstrip when -// scrollable-tabstrip is enabled. https://crbug.com/1116118 -const base::Feature kScrollableTabStripButtons{ - "ScrollableTabStripButtons", base::FEATURE_DISABLED_BY_DEFAULT}; - // Directly controls the "new" badge (as opposed to old "master switch"; see // https://crbug.com/1169907 for master switch deprecation and // https://crbug.com/968587 for the feature itself)
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index ad4e340..aca8959 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -55,8 +55,6 @@ extern const base::Feature kScrollableTabStrip; extern const char kMinimumTabWidthFeatureParameterName[]; -extern const base::Feature kScrollableTabStripButtons; - // TODO(pbos): Once kReadLater is cleaned up on Desktop, move definition into // ui_features.cc. This is currently temporarily in reading_list_switches.h. extern const base::Feature kSidePanelImprovedClobbering;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc index cfb9a2f..2983c9b 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -161,9 +161,10 @@ SkColor BrowserNonClientFrameView::GetFrameColor( BrowserFrameActiveState active_state) const { - return GetColorProvider()->GetColor(ShouldPaintAsActive(active_state) - ? ui::kColorFrameActive - : ui::kColorFrameInactive); + return GetThemeProvider()->GetColor( + ShouldPaintAsActive(active_state) + ? ThemeProperties::COLOR_FRAME_ACTIVE + : ThemeProperties::COLOR_FRAME_INACTIVE); } void BrowserNonClientFrameView::UpdateFrameColor() {
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc index 9ee7c790..433ac86 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc
@@ -37,10 +37,6 @@ #include "ui/views/test/test_views.h" #include "ui/views/view_utils.h" -#if BUILDFLAG(IS_LINUX) -#include "ui/views/linux_ui/linux_ui.h" -#endif - // Tests web-app windows that use the OpaqueBrowserFrameView implementation // for their non client frames. class WebAppOpaqueBrowserFrameViewTest : public InProcessBrowserTest { @@ -56,13 +52,7 @@ static GURL GetAppURL() { return GURL("https://test.org"); } - void SetUpOnMainThread() override { - SetThemeMode(ThemeMode::kDefault); -#if BUILDFLAG(IS_LINUX) - views::LinuxUI::instance()->SetUseSystemThemeCallback( - base::BindRepeating([](aura::Window* window) { return false; })); -#endif - } + void SetUpOnMainThread() override { SetThemeMode(ThemeMode::kDefault); } bool InstallAndLaunchWebApp( absl::optional<SkColor> theme_color = absl::nullopt) { @@ -227,7 +217,6 @@ // Tests for the appearance of the origin text in the titlebar. The origin text // shows and then hides both when the window is first opened and any time the // titlebar's appearance changes. -// TODO(crbug.com/1337118): Revise this test. IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, OriginTextVisibility) { ui_test_utils::UrlLoadObserver url_observer( GetAppURL(), content::NotificationService::AllSources());
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc index 40aa1c4..14263c4 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -1049,7 +1049,13 @@ // Verifies that we ignore the shown ratios sent from widgets other than that of // the main frame (such as widgets of the drop-down menus in web pages). // https://crbug.com/891471. -IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestDropDowns) { +// TODO(1337418): Flaky for dbg and ASan builds. +#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER) +#define MAYBE_TestDropDowns DISABLED_TestDropDowns +#else +#define MAYBE_TestDropDowns TestDropDowns +#endif +IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, MAYBE_TestDropDowns) { browser_view()->frame()->Maximize(); ToggleTabletMode(); ASSERT_TRUE(GetTabletModeEnabled());
diff --git a/chrome/browser/ui/views/translate/partial_translate_bubble_view.cc b/chrome/browser/ui/views/translate/partial_translate_bubble_view.cc index 2bf7ab0..60da14c8 100644 --- a/chrome/browser/ui/views/translate/partial_translate_bubble_view.cc +++ b/chrome/browser/ui/views/translate/partial_translate_bubble_view.cc
@@ -357,7 +357,8 @@ : LocationBarBubbleDelegateView(anchor_view, web_contents), model_(std::move(model)), error_type_(error_type), - on_closing_(std::move(on_closing)) { + on_closing_(std::move(on_closing)), + web_contents_(web_contents) { UpdateInsets(PartialTranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE); if (web_contents) // web_contents can be null in unit_tests. @@ -388,8 +389,7 @@ } void PartialTranslateBubbleView::Translate() { - // TODO(crbug/1314825): Update implementation when PartialTranslateManager is - // complete. + model_->Translate(); SwitchView(PartialTranslateBubbleModel::VIEW_STATE_TRANSLATING); translate::ReportPartialTranslateBubbleUiAction( translate::PartialTranslateBubbleUiEvent::TARGET_LANGUAGE_TAB_SELECTED); @@ -494,23 +494,15 @@ ->SetOrientation(views::LayoutOrientation::kHorizontal); auto* horizontal_view = view->AddChildView(std::move(inner_view)); - // Desktop Partial Translate - placeholder button for switch to full page - // translation button. + // Button to trigger full page translation. auto button_row = std::make_unique<views::BoxLayoutView>(); button_row->SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kEnd); auto full_page_button = std::make_unique<views::MdTextButton>( - base::BindRepeating( - [](PartialTranslateBubbleModel* model) { - translate::ReportPartialTranslateBubbleUiAction( - translate::PartialTranslateBubbleUiEvent:: - TRANSLATE_FULL_PAGE_BUTTON_CLICKED); - // TODO(crbug/1314825): Update implementation when - // PartialTranslateManager is - // complete. - model->Translate(); - }, - base::Unretained(model_.get())), - l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_ACCEPT)); + base::BindRepeating(&PartialTranslateBubbleView::TranslateFullPage, + base::Unretained(this)), + l10n_util::GetStringUTF16( + IDS_PARTIAL_TRANSLATE_BUBBLE_TRANSLATE_FULL_PAGE)); + full_page_button->SetID(BUTTON_ID_FULL_PAGE_TRANSLATE); button_row->AddChildView(std::move(full_page_button)); button_row->SetProperty( views::kMarginsKey, @@ -641,6 +633,7 @@ }, base::Unretained(model_.get())), l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_TRY_AGAIN)); + try_again_button->SetID(BUTTON_ID_TRY_AGAIN); button_row->AddChildView(std::move(try_again_button)); button_row->AddChildView(std::move(advanced_button)); button_row->SetProperty( @@ -686,12 +679,14 @@ base::BindRepeating(&PartialTranslateBubbleView::ResetLanguage, base::Unretained(this)), l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_RESET)); + advanced_reset_button->SetID(BUTTON_ID_RESET); advanced_reset_button_source_ = advanced_reset_button.get(); auto advanced_done_button = std::make_unique<views::MdTextButton>( base::BindRepeating(&PartialTranslateBubbleView::ConfirmAdvancedOptions, base::Unretained(this)), l10n_util::GetStringUTF16(IDS_DONE)); + advanced_done_button->SetID(BUTTON_ID_DONE); advanced_done_button->SetIsDefault(true); advanced_done_button_source_ = advanced_done_button.get(); advanced_done_button_source_->SetProperty(views::kElementIdentifierKey, @@ -732,12 +727,14 @@ base::BindRepeating(&PartialTranslateBubbleView::ResetLanguage, base::Unretained(this)), l10n_util::GetStringUTF16(IDS_TRANSLATE_BUBBLE_RESET)); + advanced_reset_button->SetID(BUTTON_ID_RESET); advanced_reset_button_target_ = advanced_reset_button.get(); auto advanced_done_button = std::make_unique<views::MdTextButton>( base::BindRepeating(&PartialTranslateBubbleView::ConfirmAdvancedOptions, base::Unretained(this)), l10n_util::GetStringUTF16(IDS_DONE)); + advanced_done_button->SetID(BUTTON_ID_DONE); advanced_done_button->SetIsDefault(true); advanced_done_button_target_ = advanced_done_button.get(); advanced_done_button_target_->SetProperty(views::kElementIdentifierKey, @@ -851,6 +848,7 @@ tab_translate_options_button->SetTooltipText(translate_options_button_label); tab_translate_options_button->SetRequestFocusOnPress(true); tab_translate_options_button->SetVisible(true); + tab_translate_options_button->SetID(BUTTON_ID_OPTIONS_MENU); return tab_translate_options_button; } @@ -866,6 +864,7 @@ base::Unretained(this))); close_button->SetProperty(views::kElementIdentifierKey, kCloseButton); close_button->SetVisible(true); + close_button->SetID(BUTTON_ID_CLOSE); return close_button; } @@ -999,3 +998,10 @@ set_margins(kDialogStateMargins); } } + +void PartialTranslateBubbleView::TranslateFullPage() { + translate::ReportPartialTranslateBubbleUiAction( + translate::PartialTranslateBubbleUiEvent:: + TRANSLATE_FULL_PAGE_BUTTON_CLICKED); + model_.get()->TranslateFullPage(web_contents_); +}
diff --git a/chrome/browser/ui/views/translate/partial_translate_bubble_view.h b/chrome/browser/ui/views/translate/partial_translate_bubble_view.h index ebb984a..00444ece 100644 --- a/chrome/browser/ui/views/translate/partial_translate_bubble_view.h +++ b/chrome/browser/ui/views/translate/partial_translate_bubble_view.h
@@ -94,6 +94,28 @@ void CloseBubble() override; private: + // IDs used by PartialTranslateBubbleViewTest to simulate button presses. + enum ButtonID { + BUTTON_ID_DONE = 1, + BUTTON_ID_TRY_AGAIN, + BUTTON_ID_OPTIONS_MENU, + BUTTON_ID_CLOSE, + BUTTON_ID_RESET, + BUTTON_ID_FULL_PAGE_TRANSLATE + }; + + friend class PartialTranslateBubbleViewTest; + FRIEND_TEST_ALL_PREFIXES(PartialTranslateBubbleViewTest, + TargetLanguageTabTriggersTranslate); + FRIEND_TEST_ALL_PREFIXES(PartialTranslateBubbleViewTest, + TabSelectedAfterTranslation); + FRIEND_TEST_ALL_PREFIXES(PartialTranslateBubbleViewTest, + SourceLanguageTabUpdatesViewState); + FRIEND_TEST_ALL_PREFIXES(PartialTranslateBubbleViewTest, + SourceLanguageTabSelectedLogged); + FRIEND_TEST_ALL_PREFIXES(PartialTranslateBubbleViewTest, + TranslateFullPageButton); + // views::TabbedPaneListener: void TabSelectedAt(int index) override; @@ -190,6 +212,9 @@ void UpdateInsets(PartialTranslateBubbleModel::ViewState state); + // Function bound to the "Translate full page" button. + void TranslateFullPage(); + static PartialTranslateBubbleView* partial_translate_bubble_view_; raw_ptr<views::View> translate_view_ = nullptr; @@ -221,6 +246,8 @@ std::unique_ptr<WebContentMouseHandler> mouse_handler_; base::OnceClosure on_closing_; + + content::WebContents* web_contents_; }; #endif // CHROME_BROWSER_UI_VIEWS_TRANSLATE_PARTIAL_TRANSLATE_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/translate/partial_translate_bubble_view_unittest.cc b/chrome/browser/ui/views/translate/partial_translate_bubble_view_unittest.cc new file mode 100644 index 0000000..013bdaf0 --- /dev/null +++ b/chrome/browser/ui/views/translate/partial_translate_bubble_view_unittest.cc
@@ -0,0 +1,176 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/translate/partial_translate_bubble_view.h" + +#include "base/memory/raw_ptr.h" +#include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/ui/translate/partial_translate_bubble_model.h" +#include "chrome/browser/ui/translate/partial_translate_bubble_ui_action_logger.h" +#include "chrome/test/views/chrome_views_test_base.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event.h" +#include "ui/events/keycodes/dom/dom_code.h" +#include "ui/views/test/button_test_api.h" +#include "ui/views/widget/widget.h" + +namespace { + +class FakePartialTranslateBubbleModel : public PartialTranslateBubbleModel { + public: + explicit FakePartialTranslateBubbleModel( + PartialTranslateBubbleModel::ViewState view_state) { + DCHECK_NE(VIEW_STATE_SOURCE_LANGUAGE, view_state); + DCHECK_NE(VIEW_STATE_TARGET_LANGUAGE, view_state); + current_view_state_ = view_state; + } + + PartialTranslateBubbleModel::ViewState GetViewState() const override { + return current_view_state_; + } + + void SetViewState( + PartialTranslateBubbleModel::ViewState view_state) override { + current_view_state_ = view_state; + } + + void ShowError(translate::TranslateErrors::Type error_type) override {} + + int GetNumberOfSourceLanguages() const override { return 1000; } + + int GetNumberOfTargetLanguages() const override { return 1000; } + + std::u16string GetSourceLanguageNameAt(int index) const override { + return u"English"; + } + + std::u16string GetTargetLanguageNameAt(int index) const override { + return u"English"; + } + + int GetSourceLanguageIndex() const override { return 1; } + + void UpdateSourceLanguageIndex(int index) override {} + + int GetTargetLanguageIndex() const override { return 2; } + + void UpdateTargetLanguageIndex(int index) override {} + + void Translate() override { translate_called_ = true; } + + void RevertTranslation() override {} + + bool IsCurrentSelectionTranslated() const override { return false; } + + void TranslateFullPage(content::WebContents* web_contents) override { + full_page_translate_called_ = true; + } + + ViewState current_view_state_; + bool translate_called_ = false; + bool full_page_translate_called_ = false; +}; + +} // namespace + +class PartialTranslateBubbleViewTest : public ChromeViewsTestBase { + public: + PartialTranslateBubbleViewTest() = default; + + protected: + void SetUp() override { + ChromeViewsTestBase::SetUp(); + + // The bubble needs the parent as an anchor. + anchor_widget_ = CreateTestWidget(views::Widget::InitParams::TYPE_WINDOW); + anchor_widget_->Show(); + + mock_model_ = new FakePartialTranslateBubbleModel( + PartialTranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE); + } + + void CreateAndShowBubble() { + std::unique_ptr<PartialTranslateBubbleModel> model(mock_model_); + bubble_ = new PartialTranslateBubbleView( + anchor_widget_->GetContentsView(), std::move(model), + translate::TranslateErrors::NONE, nullptr, base::DoNothing()); + views::BubbleDialogDelegateView::CreateBubble(bubble_)->Show(); + } + + void PressButton(PartialTranslateBubbleView::ButtonID id) { + views::Button* button = + static_cast<views::Button*>(bubble_->GetViewByID(id)); + ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, + ui::DomCode::ENTER, ui::EF_NONE); + views::test::ButtonTestApi(button).NotifyClick(key_event); + } + + void TearDown() override { + bubble_->GetWidget()->CloseNow(); + anchor_widget_.reset(); + + ChromeViewsTestBase::TearDown(); + } + + std::unique_ptr<views::Widget> anchor_widget_; + raw_ptr<FakePartialTranslateBubbleModel> mock_model_; + raw_ptr<PartialTranslateBubbleView> bubble_; +}; + +TEST_F(PartialTranslateBubbleViewTest, TargetLanguageTabTriggersTranslate) { + base::HistogramTester histogram_tester; + CreateAndShowBubble(); + EXPECT_FALSE(mock_model_->translate_called_); + + // Press the target language tab to start translation. + bubble_->TabSelectedAt(1); + EXPECT_TRUE(mock_model_->translate_called_); + histogram_tester.ExpectUniqueSample( + translate::kPartialTranslateBubbleUiEventHistogramName, + translate::PartialTranslateBubbleUiEvent::TARGET_LANGUAGE_TAB_SELECTED, + 1); +} + +TEST_F(PartialTranslateBubbleViewTest, TabSelectedAfterTranslation) { + CreateAndShowBubble(); + EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), + static_cast<size_t>(0)); + bubble_->SwitchView(PartialTranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE); + EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), + static_cast<size_t>(1)); +} + +TEST_F(PartialTranslateBubbleViewTest, SourceLanguageTabUpdatesViewState) { + CreateAndShowBubble(); + // Select target language tab to translate. + bubble_->TabSelectedAt(1); + EXPECT_EQ(PartialTranslateBubbleModel::VIEW_STATE_TRANSLATING, + bubble_->GetViewState()); + + // Select source language tab to revert translation. + bubble_->TabSelectedAt(0); + EXPECT_EQ(PartialTranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, + bubble_->GetViewState()); +} + +// TODO(crbug.com/1337110): For some reason calling bubble_->TabSelectedAt(1) +// before bubble_->TabSelectedAt(0) in a test causes TabSelectedAt(0) to be +// run twice, resulting in the corresponding sample being logged twice. This +// does not happen in production. For now, test this logging separately to avoid +// encountering this issue in TabSelectedAfterTranslation. +TEST_F(PartialTranslateBubbleViewTest, SourceLanguageTabSelectedLogged) { + base::HistogramTester histogram_tester; + CreateAndShowBubble(); + bubble_->TabSelectedAt(0); + histogram_tester.ExpectBucketCount( + translate::kPartialTranslateBubbleUiEventHistogramName, + translate::PartialTranslateBubbleUiEvent::SOURCE_LANGUAGE_TAB_SELECTED, + 1); +} + +TEST_F(PartialTranslateBubbleViewTest, TranslateFullPageButton) { + CreateAndShowBubble(); + PressButton(PartialTranslateBubbleView::BUTTON_ID_FULL_PAGE_TRANSLATE); + EXPECT_TRUE(mock_model_->full_page_translate_called_); +}
diff --git a/chrome/browser/ui/views/translate/translate_bubble_controller_unittest.cc b/chrome/browser/ui/views/translate/translate_bubble_controller_unittest.cc index eff3bf3..08600f72 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_controller_unittest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_controller_unittest.cc
@@ -149,6 +149,8 @@ bool IsCurrentSelectionTranslated() const override { return false; } + void TranslateFullPage(content::WebContents* web_contents) override {} + ViewState current_view_state_; }; @@ -212,7 +214,7 @@ EXPECT_THAT(controller_->GetTranslateBubble(), testing::IsNull()); EXPECT_THAT(controller_->GetPartialTranslateBubble(), testing::IsNull()); - // Show the full page translate bubble first. + // Show the Full Page Translate bubble first. controller_->ShowTranslateBubble( anchor_widget_->GetContentsView(), nullptr, translate::TranslateStep::TRANSLATE_STEP_BEFORE_TRANSLATE, "fr", "en", @@ -221,7 +223,7 @@ EXPECT_THAT(controller_->GetTranslateBubble(), testing::NotNull()); - // Showing the partial translate bubble while the full page translate bubble + // Showing the partial translate bubble while the Full Page Translate bubble // is open should close the full translate bubble. controller_->ShowPartialTranslateBubble( anchor_widget_->GetContentsView(), nullptr, @@ -248,7 +250,7 @@ "en", translate::TranslateErrors::Type::NONE); EXPECT_THAT(controller_->GetPartialTranslateBubble(), testing::NotNull()); - // Showing the full page translate bubble while the partial translate bubble + // Showing the Full Page Translate bubble while the partial translate bubble // is open should close the partial translate bubble. controller_->ShowTranslateBubble( anchor_widget_->GetContentsView(), nullptr, @@ -259,7 +261,7 @@ EXPECT_THAT(controller_->GetTranslateBubble(), testing::NotNull()); EXPECT_THAT(controller_->GetPartialTranslateBubble(), testing::IsNull()); - // Only the full page translate bubble should remain, close it. + // Only the Full Page Translate bubble should remain, close it. controller_->CloseBubble(); base::RunLoop().RunUntilIdle(); EXPECT_THAT(controller_->GetTranslateBubble(), testing::IsNull());
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h index 8635b5d..feb8b63 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view.h +++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -113,6 +113,7 @@ void CloseBubble() override; private: + // IDs used by TranslateBubbleViewTest to simulate button presses. enum ButtonID { BUTTON_ID_DONE = 1, BUTTON_ID_TRY_AGAIN, @@ -129,7 +130,8 @@ friend void ::translate::test_utils::SelectTargetLanguageByDisplayName( ::Browser*, const ::std::u16string&); - FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, TranslateButton); + FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, + TargetLanguageTabTriggersTranslate); FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, AlwaysTranslateCheckboxShortcut); FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, @@ -159,7 +161,7 @@ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, AlwaysTranslateWithNeverTranslateSite); FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, - ShowOriginalUpdatesViewState); + SourceLanguageTabUpdatesViewState); // views::TabbedPaneListener: void TabSelectedAt(int index) override;
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc index 947696c..8a86d46 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc
@@ -9,9 +9,11 @@ #include "base/memory/raw_ptr.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "chrome/browser/ui/translate/translate_bubble_model.h" +#include "chrome/browser/ui/translate/translate_bubble_ui_action_logger.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/views/chrome_views_test_base.h" #include "components/translate/core/browser/translate_prefs.h" @@ -235,16 +237,21 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -TEST_F(TranslateBubbleViewTest, TranslateButton) { +TEST_F(TranslateBubbleViewTest, TargetLanguageTabTriggersTranslate) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); EXPECT_FALSE(mock_model_->translate_called_); - // Press the "Translate" button. + // Press the target language tab to start translation. bubble_->TabSelectedAt(1); EXPECT_TRUE(mock_model_->translate_called_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::TARGET_LANGUAGE_TAB_SELECTED, 1); } TEST_F(TranslateBubbleViewTest, OptionsMenuNeverTranslateLanguage) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); EXPECT_FALSE(bubble_->GetWidget()->IsClosed()); @@ -259,9 +266,14 @@ EXPECT_TRUE(denial_button_clicked()); EXPECT_TRUE(mock_model_->never_translate_language_); EXPECT_TRUE(bubble_->GetWidget()->IsClosed()); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::NEVER_TRANSLATE_LANGUAGE_MENU_CLICKED, + 1); } TEST_F(TranslateBubbleViewTest, OptionsMenuNeverTranslateSite) { + base::HistogramTester histogram_tester; // NEVER_TRANSLATE_SITE should only show up for sites that can be blocklisted. mock_model_->SetCanAddSiteToNeverPromptList(true); CreateAndShowBubble(); @@ -278,9 +290,13 @@ EXPECT_TRUE(denial_button_clicked()); EXPECT_TRUE(mock_model_->never_translate_site_); EXPECT_TRUE(bubble_->GetWidget()->IsClosed()); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::NEVER_TRANSLATE_SITE_MENU_CLICKED, 1); } TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckboxShortcut) { + base::HistogramTester histogram_tester; mock_model_->SetShouldShowAlwaysTranslateShortcut(true); CreateAndShowBubble(); @@ -302,9 +318,13 @@ bubble_->GetViewState()); EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), static_cast<size_t>(1)); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::ALWAYS_TRANSLATE_CHECKED, 1); } TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckboxAndCloseButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE); @@ -321,14 +341,21 @@ PressButton(TranslateBubbleView::BUTTON_ID_ALWAYS_TRANSLATE); EXPECT_FALSE(mock_model_->should_always_translate_); EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::ALWAYS_TRANSLATE_UNCHECKED, 1); // Click the cancel button. The state is not saved. PressButton(TranslateBubbleView::BUTTON_ID_CLOSE); EXPECT_FALSE(mock_model_->should_always_translate_); EXPECT_EQ(0, mock_model_->set_always_translate_called_count_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::CLOSE_BUTTON_CLICKED, 1); } TEST_F(TranslateBubbleViewTest, AlwaysTranslateCheckboxAndDoneButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE); @@ -349,9 +376,13 @@ PressButton(TranslateBubbleView::BUTTON_ID_DONE); EXPECT_TRUE(mock_model_->should_always_translate_); EXPECT_EQ(1, mock_model_->set_always_translate_called_count_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::DONE_BUTTON_CLICKED, 1); } TEST_F(TranslateBubbleViewTest, SourceResetButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE); @@ -364,6 +395,9 @@ bubble_->SourceLanguageChanged(); EXPECT_EQ(10, bubble_->source_language_combobox_->GetSelectedIndex()); EXPECT_TRUE(bubble_->advanced_reset_button_source_->GetEnabled()); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::SOURCE_LANGUAGE_MENU_ITEM_CLICKED, 1); // Press the reset button. Language should change back to initial selection. PressButton(TranslateBubbleView::BUTTON_ID_RESET); @@ -372,6 +406,7 @@ } TEST_F(TranslateBubbleViewTest, TargetResetButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE); @@ -384,6 +419,9 @@ bubble_->TargetLanguageChanged(); EXPECT_EQ(10, bubble_->target_language_combobox_->GetSelectedIndex()); EXPECT_TRUE(bubble_->advanced_reset_button_target_->GetEnabled()); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::TARGET_LANGUAGE_MENU_ITEM_CLICKED, 1); // Press the reset button. Language should change back to initial selection. PressButton(TranslateBubbleView::BUTTON_ID_RESET); @@ -391,6 +429,7 @@ } TEST_F(TranslateBubbleViewTest, SourceDoneButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE); @@ -405,12 +444,16 @@ EXPECT_TRUE(mock_model_->translate_called_); EXPECT_EQ(10, mock_model_->source_language_index_); EXPECT_EQ(20, mock_model_->target_language_index_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::DONE_BUTTON_CLICKED, 1); EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE, bubble_->GetViewState()); } TEST_F(TranslateBubbleViewTest, TargetDoneButton) { + base::HistogramTester histogram_tester; CreateAndShowBubble(); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE); @@ -425,6 +468,9 @@ EXPECT_TRUE(mock_model_->translate_called_); EXPECT_EQ(10, mock_model_->source_language_index_); EXPECT_EQ(20, mock_model_->target_language_index_); + histogram_tester.ExpectBucketCount( + translate::kTranslateBubbleUiEventHistogramName, + translate::TranslateBubbleUiEvent::DONE_BUTTON_CLICKED, 1); EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE, bubble_->GetViewState()); @@ -566,21 +612,19 @@ CreateAndShowBubble(); EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), static_cast<size_t>(0)); - mock_model_->Translate(); - EXPECT_TRUE(mock_model_->translate_called_); bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE); EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), static_cast<size_t>(1)); } -TEST_F(TranslateBubbleViewTest, ShowOriginalUpdatesViewState) { +TEST_F(TranslateBubbleViewTest, SourceLanguageTabUpdatesViewState) { CreateAndShowBubble(); - // Translate. + // Select target language tab to translate. bubble_->TabSelectedAt(1); EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_TRANSLATING, bubble_->GetViewState()); - // Show Original. + // Select source language tab to revert translation. bubble_->TabSelectedAt(0); EXPECT_EQ(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE, bubble_->GetViewState());
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc index ec3cd3d..36698938 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc
@@ -17,6 +17,7 @@ #include "base/memory/ref_counted_memory.h" #include "base/memory/weak_ptr.h" #include "base/no_destructor.h" +#include "base/scoped_observation.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -253,6 +254,11 @@ // connection state. This value is reflected in portal webui for lte networks. // Initial value is true. bool lte_portal_reachable_; + + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::WeakPtrFactory<MobileSetupHandler> weak_ptr_factory_{this}; }; @@ -391,8 +397,7 @@ ash::MobileActivator::GetInstance()->RemoveObserver(this); ash::MobileActivator::GetInstance()->TerminateActivation(); } else if (type_ == TYPE_PORTAL_LTE) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); + network_state_handler_observer_.Reset(); } } @@ -432,7 +437,7 @@ if (network->network_technology() == shill::kNetworkTechnologyLte || network->network_technology() == shill::kNetworkTechnologyLteAdvanced) { type_ = TYPE_PORTAL_LTE; - nsh->AddObserver(this, FROM_HERE); + network_state_handler_observer_.Observe(nsh); // Update the network status and notify the webui. This is the initial // network state so the webui should be notified no matter what. UpdatePortalReachability(network, true /* force notification */);
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc index 988cdc5..b4ef3d8 100644 --- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -28,7 +28,6 @@ #include "chrome/grit/generated_resources.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "components/consent_auditor/consent_auditor.h" #include "components/login/localized_values_builder.h" #include "components/prefs/pref_service.h" @@ -68,8 +67,6 @@ oobe_ui->RemoveObserver(this); if (network_time_zone_observing_) { network_time_zone_observing_ = false; - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); system::TimezoneSettings::GetInstance()->RemoveObserver(this); } if (session_manager_observing_ && session_manager::SessionManager::Get()) { @@ -142,11 +139,12 @@ builder->Add("arcTermsOfServiceScreenHeadingForChild", IDS_ARC_OOBE_TERMS_HEADING_CHILD); builder->Add("arcTermsOfServiceScreenDescription", - IDS_ARC_OOBE_TERMS_DESCRIPTION); + IDS_ARC_OOBE_TERMS_DESCRIPTION); builder->Add("arcTermsOfServiceScreenDescriptionForChild", IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD); builder->Add("arcTermsOfServiceLoading", IDS_ARC_OOBE_TERMS_LOADING); - builder->Add("arcTermsOfServiceErrorTitle", IDS_OOBE_GENERIC_FATAL_ERROR_TITLE); + builder->Add("arcTermsOfServiceErrorTitle", + IDS_OOBE_GENERIC_FATAL_ERROR_TITLE); builder->Add("arcTermsOfServiceErrorMessage", IDS_ARC_OOBE_TERMS_LOAD_ERROR); builder->Add("arcTermsOfServiceRetryButton", IDS_ARC_OOBE_TERMS_BUTTON_RETRY); builder->Add("arcTermsOfServiceAcceptButton", @@ -252,8 +250,7 @@ ProfileHelper::Get()->GetUserByProfile(profile); CHECK(user); - const AccountId owner = - user_manager::UserManager::Get()->GetOwnerAccountId(); + const AccountId owner = user_manager::UserManager::Get()->GetOwnerAccountId(); // Owner may not be set in case of initial account setup. Note, in case of // enterprise enrolled devices owner is always empty and we need to account @@ -281,14 +278,16 @@ } void ArcTermsOfServiceScreenHandler::OnBackupAndRestoreModeChanged( - bool enabled, bool managed) { + bool enabled, + bool managed) { backup_restore_managed_ = managed; CallJS("login.ArcTermsOfServiceScreen.setBackupAndRestoreMode", enabled, managed); } void ArcTermsOfServiceScreenHandler::OnLocationServicesModeChanged( - bool enabled, bool managed) { + bool enabled, + bool managed) { location_services_managed_ = managed; CallJS("login.ArcTermsOfServiceScreen.setLocationServicesMode", enabled, managed); @@ -323,8 +322,7 @@ void ArcTermsOfServiceScreenHandler::Hide() { if (network_time_zone_observing_) { network_time_zone_observing_ = false; - chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); + network_state_handler_observer_.Reset(); system::TimezoneSettings::GetInstance()->RemoveObserver(this); } if (session_manager_observing_ && session_manager::SessionManager::Get()) { @@ -342,8 +340,8 @@ if (network_time_zone_observing_) return; - chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + network_state_handler_observer_.Observe( + chromeos::NetworkHandler::Get()->network_state_handler()); system::TimezoneSettings::GetInstance()->AddObserver(this); network_time_zone_observing_ = true; }
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h index 45fd506..0f1b4d0 100644 --- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
@@ -10,9 +10,11 @@ #include "ash/components/settings/timezone_settings.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "chrome/browser/ash/arc/optin/arc_optin_preference_handler_observer.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/session_manager/core/session_manager_observer.h" @@ -194,6 +196,10 @@ // To track if a child account is being set up. bool is_child_account_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + std::unique_ptr<arc::ArcOptInPreferenceHandler> pref_handler_; }; @@ -205,6 +211,6 @@ using ::chromeos::ArcTermsOfServiceScreenHandler; using ::chromeos::ArcTermsOfServiceScreenView; using ::chromeos::ArcTermsOfServiceScreenViewObserver; -} +} // namespace ash #endif // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ARC_TERMS_OF_SERVICE_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc index 19978e9..5e29bf6 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.cc
@@ -13,7 +13,6 @@ #include "chromeos/ash/components/network/proxy/proxy_config_handler.h" #include "chromeos/ash/components/network/proxy/ui_proxy_config_service.h" #include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" #include "components/proxy_config/proxy_config_dictionary.h" #include "components/proxy_config/proxy_prefs.h" #include "net/proxy_resolution/proxy_config.h" @@ -86,17 +85,13 @@ NetworkStateInformer::NetworkStateInformer() : state_(OFFLINE) {} NetworkStateInformer::~NetworkStateInformer() { - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver( - this, FROM_HERE); - } network_portal_detector::GetInstance()->RemoveObserver(this); } void NetworkStateInformer::Init() { UpdateState(); - NetworkHandler::Get()->network_state_handler()->AddObserver( - this, FROM_HERE); + network_state_handler_observer_.Observe( + NetworkHandler::Get()->network_state_handler()); network_portal_detector::GetInstance()->AddAndFireObserver(this); }
diff --git a/chrome/browser/ui/webui/chromeos/login/network_state_informer.h b/chrome/browser/ui/webui/chromeos/login/network_state_informer.h index 075dc7f9..45fa6f06 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_state_informer.h +++ b/chrome/browser/ui/webui/chromeos/login/network_state_informer.h
@@ -13,9 +13,11 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/scoped_observation.h" #include "chrome/browser/ash/login/screens/network_error.h" #include "chrome/browser/ash/login/ui/captive_portal_window_proxy.h" #include "chromeos/ash/components/network/portal_detector/network_portal_detector.h" +#include "chromeos/network/network_state_handler.h" #include "chromeos/network/network_state_handler_observer.h" namespace base { @@ -27,11 +29,10 @@ // Class which observes network state changes and calls registered callbacks. // State is considered changed if connection or the active network has been // changed. Also, it answers to the requests about current network state. -class NetworkStateInformer - : public chromeos::NetworkStateHandlerObserver, - public chromeos::NetworkPortalDetector::Observer, - public CaptivePortalWindowProxyDelegate, - public base::RefCounted<NetworkStateInformer> { +class NetworkStateInformer : public chromeos::NetworkStateHandlerObserver, + public chromeos::NetworkPortalDetector::Observer, + public CaptivePortalWindowProxyDelegate, + public base::RefCounted<NetworkStateInformer> { public: enum State { OFFLINE = 0, @@ -98,6 +99,10 @@ base::ObserverList<NetworkStateInformerObserver>::Unchecked observers_; + base::ScopedObservation<chromeos::NetworkStateHandler, + chromeos::NetworkStateHandlerObserver> + network_state_handler_observer_{this}; + base::WeakPtrFactory<NetworkStateInformer> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index a33a9e34..17a61cb 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -18,6 +18,8 @@ "commands/install_from_info_command.h", "commands/install_from_sync_command.cc", "commands/install_from_sync_command.h", + "commands/install_isolated_app_command.cc", + "commands/install_isolated_app_command.h", "commands/install_web_app_with_params_command.cc", "commands/install_web_app_with_params_command.h", "commands/run_on_os_login_command.cc", @@ -480,6 +482,7 @@ sources = [ "commands/clear_browsing_data_command_unittest.cc", "commands/install_from_sync_command_unittest.cc", + "commands/install_isolated_app_command_unittest.cc", "commands/run_on_os_login_command_unittest.cc", "daily_metrics_helper_unittest.cc", "external_install_options_unittest.cc",
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command.cc b/chrome/browser/web_applications/commands/install_isolated_app_command.cc new file mode 100644 index 0000000..9ac02768 --- /dev/null +++ b/chrome/browser/web_applications/commands/install_isolated_app_command.cc
@@ -0,0 +1,39 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <utility> + +#include "chrome/browser/web_applications/commands/install_isolated_app_command.h" + +#include "base/callback_helpers.h" +#include "base/containers/flat_set.h" +#include "base/values.h" +#include "chrome/browser/web_applications/commands/web_app_command.h" + +namespace web_app { + +InstallIsolatedAppCommand::InstallIsolatedAppCommand(base::StringPiece url) + : WebAppCommand(WebAppCommandLock::CreateForAppAndWebContentsLock( + base::flat_set<AppId>{"some random app id"})) { + weak_this_ = weak_factory_.GetWeakPtr(); +} + +InstallIsolatedAppCommand::~InstallIsolatedAppCommand() = default; + +void InstallIsolatedAppCommand::Start() { + SignalCompletionAndSelfDestruct(CommandResult::kSuccess, base::DoNothing()); +} + +void InstallIsolatedAppCommand::OnSyncSourceRemoved() { + SignalCompletionAndSelfDestruct(CommandResult::kSuccess, base::DoNothing()); +} + +void InstallIsolatedAppCommand::OnShutdown() { + SignalCompletionAndSelfDestruct(CommandResult::kSuccess, base::DoNothing()); +} + +base::Value InstallIsolatedAppCommand::ToDebugValue() const { + return base::Value{}; +} +} // namespace web_app
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command.h b/chrome/browser/web_applications/commands/install_isolated_app_command.h new file mode 100644 index 0000000..8761178 --- /dev/null +++ b/chrome/browser/web_applications/commands/install_isolated_app_command.h
@@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMMANDS_INSTALL_ISOLATED_APP_COMMAND_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_COMMANDS_INSTALL_ISOLATED_APP_COMMAND_H_ + +#include "base/memory/weak_ptr.h" +#include "base/strings/string_piece_forward.h" +#include "base/values.h" +#include "chrome/browser/web_applications/commands/web_app_command.h" + +namespace web_app { + +class InstallIsolatedAppCommand : public WebAppCommand { + public: + explicit InstallIsolatedAppCommand(base::StringPiece application_url); + ~InstallIsolatedAppCommand() override; + + base::Value ToDebugValue() const override; + + void Start() override; + void OnSyncSourceRemoved() override; + void OnShutdown() override; + + private: + base::WeakPtr<InstallIsolatedAppCommand> weak_this_; + base::WeakPtrFactory<InstallIsolatedAppCommand> weak_factory_{this}; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_COMMANDS_INSTALL_ISOLATED_APP_COMMAND_H_
diff --git a/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc b/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc new file mode 100644 index 0000000..036a6333 --- /dev/null +++ b/chrome/browser/web_applications/commands/install_isolated_app_command_unittest.cc
@@ -0,0 +1,57 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/web_applications/commands/install_isolated_app_command.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/test_web_app_url_loader.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/browser/web_applications/web_app_command_manager.h" + +namespace web_app { +namespace { + +class InstallIsolatedAppCommandTest : public WebAppTest { + public: + void SetUp() override { + WebAppTest::SetUp(); + FakeWebAppProvider* provider = FakeWebAppProvider::Get(profile()); + provider->SetDefaultFakeSubsystems(); + provider->SetRunSubsystemStartupTasks(true); + + auto url_loader = std::make_unique<TestWebAppUrlLoader>(); + url_loader_ = url_loader.get(); + provider->GetCommandManager().SetUrlLoaderForTesting(std::move(url_loader)); + + test::AwaitStartWebAppProviderAndSubsystems(profile()); + } + + void AddPrepareForLoadResults( + const std::vector<WebAppUrlLoader::Result>& results) { + url_loader_->AddPrepareForLoadResults(results); + } + + private: + base::raw_ptr<TestWebAppUrlLoader> url_loader_; +}; + +TEST_F(InstallIsolatedAppCommandTest, StartCanBeStartedSuccesfully) { + AddPrepareForLoadResults(std::vector<WebAppUrlLoader::Result>{ + WebAppUrlLoader::Result::kUrlLoaded, + }); + + auto subject = std::make_unique<InstallIsolatedAppCommand>( + "some random application URL"); + WebAppProvider::GetForTest(profile())->command_manager().ScheduleCommand( + std::move(subject)); +} +} // namespace +} // namespace web_app
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 06566e0..1ee5e73 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1655466571-3c36953a1de324b0904d8f22857f74dda49d16c4.profdata +chrome-linux-main-1655488705-a8d059e1c77d5391c62a9153e09caf1a9bb1b754.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 305ddbc..0dc6482 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1655445530-0f845484c9b2b14413a1d924e20fdc4fc7a4ea3c.profdata +chrome-mac-arm-main-1655488705-b4be757613e1b3e238b09a6f0d908398060bdf93.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index caac24a6..4dbf69cb 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1655466571-7d65938c5b97e550699896fed8a00e761848f383.profdata +chrome-mac-main-1655488705-4acb856423b136f51305aa7cbee124a7d1f32422.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 2804e23b..94edd47 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1655477874-4201f81b88bd0364e749cfca6e587c842285c543.profdata +chrome-win32-main-1655499543-52af2873e2fd92539c1b043b0a55c99b239fdfbf.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 414956f..b4885eb 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1655466571-e25340d25f6143180c76ee686afd081746c67b6f.profdata +chrome-win64-main-1655499543-61fefae39aa4d09ed380819c4114e0aa3dc658a5.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 6d2adae..5d7cfeb 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -8443,6 +8443,7 @@ "../browser/ui/views/toolbar/toolbar_action_view_unittest.cc", "../browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc", "../browser/ui/views/toolbar/toolbar_button_unittest.cc", + "../browser/ui/views/translate/partial_translate_bubble_view_unittest.cc", "../browser/ui/views/translate/translate_bubble_controller_unittest.cc", "../browser/ui/views/translate/translate_bubble_view_unittest.cc", "../browser/ui/views/user_education/browser_feature_promo_controller_unittest.cc",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn index d5d1cb6..18e57208 100644 --- a/chrome/test/android/BUILD.gn +++ b/chrome/test/android/BUILD.gn
@@ -257,7 +257,11 @@ android_library("chrome_java_integration_only_test_support") { testonly = true - visibility = [ ":*" ] + visibility = [ + ":*", + "//chrome/android/features/tab_ui:test_support_javalib", + "//chrome/android/features/tab_ui:unit_device_javatests", + ] sources = [ "javatests/src/org/chromium/chrome/browser/history/HistoryTestUtils.java", "javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java", @@ -401,6 +405,7 @@ visibility = [ ":*", "//chrome/android/features/tab_ui:unit_device_javatests", + "//chrome/browser/ui/android/night_mode:unit_device_javatests", "//chrome/browser/ui/android/omnibox:unit_device_javatests", ] sources = [
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java index 7700c8d..b154551 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeApplicationTestUtils.java
@@ -17,7 +17,6 @@ import org.chromium.base.ActivityState; import org.chromium.base.ApplicationState; import org.chromium.base.ApplicationStatus; -import org.chromium.base.Log; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.chrome.browser.app.ChromeActivity; @@ -158,7 +157,6 @@ Coordinates coord = Coordinates.createFor(tab.getWebContents()); float scale = coord.getPageScaleFactor(); - Log.i(TAG, "PageScaleFactor = " + scale); Criteria.checkThat( (double) scale, Matchers.not(Matchers.closeTo(initialScale, FLOAT_EPSILON))); });
diff --git a/chrome/test/chromedriver/js/call_function.js b/chrome/test/chromedriver/js/call_function.js index ac516eb3..9cce49a8 100644 --- a/chrome/test/chromedriver/js/call_function.js +++ b/chrome/test/chromedriver/js/call_function.js
@@ -354,7 +354,7 @@ // (above) are type 'function', so this check must be performed after. if (typeof item === 'function') return item; - // TODO(rohpavone): Implement WindowProxy serialization. + // TODO(crbug.com/1337415): Implement WindowProxy serialization. if (typeof item.toJSON === 'function' && (item.hasOwnProperty('toJSON') || Object.getPrototypeOf(item).hasOwnProperty('toJSON')))
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 07bb29d..4327fdd 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -474,11 +474,13 @@ if (!is_android) { deps += [ "access_code_cast:build_grdp", + "discards:build_grdp", "support_tool:build_grdp", "whats_new:build_grdp", ] grdp_files += [ "$target_gen_dir/access_code_cast/resources.grdp", + "$target_gen_dir/discards/resources.grdp", "$target_gen_dir/whats_new/resources.grdp", "$target_gen_dir/support_tool/resources.grdp", ] @@ -564,7 +566,10 @@ in_files = [ "chrome_timeticks_test.ts", "color_provider_css_colors_test.ts", + "resources/list_property_update_mixin_tests.ts", + "text_defaults_test.ts", ] + deps = [ "//ui/webui/resources:library" ] extra_deps = [ ":generate_definitions" ] definitions = [ "//tools/typescript/definitions/chrome_send.d.ts",
diff --git a/chrome/test/data/webui/cr_components/BUILD.gn b/chrome/test/data/webui/cr_components/BUILD.gn index daa18c22..7fe1081 100644 --- a/chrome/test/data/webui/cr_components/BUILD.gn +++ b/chrome/test/data/webui/cr_components/BUILD.gn
@@ -29,6 +29,7 @@ "color_change_listener_test.ts", "customize_themes_test.ts", "history_clusters_test.ts", + "localized_link_test.ts", "managed_dialog_test.ts", "most_visited_focus_test.ts", "most_visited_test.ts",
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 3b8e78a..081e119 100644 --- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -106,7 +106,7 @@ var CrComponentsLocalizedLinkTest = class extends CrComponentsBrowserTest { /** @override */ get browsePreload() { - return 'chrome://test/test_loader.html?module=cr_components/localized_link_test.js'; + return 'chrome://test/test_loader.html?module=cr_components/localized_link_test.js&host=webui-test'; } };
diff --git a/chrome/test/data/webui/cr_components/localized_link_test.js b/chrome/test/data/webui/cr_components/localized_link_test.ts similarity index 84% rename from chrome/test/data/webui/cr_components/localized_link_test.js rename to chrome/test/data/webui/cr_components/localized_link_test.ts index b525cd15..dceb462 100644 --- a/chrome/test/data/webui/cr_components/localized_link_test.js +++ b/chrome/test/data/webui/cr_components/localized_link_test.ts
@@ -4,14 +4,15 @@ import '//resources/cr_components/localized_link/localized_link.js'; -import {eventToPromise, flushTasks, waitAfterNextRender} from 'chrome://test/test_util.js'; - -import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../../chai_assert.js'; +import {LocalizedLinkElement} from '//resources/cr_components/localized_link/localized_link.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {eventToPromise, flushTasks} from 'chrome://webui-test/test_util.js'; suite('localized_link', function() { - let localizedStringWithLink; + let localizedStringWithLink: LocalizedLinkElement|null; - function getLocalizedStringWithLinkElementHtml(localizedString, linkUrl) { + function getLocalizedStringWithLinkElementHtml( + localizedString: string, linkUrl: string): string { return `<localized-link localized-string="${localizedString}"` + ` link-url="${linkUrl}"></localized-link>`; } @@ -20,6 +21,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml(`<a>first link</a>then text`, ``); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `<a id="id0" aria-labelledby="id0 id1" tabindex="0">first link</a>` + @@ -30,6 +32,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml( `first text <a>then link</a> then more text`, ``); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `<span id="id0" aria-hidden="true">first text </span>` + @@ -41,6 +44,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml(`first text<a>then link</a>`, ``); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `<span id="id0" aria-hidden="true">first text</span>` + @@ -51,6 +55,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml( `<a>populated link</a>`, `http://google.com`); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `<a id="id0" aria-labelledby="id0" tabindex="0" ` + @@ -61,6 +66,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml( `<a href='http://google.com'>pre-populated link</a>`, ``); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `<a href="http://google.com" id="id0" aria-labelledby="id0" tabindex="0">` + @@ -71,6 +77,7 @@ document.body.innerHTML = getLocalizedStringWithLinkElementHtml( `No anchor tags in this sentence.`, ``); localizedStringWithLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedStringWithLink); assertEquals( localizedStringWithLink.$.container.innerHTML, `No anchor tags in this sentence.`); @@ -83,7 +90,7 @@ return flushTasks().then(async () => { const localizedLink = document.body.querySelector('localized-link'); assertTrue(!!localizedLink); - const anchorTag = localizedLink.shadowRoot.querySelector('a'); + const anchorTag = localizedLink.shadowRoot!.querySelector('a'); assertTrue(!!anchorTag); const localizedLinkPromise = eventToPromise('link-clicked', localizedLink); @@ -100,7 +107,7 @@ await flushTasks(); const localizedLink = document.body.querySelector('localized-link'); assertTrue(!!localizedLink); - const anchorTag = localizedLink.shadowRoot.querySelector('a'); + const anchorTag = localizedLink.shadowRoot!.querySelector('a'); assertTrue(!!anchorTag); assertEquals(anchorTag.getAttribute('tabindex'), '0'); localizedLink.linkDisabled = true; @@ -114,6 +121,7 @@ await flushTasks(); const localizedLink = document.body.querySelector('localized-link'); + assertTrue(!!localizedLink); localizedLink.linkDisabled = true; const localizedLinkPromise = eventToPromise('link-clicked', localizedLink); await flushTasks(); @@ -122,7 +130,7 @@ await flushTasks(); // Tab index is still -1 due to it being disabled. - const anchorTag = localizedLink.shadowRoot.querySelector('a'); + const anchorTag = localizedLink.shadowRoot!.querySelector('a'); assertTrue(!!anchorTag); assertEquals(anchorTag.getAttribute('tabindex'), '-1');
diff --git a/chrome/test/data/webui/discards/BUILD.gn b/chrome/test/data/webui/discards/BUILD.gn new file mode 100644 index 0000000..657a381 --- /dev/null +++ b/chrome/test/data/webui/discards/BUILD.gn
@@ -0,0 +1,35 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//tools/typescript/ts_library.gni") +import("//ui/webui/resources/tools/generate_grd.gni") + +assert(!is_android) + +generate_grd("build_grdp") { + grd_prefix = "webui_discards" + out_grd = "$target_gen_dir/resources.grdp" + + deps = [ ":build_ts" ] + manifest_files = [ "$target_gen_dir/tsconfig.manifest" ] + resource_path_prefix = "discards" +} + +ts_library("build_ts") { + root_dir = "." + out_dir = "$target_gen_dir/tsc" + tsconfig_base = "../tsconfig_base.json" + path_mappings = [ + "chrome://discards/*|" + + rebase_path("$root_gen_dir/chrome/browser/resources/discards/tsc/*", + target_gen_dir), + "chrome://webui-test/*|" + + rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*", + target_gen_dir), + ] + in_files = [ "discards_test.ts" ] + + deps = [ "//chrome/browser/resources/discards:build_ts" ] + extra_deps = [ "..:generate_definitions" ] +}
diff --git a/chrome/test/data/webui/discards/discards_browsertest.js b/chrome/test/data/webui/discards/discards_browsertest.js index c37103d..482c8b4 100644 --- a/chrome/test/data/webui/discards/discards_browsertest.js +++ b/chrome/test/data/webui/discards/discards_browsertest.js
@@ -10,7 +10,7 @@ var DiscardsTest = class extends testing.Test { /** @override */ get browsePreload() { - return 'chrome://discards/test_loader.html?module=discards/discards_test.js'; + return 'chrome://discards/test_loader.html?module=discards/discards_test.js&host=webui-test'; } };
diff --git a/chrome/test/data/webui/discards/discards_test.js b/chrome/test/data/webui/discards/discards_test.ts similarity index 68% rename from chrome/test/data/webui/discards/discards_test.js rename to chrome/test/data/webui/discards/discards_test.ts index 16c488d..09f0f68 100644 --- a/chrome/test/data/webui/discards/discards_test.js +++ b/chrome/test/data/webui/discards/discards_test.ts
@@ -8,6 +8,7 @@ import {durationToString, maybeMakePlural} from 'chrome://discards/discards.js'; import {compareTabDiscardsInfos} from 'chrome://discards/discards_tab.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; suite('discards', function() { test('CompareTabDiscardsInfo', function() { @@ -44,19 +45,28 @@ test('DurationToString', function() { // Test cases have the form [ 'expected output', input_in_seconds ]. - [['just now', 0], ['just now', 10], ['just now', 59], ['1 minute ago', 60], - ['10 minutes ago', 10 * 60 + 30], ['59 minutes ago', 59 * 60 + 59], - ['1 hour ago', 60 * 60], ['1 hour and 1 minute ago', 61 * 60], - ['1 hour and 10 minutes ago', 70 * 60 + 30], ['1 day ago', 24 * 60 * 60], - ['2 days ago', 2.5 * 24 * 60 * 60], ['6 days ago', 6.9 * 24 * 60 * 60], - ['over 1 week ago', 7 * 24 * 60 * 60], - ['over 2 weeks ago', 2.5 * 7 * 24 * 60 * 60], - ['over 4 weeks ago', 30 * 24 * 60 * 60], - ['over 1 month ago', 30.5 * 24 * 60 * 60], - ['over 2 months ago', 2.5 * 30.5 * 24 * 60 * 60], - ['over 11 months ago', 364 * 24 * 60 * 60], - ['over 1 year ago', 365 * 24 * 60 * 60], - ['over 2 years ago', 2.3 * 365 * 24 * 60 * 60]] + ([ + ['just now', 0], + ['just now', 10], + ['just now', 59], + ['1 minute ago', 60], + ['10 minutes ago', 10 * 60 + 30], + ['59 minutes ago', 59 * 60 + 59], + ['1 hour ago', 60 * 60], + ['1 hour and 1 minute ago', 61 * 60], + ['1 hour and 10 minutes ago', 70 * 60 + 30], + ['1 day ago', 24 * 60 * 60], + ['2 days ago', 2.5 * 24 * 60 * 60], + ['6 days ago', 6.9 * 24 * 60 * 60], + ['over 1 week ago', 7 * 24 * 60 * 60], + ['over 2 weeks ago', 2.5 * 7 * 24 * 60 * 60], + ['over 4 weeks ago', 30 * 24 * 60 * 60], + ['over 1 month ago', 30.5 * 24 * 60 * 60], + ['over 2 months ago', 2.5 * 30.5 * 24 * 60 * 60], + ['over 11 months ago', 364 * 24 * 60 * 60], + ['over 1 year ago', 365 * 24 * 60 * 60], + ['over 2 years ago', 2.3 * 365 * 24 * 60 * 60], + ] as Array<[string, number]>) .forEach((data) => { assertEquals(data[0], durationToString(data[1])); });
diff --git a/chrome/test/data/webui/resources/list_property_update_mixin_tests.js b/chrome/test/data/webui/resources/list_property_update_mixin_tests.ts similarity index 68% rename from chrome/test/data/webui/resources/list_property_update_mixin_tests.js rename to chrome/test/data/webui/resources/list_property_update_mixin_tests.ts index 659be7a..5db1286a 100644 --- a/chrome/test/data/webui/resources/list_property_update_mixin_tests.js +++ b/chrome/test/data/webui/resources/list_property_update_mixin_tests.ts
@@ -6,140 +6,158 @@ import {ListPropertyUpdateMixin} from 'chrome://resources/js/list_property_update_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assertDeepEquals, assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; + +type SimpleArrayEntry = { + id: number, +}; + +type ComplexArrayEntry = { + letter: string, + words: string[], +}; + +/** A test element that implements the ListPropertyUpdateMixin. */ +const ListPropertyUpdateMixinTestElementBase = + ListPropertyUpdateMixin(PolymerElement); + +class ListPropertyUpdateMixinTestElement extends + ListPropertyUpdateMixinTestElementBase { + static get is() { + return 'list-property-update-mixin-test-element'; + } + + static get properties() { + return { + /** + * A test array containing objects with Array properties. The elements + * in the array represent an object that maps a list of |words| to the + * |letter| that they begin with. + */ + complexArray: Array, + + /** + * A test array containing objects with numerical |id|s. + */ + simpleArray: Array, + }; + } + + complexArray: ComplexArrayEntry[] = []; + simpleArray: SimpleArrayEntry[] = []; + + constructor() { + super(); + + this.resetSimpleArray(); + this.resetComplexArray(); + } + + resetComplexArray() { + this.complexArray = [ + {letter: 'a', words: ['adventure', 'apple']}, + {letter: 'b', words: ['banana', 'bee', 'bottle']}, + {letter: 'c', words: ['car']}, + ]; + } + + resetSimpleArray() { + this.simpleArray = [{id: 1}, {id: 2}, {id: 3}]; + } + + /** + * Updates the |complexArray| with |newArray| using the + * ListPropertyUpdateBehavior.updateList() method. This method will + * iterate through the elements of |complexArray| to check if their + * |words| property array need to be updated if |complexArray| did not + * have any changes. + * @param newArray The array update |complexArray| with. + * @return An object that has a |topArrayChanged| property set to true if + * notifySplices() was called for the 'complexArray' property path and + * a |wordsArrayChanged| property set to true if notifySplices() was + * called for the |words| property on an item of |complexArray|. + */ + updateComplexArray(newArray: ComplexArrayEntry[]): + {topArrayChanged: boolean, wordsArrayChanged: boolean} { + if (this.updateList( + 'complexArray', x => x.letter, newArray, + true /* identityBasedUpdate */)) { + return {topArrayChanged: true, wordsArrayChanged: false}; + } + + // At this point, |complexArray| and |newArray| should have the same + // elements. + let wordsSplicesNotified = false; + assertEquals(this.complexArray.length, newArray.length); + this.complexArray.forEach((item, i) => { + assertEquals(item.letter, newArray[i]!.letter); + const propertyPath = 'complexArray.' + i + '.words'; + const newWordsArray = newArray[i]!.words; + + if (this.updateList(propertyPath, x => x, newWordsArray)) { + wordsSplicesNotified = true; + } + }); + + return { + topArrayChanged: false, + wordsArrayChanged: wordsSplicesNotified, + }; + } + + /** + * Updates the |simpleArray| with |newArray| using the + * ListPropertyUpdateBehavior.updateList() method. + * @param newArray The array to update |simpleArray| with. + * @returns True if the update called notifySplices() for + * |simpleArray|. + */ + updateSimpleArray(newArray: SimpleArrayEntry[]): boolean { + return this.updateList('simpleArray', x => String(x.id), newArray); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'list-property-update-mixin-test-element': + ListPropertyUpdateMixinTestElement; + } +} + +customElements.define( + ListPropertyUpdateMixinTestElement.is, ListPropertyUpdateMixinTestElement); suite('ListPropertyUpdateMixin', function() { /** * A list property update mixin test element created before each test. - * @type {ListPropertyUpdateMixinTestElement} */ - let testElement; - - suiteSetup(function() { - /** A test element that implements the ListPropertyUpdateMixin. */ - const ListPropertyUpdateMixinTestElementBase = - ListPropertyUpdateMixin(PolymerElement); - - class ListPropertyUpdateMixinTestElement extends - ListPropertyUpdateMixinTestElementBase { - static get properties() { - return { - /** - * A test array containing objects with Array properties. The elements - * in the array represent an object that maps a list of |words| to the - * |letter| that they begin with. - * @type {!Array<{letter: !string, words: !Array<string>}>} - */ - complexArray: Array, - - /** - * A test array containing objects with numerical |id|s. - * @type {!Array<{id: !number}>} - */ - simpleArray: Array, - }; - } - - constructor() { - super(); - - this.resetSimpleArray(); - this.resetComplexArray(); - } - - resetComplexArray() { - this.complexArray = [ - {letter: 'a', words: ['adventure', 'apple']}, - {letter: 'b', words: ['banana', 'bee', 'bottle']}, - {letter: 'c', words: ['car']}, - ]; - } - - resetSimpleArray() { - this.simpleArray = [{id: 1}, {id: 2}, {id: 3}]; - } - - /** - * Updates the |complexArray| with |newArray| using the - * ListPropertyUpdateBehavior.updateList() method. This method will - * iterate through the elements of |complexArray| to check if their - * |words| property array need to be updated if |complexArray| did not - * have any changes. - * @param {!Array{letter: !string, words: !Array<string>}>} newArray The - * array update |complexArray| with. - * @returns {{topArrayChanged: boolean, wordsArrayChanged: boolean}} An - * object that has a |topArrayChanged| property set to true if - * notifySplices() was called for the 'complexArray' property path and - * a |wordsArrayChanged| property set to true if notifySplices() was - * called for the |words| property on an item of |complexArray|. - */ - updateComplexArray(newArray) { - if (this.updateList( - 'complexArray', x => x.letter, newArray, - true /* identityBasedUpdate */)) { - return {topArrayChanged: true, wordsArrayChanged: false}; - } - - // At this point, |complexArray| and |newArray| should have the same - // elements. - let wordsSplicesNotified = false; - assertEquals(this.complexArray.length, newArray.length); - this.complexArray.forEach((item, i) => { - assertEquals(item.letter, newArray[i].letter); - const propertyPath = 'complexArray.' + i + '.words'; - const newWordsArray = newArray[i].words; - - if (this.updateList(propertyPath, x => x, newWordsArray)) { - wordsSplicesNotified = true; - } - }); - - return { - topArrayChanged: false, - wordsArrayChanged: wordsSplicesNotified, - }; - } - - /** - * Updates the |simpleArray| with |newArray| using the - * ListPropertyUpdateBehavior.updateList() method. - * @param {!Array{id: !number}>} newArray The array to update - * |simpleArray| with. - * @returns {boolean} True if the update called notifySplices() for - * |simpleArray|. - */ - updateSimpleArray(newArray) { - return this.updateList('simpleArray', x => x.id, newArray); - } - } - - customElements.define( - 'list-property-update-mixin-test-element', - ListPropertyUpdateMixinTestElement); - }); + let testElement: ListPropertyUpdateMixinTestElement; // Initialize a list-property-update-mixin-test-element before each test. setup(function() { - PolymerTest.clearBody(); + document.body.innerHTML = ''; testElement = document.createElement('list-property-update-mixin-test-element'); document.body.appendChild(testElement); }); - function assertSimpleArrayEquals(array, expectedArray) { + function assertSimpleArrayEquals( + array: SimpleArrayEntry[], expectedArray: SimpleArrayEntry[]) { assertEquals(array.length, expectedArray.length); array.forEach((item, i) => { - assertEquals(item.id, expectedArray[i].id); + assertEquals(item.id, expectedArray[i]!.id); }); } - function assertComplexArrayEquals(array, expectedArray) { + function assertComplexArrayEquals( + array: ComplexArrayEntry[], expectedArray: ComplexArrayEntry[]) { assertEquals(array.length, expectedArray.length); array.forEach((item, i) => { - assertEquals(item.letter, expectedArray[i].letter); - assertEquals(item.words.length, expectedArray[i].words.length); + assertEquals(item.letter, expectedArray[i]!.letter); + assertEquals(item.words.length, expectedArray[i]!.words.length); item.words.forEach((word, j) => { - assertEquals(word, expectedArray[i].words[j]); + assertEquals(word, expectedArray[i]!.words[j]); }); }); } @@ -294,8 +312,9 @@ assertTrue(newArray[0].words.length > 0); assertNotEquals('apricot', newArray[0].words[0]); newArray[0].words = ['apricot']; - assertTrue(testElement.updateList('complexArray', x => x.letter, newArray)); - assertDeepEquals(['apricot'], testElement.complexArray[0].words); + assertTrue(testElement.updateList( + 'complexArray', (x: ComplexArrayEntry) => x.letter, newArray)); + assertDeepEquals(['apricot'], testElement.complexArray[0]!.words); }); test('first item modified with same uid and last item removed', () => { @@ -305,8 +324,9 @@ newArray[0].words = ['apricot']; assertTrue(newArray.length > 1); newArray.pop(); - assertTrue(testElement.updateList('complexArray', x => x.letter, newArray)); - assertDeepEquals(['apricot'], testElement.complexArray[0].words); + assertTrue(testElement.updateList( + 'complexArray', (x: ComplexArrayEntry) => x.letter, newArray)); + assertDeepEquals(['apricot'], testElement.complexArray[0]!.words); }); test('updateList() function triggers notifySplices()', () => {
diff --git a/chrome/test/data/webui/resources/webui_resources_browsertest.js b/chrome/test/data/webui/resources/webui_resources_browsertest.js index 39dd41cf..a8611b48 100644 --- a/chrome/test/data/webui/resources/webui_resources_browsertest.js +++ b/chrome/test/data/webui/resources/webui_resources_browsertest.js
@@ -39,7 +39,7 @@ class extends WebUIResourcesBrowserTest { /** @override */ get browsePreload() { - return 'chrome://test/test_loader.html?module=resources/list_property_update_mixin_tests.js'; + return 'chrome://test/test_loader.html?module=resources/list_property_update_mixin_tests.js&host=webui-test'; } };
diff --git a/chrome/test/data/webui/text_defaults_browsertest.js b/chrome/test/data/webui/text_defaults_browsertest.js index f8b095d..b121ad3b 100644 --- a/chrome/test/data/webui/text_defaults_browsertest.js +++ b/chrome/test/data/webui/text_defaults_browsertest.js
@@ -12,7 +12,7 @@ * @override */ get browsePreload() { - return 'chrome://test/test_loader.html?module=text_defaults_test.js'; + return 'chrome://test/test_loader.html?module=text_defaults_test.js&host=webui-test'; } /** @override */
diff --git a/chrome/test/data/webui/text_defaults_test.js b/chrome/test/data/webui/text_defaults_test.ts similarity index 65% rename from chrome/test/data/webui/text_defaults_test.js rename to chrome/test/data/webui/text_defaults_test.ts index 039cb9a..312284b 100644 --- a/chrome/test/data/webui/text_defaults_test.js +++ b/chrome/test/data/webui/text_defaults_test.ts
@@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {assertEquals, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; + /** - * @param {string} html Text, possibly with HTML &entities; in it. - * @return {string} The HTML decoded text. + * @param html Text, possibly with HTML &entities; in it. */ -function decodeHtmlEntities(html) { +function decodeHtmlEntities(html: string): string { const element = document.createElement('div'); element.innerHTML = html; - return element.textContent; + return element.textContent!; } suite('TextDefaults', function() { @@ -18,7 +19,9 @@ link.rel = 'stylesheet'; link.href = 'chrome://resources/css/text_defaults.css'; link.onload = function() { - const fontFamily = link.sheet.rules[1].style['font-family']; + assertTrue(!!link.sheet); + const fontFamily = (link.sheet.rules[1] as CSSStyleRule) + .style.getPropertyValue('font-family'); assertNotEquals('', fontFamily); assertEquals(decodeHtmlEntities(fontFamily), fontFamily); done(); @@ -31,7 +34,9 @@ link.rel = 'stylesheet'; link.href = 'chrome://resources/css/text_defaults_md.css'; link.onload = function() { - const fontFamily = link.sheet.rules[2].style['font-family']; + assertTrue(!!link.sheet); + const fontFamily = (link.sheet.rules[2] as CSSStyleRule) + .style.getPropertyValue('font-family'); assertNotEquals('', fontFamily); assertEquals(decodeHtmlEntities(fontFamily), fontFamily); done();
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java index f85d201..a99c37f 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java
@@ -99,6 +99,8 @@ mIsFinishingState.andThen(mGotIntentState).map(Both::getSecond); Observable<?> createdAndNotTestingState = mCreatedState.and(Observable.not(mIsTestingState)); + Observable<?> startedAndNotTestingState = + mStartedState.and(Observable.not(mIsTestingState)); createdAndNotTestingState.subscribe(x -> { // Register handler for web content stopped event while we have an Intent. IntentFilter filter = new IntentFilter(); @@ -112,13 +114,6 @@ CastBrowserHelper.initializeBrowser(getApplicationContext()); setContentView(R.layout.cast_web_contents_activity); - - mSurfaceHelperState.set(new CastWebContentsSurfaceHelper( - CastWebContentsScopes.onLayoutActivity(this, - (FrameLayout) findViewById(R.id.web_contents_container), - CastSwitches.getSwitchValueColor( - CastSwitches.CAST_APP_BACKGROUND_COLOR, Color.BLACK)), - (Uri uri) -> mIsFinishingState.set("Delayed teardown for URI: " + uri))); })); mSurfaceHelperState.subscribe((CastWebContentsSurfaceHelper surfaceHelper) -> { @@ -163,6 +158,7 @@ Intent visible = CastWebContentsIntentUtils.onVisibilityChange( instanceId, CastWebContentsIntentUtils.VISIBITY_TYPE_FULL_SCREEN); LocalBroadcastManager.getInstance(ctx).sendBroadcastSync(visible); + return () -> { Intent hidden = CastWebContentsIntentUtils.onVisibilityChange( instanceId, CastWebContentsIntentUtils.VISIBITY_TYPE_HIDDEN); @@ -170,6 +166,18 @@ }; }); + startedAndNotTestingState.subscribe(x -> { + mSurfaceHelperState.set(new CastWebContentsSurfaceHelper( + CastWebContentsScopes.onLayoutActivity(this, + (FrameLayout) findViewById(R.id.web_contents_container), + CastSwitches.getSwitchValueColor( + CastSwitches.CAST_APP_BACKGROUND_COLOR, Color.BLACK)), + (Uri uri) -> mIsFinishingState.set("Delayed teardown for URI: " + uri))); + return () -> { + mSurfaceHelperState.reset(); + }; + }); + // If a new Intent arrives after finishing, start a new Activity instead of recycling this. gotIntentAfterFinishingState.subscribe(Observers.onEnter((Intent intent) -> { Log.d(TAG, "Got intent while finishing current activity, so start new activity.");
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java index 669cb90..8a9765c 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
@@ -17,6 +17,8 @@ import org.chromium.base.Log; import org.chromium.chromecast.base.Controller; +import org.chromium.chromecast.base.Observers; +import org.chromium.chromecast.base.Scope; import org.chromium.content_public.browser.WebContents; /** @@ -90,11 +92,20 @@ class ActivityDelegate implements Delegate { private static final String TAG = "CastWebContent_AD"; private boolean mStarted; + private Scope mVisibilityScope; + private ServiceDelegate mBackgroundService = new ServiceDelegate(); @Override public void start(StartParams params) { if (mStarted) return; // No-op if already started. if (DEBUG) Log.d(TAG, "start: SHOW_WEB_CONTENT in activity"); + mVisibilityScope = mVisibility.subscribe(Observers.onEnter(visibility -> { + if (visibility == CastWebContentsIntentUtils.VISIBITY_TYPE_HIDDEN) { + mBackgroundService.start(params); + } else if (visibility == CastWebContentsIntentUtils.VISIBITY_TYPE_FULL_SCREEN) { + mBackgroundService.stop(params.context); + } + })); startCastActivity(params.context, params.webContents, mEnableTouchInput, mIsRemoteControlMode, mTurnOnScreen); mStarted = true; @@ -102,6 +113,8 @@ @Override public void stop(Context context) { + mVisibilityScope.close(); + mBackgroundService.stop(context); sendStopWebContentEvent(); mStarted = false; } @@ -131,25 +144,25 @@ public void onServiceConnected(ComponentName name, IBinder service) {} @Override - public void onServiceDisconnected(ComponentName name) { - if (DEBUG) Log.d(TAG, "onServiceDisconnected"); - - if (mComponentClosedHandler != null) mComponentClosedHandler.onComponentClosed(); - } + public void onServiceDisconnected(ComponentName name) {} }; + private boolean mBound; @Override public void start(StartParams params) { if (DEBUG) Log.d(TAG, "start"); Intent intent = CastWebContentsIntentUtils.requestStartCastService( params.context, params.webContents, mSessionId); - params.context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + mBound = params.context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override public void stop(Context context) { if (DEBUG) Log.d(TAG, "stop"); - context.unbindService(mConnection); + if (mBound) { + context.unbindService(mConnection); + mBound = false; + } } } @@ -162,6 +175,7 @@ private final String mSessionId; private final SurfaceEventHandler mSurfaceEventHandler; private final Controller<WebContents> mHasWebContentsState = new Controller<>(); + private final Controller<Integer> mVisibility = new Controller<>(); private Delegate mDelegate; private boolean mStarted; private boolean mEnableTouchInput; @@ -206,6 +220,7 @@ if (mComponentClosedHandler != null) mComponentClosedHandler.onComponentClosed(); } else if (CastWebContentsIntentUtils.isIntentOfVisibilityChange(intent)) { int visibilityType = CastWebContentsIntentUtils.getVisibilityType(intent); + mVisibility.set(visibilityType); if (DEBUG) { Log.d(TAG, "onReceive ACTION_ON_VISIBILITY_CHANGE instance=" + mSessionId @@ -279,6 +294,7 @@ mHasWebContentsState.reset(); if (DEBUG) Log.d(TAG, "Call delegate to stop"); mDelegate.stop(context); + mDelegate = null; mStarted = false; }
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java index 187bf56..9365af0 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsScopes.java
@@ -90,7 +90,9 @@ layout.setForeground(new ColorDrawable(backgroundColor)); layout.removeView(contentView); layout.removeView(contentViewRenderView); - webContents.setTopLevelNativeWindow(null); + if (webContents.getTopLevelNativeWindow() == window) { + webContents.setTopLevelNativeWindow(null); + } contentViewRenderView.destroy(); window.destroy(); }; @@ -109,9 +111,9 @@ if (!webContents.isDestroyed()) { // WebContents can be destroyed by the app before CastWebContentsComponent // unbinds, which is why we need this check. - webContents.onHide(); if (webContents.getTopLevelNativeWindow() == window) { + webContents.onHide(); webContents.setTopLevelNativeWindow(null); } }
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java index 85d09fb..11cc1fe 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsService.java
@@ -10,7 +10,6 @@ import android.app.Service; import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.os.Build; import android.os.IBinder; @@ -59,9 +58,6 @@ }); mWebContentsState.map(this::getMediaSessionImpl) .subscribe(Observers.onEnter(MediaSessionImpl::requestSystemAudioFocus)); - // Inform CastContentWindowAndroid we're detaching. - Observable<String> instanceIdState = mIntentState.map(Intent::getData).map(Uri::getPath); - instanceIdState.subscribe(Observers.onExit(CastWebContentsComponent::onComponentClosed)); if (DEBUG) { mWebContentsState.subscribe(x -> {
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/WebContentsRegistry.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/WebContentsRegistry.java index f4cf288..f6605dd 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/WebContentsRegistry.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/WebContentsRegistry.java
@@ -46,7 +46,7 @@ public static void initializeWebContents( WebContents webContents, ContentView contentView, WindowAndroid window) { for (WebContentsHolder holder : sSesionIdToWebContents.values()) { - if (holder.webContents.equals(webContents)) { + if (holder.webContents.equals(webContents) && !webContents.isDestroyed()) { if (!holder.initialized) { // TODO(derekjchow): productVersion webContents.initialize("", ViewAndroidDelegate.createBasicDelegate(contentView),
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java index 85b3fc1..34e5ad5c 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
@@ -143,6 +143,44 @@ } @Test + public void testServiceBoundWhenActivityIsHidden() { + Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); + + CastWebContentsComponent component = + new CastWebContentsComponent(SESSION_ID, null, null, false, false, true); + component.start(mStartParams, false); + + LocalBroadcastManager.getInstance(ContextUtils.getApplicationContext()) + .sendBroadcastSync(CastWebContentsIntentUtils.onVisibilityChange( + SESSION_ID, CastWebContentsIntentUtils.VISIBITY_TYPE_HIDDEN)); + + ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class); + verify(mActivity).bindService( + intent.capture(), any(ServiceConnection.class), eq(Context.BIND_AUTO_CREATE)); + Assert.assertEquals(intent.getValue().getComponent().getClassName(), + CastWebContentsService.class.getName()); + } + + @Test + public void testServiceUnboundWhenActivityIsShown() { + Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); + + CastWebContentsComponent component = + new CastWebContentsComponent(SESSION_ID, null, null, false, false, true); + component.start(mStartParams, false); + + LocalBroadcastManager.getInstance(ContextUtils.getApplicationContext()) + .sendBroadcastSync(CastWebContentsIntentUtils.onVisibilityChange( + SESSION_ID, CastWebContentsIntentUtils.VISIBITY_TYPE_HIDDEN)); + + LocalBroadcastManager.getInstance(ContextUtils.getApplicationContext()) + .sendBroadcastSync(CastWebContentsIntentUtils.onVisibilityChange( + SESSION_ID, CastWebContentsIntentUtils.VISIBITY_TYPE_FULL_SCREEN)); + + verify(mActivity).unbindService(any(ServiceConnection.class)); + } + + @Test public void testEnableTouchInputSendsEnableTouchToActivity() { Assume.assumeTrue(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE);
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsServiceTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsServiceTest.java index b15aa4fc..fb7866b 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsServiceTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsServiceTest.java
@@ -141,13 +141,6 @@ } @Test - public void testBroadcastsComponentClosedWhenUnbind() { - mServiceLifecycle.bind(); - IntentFilter filter = filterFor(CastWebContentsIntentUtils.ACTION_ACTIVITY_STOPPED); - expectBroadcastedIntent(filter, () -> mServiceLifecycle.unbind()); - } - - @Test public void testDisplaysContentsOnBindAndReleasesOnUnbind() { ReactiveRecorder recordWebContentsPresentation = ReactiveRecorder.record(mService.observeWebContentsStateForTesting());
diff --git a/chromecast/cast_core/runtime/browser/BUILD.gn b/chromecast/cast_core/runtime/browser/BUILD.gn index 55fb4af..14d0f70a 100644 --- a/chromecast/cast_core/runtime/browser/BUILD.gn +++ b/chromecast/cast_core/runtime/browser/BUILD.gn
@@ -172,13 +172,6 @@ } } -cast_source_set("runtime_application_watcher") { - sources = [ - "runtime_application_watcher.cc", - "runtime_application_watcher.h", - ] -} - cast_source_set("runtime_application_dispatcher") { sources = [ "runtime_application_base.cc", @@ -195,7 +188,6 @@ ":grpc_webui", ":metrics_recorder", ":runtime_application", - ":runtime_application_watcher", "//base", "//chromecast/browser:browser_base", "//chromecast/common:feature_constants", @@ -255,17 +247,18 @@ deps = [ ":core_browser_cast_service", - ":runtime_application_watcher", "//base", "//chromecast/cast_core/runtime/common:cors_exempt_headers", "//components/url_rewrite/browser", "//components/url_rewrite/common", "//content/public/common", "//media", - "//third_party/cast_core/public/src/proto/runtime:runtime_service_proto", ] - public_deps = [ "//chromecast/browser:browser_base" ] + public_deps = [ + ":runtime_application_dispatcher", + "//chromecast/browser:browser_base", + ] if (enable_cast_media_runtime) { sources += [ "cast_content_browser_client_factory.cc" ]
diff --git a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc index 6a1364f0..ed69a0ce 100644 --- a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc +++ b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.cc
@@ -25,7 +25,11 @@ CastFeatureListCreator* feature_list_creator) : shell::CastContentBrowserClient(feature_list_creator) {} -CastRuntimeContentBrowserClient::~CastRuntimeContentBrowserClient() = default; +CastRuntimeContentBrowserClient::~CastRuntimeContentBrowserClient() { + if (core_browser_cast_service_) { + core_browser_cast_service_->app_dispatcher()->RemoveObserver(this); + } +} CoreBrowserCastService* CastRuntimeContentBrowserClient::GetCastService() { return core_browser_cast_service_; @@ -48,9 +52,11 @@ }, this); auto core_browser_cast_service = std::make_unique<CoreBrowserCastService>( - web_service, std::move(network_context_getter), video_plane_controller, - this); + web_service, std::move(network_context_getter), video_plane_controller); core_browser_cast_service_ = core_browser_cast_service.get(); + + core_browser_cast_service_->app_dispatcher()->AddObserver(this); + return core_browser_cast_service; } @@ -80,50 +86,19 @@ return origin.host() == kCastWebUIHomeHost; } -std::vector<std::unique_ptr<blink::URLLoaderThrottle>> -CastRuntimeContentBrowserClient::CreateURLLoaderThrottles( - const network::ResourceRequest& request, - content::BrowserContext* browser_context, - const base::RepeatingCallback<content::WebContents*()>& wc_getter, - content::NavigationUIData* navigation_ui_data, - int frame_tree_node_id) { - std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles; - auto url_rewrite_rules_throttle = - CreateUrlRewriteRulesThrottle(wc_getter.Run()); - if (url_rewrite_rules_throttle) { - throttles.emplace_back(std::move(url_rewrite_rules_throttle)); - } - return throttles; -} - -std::unique_ptr<blink::URLLoaderThrottle> -CastRuntimeContentBrowserClient::CreateUrlRewriteRulesThrottle( - content::WebContents* web_contents) { - DCHECK(runtime_application_); - - const auto& rules = runtime_application_->GetCastWebContents() - ->url_rewrite_rules_manager() - ->GetCachedRules(); - if (!rules) { - LOG(WARNING) << "Can't create URL throttle as URL rules are not available"; - return nullptr; - } - - return std::make_unique<url_rewrite::URLLoaderThrottle>( - rules, base::BindRepeating(&IsHeaderCorsExempt)); -} - bool CastRuntimeContentBrowserClient::IsBufferingEnabled() { - bool is_buffering_enabled = !is_runtime_application_for_streaming_.load(); - LOG_IF(INFO, !is_buffering_enabled) << "Buffering has been disabled!"; - return is_buffering_enabled; + return is_buffering_enabled_.load(); } -void CastRuntimeContentBrowserClient::OnRuntimeApplicationChanged( - RuntimeApplication* application) { - runtime_application_ = application; - is_runtime_application_for_streaming_.store( - runtime_application_ && runtime_application_->IsStreamingApplication()); +void CastRuntimeContentBrowserClient::OnForegroundApplicationChanged( + RuntimeApplication* app) { + bool enabled = true; + // Buffering must be disabled for streaming applications. + if (app && app->IsStreamingApplication()) { + enabled = false; + } + is_buffering_enabled_.store(enabled); + LOG(INFO) << "Buffering is " << (enabled ? "enabled" : "disabled"); } } // namespace chromecast
diff --git a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h index e620272..f8e5d390 100644 --- a/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h +++ b/chromecast/cast_core/runtime/browser/cast_runtime_content_browser_client.h
@@ -8,7 +8,7 @@ #include <atomic> #include "chromecast/browser/cast_content_browser_client.h" -#include "chromecast/cast_core/runtime/browser/runtime_application_watcher.h" +#include "chromecast/cast_core/runtime/browser/runtime_application_dispatcher.h" namespace chromecast { @@ -16,8 +16,9 @@ class CastFeatureListCreator; class RuntimeApplication; -class CastRuntimeContentBrowserClient : public shell::CastContentBrowserClient, - public RuntimeApplicationWatcher { +class CastRuntimeContentBrowserClient + : public shell::CastContentBrowserClient, + public RuntimeApplicationDispatcher::Observer { public: static std::unique_ptr<CastRuntimeContentBrowserClient> Create( CastFeatureListCreator* feature_list_creator); @@ -41,37 +42,19 @@ shell::AccessibilityServiceImpl* accessibility_service) override; std::unique_ptr<::media::CdmFactory> CreateCdmFactory( ::media::mojom::FrameInterfaceFactory* frame_interfaces) override; - // This function is used to allow/disallow WebUIs to make network requests. bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override; void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) override; - std::vector<std::unique_ptr<blink::URLLoaderThrottle>> - CreateURLLoaderThrottles( - const network::ResourceRequest& request, - content::BrowserContext* browser_context, - const base::RepeatingCallback<content::WebContents*()>& wc_getter, - content::NavigationUIData* navigation_ui_data, - int frame_tree_node_id) override; bool IsBufferingEnabled() override; + // RuntimeApplicationDispatcher::Observer implementation: + void OnForegroundApplicationChanged(RuntimeApplication* app) override; + private: - // RuntimeApplicationWatcher overrides: - void OnRuntimeApplicationChanged(RuntimeApplication* application) override; - - std::unique_ptr<blink::URLLoaderThrottle> CreateUrlRewriteRulesThrottle( - content::WebContents* web_contents); - - // The current application running in this runtime, or nullptr if no such app - // exists - RuntimeApplication* runtime_application_ = nullptr; - - // Tracks whether the current application is a streaming application, for the - // purposes of disabling buffering. - std::atomic_bool is_runtime_application_for_streaming_{false}; - // An instance of |CoreBrowserCastService| created once during the lifetime of // the runtime. CoreBrowserCastService* core_browser_cast_service_ = nullptr; + std::atomic_bool is_buffering_enabled_{false}; }; } // namespace chromecast
diff --git a/chromecast/cast_core/runtime/browser/core_browser_cast_service.cc b/chromecast/cast_core/runtime/browser/core_browser_cast_service.cc index 25eab23..09ec52f 100644 --- a/chromecast/cast_core/runtime/browser/core_browser_cast_service.cc +++ b/chromecast/cast_core/runtime/browser/core_browser_cast_service.cc
@@ -8,6 +8,7 @@ #include "base/process/process.h" #include "chromecast/browser/cast_browser_process.h" #include "chromecast/cast_core/cast_core_switches.h" +#include "chromecast/cast_core/runtime/browser/runtime_application.h" #include "chromecast/metrics/cast_event_builder_simple.h" namespace chromecast { @@ -15,15 +16,11 @@ CoreBrowserCastService::CoreBrowserCastService( CastWebService* web_service, NetworkContextGetter network_context_getter, - media::VideoPlaneController* video_plane_controller, - RuntimeApplicationWatcher* application_watcher) + media::VideoPlaneController* video_plane_controller) : app_dispatcher_(web_service, this, std::move(network_context_getter), - video_plane_controller, - application_watcher) {} - -CoreBrowserCastService::~CoreBrowserCastService() = default; + video_plane_controller) {} void CoreBrowserCastService::InitializeInternal() {}
diff --git a/chromecast/cast_core/runtime/browser/core_browser_cast_service.h b/chromecast/cast_core/runtime/browser/core_browser_cast_service.h index 31e42b42..e3f7d58 100644 --- a/chromecast/cast_core/runtime/browser/core_browser_cast_service.h +++ b/chromecast/cast_core/runtime/browser/core_browser_cast_service.h
@@ -24,7 +24,6 @@ class CastWebService; class WebCryptoServer; -class RuntimeApplicationWatcher; namespace receiver { class MediaManager; @@ -47,9 +46,10 @@ CoreBrowserCastService(CastWebService* web_service, NetworkContextGetter network_context_getter, - media::VideoPlaneController* video_plane_controller, - RuntimeApplicationWatcher* application_watcher); - ~CoreBrowserCastService() override; + media::VideoPlaneController* video_plane_controller); + + // Flags if buffering is enabled. + RuntimeApplicationDispatcher* app_dispatcher() { return &app_dispatcher_; } // Returns WebCryptoServer. virtual WebCryptoServer* GetWebCryptoServer(); @@ -57,7 +57,7 @@ // Returns MediaManager. virtual receiver::MediaManager* GetMediaManager(); - protected: + private: // CastService implementation: void InitializeInternal() override; void FinalizeInternal() override;
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.cc b/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.cc index 3b256b4..cea811d 100644 --- a/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.cc +++ b/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.cc
@@ -7,12 +7,12 @@ #include "base/check.h" #include "base/logging.h" #include "base/notreached.h" +#include "base/ranges/algorithm.h" #include "base/task/bind_post_task.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "chromecast/browser/cast_content_window.h" #include "chromecast/browser/cast_web_service.h" -#include "chromecast/cast_core/runtime/browser/runtime_application_watcher.h" #include "chromecast/cast_core/runtime/browser/streaming_runtime_application.h" #include "chromecast/cast_core/runtime/browser/web_runtime_application.h" #include "third_party/cast_core/public/src/proto/common/application_config.pb.h" @@ -32,13 +32,11 @@ CastWebService* web_service, CastRuntimeMetricsRecorder::EventBuilderFactory* event_builder_factory, cast_streaming::NetworkContextGetter network_context_getter, - media::VideoPlaneController* video_plane_controller, - RuntimeApplicationWatcher* application_watcher) + media::VideoPlaneController* video_plane_controller) : web_service_(web_service), network_context_getter_(std::move(network_context_getter)), metrics_recorder_(event_builder_factory), video_plane_controller_(video_plane_controller), - application_watcher_(application_watcher), task_runner_(base::SequencedTaskRunnerHandle::Get()) { DCHECK(web_service_); @@ -50,6 +48,18 @@ Stop(); } +void RuntimeApplicationDispatcher::AddObserver(Observer* observer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(observer); + observers_.AddObserver(observer); +} + +void RuntimeApplicationDispatcher::RemoveObserver(Observer* observer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(observer); + observers_.RemoveObserver(observer); +} + bool RuntimeApplicationDispatcher::Start( const std::string& runtime_id, const std::string& runtime_service_endpoint) { @@ -108,7 +118,7 @@ void RuntimeApplicationDispatcher::Stop() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - ResetApp(); + loaded_apps_.clear(); if (heartbeat_reactor_) { heartbeat_timer_.Stop(); @@ -137,66 +147,92 @@ "Application session ID is missing")); return; } + if (loaded_apps_.contains(request.cast_session_id())) { + reactor->Write(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Application already exists")); + return; + } if (!request.has_application_config()) { reactor->Write( grpc::Status(grpc::INVALID_ARGUMENT, "Application config is missing")); return; } - const std::string& app_id = request.application_config().app_id(); - if (openscreen::cast::IsCastStreamingReceiverAppId(app_id)) { + std::unique_ptr<RuntimeApplication> app; + if (openscreen::cast::IsCastStreamingReceiverAppId( + request.application_config().app_id())) { DCHECK(video_plane_controller_); // Deliberately copy |network_context_getter_|. - app_ = std::make_unique<StreamingRuntimeApplication>( + app = std::make_unique<StreamingRuntimeApplication>( request.cast_session_id(), request.application_config(), web_service_, task_runner_, network_context_getter_, video_plane_controller_); } else { - app_ = std::make_unique<WebRuntimeApplication>(request.cast_session_id(), - request.application_config(), - web_service_, task_runner_); + app = std::make_unique<WebRuntimeApplication>(request.cast_session_id(), + request.application_config(), + web_service_, task_runner_); } - if (application_watcher_) { - application_watcher_->OnRuntimeApplicationChanged(app_.get()); - } + // TODO(b/232140331): Call this only when foreground app changes. + base::ranges::for_each(observers_, [app = app.get()](auto& observer) { + observer.OnForegroundApplicationChanged(app); + }); - app_->Load( + // Need to cache session_id as |request| object is moved. + std::string session_id = request.cast_session_id(); + app->Load( std::move(request), base::BindPostTask( task_runner_, base::BindOnce(&RuntimeApplicationDispatcher::OnApplicationLoaded, - weak_factory_.GetWeakPtr(), std::move(reactor)))); + weak_factory_.GetWeakPtr(), session_id, + std::move(reactor)))); + + loaded_apps_.emplace(std::move(session_id), std::move(app)); } void RuntimeApplicationDispatcher::HandleLaunchApplication( cast::runtime::LaunchApplicationRequest request, cast::runtime::RuntimeServiceHandler::LaunchApplication::Reactor* reactor) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - app_->Launch( + // Need to cache session_id as |request| object is moved. + std::string session_id = request.cast_session_id(); + auto* app = GetApp(session_id); + if (!app) { + LOG(ERROR) << "Application doesn't exist anymore: session_id" << session_id; + reactor->Write( + grpc::Status(grpc::StatusCode::NOT_FOUND, "Application not found")); + return; + } + + app->Launch( std::move(request), base::BindPostTask( task_runner_, base::BindOnce(&RuntimeApplicationDispatcher::OnApplicationLaunched, - weak_factory_.GetWeakPtr(), std::move(reactor)))); + weak_factory_.GetWeakPtr(), std::move(session_id), + std::move(reactor)))); } void RuntimeApplicationDispatcher::HandleStopApplication( cast::runtime::StopApplicationRequest request, cast::runtime::RuntimeServiceHandler::StopApplication::Reactor* reactor) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!app_) { - reactor->Write(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, - "No application is running")); + auto* app = GetApp(request.cast_session_id()); + if (!app) { + LOG(ERROR) << "Application doesn't exist anymore: session_id" + << request.cast_session_id(); + reactor->Write( + grpc::Status(grpc::StatusCode::NOT_FOUND, "Application not found")); return; } // Reset the app only after the response is constructed. cast::runtime::StopApplicationResponse response; - response.set_app_id(app_->GetAppConfig().app_id()); - response.set_cast_session_id(app_->GetCastSessionId()); - - ResetApp(); + response.set_app_id(app->GetAppConfig().app_id()); + response.set_cast_session_id(app->GetCastSessionId()); reactor->Write(std::move(response)); + + ResetApp(request.cast_session_id()); } void RuntimeApplicationDispatcher::HandleHeartbeat( @@ -258,34 +294,52 @@ } void RuntimeApplicationDispatcher::OnApplicationLoaded( + std::string session_id, cast::runtime::RuntimeServiceHandler::LoadApplication::Reactor* reactor, grpc::Status status) { + auto* app = GetApp(session_id); + if (!app) { + LOG(ERROR) << "Application doesn't exist anymore: session_id" << session_id; + reactor->Write( + grpc::Status(grpc::StatusCode::NOT_FOUND, "Application not found")); + return; + } + if (!status.ok()) { - LOG(ERROR) << "Failed to load application: " << *app_ + LOG(ERROR) << "Failed to load application: " << *app << ", status=" << cast::utils::GrpcStatusToString(status); - ResetApp(); + ResetApp(session_id); reactor->Write(status); return; } - LOG(INFO) << "Application loaded: " << *app_; + LOG(INFO) << "Application loaded: " << *app; cast::runtime::LoadApplicationResponse response; response.mutable_message_port_info(); reactor->Write(std::move(response)); } void RuntimeApplicationDispatcher::OnApplicationLaunched( + std::string session_id, cast::runtime::RuntimeServiceHandler::LaunchApplication::Reactor* reactor, grpc::Status status) { + auto* app = GetApp(session_id); + if (!app) { + LOG(ERROR) << "Application doesn't exist anymore: session_id" << session_id; + reactor->Write( + grpc::Status(grpc::StatusCode::NOT_FOUND, "Application not found")); + return; + } + if (!status.ok()) { - LOG(ERROR) << "Failed to launch application: " << *app_ + LOG(ERROR) << "Failed to launch application: " << *app << ", status=" << cast::utils::GrpcStatusToString(status); - ResetApp(); + ResetApp(session_id); reactor->Write(status); return; } - LOG(INFO) << "Application launched: " << *app_; + LOG(INFO) << "Application launched: " << *app; reactor->Write(cast::runtime::LaunchApplicationResponse()); } @@ -356,24 +410,31 @@ reactor->Write(cast::runtime::StopMetricsRecorderResponse()); } -void RuntimeApplicationDispatcher::ResetApp() { - app_.reset(); - if (application_watcher_) { - application_watcher_->OnRuntimeApplicationChanged(nullptr); +RuntimeApplication* RuntimeApplicationDispatcher::GetApp( + const std::string& session_id) const { + auto iter = loaded_apps_.find(session_id); + if (iter == loaded_apps_.end()) { + return nullptr; } + return iter->second.get(); +} + +void RuntimeApplicationDispatcher::ResetApp(const std::string& session_id) { + auto iter = loaded_apps_.find(session_id); + DCHECK(iter != loaded_apps_.end()); + loaded_apps_.erase(iter); + + // TODO(b/232140331): Call this only when foreground app changes. + base::ranges::for_each(observers_, [](auto& observer) { + observer.OnForegroundApplicationChanged(nullptr); + }); } const std::string& RuntimeApplicationDispatcher::GetCastMediaServiceEndpoint() const { - return app_->GetCastMediaServiceEndpoint(); -} - -CastWebService* RuntimeApplicationDispatcher::GetCastWebService() const { - return web_service_; -} - -RuntimeApplication* RuntimeApplicationDispatcher::GetRuntimeApplication() { - return app_.get(); + // TODO(b/232140331): Call this only when foreground app changes. + DCHECK(!loaded_apps_.empty()); + return loaded_apps_.begin()->second->GetCastMediaServiceEndpoint(); } } // namespace chromecast
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.h b/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.h index 8b61a0a..103a295 100644 --- a/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.h +++ b/chromecast/cast_core/runtime/browser/runtime_application_dispatcher.h
@@ -7,7 +7,10 @@ #include <memory> +#include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/observer_list_types.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chromecast/cast_core/grpc/grpc_server.h" @@ -27,26 +30,33 @@ class CastWebService; class RuntimeApplication; -class RuntimeApplicationWatcher; -class RuntimeApplicationDispatcher { +class RuntimeApplicationDispatcher final { public: + // Observer interface for dispatcher notifications. + class Observer : public base::CheckedObserver { + public: + // Called with a valid pointer when application is brought to the + // foreground. Otherwise a nullptr is passed. + virtual void OnForegroundApplicationChanged(RuntimeApplication* app) = 0; + }; + RuntimeApplicationDispatcher( CastWebService* web_service, CastRuntimeMetricsRecorder::EventBuilderFactory* event_builder_factory, cast_streaming::NetworkContextGetter network_context_getter, - media::VideoPlaneController* video_plane_controller, - RuntimeApplicationWatcher* application_watcher); + media::VideoPlaneController* video_plane_controller); ~RuntimeApplicationDispatcher(); + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + // Starts and stops the runtime service, including the gRPC completion queue. bool Start(const std::string& runtime_id, const std::string& runtime_service_endpoint); void Stop(); const std::string& GetCastMediaServiceEndpoint() const; - CastWebService* GetCastWebService() const; - RuntimeApplication* GetRuntimeApplication(); private: // RuntimeService gRPC handlers: @@ -74,9 +84,11 @@ // Helper methods. void OnApplicationLoaded( + std::string session_id, cast::runtime::RuntimeServiceHandler::LoadApplication::Reactor* reactor, grpc::Status status); void OnApplicationLaunched( + std::string session_id, cast::runtime::RuntimeServiceHandler::LaunchApplication::Reactor* reactor, grpc::Status status); void SendHeartbeat(); @@ -94,12 +106,29 @@ void OnMetricsRecorderServiceStopped( cast::runtime::RuntimeServiceHandler::StopMetricsRecorder::Reactor* reactor); - void ResetApp(); + // Returns an app for the |session_id| or nullptr if not found. + RuntimeApplication* GetApp(const std::string& session_id) const; + // Destroys the app for the |session_id|. + void ResetApp(const std::string& session_id); + SEQUENCE_CHECKER(sequence_checker_); CastWebService* const web_service_; cast_streaming::NetworkContextGetter network_context_getter_; - std::unique_ptr<RuntimeApplication> app_; + CastRuntimeMetricsRecorder metrics_recorder_; + media::VideoPlaneController* const video_plane_controller_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; + base::ObserverList<Observer> observers_; + base::flat_map<std::string, std::unique_ptr<RuntimeApplication>> loaded_apps_; + + // Allows histogram and action recording, which can be reported by + // CastRuntimeMetricsRecorderService if Cast Core starts it. + CastRuntimeActionRecorder action_recorder_; + + absl::optional<cast::utils::GrpcServer> grpc_server_; + absl::optional<cast::metrics::MetricsRecorderServiceStub> + metrics_recorder_stub_; + absl::optional<CastRuntimeMetricsRecorderService> metrics_recorder_service_; // Heartbeat period as set by Cast Core. base::TimeDelta heartbeat_period_; // Heartbeat timeout timer. @@ -108,22 +137,6 @@ cast::runtime::RuntimeServiceHandler::Heartbeat::Reactor* heartbeat_reactor_ = nullptr; - // Allows histogram and action recording, which can be reported by - // CastRuntimeMetricsRecorderService if Cast Core starts it. - CastRuntimeMetricsRecorder metrics_recorder_; - CastRuntimeActionRecorder action_recorder_; - - absl::optional<cast::utils::GrpcServer> grpc_server_; - absl::optional<cast::metrics::MetricsRecorderServiceStub> - metrics_recorder_stub_; - absl::optional<CastRuntimeMetricsRecorderService> metrics_recorder_service_; - - media::VideoPlaneController* video_plane_controller_; - RuntimeApplicationWatcher* application_watcher_; - - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<RuntimeApplicationDispatcher> weak_factory_{this}; };
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_watcher.cc b/chromecast/cast_core/runtime/browser/runtime_application_watcher.cc deleted file mode 100644 index ef01faf..0000000 --- a/chromecast/cast_core/runtime/browser/runtime_application_watcher.cc +++ /dev/null
@@ -1,11 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromecast/cast_core/runtime/browser/runtime_application_watcher.h" - -namespace chromecast { - -RuntimeApplicationWatcher::~RuntimeApplicationWatcher() = default; - -} // namespace chromecast
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_watcher.h b/chromecast/cast_core/runtime/browser/runtime_application_watcher.h deleted file mode 100644 index 6dd2319..0000000 --- a/chromecast/cast_core/runtime/browser/runtime_application_watcher.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMECAST_CAST_CORE_RUNTIME_BROWSER_RUNTIME_APPLICATION_WATCHER_H_ -#define CHROMECAST_CAST_CORE_RUNTIME_BROWSER_RUNTIME_APPLICATION_WATCHER_H_ - -namespace chromecast { - -class RuntimeApplication; - -// This class is responsible for providing a callback when the current runtime -// application changes. -class RuntimeApplicationWatcher { - public: - virtual ~RuntimeApplicationWatcher(); - - // Called when the current runtime application changes, with |application| - // being a pointer to this instance or nullptr if no such instance exists. - virtual void OnRuntimeApplicationChanged(RuntimeApplication* application) = 0; -}; - -} // namespace chromecast - -#endif // CHROMECAST_CAST_CORE_RUNTIME_BROWSER_RUNTIME_APPLICATION_WATCHER_H_
diff --git a/chromeos/components/quick_answers/quick_answers_client.cc b/chromeos/components/quick_answers/quick_answers_client.cc index ad7dfc1..92d66fce 100644 --- a/chromeos/components/quick_answers/quick_answers_client.cc +++ b/chromeos/components/quick_answers/quick_answers_client.cc
@@ -11,7 +11,6 @@ #include "chromeos/components/quick_answers/utils/quick_answers_metrics.h" #include "chromeos/components/quick_answers/utils/quick_answers_utils.h" #include "chromeos/components/quick_answers/utils/spell_checker.h" -#include "chromeos/constants/chromeos_features.h" #include "services/network/public/cpp/shared_url_loader_factory.h" namespace quick_answers { @@ -39,11 +38,9 @@ QuickAnswersClient::QuickAnswersClient( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, QuickAnswersDelegate* delegate) - : url_loader_factory_(url_loader_factory), delegate_(delegate) { - if (chromeos::features::IsQuickAnswersAlwaysTriggerForSingleWord()) { - spell_checker_ = std::make_unique<SpellChecker>(url_loader_factory); - } -} + : url_loader_factory_(url_loader_factory), + delegate_(delegate), + spell_checker_(std::make_unique<SpellChecker>(url_loader_factory)) {} QuickAnswersClient::~QuickAnswersClient() = default;
diff --git a/chromeos/components/quick_answers/understanding/intent_generator.cc b/chromeos/components/quick_answers/understanding/intent_generator.cc index 0d3d51d5..df50080 100644 --- a/chromeos/components/quick_answers/understanding/intent_generator.cc +++ b/chromeos/components/quick_answers/understanding/intent_generator.cc
@@ -148,32 +148,30 @@ } void IntentGenerator::GenerateIntent(const QuickAnswersRequest& request) { - if (chromeos::features::IsQuickAnswersAlwaysTriggerForSingleWord()) { - const std::u16string& u16_text = base::UTF8ToUTF16(request.selected_text); - base::i18n::BreakIterator iter(u16_text, - base::i18n::BreakIterator::BREAK_WORD); - if (!iter.Init() || !iter.Advance()) { - NOTREACHED() << "Failed to load BreakIterator."; + const std::u16string& u16_text = base::UTF8ToUTF16(request.selected_text); + base::i18n::BreakIterator iter(u16_text, + base::i18n::BreakIterator::BREAK_WORD); + if (!iter.Init() || !iter.Advance()) { + NOTREACHED() << "Failed to load BreakIterator."; - std::move(complete_callback_) - .Run(IntentInfo(request.selected_text, IntentType::kUnknown)); - return; - } + std::move(complete_callback_) + .Run(IntentInfo(request.selected_text, IntentType::kUnknown)); + return; + } - DCHECK(spell_checker_.get()) << "spell_checker_ should exist when the " - "always trigger feature is enabled"; - // Check spelling if the selected text is a valid single word. - if (iter.IsWord() && iter.prev() == 0 && iter.pos() == u16_text.length()) { - // Search server do not provide useful information for proper nouns and - // abbreviations (such as "Amy" and "ASAP"). Check spelling of the word in - // lower case to filter out such cases. - auto text = base::UTF16ToUTF8( - base::i18n::ToLower(base::UTF8ToUTF16(request.selected_text))); - spell_checker_->CheckSpelling( - text, base::BindOnce(&IntentGenerator::CheckSpellingCallback, - weak_factory_.GetWeakPtr(), request)); - return; - } + DCHECK(spell_checker_.get()) << "spell_checker_ should exist when the " + "always trigger feature is enabled"; + // Check spelling if the selected text is a valid single word. + if (iter.IsWord() && iter.prev() == 0 && iter.pos() == u16_text.length()) { + // Search server do not provide useful information for proper nouns and + // abbreviations (such as "Amy" and "ASAP"). Check spelling of the word in + // lower case to filter out such cases. + auto text = base::UTF16ToUTF8( + base::i18n::ToLower(base::UTF8ToUTF16(request.selected_text))); + spell_checker_->CheckSpelling( + text, base::BindOnce(&IntentGenerator::CheckSpellingCallback, + weak_factory_.GetWeakPtr(), request)); + return; } // Fallback to text classifier.
diff --git a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc index eb074b6..1a33e09 100644 --- a/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc +++ b/chromeos/components/quick_answers/understanding/intent_generator_unittest.cc
@@ -8,14 +8,12 @@ #include <string> #include "base/bind.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" #include "chromeos/components/quick_answers/quick_answers_model.h" #include "chromeos/components/quick_answers/test/quick_answers_test_base.h" #include "chromeos/components/quick_answers/utils/quick_answers_utils.h" #include "chromeos/components/quick_answers/utils/spell_checker.h" -#include "chromeos/constants/chromeos_features.h" #include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h" #include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h" #include "chromeos/services/machine_learning/public/mojom/text_classifier.mojom.h" @@ -551,10 +549,6 @@ } TEST_F(IntentGeneratorTest, ShouldTriggerForSingleWordInDictionary) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kWord = "single"; // No Annotation provided. @@ -579,10 +573,6 @@ TEST_F(IntentGeneratorTest, ShouldNotTriggerForSingleWordInDictionaryWithDigits) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kWord = "1st"; // No Annotation provided. @@ -607,10 +597,6 @@ } TEST_F(IntentGeneratorTest, ShouldNotTriggerForProperNounInDictionary) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kWord = "Amy"; // No Annotation provided. @@ -636,10 +622,6 @@ TEST_F(IntentGeneratorTest, ShouldFallbackToAnnotationsForWordNotInDictionaryNoAnnotation) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kWord = "single"; // No Annotation provided, and not add the word to the dictionary. @@ -663,10 +645,6 @@ TEST_F( IntentGeneratorTest, ShouldFallbackToAnnotationsForWordNotInDictionaryWithDictionaryAnnotation) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kWord = "unfathomable"; // Annotation provided, and not add the word to the dictionary. @@ -699,10 +677,6 @@ TEST_F( IntentGeneratorTest, ShouldFallbackToAnnotationsForWordNotInDictionaryWithUnitConversionAnnotation) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - const std::string kText = "50kg"; // Annotation provided, and not add the text to the dictionary. @@ -733,10 +707,6 @@ } TEST_F(IntentGeneratorTest, ShouldNotTriggerForMultipleWords) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature( - chromeos::features::kQuickAnswersAlwaysTriggerForSingleWord); - // No Annotation provided. std::vector<TextAnnotationPtr> annotations; UseFakeServiceConnection(annotations);
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 715cc51..ccce310 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -42,10 +42,6 @@ const base::Feature kQuickAnswersV2SettingsSubToggle{ "QuickAnswersV2SettingsSubToggle", base::FEATURE_DISABLED_BY_DEFAULT}; -// Controls whether to always trigger Quick Answers with single word selection. -const base::Feature kQuickAnswersAlwaysTriggerForSingleWord{ - "QuickAnswersAlwaysTriggerForSingleWord", base::FEATURE_ENABLED_BY_DEFAULT}; - // Enables Quick Answers for more locales. const base::Feature kQuickAnswersForMoreLocales{ "QuickAnswersForMoreLocales", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -66,10 +62,6 @@ return base::FeatureList::IsEnabled(kQuickAnswersV2SettingsSubToggle); } -bool IsQuickAnswersAlwaysTriggerForSingleWord() { - return base::FeatureList::IsEnabled(kQuickAnswersAlwaysTriggerForSingleWord); -} - bool IsQuickAnswersForMoreLocalesEnabled() { return base::FeatureList::IsEnabled(kQuickAnswersForMoreLocales); }
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 9a9ee0c5..a963fcfa 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -34,8 +34,6 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kQuickAnswersV2SettingsSubToggle; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) -extern const base::Feature kQuickAnswersAlwaysTriggerForSingleWord; -COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kQuickAnswersForMoreLocales; // Keep alphabetized.
diff --git a/chromeos/network/cellular_metrics_logger.cc b/chromeos/network/cellular_metrics_logger.cc index 8708bb56..383ab68 100644 --- a/chromeos/network/cellular_metrics_logger.cc +++ b/chromeos/network/cellular_metrics_logger.cc
@@ -67,8 +67,12 @@ "Network.Cellular.PSim.ConnectionResult.All"; // static -const char CellularMetricsLogger::kSimPinLockSuccessHistogram[] = - "Network.Cellular.Pin.LockSuccess"; +const char CellularMetricsLogger::kSimPinRequireLockSuccessHistogram[] = + "Network.Cellular.Pin.RequireLockSuccess"; + +// static +const char CellularMetricsLogger::kSimPinRemoveLockSuccessHistogram[] = + "Network.Cellular.Pin.RemoveLockSuccess"; // static const char CellularMetricsLogger::kSimPinUnlockSuccessHistogram[] = @@ -121,8 +125,11 @@ : SimPinOperationResult::kSuccess; switch (pin_operation) { - case SimPinOperation::kLock: - base::UmaHistogramEnumeration(kSimPinLockSuccessHistogram, result); + case SimPinOperation::kRequireLock: + base::UmaHistogramEnumeration(kSimPinRequireLockSuccessHistogram, result); + return; + case SimPinOperation::kRemoveLock: + base::UmaHistogramEnumeration(kSimPinRemoveLockSuccessHistogram, result); return; case SimPinOperation::kUnlock: base::UmaHistogramEnumeration(kSimPinUnlockSuccessHistogram, result);
diff --git a/chromeos/network/cellular_metrics_logger.h b/chromeos/network/cellular_metrics_logger.h index 94079df..c90346b 100644 --- a/chromeos/network/cellular_metrics_logger.h +++ b/chromeos/network/cellular_metrics_logger.h
@@ -49,7 +49,8 @@ public NetworkConnectionObserver { public: // Histograms associated with SIM Pin operations. - static const char kSimPinLockSuccessHistogram[]; + static const char kSimPinRequireLockSuccessHistogram[]; + static const char kSimPinRemoveLockSuccessHistogram[]; static const char kSimPinUnlockSuccessHistogram[]; static const char kSimPinUnblockSuccessHistogram[]; static const char kSimPinChangeSuccessHistogram[]; @@ -65,10 +66,11 @@ // PIN operations that are tracked by metrics. enum class SimPinOperation { - kLock = 0, - kUnlock = 1, - kUnblock = 2, - kChange = 3, + kRequireLock = 0, + kRemoveLock = 1, + kUnlock = 2, + kUnblock = 3, + kChange = 4, }; // Records the result of pin operations performed.
diff --git a/chromeos/network/network_device_handler_impl.cc b/chromeos/network/network_device_handler_impl.cc index 0769095..3983a4b 100644 --- a/chromeos/network/network_device_handler_impl.cc +++ b/chromeos/network/network_device_handler_impl.cc
@@ -174,14 +174,16 @@ return; } + const CellularMetricsLogger::SimPinOperation pin_operation = + require_pin ? CellularMetricsLogger::SimPinOperation::kRequireLock + : CellularMetricsLogger::SimPinOperation::kRemoveLock; + NET_LOG(USER) << "Device.RequirePin: " << device_path << ": " << require_pin; ShillDeviceClient::Get()->RequirePin( dbus::ObjectPath(device_path), pin, require_pin, - base::BindOnce(&HandleSimPinOperationSuccess, - CellularMetricsLogger::SimPinOperation::kLock, + base::BindOnce(&HandleSimPinOperationSuccess, pin_operation, std::move(callback)), - base::BindOnce(&HandleSimPinOperationFailure, - CellularMetricsLogger::SimPinOperation::kLock, device_path, + base::BindOnce(&HandleSimPinOperationFailure, pin_operation, device_path, std::move(error_callback))); }
diff --git a/chromeos/network/network_device_handler_unittest.cc b/chromeos/network/network_device_handler_unittest.cc index 0e26b8a..9f06b89f0 100644 --- a/chromeos/network/network_device_handler_unittest.cc +++ b/chromeos/network/network_device_handler_unittest.cc
@@ -439,9 +439,9 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(kResultSuccess, result_); histogram_tester.ExpectTotalCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, 1); + CellularMetricsLogger::kSimPinRequireLockSuccessHistogram, 1); histogram_tester.ExpectBucketCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, + CellularMetricsLogger::kSimPinRequireLockSuccessHistogram, CellularMetricsLogger::SimPinOperationResult::kSuccess, 1); // Test that the shill error propagates to the error callback. @@ -452,9 +452,9 @@ EXPECT_EQ(NetworkDeviceHandler::kErrorDeviceMissing, result_); histogram_tester.ExpectTotalCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, 2); + CellularMetricsLogger::kSimPinRequireLockSuccessHistogram, 2); histogram_tester.ExpectBucketCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, + CellularMetricsLogger::kSimPinRequireLockSuccessHistogram, CellularMetricsLogger::SimPinOperationResult::kErrorUnknown, 1); } @@ -559,7 +559,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(NetworkDeviceHandler::kErrorBlockedByPolicy, result_); histogram_tester.ExpectTotalCount( - CellularMetricsLogger::kSimPinUnlockSuccessHistogram, 0); + CellularMetricsLogger::kSimPinRequireLockSuccessHistogram, 0); // Test that the success callback gets called when removing a PIN lock. network_device_handler_->RequirePin(kDefaultCellularDevicePath, false, @@ -567,6 +567,8 @@ GetErrorCallback()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kResultSuccess, result_); + histogram_tester.ExpectTotalCount( + CellularMetricsLogger::kSimPinRemoveLockSuccessHistogram, 1); } TEST_F(NetworkDeviceHandlerTest, ChangePinBlockedByPolicy) { @@ -602,7 +604,7 @@ base::RunLoop().RunUntilIdle(); histogram_tester.ExpectTotalCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, 0); + CellularMetricsLogger::kSimPinRemoveLockSuccessHistogram, 0); histogram_tester.ExpectTotalCount( CellularMetricsLogger::kSimPinUnlockSuccessHistogram, 1); @@ -616,7 +618,7 @@ base::RunLoop().RunUntilIdle(); histogram_tester.ExpectTotalCount( - CellularMetricsLogger::kSimPinLockSuccessHistogram, 1); + CellularMetricsLogger::kSimPinRemoveLockSuccessHistogram, 1); histogram_tester.ExpectTotalCount( CellularMetricsLogger::kSimPinUnlockSuccessHistogram, 1); }
diff --git a/components/browser_ui/settings/android/BUILD.gn b/components/browser_ui/settings/android/BUILD.gn index 5ffce69..5ec0d7f 100644 --- a/components/browser_ui/settings/android/BUILD.gn +++ b/components/browser_ui/settings/android/BUILD.gn
@@ -106,7 +106,18 @@ android_library("test_support_java") { testonly = true - sources = [ "widget/java/src/org/chromium/components/browser_ui/settings/PlaceholderSettingsForTest.java" ] + sources = [ + "java/src/org/chromium/components/browser_ui/settings/BlankUiTestActivitySettingsTestRule.java", + "widget/java/src/org/chromium/components/browser_ui/settings/PlaceholderSettingsForTest.java", + ] - deps = [ "//third_party/androidx:androidx_preference_preference_java" ] + deps = [ + "//base:base_java_test_support", + "//content/public/test/android:content_java_test_support", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_fragment_fragment_java", + "//third_party/androidx:androidx_preference_preference_java", + "//third_party/hamcrest:hamcrest_java", + "//ui/android:ui_java_test_support", + ] }
diff --git a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/BlankUiTestActivitySettingsTestRule.java b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/BlankUiTestActivitySettingsTestRule.java new file mode 100644 index 0000000..54181c9 --- /dev/null +++ b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/BlankUiTestActivitySettingsTestRule.java
@@ -0,0 +1,103 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.browser_ui.settings; + +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +import org.hamcrest.Matchers; + +import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.test.util.Criteria; +import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.test.util.BlankUiTestActivity; + +/** + * Facilitates testing of Fragments/Settings using the BlankUiTestActivity + */ +public class BlankUiTestActivitySettingsTestRule extends BaseActivityTestRule<BlankUiTestActivity> { + private PreferenceFragmentCompat mPreferenceFragment; + private PreferenceScreen mPreferenceScreen; + + public BlankUiTestActivitySettingsTestRule() { + super(BlankUiTestActivity.class); + } + + /** + * Ensures the activity is launched, and creates an instance of the preference class specified + * and attaches it. + * @param preferenceClass The preference type to be created. + */ + public void launchPreference(Class<? extends PreferenceFragmentCompat> preferenceClass) { + launchPreference(preferenceClass, null); + } + + /** + * Ensures the activity is launched, and creates an instance of the preference class specified + * and attaches it. + * @param preferenceClass The preference type to be created. + * @param fragmentArgs Optional arguments to be set on the fragment. + */ + public void launchPreference(Class<? extends PreferenceFragmentCompat> preferenceClass, + @Nullable Bundle fragmentArgs) { + if (getActivity() == null) launchActivity(null); + + PreferenceFragmentCompat preference = + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + PreferenceFragmentCompat fragment = + (PreferenceFragmentCompat) getActivity() + .getSupportFragmentManager() + .getFragmentFactory() + .instantiate(preferenceClass.getClassLoader(), + preferenceClass.getName()); + if (fragmentArgs != null) { + fragment.setArguments(fragmentArgs); + } + return fragment; + }); + launchPreference(preference); + } + + /** + * Ensures the activity is launched and attaches the given preference. + * @param preference The preference to be attached. + */ + public void launchPreference(PreferenceFragmentCompat preference) { + if (getActivity() == null) launchActivity(null); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + mPreferenceFragment = preference; + getActivity() + .getSupportFragmentManager() + .beginTransaction() + .replace(android.R.id.content, mPreferenceFragment) + .commit(); + }); + CriteriaHelper.pollUiThread(() -> { + Criteria.checkThat(mPreferenceFragment.getPreferenceManager(), Matchers.notNullValue()); + Criteria.checkThat(mPreferenceFragment.getPreferenceScreen(), Matchers.notNullValue()); + }); + TestThreadUtils.runOnUiThreadBlocking( + () -> { mPreferenceScreen = mPreferenceFragment.getPreferenceScreen(); }); + } + + /** + * @return The preference fragment attached in {@link #launchPreference}. + */ + public PreferenceFragmentCompat getPreferenceFragment() { + return mPreferenceFragment; + } + + /** + * @return The preference screen associated with the attached preference. + */ + public PreferenceScreen getPreferenceScreen() { + return mPreferenceScreen; + } +}
diff --git a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java index 9afd531c..f0c2210 100644 --- a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java +++ b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java
@@ -14,6 +14,8 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.stringContainsInOrder; +import android.app.Activity; + import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import androidx.test.espresso.ViewInteraction; @@ -21,16 +23,15 @@ import com.google.common.collect.ImmutableList; -import org.hamcrest.Matchers; import org.junit.Assert; +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.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Criteria; -import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivityTestCase; +import org.chromium.ui.test.util.DisableAnimationsTestRule; import java.util.List; @@ -38,36 +39,33 @@ * Tests of {@link ChromeBasePreference}. */ @RunWith(BaseJUnit4ClassRunner.class) -public class ChromeBasePreferenceTest extends BlankUiTestActivityTestCase { +public class ChromeBasePreferenceTest { + @ClassRule + public static final DisableAnimationsTestRule disableAnimationsRule = + new DisableAnimationsTestRule(); + @Rule + public final BlankUiTestActivitySettingsTestRule mSettingsRule = + new BlankUiTestActivitySettingsTestRule(); + private static final String TITLE = "Preference Title"; private static final String SUMMARY = "This is a summary."; + private Activity mActivity; private PreferenceFragmentCompat mPreferenceFragment; private PreferenceScreen mPreferenceScreen; - @Override - public void setUpTest() throws Exception { - super.setUpTest(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - mPreferenceFragment = new PlaceholderSettingsForTest(); - getActivity() - .getSupportFragmentManager() - .beginTransaction() - .replace(android.R.id.content, mPreferenceFragment) - .commit(); - }); - CriteriaHelper.pollUiThread(() -> { - Criteria.checkThat(mPreferenceFragment.getPreferenceManager(), Matchers.notNullValue()); - Criteria.checkThat(mPreferenceFragment.getPreferenceScreen(), Matchers.notNullValue()); - }); - TestThreadUtils.runOnUiThreadBlocking( - () -> { mPreferenceScreen = mPreferenceFragment.getPreferenceScreen(); }); + @Before + public void setUp() { + mSettingsRule.launchPreference(PlaceholderSettingsForTest.class); + mActivity = mSettingsRule.getActivity(); + mPreferenceFragment = mSettingsRule.getPreferenceFragment(); + mPreferenceScreen = mSettingsRule.getPreferenceScreen(); } @Test @SmallTest public void testUnmanagedPreference() { - ChromeBasePreference preference = new ChromeBasePreference(getActivity()); + ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.UNMANAGED_DELEGATE); @@ -83,7 +81,7 @@ @Test @SmallTest public void testPolicyManagedPreferenceWithoutSummary() { - ChromeBasePreference preference = new ChromeBasePreference(getActivity()); + ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); @@ -99,14 +97,14 @@ @Test @SmallTest public void testPolicyManagedPreferenceWithSummary() { - ChromeBasePreference preference = new ChromeBasePreference(getActivity()); + ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); List<String> expectedSummaryContains = ImmutableList.of( - SUMMARY, getActivity().getString(R.string.managed_by_your_organization)); + SUMMARY, mActivity.getString(R.string.managed_by_your_organization)); Assert.assertFalse(preference.isEnabled()); @@ -119,7 +117,7 @@ @Test @SmallTest public void testSingleCustodianManagedPreference() { - ChromeBasePreference preference = new ChromeBasePreference(getActivity()); + ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( ManagedPreferencesUtilsTest.SINGLE_CUSTODIAN_DELEGATE); @@ -136,7 +134,7 @@ @Test @SmallTest public void testMultipleCustodianManagedPreference() { - ChromeBasePreference preference = new ChromeBasePreference(getActivity()); + ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( ManagedPreferencesUtilsTest.MULTI_CUSTODIAN_DELEGATE);
diff --git a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java index cd044ecd..9e5c0be 100644 --- a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java +++ b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java
@@ -12,59 +12,56 @@ import static org.hamcrest.Matchers.allOf; +import android.app.Activity; + import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import androidx.test.espresso.ViewInteraction; import androidx.test.filters.SmallTest; -import org.hamcrest.Matchers; import org.junit.Assert; +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.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Criteria; -import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivityTestCase; +import org.chromium.ui.test.util.DisableAnimationsTestRule; /** * Tests of {@link ChromeImageViewPreference}. */ @RunWith(BaseJUnit4ClassRunner.class) -public class ChromeImageViewPreferenceTest extends BlankUiTestActivityTestCase { +public class ChromeImageViewPreferenceTest { private static final String TITLE = "Preference Title"; private static final String SUMMARY = "This is a summary."; private static final int DRAWABLE_RES = R.drawable.ic_folder_blue_24dp; private static final int CONTENT_DESCRIPTION_RES = R.string.ok; + @ClassRule + public static final DisableAnimationsTestRule disableAnimationsRule = + new DisableAnimationsTestRule(); + @Rule + public final BlankUiTestActivitySettingsTestRule mSettingsRule = + new BlankUiTestActivitySettingsTestRule(); + + private Activity mActivity; private PreferenceFragmentCompat mPreferenceFragment; private PreferenceScreen mPreferenceScreen; - @Override - public void setUpTest() throws Exception { - super.setUpTest(); - - TestThreadUtils.runOnUiThreadBlocking(() -> { - mPreferenceFragment = new PlaceholderSettingsForTest(); - getActivity() - .getSupportFragmentManager() - .beginTransaction() - .replace(android.R.id.content, mPreferenceFragment) - .commit(); - }); - CriteriaHelper.pollUiThread(() -> { - Criteria.checkThat(mPreferenceFragment.getPreferenceManager(), Matchers.notNullValue()); - Criteria.checkThat(mPreferenceFragment.getPreferenceScreen(), Matchers.notNullValue()); - }); - TestThreadUtils.runOnUiThreadBlocking( - () -> { mPreferenceScreen = mPreferenceFragment.getPreferenceScreen(); }); + @Before + public void setUp() { + mSettingsRule.launchPreference(PlaceholderSettingsForTest.class); + mActivity = mSettingsRule.getActivity(); + mPreferenceFragment = mSettingsRule.getPreferenceFragment(); + mPreferenceScreen = mSettingsRule.getPreferenceScreen(); } @Test @SmallTest public void testChromeImageViewPreference() { - ChromeImageViewPreference preference = new ChromeImageViewPreference(getActivity()); + ChromeImageViewPreference preference = new ChromeImageViewPreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); preference.setImageView(DRAWABLE_RES, CONTENT_DESCRIPTION_RES, null); @@ -80,7 +77,7 @@ @Test @SmallTest public void testChromeImageViewPreferenceManaged() { - ChromeImageViewPreference preference = new ChromeImageViewPreference(getActivity()); + ChromeImageViewPreference preference = new ChromeImageViewPreference(mActivity); preference.setTitle(TITLE); preference.setImageView(DRAWABLE_RES, CONTENT_DESCRIPTION_RES, null); preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE);
diff --git a/components/domain_reliability/context.cc b/components/domain_reliability/context.cc index 9bb8a2ad..411ac4e 100644 --- a/components/domain_reliability/context.cc +++ b/components/domain_reliability/context.cc
@@ -85,18 +85,6 @@ uploading_beacons_size_ = 0; } -base::Value DomainReliabilityContext::GetWebUIData() const { - base::Value context_value(base::Value::Type::DICTIONARY); - - context_value.SetStringKey("origin", config().origin.spec()); - context_value.SetIntKey("beacon_count", static_cast<int>(beacons_.size())); - context_value.SetIntKey("uploading_beacon_count", - static_cast<int>(uploading_beacons_size_)); - context_value.SetKey("scheduler", scheduler_.GetWebUIData()); - - return context_value; -} - void DomainReliabilityContext::GetQueuedBeaconsForTesting( std::vector<const DomainReliabilityBeacon*>* beacons_out) const { DCHECK(beacons_out);
diff --git a/components/domain_reliability/context.h b/components/domain_reliability/context.h index 10fad68..6799743 100644 --- a/components/domain_reliability/context.h +++ b/components/domain_reliability/context.h
@@ -69,10 +69,6 @@ // Called to clear browsing data, since beacons are like browsing history. void ClearBeacons(); - // Gets a Value containing data that can be formatted into a web page for - // debugging purposes. - base::Value GetWebUIData() const; - // Gets the beacons queued for upload in this context. `*beacons_out` will be // cleared and filled with pointers to the beacons; the pointers remain valid // as long as no other requests are reported to the DomainReliabilityMonitor.
diff --git a/components/domain_reliability/context_manager.cc b/components/domain_reliability/context_manager.cc index a7c324c..60500728 100644 --- a/components/domain_reliability/context_manager.cc +++ b/components/domain_reliability/context_manager.cc
@@ -101,13 +101,6 @@ } } -base::Value DomainReliabilityContextManager::GetWebUIData() const { - base::Value contexts_value(base::Value::Type::LIST); - for (const auto& context_entry : contexts_) - contexts_value.Append(context_entry.second->GetWebUIData()); - return contexts_value; -} - DomainReliabilityContext* DomainReliabilityContextManager::GetContext( const std::string& host) const { ContextMap::const_iterator context_it = contexts_.find(host);
diff --git a/components/domain_reliability/context_manager.h b/components/domain_reliability/context_manager.h index 165bcca..71fbaecc 100644 --- a/components/domain_reliability/context_manager.h +++ b/components/domain_reliability/context_manager.h
@@ -81,8 +81,6 @@ // |uploader_| needs to be set before any contexts are created. void SetUploader(DomainReliabilityUploader* uploader); - base::Value GetWebUIData() const; - size_t contexts_size_for_testing() const { return contexts_.size(); } private:
diff --git a/components/domain_reliability/monitor.cc b/components/domain_reliability/monitor.cc index 6c61b80..7e085b0 100644 --- a/components/domain_reliability/monitor.cc +++ b/components/domain_reliability/monitor.cc
@@ -156,12 +156,6 @@ } } -base::Value DomainReliabilityMonitor::GetWebUIData() const { - base::Value data_value(base::Value::Type::DICTIONARY); - data_value.SetKey("contexts", context_manager_.GetWebUIData()); - return data_value; -} - const DomainReliabilityContext* DomainReliabilityMonitor::AddContextForTesting( std::unique_ptr<const DomainReliabilityConfig> config) { DCHECK(config);
diff --git a/components/domain_reliability/monitor.h b/components/domain_reliability/monitor.h index 6ca305d..12e32be2 100644 --- a/components/domain_reliability/monitor.h +++ b/components/domain_reliability/monitor.h
@@ -30,10 +30,6 @@ #include "net/http/http_response_info.h" #include "net/socket/connection_attempts.h" -namespace base { -class Value; -} // namespace base - namespace net { class URLRequest; class URLRequestContext; @@ -125,10 +121,6 @@ DomainReliabilityClearMode mode, const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter); - // Gets a Value containing data that can be formatted into a web page for - // debugging purposes. - base::Value GetWebUIData() const; - // Returns pointer to the added context. const DomainReliabilityContext* AddContextForTesting( std::unique_ptr<const DomainReliabilityConfig> config);
diff --git a/components/domain_reliability/scheduler.cc b/components/domain_reliability/scheduler.cc index 86856ab..6bb90e78 100644 --- a/components/domain_reliability/scheduler.cc +++ b/components/domain_reliability/scheduler.cc
@@ -83,8 +83,7 @@ upload_pending_(false), upload_scheduled_(false), upload_running_(false), - collector_index_(kInvalidCollectorIndex), - last_upload_finished_(false) { + collector_index_(kInvalidCollectorIndex) { backoff_policy_.num_errors_to_ignore = 0; backoff_policy_.initial_delay_ms = params.upload_retry_interval.InMilliseconds(); @@ -123,9 +122,6 @@ VLOG(1) << "Starting upload to collector " << collector_index_ << "."; - last_upload_start_time_ = now; - last_upload_collector_index_ = collector_index_; - return collector_index_; } @@ -152,50 +148,9 @@ first_beacon_time_ = old_first_beacon_time_; } - last_upload_end_time_ = time_->NowTicks(); - last_upload_success_ = result.is_success(); - last_upload_finished_ = true; - MaybeScheduleUpload(); } -base::Value DomainReliabilityScheduler::GetWebUIData() const { - base::TimeTicks now = time_->NowTicks(); - - base::Value data(base::Value::Type::DICTIONARY); - - data.SetBoolKey("upload_pending", upload_pending_); - data.SetBoolKey("upload_scheduled", upload_scheduled_); - data.SetBoolKey("upload_running", upload_running_); - - data.SetIntKey("scheduled_min", (scheduled_min_time_ - now).InSeconds()); - data.SetIntKey("scheduled_max", (scheduled_max_time_ - now).InSeconds()); - - data.SetIntKey("collector_index", static_cast<int>(collector_index_)); - - if (last_upload_finished_) { - base::Value last(base::Value::Type::DICTIONARY); - last.SetIntKey("start_time", (now - last_upload_start_time_).InSeconds()); - last.SetIntKey("end_time", (now - last_upload_end_time_).InSeconds()); - last.SetIntKey("collector_index", - static_cast<int>(last_upload_collector_index_)); - last.SetBoolKey("success", last_upload_success_); - data.SetKey("last_upload", std::move(last)); - } - - base::Value collectors_value(base::Value::Type::LIST); - for (const auto& collector : collectors_) { - base::Value value(base::Value::Type::DICTIONARY); - value.SetIntKey("failures", collector->failure_count()); - value.SetIntKey("next_upload", - (collector->GetReleaseTime() - now).InSeconds()); - collectors_value.Append(std::move(value)); - } - data.SetKey("collectors", std::move(collectors_value)); - - return data; -} - void DomainReliabilityScheduler::MakeDeterministicForTesting() { backoff_policy_.jitter_factor = 0.0; } @@ -218,11 +173,13 @@ size_t collector_index; GetNextUploadTimeAndCollector(now, &min_by_backoff, &collector_index); - scheduled_min_time_ = std::max(min_by_deadline, min_by_backoff); - scheduled_max_time_ = std::max(max_by_deadline, min_by_backoff); + base::TimeTicks scheduled_min_time = + std::max(min_by_deadline, min_by_backoff); + base::TimeTicks scheduled_max_time = + std::max(max_by_deadline, min_by_backoff); - base::TimeDelta min_delay = scheduled_min_time_ - now; - base::TimeDelta max_delay = scheduled_max_time_ - now; + base::TimeDelta min_delay = scheduled_min_time - now; + base::TimeDelta max_delay = scheduled_max_time - now; VLOG(1) << "Scheduling upload for between " << min_delay.InSeconds() << " and " << max_delay.InSeconds() << " seconds from now.";
diff --git a/components/domain_reliability/scheduler.h b/components/domain_reliability/scheduler.h index 4408515..ecf11ee 100644 --- a/components/domain_reliability/scheduler.h +++ b/components/domain_reliability/scheduler.h
@@ -17,10 +17,6 @@ #include "components/domain_reliability/uploader.h" #include "net/base/backoff_entry.h" -namespace base { -class Value; -} // namespace base - namespace domain_reliability { class MockableTime; @@ -79,8 +75,6 @@ // passed to the upload callback by the Uploader. void OnUploadComplete(const DomainReliabilityUploader::UploadResult& result); - base::Value GetWebUIData() const; - // Disables jitter in BackoffEntries to make scheduling deterministic for // unit tests. void MakeDeterministicForTesting(); @@ -121,16 +115,6 @@ // first_beacon_time_ saved during uploads. Restored if upload fails. base::TimeTicks old_first_beacon_time_; - - // Extra bits to return in GetWebUIData. - base::TimeTicks scheduled_min_time_; - base::TimeTicks scheduled_max_time_; - // Whether the other last_upload_* fields are populated. - bool last_upload_finished_; - base::TimeTicks last_upload_start_time_; - base::TimeTicks last_upload_end_time_; - size_t last_upload_collector_index_; - bool last_upload_success_; }; } // namespace domain_reliability
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc index c35d8939..8081a17 100644 --- a/components/lens/lens_features.cc +++ b/components/lens/lens_features.cc
@@ -28,6 +28,9 @@ const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText3{ &kLensStandalone, "use-menu-item-alt-text-3", false}; +const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText4{ + &kLensStandalone, "use-menu-item-alt-text-4", false}; + const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch{ &kLensStandalone, "region-search-enable-ukm-logging", true}; @@ -91,6 +94,11 @@ kRegionSearchUseMenuItemAltText3.Get(); } +bool UseRegionSearchMenuItemAltText4() { + return base::FeatureList::IsEnabled(kLensStandalone) && + kRegionSearchUseMenuItemAltText4.Get(); +} + bool IsLensFullscreenSearchEnabled() { return base::FeatureList::IsEnabled(kLensFullscreenSearch); }
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h index 4e23b1b6..a21a49d 100644 --- a/components/lens/lens_features.h +++ b/components/lens/lens_features.h
@@ -32,6 +32,9 @@ // Enables alternate option 3 for the Region Search context menu item text. extern const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText3; +// Enables alternate option 4 for the Region Search context menu item text. +extern const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText4; + // Enables UKM logging for the Lens Region Search feature. extern const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch; @@ -78,6 +81,10 @@ // menu item text. extern bool UseRegionSearchMenuItemAltText3(); +// Returns whether to use alternative option 4 for the Region Search context +// menu item text. +extern bool UseRegionSearchMenuItemAltText4(); + // Returns whether the Lens side panel is enabled. extern bool IsLensSidePanelEnabled();
diff --git a/components/ntp_tiles/custom_links_manager_impl_unittest.cc b/components/ntp_tiles/custom_links_manager_impl_unittest.cc index 51c9af9..3717dc6 100644 --- a/components/ntp_tiles/custom_links_manager_impl_unittest.cc +++ b/components/ntp_tiles/custom_links_manager_impl_unittest.cc
@@ -58,15 +58,15 @@ "chrome-extension://pjkljhegncpnkpknbcohdijeoejaedia/index.html"; #endif -base::Value::ListStorage FillTestListStorage(const char* url, - const char* title, - const bool is_most_visited) { - base::Value::ListStorage new_link_list; - base::DictionaryValue new_link; - new_link.SetKey("url", base::Value(url)); - new_link.SetKey("title", base::Value(title)); - new_link.SetKey("isMostVisited", base::Value(is_most_visited)); - new_link_list.push_back(std::move(new_link)); +base::Value::List FillTestList(const char* url, + const char* title, + const bool is_most_visited) { + base::Value::List new_link_list; + base::Value::Dict new_link; + new_link.Set("url", url); + new_link.Set("title", title); + new_link.Set("isMostVisited", is_most_visited); + new_link_list.Append(std::move(new_link)); return new_link_list; } @@ -99,8 +99,8 @@ public: CustomLinksManagerImplTest() { CustomLinksManagerImpl::RegisterProfilePrefs(prefs_.registry()); - base::Value::ListStorage defaults; - defaults.emplace_back("pjkljhegncpnkpknbcohdijeoejaedia"); + base::Value::List defaults; + defaults.Append("pjkljhegncpnkpknbcohdijeoejaedia"); prefs_.registry()->RegisterListPref( webapps::kWebAppsMigratedPreinstalledApps, base::Value(std::move(defaults))); @@ -696,8 +696,7 @@ // links. EXPECT_CALL(callback, Run()); prefs_.SetUserPref(prefs::kCustomLinksList, - std::make_unique<base::Value>( - FillTestListStorage(kTestUrl, kTestTitle, true))); + base::Value(FillTestList(kTestUrl, kTestTitle, true))); EXPECT_EQ(std::vector<Link>({Link{GURL(kTestUrl), kTestTitle16, true}}), custom_links_->GetLinks()); } @@ -712,11 +711,9 @@ // Modify the preference. This should notify and initialize custom links. EXPECT_CALL(callback, Run()).Times(2); - prefs_.SetUserPref(prefs::kCustomLinksInitialized, - std::make_unique<base::Value>(true)); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, base::Value(true)); prefs_.SetUserPref(prefs::kCustomLinksList, - std::make_unique<base::Value>( - FillTestListStorage(kTestUrl, kTestTitle, false))); + base::Value(FillTestList(kTestUrl, kTestTitle, false))); EXPECT_TRUE(custom_links_->IsInitialized()); EXPECT_EQ(std::vector<Link>({Link{GURL(kTestUrl), kTestTitle16, false}}), custom_links_->GetLinks()); @@ -734,10 +731,8 @@ // Modify the preference. This should notify and uninitialize custom links. EXPECT_CALL(callback, Run()).Times(2); - prefs_.SetUserPref(prefs::kCustomLinksInitialized, - std::make_unique<base::Value>(false)); - prefs_.SetUserPref(prefs::kCustomLinksList, - std::make_unique<base::Value>(base::Value::ListStorage())); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, base::Value(false)); + prefs_.SetUserPref(prefs::kCustomLinksList, base::Value(base::Value::List())); EXPECT_FALSE(custom_links_->IsInitialized()); EXPECT_EQ(std::vector<Link>(), custom_links_->GetLinks()); } @@ -756,12 +751,10 @@ // the initialized preference. This should notify and uninitialize custom // links. EXPECT_CALL(callback, Run()).Times(2); - prefs_.SetUserPref(prefs::kCustomLinksList, - std::make_unique<base::Value>(base::Value::ListStorage())); + prefs_.SetUserPref(prefs::kCustomLinksList, base::Value(base::Value::List())); EXPECT_TRUE(custom_links_->IsInitialized()); EXPECT_EQ(std::vector<Link>(), custom_links_->GetLinks()); - prefs_.SetUserPref(prefs::kCustomLinksInitialized, - std::make_unique<base::Value>(false)); + prefs_.SetUserPref(prefs::kCustomLinksInitialized, base::Value(false)); EXPECT_FALSE(custom_links_->IsInitialized()); EXPECT_EQ(std::vector<Link>(), custom_links_->GetLinks()); }
diff --git a/components/ntp_tiles/custom_links_store.cc b/components/ntp_tiles/custom_links_store.cc index 82a119b9..1e21fa3 100644 --- a/components/ntp_tiles/custom_links_store.cc +++ b/components/ntp_tiles/custom_links_store.cc
@@ -34,41 +34,43 @@ std::vector<CustomLinksManager::Link> CustomLinksStore::RetrieveLinks() { std::vector<CustomLinksManager::Link> links; - const base::Value* stored_links = prefs_->GetList(prefs::kCustomLinksList); + const base::Value::List* stored_links = + prefs_->GetValueList(prefs::kCustomLinksList); - for (const base::Value& link : stored_links->GetListDeprecated()) { - const base::Value* url_value = link.FindKey(kDictionaryKeyUrl); - const base::Value* title_value = link.FindKey(kDictionaryKeyTitle); - const base::Value* mv_value = link.FindKey(kDictionaryKeyIsMostVisited); + for (const base::Value& link : *stored_links) { + const std::string* url_string = + link.GetDict().FindString(kDictionaryKeyUrl); + const std::string* title_string = + link.GetDict().FindString(kDictionaryKeyTitle); + const absl::optional<bool> mv_value = + link.GetDict().FindBool(kDictionaryKeyIsMostVisited); - GURL url = GURL(url_value->GetString()); - if (!url_value || !title_value || !url.is_valid()) { + GURL url = GURL(url_string ? *url_string : std::string()); + if (!url_string || !title_string || !url.is_valid()) { ClearLinks(); links.clear(); return links; } // Assume false if this value was not stored. - bool is_most_visited = mv_value ? mv_value->GetBool() : false; + bool is_most_visited = mv_value.value_or(false); links.emplace_back(CustomLinksManager::Link{ - std::move(url), base::UTF8ToUTF16(title_value->GetString()), - is_most_visited}); + std::move(url), base::UTF8ToUTF16(*title_string), is_most_visited}); } return links; } void CustomLinksStore::StoreLinks( const std::vector<CustomLinksManager::Link>& links) { - base::Value::ListStorage new_link_list; + base::Value::List new_link_list; for (const CustomLinksManager::Link& link : links) { - base::DictionaryValue new_link; - new_link.SetKey(kDictionaryKeyUrl, base::Value(link.url.spec())); - new_link.SetKey(kDictionaryKeyTitle, base::Value(link.title)); - new_link.SetKey(kDictionaryKeyIsMostVisited, - base::Value(link.is_most_visited)); - new_link_list.push_back(std::move(new_link)); + base::Value::Dict new_link; + new_link.Set(kDictionaryKeyUrl, link.url.spec()); + new_link.Set(kDictionaryKeyTitle, link.title); + new_link.Set(kDictionaryKeyIsMostVisited, link.is_most_visited); + new_link_list.Append(std::move(new_link)); } - prefs_->Set(prefs::kCustomLinksList, base::Value(std::move(new_link_list))); + prefs_->SetList(prefs::kCustomLinksList, std::move(new_link_list)); } void CustomLinksStore::ClearLinks() {
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc index 3c4980c..93a7e1b2a 100644 --- a/components/ntp_tiles/most_visited_sites.cc +++ b/components/ntp_tiles/most_visited_sites.cc
@@ -765,11 +765,11 @@ // static bool MostVisitedSites::WasNtpAppMigratedToWebApp(PrefService* prefs, GURL url) { - const base::Value* migrated_apps = - prefs->GetList(webapps::kWebAppsMigratedPreinstalledApps); + const base::Value::List* migrated_apps = + prefs->GetValueList(webapps::kWebAppsMigratedPreinstalledApps); if (!migrated_apps) return false; - for (const auto& val : migrated_apps->GetListDeprecated()) { + for (const auto& val : *migrated_apps) { if (val.is_string() && val.GetString() == url.host()) return true; }
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc index 918195d..e32bb20 100644 --- a/components/ntp_tiles/most_visited_sites_unittest.cc +++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -384,8 +384,8 @@ // Updating list value in pref with default gmail URL for unit testing. // Also adding migration feature to be enabled for unit test. - base::Value::ListStorage defaults; - defaults.emplace_back("pjkljhegncpnkpknbcohdijeoejaedia"); + base::Value::List defaults; + defaults.Append("pjkljhegncpnkpknbcohdijeoejaedia"); pref_service_.registry()->RegisterListPref( webapps::kWebAppsMigratedPreinstalledApps, base::Value(std::move(defaults)));
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc index c166ae2..e2dcf668 100644 --- a/components/ntp_tiles/popular_sites_impl.cc +++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -115,33 +115,31 @@ "directory"); } -PopularSites::SitesVector ParseSiteList( - const base::Value::ConstListView& list) { +PopularSites::SitesVector ParseSiteList(const base::Value::List& list) { PopularSites::SitesVector sites; for (const base::Value& item_value : list) { if (!item_value.is_dict()) continue; - const base::DictionaryValue& item = - base::Value::AsDictionaryValue(item_value); + const base::Value::Dict& item = item_value.GetDict(); std::u16string title; - if (const std::string* ptr = item.FindStringKey("title")) + if (const std::string* ptr = item.FindString("title")) title = base::UTF8ToUTF16(*ptr); else continue; std::string url; - if (const std::string* ptr = item.FindStringKey("url")) + if (const std::string* ptr = item.FindString("url")) url = *ptr; else continue; std::string favicon_url; - if (const std::string* ptr = item.FindStringKey("favicon_url")) + if (const std::string* ptr = item.FindString("favicon_url")) favicon_url = *ptr; std::string large_icon_url; - if (const std::string* ptr = item.FindStringKey("large_icon_url")) + if (const std::string* ptr = item.FindString("large_icon_url")) large_icon_url = *ptr; TileTitleSource title_source = TileTitleSource::UNKNOWN; - absl::optional<int> title_source_int = item.FindIntKey("title_source"); + absl::optional<int> title_source_int = item.FindInt("title_source"); if (!title_source_int) { // Only v6 and later have "title_source". Earlier versions use title tags. title_source = TileTitleSource::TITLE_TAG; @@ -153,10 +151,10 @@ sites.emplace_back(title, GURL(url), GURL(favicon_url), GURL(large_icon_url), title_source); absl::optional<int> default_icon_resource = - item.FindIntKey("default_icon_resource"); + item.FindInt("default_icon_resource"); if (default_icon_resource) sites.back().default_icon_resource = *default_icon_resource; - absl::optional<bool> baked_in = item.FindBoolKey("baked_in"); + absl::optional<bool> baked_in = item.FindBool("baked_in"); if (baked_in.has_value()) sites.back().baked_in = baked_in.value(); } @@ -164,23 +162,23 @@ } std::map<SectionType, PopularSites::SitesVector> ParseVersion5( - const base::Value::ConstListView& list) { + const base::Value::List& list) { return {{SectionType::PERSONALIZED, ParseSiteList(list)}}; } std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove( - const base::Value::ConstListView& list) { + const base::Value::List& list) { // Valid lists would have contained at least the PERSONALIZED section. std::map<SectionType, PopularSites::SitesVector> sections = { std::make_pair(SectionType::PERSONALIZED, PopularSites::SitesVector{})}; for (size_t i = 0; i < list.size(); i++) { - const base::Value& item_value = list[i]; - if (!item_value.is_dict()) { + const base::Value::Dict* item_dict = list[i].GetIfDict(); + if (!item_dict) { LOG(WARNING) << "Parsed SitesExploration list contained an invalid " << "section at position " << i << "."; continue; } - int section = item_value.FindIntKey("section").value_or(-1); + int section = item_dict->FindInt("section").value_or(-1); if (section < 0 || section > static_cast<int>(SectionType::LAST)) { LOG(WARNING) << "Parsed SitesExploration list contained a section with " << "invalid ID (" << section << ")"; @@ -191,16 +189,16 @@ SectionType section_type = static_cast<SectionType>(section); if (section_type != SectionType::PERSONALIZED) continue; - const base::Value* sites_list = item_value.FindListKey("sites"); + const base::Value::List* sites_list = item_dict->FindList("sites"); if (!sites_list) continue; - sections[section_type] = ParseSiteList(sites_list->GetListDeprecated()); + sections[section_type] = ParseSiteList(*sites_list); } return sections; } std::map<SectionType, PopularSites::SitesVector> ParseSites( - const base::Value::ConstListView& list, + const base::Value::List& list, int version) { if (version >= kSitesExplorationStartVersion) return ParseVersion6OrAbove(list); @@ -211,12 +209,11 @@ (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)) void SetDefaultResourceForSite(size_t index, int resource_id, - base::Value* sites) { - base::Value::ListView list = sites->GetListDeprecated(); - if (index >= list.size() || !list[index].is_dict()) + base::Value::List& sites) { + if (index >= sites.size() || !sites[index].is_dict()) return; - list[index].SetIntKey("default_icon_resource", resource_id); + sites[index].GetDict().Set("default_icon_resource", resource_id); } #endif @@ -231,8 +228,8 @@ absl::optional<base::Value> sites = base::JSONReader::Read( ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( IDR_DEFAULT_POPULAR_SITES_JSON)); - for (base::Value& site : sites.value().GetListDeprecated()) - site.SetBoolKey("baked_in", true); + for (base::Value& site : sites.value().GetList()) + site.GetDict().Set("baked_in", true); #if BUILDFLAG(GOOGLE_CHROME_BRANDING) size_t index = 0; @@ -241,7 +238,7 @@ IDR_DEFAULT_POPULAR_SITES_ICON2, IDR_DEFAULT_POPULAR_SITES_ICON3, IDR_DEFAULT_POPULAR_SITES_ICON4, IDR_DEFAULT_POPULAR_SITES_ICON5, IDR_DEFAULT_POPULAR_SITES_ICON6, IDR_DEFAULT_POPULAR_SITES_ICON7}) { - SetDefaultResourceForSite(index++, icon_resource, &sites.value()); + SetDefaultResourceForSite(index++, icon_resource, sites.GetList()); } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) return std::move(sites.value()); @@ -277,9 +274,9 @@ variations_(variations_service), url_loader_factory_(std::move(url_loader_factory)), is_fallback_(false), - sections_(ParseSites( - prefs->GetList(prefs::kPopularSitesJsonPref)->GetListDeprecated(), - prefs_->GetInteger(prefs::kPopularSitesVersionPref))) {} + sections_( + ParseSites(*prefs->GetValueList(prefs::kPopularSitesJsonPref), + prefs_->GetInteger(prefs::kPopularSitesVersionPref))) {} PopularSitesImpl::~PopularSitesImpl() {} @@ -490,13 +487,13 @@ OnDownloadFailed(); return; } - prefs_->Set(prefs::kPopularSitesJsonPref, list); + sections_ = ParseSites(list.GetList(), version_in_pending_url_); + prefs_->SetList(prefs::kPopularSitesJsonPref, std::move(list.GetList())); prefs_->SetInt64(prefs::kPopularSitesLastDownloadPref, base::Time::Now().ToInternalValue()); prefs_->SetInteger(prefs::kPopularSitesVersionPref, version_in_pending_url_); prefs_->SetString(prefs::kPopularSitesURLPref, pending_url_.spec()); - sections_ = ParseSites(list.GetListDeprecated(), version_in_pending_url_); std::move(callback_).Run(true); }
diff --git a/components/ntp_tiles/popular_sites_impl_unittest.cc b/components/ntp_tiles/popular_sites_impl_unittest.cc index 158fb0e..87c006e 100644 --- a/components/ntp_tiles/popular_sites_impl_unittest.cc +++ b/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -112,23 +112,24 @@ prefs_->SetString(prefs::kPopularSitesOverrideVersion, version); } - base::Value CreateListFromTestSites(const TestPopularSiteVector& sites) { - base::Value::ListStorage sites_value; + base::Value::List CreateListFromTestSites( + const TestPopularSiteVector& sites) { + base::Value::List sites_value; for (const TestPopularSite& site : sites) { - base::Value site_value(base::Value::Type::DICTIONARY); + base::Value::Dict site_value; for (const std::pair<const std::string, std::string>& kv : site) { if (kv.first == kTitleSource) { int source; bool convert_success = base::StringToInt(kv.second, &source); DCHECK(convert_success); - site_value.SetIntKey(kv.first, source); + site_value.Set(kv.first, source); continue; } - site_value.SetStringKey(kv.first, kv.second); + site_value.Set(kv.first, kv.second); } - sites_value.push_back(std::move(site_value)); + sites_value.Append(std::move(site_value)); } - return base::Value(sites_value); + return sites_value; } void RespondWithV5JSON(const std::string& url, @@ -140,15 +141,16 @@ void RespondWithV6JSON(const std::string& url, const TestPopularSectionVector& sections) { - base::Value::ListStorage sections_value(sections.size()); + base::Value::List sections_value; + sections_value.reserve(sections.size()); for (const TestPopularSection& section : sections) { - base::Value section_value(base::Value::Type::DICTIONARY); - section_value.SetIntKey(kSection, static_cast<int>(section.first)); - section_value.SetKey(kSites, CreateListFromTestSites(section.second)); - sections_value.push_back(std::move(section_value)); + base::Value::Dict section_value; + section_value.Set(kSection, static_cast<int>(section.first)); + section_value.Set(kSites, CreateListFromTestSites(section.second)); + sections_value.Append(std::move(section_value)); } std::string sites_string; - base::JSONWriter::Write(base::Value(sections_value), &sites_string); + base::JSONWriter::Write(sections_value, &sites_string); test_url_loader_factory_.AddResponse(url, sites_string); }
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc index 2d43720..24cd165 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -88,13 +88,13 @@ void NTPTilesInternalsMessageHandler::HandleRegisterForEvents( const base::ListValue* args) { if (!client_->SupportsNTPTiles()) { - base::Value disabled(base::Value::Type::DICTIONARY); - disabled.SetBoolKey("topSites", false); - disabled.SetBoolKey("popular", false); - disabled.SetBoolKey("customLinks", false); + base::Value::Dict disabled; + disabled.Set("topSites", false); + disabled.Set("popular", false); + disabled.Set("customLinks", false); client_->CallJavascriptFunction("cr.webUIListenerCallback", base::Value("receive-source-info"), - disabled); + base::Value(std::move(disabled))); SendTiles(NTPTilesVector(), FaviconResultMap()); return; } @@ -179,81 +179,79 @@ void NTPTilesInternalsMessageHandler::SendSourceInfo() { PrefService* prefs = client_->GetPrefs(); - base::Value value(base::Value::Type::DICTIONARY); + base::Value::Dict value; - value.SetBoolKey("topSites", - most_visited_sites_->DoesSourceExist(TileSource::TOP_SITES)); - value.SetBoolKey("customLinks", most_visited_sites_->DoesSourceExist( - TileSource::CUSTOM_LINKS)); + value.Set("topSites", + most_visited_sites_->DoesSourceExist(TileSource::TOP_SITES)); + value.Set("customLinks", + most_visited_sites_->DoesSourceExist(TileSource::CUSTOM_LINKS)); if (most_visited_sites_->DoesSourceExist(TileSource::POPULAR)) { auto* popular_sites = most_visited_sites_->popular_sites(); - value.SetStringKey("popular.url", popular_sites->GetURLToFetch().spec()); - value.SetStringKey("popular.directory", - popular_sites->GetDirectoryToFetch()); - value.SetStringKey("popular.country", popular_sites->GetCountryToFetch()); - value.SetStringKey("popular.version", popular_sites->GetVersionToFetch()); + value.Set("popular.url", popular_sites->GetURLToFetch().spec()); + value.Set("popular.directory", popular_sites->GetDirectoryToFetch()); + value.Set("popular.country", popular_sites->GetCountryToFetch()); + value.Set("popular.version", popular_sites->GetVersionToFetch()); - value.SetStringKey( - "popular.overrideURL", - prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL)); - value.SetStringKey( + value.Set("popular.overrideURL", + prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL)); + value.Set( "popular.overrideDirectory", prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideDirectory)); - value.SetStringKey( - "popular.overrideCountry", - prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideCountry)); - value.SetStringKey( - "popular.overrideVersion", - prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion)); + value.Set("popular.overrideCountry", + prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideCountry)); + value.Set("popular.overrideVersion", + prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion)); - value.SetStringKey("popular.json", popular_sites_json_); + value.Set("popular.json", popular_sites_json_); } else { - value.SetBoolKey("popular", false); + value.Set("popular", false); } client_->CallJavascriptFunction("cr.webUIListenerCallback", - base::Value("receive-source-info"), value); + base::Value("receive-source-info"), + base::Value(std::move(value))); } void NTPTilesInternalsMessageHandler::SendTiles( const NTPTilesVector& tiles, const FaviconResultMap& result_map) { - base::Value sites_list(base::Value::Type::LIST); + base::Value::List sites_list; for (const NTPTile& tile : tiles) { - base::Value entry(base::Value::Type::DICTIONARY); - entry.SetStringKey("title", tile.title); - entry.SetStringKey("url", tile.url.spec()); - entry.SetIntKey("source", static_cast<int>(tile.source)); + base::Value::Dict entry; + entry.Set("title", tile.title); + entry.Set("url", tile.url.spec()); + entry.Set("source", static_cast<int>(tile.source)); if (tile.source == TileSource::CUSTOM_LINKS) { - entry.SetBoolKey("fromMostVisited", tile.from_most_visited); + entry.Set("fromMostVisited", tile.from_most_visited); } - base::Value icon_list(base::Value::Type::LIST); + base::Value::List icon_list; for (const auto& type_and_name : kIconTypesAndNames) { auto it = result_map.find( FaviconResultMap::key_type(tile.url, type_and_name.type_enum)); if (it != result_map.end()) { const favicon_base::FaviconRawBitmapResult& result = it->second; - base::Value icon(base::Value::Type::DICTIONARY); - icon.SetStringKey("url", result.icon_url.spec()); - icon.SetStringKey("type", type_and_name.type_name); - icon.SetBoolKey("onDemand", !result.fetched_because_of_page_visit); - icon.SetIntKey("width", result.pixel_size.width()); - icon.SetIntKey("height", result.pixel_size.height()); + base::Value::Dict icon; + icon.Set("url", result.icon_url.spec()); + icon.Set("type", type_and_name.type_name); + icon.Set("onDemand", !result.fetched_because_of_page_visit); + icon.Set("width", result.pixel_size.width()); + icon.Set("height", result.pixel_size.height()); icon_list.Append(std::move(icon)); } } - entry.SetKey("icons", std::move(icon_list)); + entry.Set("icons", std::move(icon_list)); sites_list.Append(std::move(entry)); } - base::Value result(base::Value::Type::DICTIONARY); - result.SetKey("sites", std::move(sites_list)); + base::Value::Dict result; + result.Set("sites", std::move(sites_list)); client_->CallJavascriptFunction("cr.webUIListenerCallback", - base::Value("receive-sites"), result); + base::Value("receive-sites"), + base::Value(std::move(result))); } void NTPTilesInternalsMessageHandler::OnURLsAvailable(
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc index 2f0a46f..48ada56 100644 --- a/components/omnibox/browser/autocomplete_result.cc +++ b/components/omnibox/browser/autocomplete_result.cc
@@ -293,7 +293,15 @@ RotateMatchToFront(top_match, &matches_); - DiscourageTopMatchFromBeingSearchEntity(&matches_); + // The search provider may pre-deduplicate search suggestions. It's possible + // for the un-deduped search suggestion that replaces a default search + // entity suggestion to not have had `ComputeStrippedDestinationURL()` + // invoked. Make sure to invoke it now as `AutocompleteController` relies on + // `stripped_destination_url` to detect result changes. If + // `stripped_destination_url` is already set, i.e. it was not a pre-deduped + // search suggestion, `ComputeStrippedDestinationURL()` will early exit. + if (DiscourageTopMatchFromBeingSearchEntity(&matches_)) + matches_[0].ComputeStrippedDestinationURL(input, template_url_service); } // Limit URL matches per OmniboxMaxURLMatches. @@ -647,14 +655,14 @@ } // static -void AutocompleteResult::DiscourageTopMatchFromBeingSearchEntity( +bool AutocompleteResult::DiscourageTopMatchFromBeingSearchEntity( ACMatches* matches) { if (matches->empty()) - return; + return false; auto top_match = matches->begin(); if (top_match->type != ACMatchType::SEARCH_SUGGEST_ENTITY) - return; + return false; // Search the duplicates for an equivalent non-entity search suggestion. for (auto it = top_match->duplicate_matches.begin(); @@ -675,8 +683,9 @@ // Promote the non-entity match to the top, then immediately return, since // all our iterators are invalid after the insertion. matches->insert(matches->begin(), std::move(non_entity_match_copy)); - return; + return true; } + return false; } // static
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h index 4fb0d7aa..b5cfea0 100644 --- a/components/omnibox/browser/autocomplete_result.h +++ b/components/omnibox/browser/autocomplete_result.h
@@ -168,8 +168,8 @@ // If the top match is a Search Entity, and it was deduplicated with a // non-entity match, split off the non-entity match from the list of - // duplicates and promote it to the top. - static void DiscourageTopMatchFromBeingSearchEntity(ACMatches* matches); + // duplicates, promote it to the top, and return true. + static bool DiscourageTopMatchFromBeingSearchEntity(ACMatches* matches); // Just a helper function to encapsulate the logic of deciding how many // matches to keep, with respect to configured maximums, URL limits,
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc index fb13b0eb..bafda6c2 100644 --- a/components/omnibox/browser/autocomplete_result_unittest.cc +++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -1564,6 +1564,104 @@ EXPECT_EQ(u"oo", result.match_at(1)->inline_autocompletion); } +TEST_F(AutocompleteResultTest, + SortAndCullPreferNonEntitiesForDefaultSuggestion) { + // When the top scoring allowed_to_be_default suggestion is a search entity, + // and there is a duplicate non-entity search suggest that is also + // allowed_to_be_default, prefer the latter. + + std::vector<EntityTestData> test_cases = { + {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY, GetProvider(1), + "http://search/?q=foo", 1000, true}, + {AutocompleteMatchType::SEARCH_SUGGEST, GetProvider(1), + "http://search/?q=foo2", 1200}, + // A duplicate search suggestion should be preferred to a search entity + // suggestion, even if the former is scored lower. + {AutocompleteMatchType::SEARCH_SUGGEST, GetProvider(1), + "http://search/?q=foo", 900, true}, + }; + ACMatches matches; + PopulateEntityTestCases(test_cases, &matches); + + // Simulate the search provider pre-grouping duplicate suggestions. We want + // to make sure `stripped_destination_url` is correctly appended to pre-duped + // suggestions. + matches[0].duplicate_matches.push_back(matches.back()); + matches.pop_back(); + + AutocompleteInput input(u"f", metrics::OmniboxEventProto::OTHER, + TestSchemeClassifier()); + AutocompleteResult result; + result.AppendMatches(matches); + result.SortAndCull(input, template_url_service_.get()); + + ASSERT_EQ(result.size(), 3u); + + auto* match = result.match_at(0); + EXPECT_EQ(match->type, AutocompleteMatchType::SEARCH_SUGGEST); + // Should not inherit the search entity suggestion's relevance; only the + // non-dup suggestion inherits from the dup suggestions; not vice versa. + EXPECT_EQ(match->relevance, 900); + EXPECT_TRUE(match->allowed_to_be_default_match); + EXPECT_EQ(match->stripped_destination_url.spec(), "http://search/?q=foo"); + + match = result.match_at(1); + // The search entity suggestion should be ranked higher than the higher + // scoring 'foo2' search suggestion. When demoting default entity suggestions, + // they are moved to position 2 rather than re-ranked according to their + // relevance. + EXPECT_EQ(match->type, AutocompleteMatchType::SEARCH_SUGGEST_ENTITY); + EXPECT_EQ(match->relevance, 1000); + EXPECT_TRUE(match->allowed_to_be_default_match); + EXPECT_EQ(match->stripped_destination_url.spec(), "http://search/?q=foo"); + + match = result.match_at(2); + EXPECT_EQ(match->type, AutocompleteMatchType::SEARCH_SUGGEST); + EXPECT_EQ(match->relevance, 1200); + EXPECT_FALSE(match->allowed_to_be_default_match); + EXPECT_EQ(match->stripped_destination_url.spec(), "http://search/?q=foo2"); +} + +TEST_F(AutocompleteResultTest, + SortAndCullDontPreferNonEntityNonDefaultForDefaultSuggestion) { + // When the top scoring allowed_to_be_default suggestion is a search entity, + // and there are no duplicate allowed_to_be_default suggestions, keep the + // search entity suggestion default. + + std::vector<EntityTestData> test_cases = { + {AutocompleteMatchType::SEARCH_SUGGEST_ENTITY, GetProvider(1), + "http://search/?q=foo", 1000, true}, + // A duplicate non-allowed_to_be_default search suggestion should not be + // preferred to a lower ranked search entity suggestion. + {AutocompleteMatchType::SEARCH_SUGGEST, GetProvider(1), + "http://search/?q=foo", 1300}, + // A non-duplicate allowed_to_be_default search suggestion should not be + // preferred to a higher ranked search entity suggestion. + {AutocompleteMatchType::SEARCH_SUGGEST, GetProvider(1), + "http://search/?q=foo2", 900, true}, + }; + ACMatches matches; + PopulateEntityTestCases(test_cases, &matches); + + AutocompleteInput input(u"f", metrics::OmniboxEventProto::OTHER, + TestSchemeClassifier()); + AutocompleteResult result; + result.AppendMatches(matches); + result.SortAndCull(input, template_url_service_.get()); + + ASSERT_EQ(result.size(), 2u); + + auto* match = result.match_at(0); + EXPECT_EQ(match->type, AutocompleteMatchType::SEARCH_SUGGEST_ENTITY); + EXPECT_EQ(match->relevance, 1300); + EXPECT_TRUE(match->allowed_to_be_default_match); + + match = result.match_at(1); + EXPECT_EQ(match->type, AutocompleteMatchType::SEARCH_SUGGEST); + EXPECT_EQ(match->relevance, 900); + EXPECT_TRUE(match->allowed_to_be_default_match); +} + TEST_F(AutocompleteResultTest, SortAndCullPreferEntitiesFillIntoEditMustMatch) { // clang-format off std::vector<EntityTestData> test_cases = {
diff --git a/components/sync/driver/resources/BUILD.gn b/components/sync/driver/resources/BUILD.gn index b3e0abd..0dcf657 100644 --- a/components/sync/driver/resources/BUILD.gn +++ b/components/sync/driver/resources/BUILD.gn
@@ -2,47 +2,80 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//third_party/closure_compiler/compile_js.gni") import("//tools/grit/grit_rule.gni") import("//tools/grit/preprocess_if_expr.gni") +import("//tools/typescript/ts_library.gni") import("//ui/webui/resources/tools/generate_grd.gni") grd_file = "$target_gen_dir/resources.grd" -preprocess_if_expr("preprocess") { +preprocess_if_expr("preprocess_css") { in_folder = "./" out_folder = "$target_gen_dir/preprocess" - out_manifest = "$target_gen_dir/manifest.json" + out_manifest = "$target_gen_dir/css_manifest.json" in_files = [ - "sync_index.js", "sync_node_browser.css", "sync_search.css", ] } +#TODO(crbug.com/986001): Migrate the files below to TypeScript. +preprocessed_files = [ "sync_index.js" ] +non_preprocessed_files = [ + "about.js", + "chrome_sync.js", + "data.js", + "invalidations.js", + "search.js", + "sync_log.js", + "sync_node_browser.js", + "sync_search.js", + "traffic_log.js", + "user_events.js", +] + +preprocess_if_expr("preprocess") { + in_folder = "./" + out_folder = "$target_gen_dir/preprocess" + in_files = preprocessed_files +} + +copy("copy_files") { + sources = non_preprocessed_files + outputs = [ "$target_gen_dir/preprocess/{{source_file_part}}" ] +} + +ts_library("build_ts") { + root_dir = "$target_gen_dir/preprocess" + in_files = non_preprocessed_files + preprocessed_files + out_dir = "$target_gen_dir/tsc" + tsconfig_base = "tsconfig_base.json" + deps = [ "//ui/webui/resources:library" ] + extra_deps = [ + ":copy_files", + ":preprocess", + ] +} + generate_grd("build_grd") { - deps = [ ":preprocess" ] + deps = [ + ":build_ts", + ":preprocess_css", + ] grd_prefix = "sync_driver_sync_internals" out_grd = grd_file input_files = [ "about.css", - "about.js", - "chrome_sync.js", - "data.js", "index.html", "invalidations.css", - "invalidations.js", - "search.js", "star_small.png", - "sync_log.js", - "sync_node_browser.js", - "sync_search.js", "traffic_log.css", - "traffic_log.js", - "user_events.js", ] input_files_base_dir = rebase_path("./", "//") - manifest_files = [ "$target_gen_dir/manifest.json" ] + manifest_files = [ + "$target_gen_dir/css_manifest.json", + "$target_gen_dir/tsconfig.manifest", + ] } grit("resources") { @@ -60,81 +93,3 @@ output_dir = "$root_gen_dir/components" deps = [ ":build_grd" ] } - -js_type_check("closure_compile") { - deps = [ - #TODO(crbug.com/986001): Fix compilation errors and enable all targets. - - #":about", - ":chrome_sync", - - #":data", - #":search", - ":sync_index", - ":sync_log", - - #":sync_node_browser", - #":sync_search", - ":invalidations", - ":traffic_log", - ":user_events", - ] -} - -js_library("about") { - deps = [ - "//third_party/jstemplate:jstemplate", - "//ui/webui/resources/js:util.m", - ] -} - -js_library("chrome_sync") { - deps = [ - "//ui/webui/resources/js:cr.m", - "//ui/webui/resources/js:util.m", - ] -} - -js_library("data") { -} - -js_library("search") { - deps = [ "//ui/webui/resources/js:util.m" ] -} - -js_library("sync_index") { - deps = [ "//ui/webui/resources/js:util.m" ] -} - -js_library("sync_log") { - deps = [ - "//ui/webui/resources/js:cr.m", - "//ui/webui/resources/js/cr:event_target.m", - ] -} - -js_library("sync_node_browser") { - deps = [ "//ui/webui/resources/js:cr.m" ] -} - -js_library("sync_search") { - deps = [ ":chrome_sync" ] -} - -js_library("traffic_log") { - deps = [ - "//third_party/jstemplate:jstemplate", - "//ui/webui/resources/js:cr.m", - ] -} - -js_library("user_events") { - deps = [ - "//ui/webui/resources/js:cr.m", - "//ui/webui/resources/js:util.m", - ] -} - -js_library("invalidations") { - deps = [ "//ui/webui/resources/js:cr.m" ] -}
diff --git a/components/sync/driver/resources/tsconfig_base.json b/components/sync/driver/resources/tsconfig_base.json new file mode 100644 index 0000000..99a81eca --- /dev/null +++ b/components/sync/driver/resources/tsconfig_base.json
@@ -0,0 +1,6 @@ +{ + "extends": "../../../../tools/typescript/tsconfig_base.json", + "compilerOptions": { + "allowJs": true + } +}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index c257212..87c464f 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1298,6 +1298,8 @@ "net/network_quality_observer_impl.h", "net/reporting_service_proxy.cc", "net/reporting_service_proxy.h", + "net/socket_broker_impl.cc", + "net/socket_broker_impl.h", "network_context_client_base_impl.cc", "network_context_client_base_impl.h", "network_sandbox_grant_result.h",
diff --git a/content/browser/attribution_reporting/attribution_src_browsertest.cc b/content/browser/attribution_reporting/attribution_src_browsertest.cc index 4334429..1e15589 100644 --- a/content/browser/attribution_reporting/attribution_src_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_src_browsertest.cc
@@ -147,40 +147,86 @@ EXPECT_THAT(source_data.front()->aggregation_keys, IsEmpty()); } -IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, SourceRegistered_Script) { +IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, + SourceRegisteredViaEligibilityHeader) { + const char* kTestCases[] = { + "createAttributionEligibleImgSrc($1);", "createAttributionSrcScript($1);", + "doAttributionEligibleFetch($1);", "doAttributionEligibleXHR($1);"}; + GURL page_url = + https_server()->GetURL("b.test", "/page_with_impression_creator.html"); + + for (const char* registration_js : kTestCases) { + EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); + std::unique_ptr<MockDataHost> data_host; + base::RunLoop loop; + EXPECT_CALL(mock_attribution_host(), RegisterDataHost) + .WillOnce( + [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host) { + data_host = GetRegisteredDataHost(std::move(host)); + loop.Quit(); + }); + + GURL register_url = + https_server()->GetURL("c.test", "/register_source_headers.html"); + + EXPECT_TRUE( + ExecJs(web_contents(), JsReplace(registration_js, register_url))); + if (!data_host) + loop.Run(); + data_host->WaitForSourceData(/*num_source_data=*/1); + const auto& source_data = data_host->source_data(); + + EXPECT_EQ(source_data.size(), 1u); + EXPECT_EQ(source_data.front()->source_event_id, 5UL); + EXPECT_EQ(source_data.front()->destination, + url::Origin::Create(GURL("https://d.test"))); + EXPECT_EQ(source_data.front()->priority, 0); + EXPECT_EQ(source_data.front()->expiry, absl::nullopt); + EXPECT_FALSE(source_data.front()->debug_key); + EXPECT_THAT(source_data.front()->filter_data->filter_values, IsEmpty()); + EXPECT_THAT(source_data.front()->aggregation_keys, IsEmpty()); + } +} + +// TODO(johnidel): Remove when redirect chains consistently register sources or +// triggers. Currently, responses not handled via attributionsrc="url" use +// their own independent data host, so we do not enforce consistency on +// these redirect chains. +IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, + SourceTriggerRegistered_ImgSrc) { GURL page_url = https_server()->GetURL("b.test", "/page_with_impression_creator.html"); EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - std::unique_ptr<MockDataHost> data_host; - base::RunLoop loop; + std::unique_ptr<MockDataHost> source_data_host; + std::unique_ptr<MockDataHost> trigger_data_host; + base::RunLoop source_loop; + base::RunLoop trigger_loop; EXPECT_CALL(mock_attribution_host(), RegisterDataHost) - .WillOnce( + .WillRepeatedly( [&](mojo::PendingReceiver<blink::mojom::AttributionDataHost> host) { - data_host = GetRegisteredDataHost(std::move(host)); - loop.Quit(); + if (!source_data_host) { + source_data_host = GetRegisteredDataHost(std::move(host)); + source_loop.Quit(); + } else { + trigger_data_host = GetRegisteredDataHost(std::move(host)); + trigger_loop.Quit(); + } }); - GURL register_url = - https_server()->GetURL("c.test", "/register_source_headers.html"); + GURL register_url = https_server()->GetURL( + "c.test", "/register_source_trigger_redirect_chain.html"); EXPECT_TRUE( ExecJs(web_contents(), - JsReplace("createAttributionSrcScript($1);", register_url))); - if (!data_host) - loop.Run(); - data_host->WaitForSourceData(/*num_source_data=*/1); - const auto& source_data = data_host->source_data(); + JsReplace("createAttributionEligibleImgSrc($1);", register_url))); + if (!source_data_host) + source_loop.Run(); + source_data_host->WaitForSourceData(/*num_source_data=*/1); - EXPECT_EQ(source_data.size(), 1u); - EXPECT_EQ(source_data.front()->source_event_id, 5UL); - EXPECT_EQ(source_data.front()->destination, - url::Origin::Create(GURL("https://d.test"))); - EXPECT_EQ(source_data.front()->priority, 0); - EXPECT_EQ(source_data.front()->expiry, absl::nullopt); - EXPECT_FALSE(source_data.front()->debug_key); - EXPECT_THAT(source_data.front()->filter_data->filter_values, IsEmpty()); - EXPECT_THAT(source_data.front()->aggregation_keys, IsEmpty()); + if (!trigger_data_host) + trigger_loop.Run(); + trigger_data_host->WaitForTriggerData(/*num_trigger_data=*/1); } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, @@ -610,6 +656,38 @@ } IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, + ImgSrcWithAttributionSrc_SetsEligibleHeader) { + // Create a separate server as we cannot register a `ControllableHttpResponse` + // after the server starts. + auto https_server = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + https_server->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); + net::test_server::RegisterDefaultHandlers(https_server.get()); + https_server->ServeFilesFromSourceDirectory( + "content/test/data/attribution_reporting"); + https_server->ServeFilesFromSourceDirectory("content/test/data"); + + auto register_response1 = + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server.get(), "/register_source1"); + ASSERT_TRUE(https_server->Start()); + + GURL page_url = + https_server->GetURL("b.test", "/page_with_impression_creator.html"); + ASSERT_TRUE(NavigateToURL(web_contents(), page_url)); + + GURL register_url = https_server->GetURL("d.test", "/register_source1"); + ASSERT_TRUE( + ExecJs(web_contents(), + JsReplace("createAttributionEligibleImgSrc($1);", register_url))); + + register_response1->WaitForRequest(); + ASSERT_EQ(register_response1->http_request()->headers.at( + "Attribution-Reporting-Eligible"), + "event-source, trigger"); +} + +IN_PROC_BROWSER_TEST_F(AttributionSrcBrowserTest, ReferrerPolicy_RespectsDocument) { // Create a separate server as we cannot register a `ControllableHttpResponse` // after the server starts.
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc index a6d38c499..d49b1ad 100644 --- a/content/browser/attribution_reporting/attributions_browsertest.cc +++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -179,6 +179,8 @@ https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); net::test_server::RegisterDefaultHandlers(https_server_.get()); https_server_->ServeFilesFromSourceDirectory("content/test/data"); + https_server_->ServeFilesFromSourceDirectory( + "content/test/data/attribution_reporting"); } void TearDownOnMainThread() override { @@ -842,6 +844,48 @@ expected_report2.WaitForReport(); } +IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, + TriggerAndSourceSameRedirectChain_Handled) { + ASSERT_TRUE(https_server()->Start()); + + GURL impression_url = https_server()->GetURL( + "a.test", "/attribution_reporting/page_with_impression_creator.html"); + EXPECT_TRUE(NavigateToURL(web_contents(), impression_url)); + + MockAttributionObserver observer; + base::ScopedObservation<AttributionManager, AttributionObserver> observation( + &observer); + observation.Observe(attribution_manager()); + + base::RunLoop loop; + int count = 0; + EXPECT_CALL(observer, OnTriggerHandled).WillRepeatedly([&]() { + count++; + if (count < 2) + return; + loop.Quit(); + }); + + bool received_source = false; + base::RunLoop source_loop; + EXPECT_CALL(observer, OnSourceHandled).WillOnce([&]() { + received_source = true; + source_loop.Quit(); + }); + + GURL register_url = https_server()->GetURL( + "a.test", "/attribution_reporting/register_trigger_source_trigger.html"); + EXPECT_TRUE( + ExecJs(web_contents(), + JsReplace("createAttributionEligibleImgSrc($1);", register_url))); + + // Ensure we don't error out processing the redirect chain. + if (count < 2) + loop.Run(); + + if (!received_source) + source_loop.Run(); +} class AttributionsPrerenderBrowserTest : public AttributionsBrowserTest { public: AttributionsPrerenderBrowserTest()
diff --git a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc index 093342d..e2a71f3 100644 --- a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc +++ b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
@@ -210,7 +210,7 @@ RunUntilIdle(); } -// Disabled (crbug.com/1096988) +// Disabled (https://crbug.com/1096946) // Tests that the device starts, captures a frame, and then gracefully // errors-out because the target window is destroyed before the device is // stopped. @@ -233,7 +233,7 @@ StopAndDeAllocate(); } -// Disabled (crbug.com/1096988) +// Disabled (https://crbug.com/1096946) // Tests that the device stops delivering frames while suspended. When resumed, // any content changes that occurred during the suspend should cause a new frame // to be delivered, to ensure the client is up-to-date. @@ -268,7 +268,7 @@ StopAndDeAllocate(); } -// Disabled (crbug.com/1096988) +// Disabled (https://crbug.com/1096946) // Tests that the device delivers refresh frames when asked, while the source // content is not changing. IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTest, @@ -309,7 +309,7 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// TODO(crbug.com/1096946): enable. +// TODO(https://crbug.com/1096946): enable. IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTestWin, DISABLED_CapturesOccludedWindow) { aura::WindowTreeHost* window_tree_host = shell()->window()->GetHost(); @@ -337,7 +337,7 @@ #endif #if BUILDFLAG(IS_CHROMEOS_ASH) -// Disabled (crbug.com/1096988) +// Disabled (https://crbug.com/1096946) // On ChromeOS, another window may occlude a window that is being captured. // Make sure the visibility is set to visible during capture if it's occluded. IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTest, @@ -393,7 +393,7 @@ true /* fixed aspect ratio */))); #endif // BUILDFLAG(IS_CHROMEOS_ASH) -// Disabled (crbug.com/1096988) +// Disabled (https://crbug.com/1096946) // Tests that the device successfully captures a series of content changes, // whether the browser is running with software compositing or GPU-accelerated // compositing.
diff --git a/content/browser/media/capture/content_capture_device_browsertest_base.cc b/content/browser/media/capture/content_capture_device_browsertest_base.cc index 0efbb25..046a5fe 100644 --- a/content/browser/media/capture/content_capture_device_browsertest_base.cc +++ b/content/browser/media/capture/content_capture_device_browsertest_base.cc
@@ -21,6 +21,7 @@ #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "content/shell/common/shell_switches.h" +#include "media/base/video_types.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" @@ -47,18 +48,20 @@ // See the HandleRequest() method for the original documents being modified // here. std::string script; + const std::string color_string = + base::StringPrintf("%02x%02x%02x", SkColorGetR(color), SkColorGetG(color), + SkColorGetB(color)); if (IsCrossSiteCaptureTest()) { const GURL& inner_frame_url = embedded_test_server()->GetURL(kInnerFrameHostname, kInnerFramePath); script = base::StringPrintf( - "document.getElementsByTagName('iframe')[0].src = '%s?color=123456';", - inner_frame_url.spec().c_str()); + "document.getElementsByTagName('iframe')[0].src = '%s?color=%s';", + inner_frame_url.spec().c_str(), color_string.c_str()); } else { - script = "document.body.style.backgroundColor = '#123456';"; + script = base::StringPrintf("document.body.style.backgroundColor = '#%s';", + color_string.c_str()); } - script.replace(script.find("123456"), 6, - base::StringPrintf("%02x%02x%02x", SkColorGetR(color), - SkColorGetG(color), SkColorGetB(color))); + CHECK(ExecJs(shell()->web_contents(), script)); } @@ -94,7 +97,7 @@ media::VideoCaptureParams params; params.requested_format = media::VideoCaptureFormat( - capture_size, kMaxFramesPerSecond, media::PIXEL_FORMAT_I420); + capture_size, kMaxFramesPerSecond, GetVideoPixelFormat()); params.resolution_change_policy = IsFixedAspectRatioTest() ? media::ResolutionChangePolicy::FIXED_ASPECT_RATIO @@ -102,6 +105,11 @@ return params; } +media::VideoPixelFormat +ContentCaptureDeviceBrowserTestBase::GetVideoPixelFormat() const { + return media::VideoPixelFormat::PIXEL_FORMAT_I420; +} + base::TimeDelta ContentCaptureDeviceBrowserTestBase::GetMinCapturePeriod() { return base::Microseconds( base::Time::kMicrosecondsPerSecond /
diff --git a/content/browser/media/capture/content_capture_device_browsertest_base.h b/content/browser/media/capture/content_capture_device_browsertest_base.h index 28a0fab..cc9947d 100644 --- a/content/browser/media/capture/content_capture_device_browsertest_base.h +++ b/content/browser/media/capture/content_capture_device_browsertest_base.h
@@ -11,6 +11,7 @@ #include "build/build_config.h" #include "content/browser/media/capture/fake_video_capture_stack.h" #include "content/public/test/content_browser_test.h" +#include "media/base/video_types.h" #include "media/capture/video_capture_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkColor.h" @@ -54,6 +55,8 @@ gfx::Size GetExpectedSourceSize(); // Returns capture parameters based on the captured source size. + // Capture format can be customized by the subclasses, see + // |GetVideoPixelFormat()|. media::VideoCaptureParams SnapshotCaptureParams(); // Returns the actual minimum capture period the device is using. This should @@ -99,6 +102,9 @@ virtual bool IsFixedAspectRatioTest() const; virtual bool IsCrossSiteCaptureTest() const; + // Used to customize the video pixel format that will be used for capture. + virtual media::VideoPixelFormat GetVideoPixelFormat() const; + // Returns the size of the original content (i.e., not including any // stretching/scaling being done to fit it within a video frame). virtual gfx::Size GetCapturedSourceSize() const = 0;
diff --git a/content/browser/media/capture/fake_video_capture_stack.cc b/content/browser/media/capture/fake_video_capture_stack.cc index 2af1cad..5515600f 100644 --- a/content/browser/media/capture/fake_video_capture_stack.cc +++ b/content/browser/media/capture/fake_video_capture_stack.cc
@@ -6,17 +6,25 @@ #include <stdint.h> +#include <memory> #include <utility> #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "content/browser/media/capture/frame_test_util.h" +#include "gpu/command_buffer/common/mailbox_holder.h" +#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/video_frame.h" +#include "media/base/video_types.h" +#include "media/base/video_util.h" #include "media/capture/video/video_frame_receiver.h" #include "media/capture/video_capture_types.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/gpu_memory_buffer.h" namespace content { @@ -47,15 +55,9 @@ buffers_[buffer_id] = std::move(buffer_handle); } - void OnFrameReadyInBuffer( + scoped_refptr<media::VideoFrame> GetVideoFrameFromSharedMemory( media::ReadyFrameInBuffer frame, - std::vector<media::ReadyFrameInBuffer> scaled_frames) override { - const auto it = buffers_.find(frame.buffer_id); - CHECK(it != buffers_.end()); - - CHECK(it->second->is_read_only_shmem_region()); - base::ReadOnlySharedMemoryMapping mapping = - it->second->get_read_only_shmem_region().Map(); + base::ReadOnlySharedMemoryMapping mapping) { CHECK(mapping.IsValid()); const auto& frame_format = media::VideoCaptureFormat( @@ -70,9 +72,12 @@ const_cast<uint8_t*>(static_cast<const uint8_t*>(mapping.memory())), mapping.size(), frame.frame_info->timestamp); CHECK(video_frame); + video_frame->set_metadata(frame.frame_info->metadata); - if (frame.frame_info->color_space.has_value()) + if (frame.frame_info->color_space.has_value()) { video_frame->set_color_space(frame.frame_info->color_space.value()); + } + // This destruction observer will unmap the shared memory when the // VideoFrame goes out-of-scope. video_frame->AddDestructionObserver(base::BindOnce( @@ -83,6 +88,68 @@ [](std::unique_ptr<Buffer::ScopedAccessPermission> access) {}, std::move(frame.buffer_read_permission))); + return video_frame; + } + + scoped_refptr<media::VideoFrame> GetVideoFrameFromGpuMemoryBuffer( + media::ReadyFrameInBuffer frame, + const gfx::GpuMemoryBufferHandle& gmb_handle) { + CHECK(!gmb_handle.is_null()); + CHECK_EQ(frame.frame_info->pixel_format, + media::VideoPixelFormat::PIXEL_FORMAT_NV12); + + gpu::GpuMemoryBufferSupport gmb_support; + std::unique_ptr<gfx::GpuMemoryBuffer> gmb = + gmb_support.CreateGpuMemoryBufferImplFromHandle( + gmb_handle.Clone(), frame.frame_info->coded_size, + gfx::BufferFormat::YUV_420_BIPLANAR, + gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing()); + CHECK(gmb); + + gfx::Size size = gmb->GetSize(); + gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes]; + auto video_frame = media::VideoFrame::WrapExternalGpuMemoryBuffer( + frame.frame_info->visible_rect, size, std::move(gmb), mailbox_holders, + base::BindOnce([](const gpu::SyncToken& token, + std::unique_ptr<gfx::GpuMemoryBuffer> gmb) {}), + frame.frame_info->timestamp); + CHECK(video_frame); + + video_frame->set_metadata(frame.frame_info->metadata); + if (frame.frame_info->color_space.has_value()) { + video_frame->set_color_space(frame.frame_info->color_space.value()); + } + + auto mapped_frame = media::ConvertToMemoryMappedFrame(video_frame); + CHECK(mapped_frame); + + // This destruction observer will notify the video capture device once all + // downstream code is done using the VideoFrame. + mapped_frame->AddDestructionObserver(base::BindOnce( + [](std::unique_ptr<Buffer::ScopedAccessPermission> access) {}, + std::move(frame.buffer_read_permission))); + + return mapped_frame; + } + + void OnFrameReadyInBuffer( + media::ReadyFrameInBuffer frame, + std::vector<media::ReadyFrameInBuffer> scaled_frames) override { + const auto it = buffers_.find(frame.buffer_id); + CHECK(it != buffers_.end()); + + CHECK(it->second->is_read_only_shmem_region() || + it->second->is_gpu_memory_buffer_handle()); + + scoped_refptr<media::VideoFrame> video_frame = nullptr; + if (it->second->is_read_only_shmem_region()) { + video_frame = GetVideoFrameFromSharedMemory( + std::move(frame), it->second->get_read_only_shmem_region().Map()); + } else { + video_frame = GetVideoFrameFromGpuMemoryBuffer( + std::move(frame), it->second->get_gpu_memory_buffer_handle()); + } + // This implementation does not forward scaled frames. capture_stack_->OnReceivedFrame(std::move(video_frame)); } @@ -155,6 +222,10 @@ EXPECT_TRUE(frame->ColorSpace().IsValid()); + if (on_frame_received_) { + on_frame_received_.Run(frame.get()); + } + frames_.emplace_back(std::move(frame)); }
diff --git a/content/browser/media/capture/fake_video_capture_stack.h b/content/browser/media/capture/fake_video_capture_stack.h index 975e0c77..f1be3ea9 100644 --- a/content/browser/media/capture/fake_video_capture_stack.h +++ b/content/browser/media/capture/fake_video_capture_stack.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/callback_forward.h" #include "base/containers/circular_deque.h" #include "base/memory/scoped_refptr.h" #include "base/time/time.h" @@ -58,6 +59,15 @@ // capture stack. void ExpectNoLogMessages(); + using FrameReceivedCallback = + base::RepeatingCallback<void(media::VideoFrame*)>; + + // Sets a callback that will be invoked with a pointer to VideoFrame every + // time new frame gets added to the queue. + void SetFrameReceivedCallback(FrameReceivedCallback callback) { + on_frame_received_ = std::move(callback); + } + private: // A minimal implementation of VideoFrameReceiver that wraps buffers into // VideoFrame instances and forwards all relevant callbacks and data to the @@ -73,6 +83,7 @@ base::circular_deque<std::string> log_messages_; base::circular_deque<scoped_refptr<media::VideoFrame>> frames_; base::TimeDelta last_frame_timestamp_ = base::TimeDelta::Min(); + FrameReceivedCallback on_frame_received_; }; } // namespace content
diff --git a/content/browser/media/capture/frame_test_util.cc b/content/browser/media/capture/frame_test_util.cc index 1ebfdf5..bc510b9 100644 --- a/content/browser/media/capture/frame_test_util.cc +++ b/content/browser/media/capture/frame_test_util.cc
@@ -10,7 +10,10 @@ #include "base/numerics/safe_conversions.h" #include "media/base/video_frame.h" +#include "media/base/video_types.h" +#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColorSpace.h" +#include "third_party/skia/include/core/SkTypes.h" #include "ui/gfx/color_space.h" #include "ui/gfx/color_transform.h" #include "ui/gfx/geometry/rect.h" @@ -38,6 +41,34 @@ } } +void LoadStimsFromYUV(const uint8_t y_src[], + const uint16_t uv_src[], + int width, + TriStim stims[]) { +// https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#nv12 +// "All of the Y samples appear first in memory as an array of unsigned char +// values with an even number of lines. The Y plane is followed immediately by +// an array of unsigned char values that contains packed U (Cb) and V (Cr) +// samples. When the combined U-V array is addressed as an array of +// little-endian WORD values, the LSBs contain the U values, and the MSBs +// contain the V values." +#if defined(SK_CPU_BENDIAN) + for (int i = 0; i < width; ++i) { + stims[i].SetPoint( + y_src[i] / 255.0f, + (uv_src[i / 2] >> 8) / 255.0f, // MSB contains U values on LE + (uv_src[i / 2] & 0xFF) / 255.0f); + } +#else + for (int i = 0; i < width; ++i) { + stims[i].SetPoint( + y_src[i] / 255.0f, + (uv_src[i / 2] & 0xFF) / 255.0f, // LSB contains U values on LE + (uv_src[i / 2] >> 8) / 255.0f); + } +#endif +} + // Maps [0.0,1.0]⇒[0,255], rounding to the nearest integer. uint8_t QuantizeAndClamp(float value) { return base::saturated_cast<uint8_t>( @@ -82,13 +113,24 @@ // Convert one row at a time. std::vector<gfx::ColorTransform::TriStim> stims(bitmap.width()); for (int row = 0; row < bitmap.height(); ++row) { - LoadStimsFromYUV(frame.visible_data(media::VideoFrame::kYPlane) + - row * frame.stride(media::VideoFrame::kYPlane), - frame.visible_data(media::VideoFrame::kUPlane) + - (row / 2) * frame.stride(media::VideoFrame::kUPlane), - frame.visible_data(media::VideoFrame::kVPlane) + - (row / 2) * frame.stride(media::VideoFrame::kVPlane), - bitmap.width(), stims.data()); + if (frame.format() == media::VideoPixelFormat::PIXEL_FORMAT_I420) { + LoadStimsFromYUV(frame.visible_data(media::VideoFrame::kYPlane) + + row * frame.stride(media::VideoFrame::kYPlane), + frame.visible_data(media::VideoFrame::kUPlane) + + (row / 2) * frame.stride(media::VideoFrame::kUPlane), + frame.visible_data(media::VideoFrame::kVPlane) + + (row / 2) * frame.stride(media::VideoFrame::kVPlane), + bitmap.width(), stims.data()); + } else { + CHECK_EQ(frame.format(), media::VideoPixelFormat::PIXEL_FORMAT_NV12); + LoadStimsFromYUV( + frame.visible_data(media::VideoFrame::kYPlane) + + row * frame.stride(media::VideoFrame::kYPlane), + reinterpret_cast<const uint16_t*>( + frame.visible_data(media::VideoFrame::kUVPlane) + + (row / 2) * frame.stride(media::VideoFrame::kUVPlane)), + bitmap.width(), stims.data()); + } transform->Transform(stims.data(), stims.size()); StimsToN32Row(stims.data(), bitmap.width(), reinterpret_cast<uint8_t*>(bitmap.getAddr32(0, row))); @@ -134,10 +176,11 @@ ++y) { for (int x = include_rect.x(), right = include_rect.right(); x < right; ++x) { - const SkColor color = frame.getColor(x, y); if (exclude_rect.Contains(x, y)) { continue; } + + const SkColor color = frame.getColor(x, y); include_sums[0] += SkColorGetR(color); include_sums[1] += SkColorGetG(color); include_sums[2] += SkColorGetB(color); @@ -168,6 +211,49 @@ } // static +bool FrameTestUtil::IsApproximatelySameColor(SkColor color, + SkColor expected_color, + int max_diff) { + const int r_diff = std::abs(static_cast<int>(SkColorGetR(color)) - + static_cast<int>(SkColorGetR(expected_color))); + const int g_diff = std::abs(static_cast<int>(SkColorGetG(color)) - + static_cast<int>(SkColorGetG(expected_color))); + const int b_diff = std::abs(static_cast<int>(SkColorGetB(color)) - + static_cast<int>(SkColorGetB(expected_color))); + return r_diff < max_diff && g_diff < max_diff && b_diff < max_diff; +} + +bool FrameTestUtil::IsApproximatelySameColor(SkBitmap frame, + const gfx::Rect& raw_include_rect, + const gfx::Rect& raw_exclude_rect, + SkColor expected_color, + int max_diff) { + // Clip the rects to the valid region within |frame|. Also, only the subregion + // of |exclude_rect| within |include_rect| is relevant. + gfx::Rect include_rect = raw_include_rect; + include_rect.Intersect(gfx::Rect(0, 0, frame.width(), frame.height())); + gfx::Rect exclude_rect = raw_exclude_rect; + exclude_rect.Intersect(include_rect); + + for (int y = include_rect.y(), bottom = include_rect.bottom(); y < bottom; + ++y) { + for (int x = include_rect.x(), right = include_rect.right(); x < right; + ++x) { + if (exclude_rect.Contains(x, y)) { + continue; + } + + const SkColor color = frame.getColor(x, y); + if (!IsApproximatelySameColor(color, expected_color, max_diff)) { + return false; + } + } + } + + return true; +} + +// static gfx::RectF FrameTestUtil::TransformSimilarly(const gfx::Rect& original, const gfx::RectF& transformed, const gfx::Rect& rect) {
diff --git a/content/browser/media/capture/frame_test_util.h b/content/browser/media/capture/frame_test_util.h index 248c035..eb4d2d7 100644 --- a/content/browser/media/capture/frame_test_util.h +++ b/content/browser/media/capture/frame_test_util.h
@@ -52,12 +52,28 @@ const gfx::Rect& include_rect, const gfx::Rect& exclude_rect); - // Returns true if the red, green, and blue components are all within - // |max_diff| of each other. + // Returns true if the red, green, and blue components of |color| and |rgb| + // are all within |max_diff| of each other. static bool IsApproximatelySameColor(SkColor color, const RGB& rgb, int max_diff = kMaxColorDifference); + // Returns true if the red, green, and blue components of |color| and + // |expected_color| are all within |max_diff| of each other. + static bool IsApproximatelySameColor(SkColor color, + SkColor expected_color, + int max_diff = kMaxColorDifference); + + // Returns true if the red, green, and blue components of pixels in + // |frame| are within |max_diff| of |expected_color|. Only the pixels + // contained within |raw_include_rect| and not contained within + // |raw_exclude_rect| will be considered. + static bool IsApproximatelySameColor(SkBitmap frame, + const gfx::Rect& raw_include_rect, + const gfx::Rect& raw_exclude_rect, + SkColor expected_color, + int max_diff = kMaxColorDifference); + // Determines how |original| has been scaled and translated to become // |transformed|, and then applies the same transform on |rect| and returns // the result.
diff --git a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc index 6ab8110..c20c14b5 100644 --- a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc +++ b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
@@ -6,7 +6,11 @@ #include <tuple> +#include "base/bind.h" #include "base/run_loop.h" +#include "base/strings/strcat.h" +#include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "cc/test/pixel_test_utils.h" @@ -23,15 +27,18 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/shell/browser/shell.h" +#include "media/base/video_frame.h" +#include "media/base/video_types.h" #include "media/base/video_util.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_f.h" #if BUILDFLAG(IS_WIN) -#include "base/test/scoped_feature_list.h" #include "ui/aura/test/aura_test_utils.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" @@ -56,11 +63,25 @@ // Runs the browser until a frame whose content matches the given |color| is // found in the captured frames queue, or until a testing failure has - // occurred. - void WaitForFrameWithColor(SkColor color) { - VLOG(1) << "Waiting for frame content area filled with color: red=" - << SkColorGetR(color) << ", green=" << SkColorGetG(color) - << ", blue=" << SkColorGetB(color); + // occurred. When |tolerate_color| is non-nullopt, encountering a frame that + // does not match both |color| and |tolerate_color| will cause a testing + // failure. This allows the callers to tighten the tolerance on the frames + // they are willing to accept (since specifying `tolerate_color` causes the + // test to fail in case we encounter something else). + void WaitForFrameWithColor( + SkColor color, + absl::optional<SkColor> tolerate_color = absl::nullopt) { + const std::string color_string = + base::StringPrintf("red=%d, green=%d, blue=%d", SkColorGetR(color), + SkColorGetG(color), SkColorGetB(color)); + const std::string tolerated_color_string = + tolerate_color + ? base::StringPrintf( + "red=%d, green=%d, blue=%d", SkColorGetR(*tolerate_color), + SkColorGetG(*tolerate_color), SkColorGetB(*tolerate_color)) + : std::string("<none>"); + VLOG(1) << "Waiting for frame content area filled with color: " + << color_string << ", tolerated color: " << tolerated_color_string; while (!testing::Test::HasFailure()) { EXPECT_TRUE(capture_stack()->started()); @@ -74,10 +95,20 @@ const SkBitmap rgb_frame = capture_stack()->NextCapturedFrame(); EXPECT_FALSE(rgb_frame.empty()); - // Three regions of the frame will be analyzed: 1) the upper-left - // quadrant of the content region where the iframe draws; 2) the - // remaining three quadrants of the content region where the main frame - // draws; and 3) the non-content (i.e., letterboxed) region. + // Three regions of the frame will be analyzed: + // 1. The upper-left quadrant of the content region where the iframe + // draws. If the iframe is not present (the non-cross-frame test + // variant), this region will come from the main frame. + // 2. The remaining three quadrants of the content region where the main + // frame draws. + // 3. The non-content (i.e., letterboxed) region. + // + // In both cross-site and non-cross-site variants, region #1 should be + // of |color|. Region #2 should be of |color| in non-cross-site tests, + // and white in cross-site tests. And region #3 must always be black, + // but won't be present at all if the tests don't request fixed aspect + // ratio frames. + const gfx::Size frame_size(rgb_frame.width(), rgb_frame.height()); const gfx::Size source_size = GetExpectedSourceSize(); const gfx::Rect iframe_rect(0, 0, source_size.width() / 2, @@ -117,39 +148,69 @@ "approx. " << ToSafeIncludeRect(content_in_frame_rect_f).ToString() << " and has average color " << average_mainframe_rgb - << ", letterbox region has average color " << average_letterbox_rgb; + << ", letterbox region has average color " << average_letterbox_rgb + << ", max_color_diff is " << max_color_diff; - // The letterboxed region should always be black. - if (IsFixedAspectRatioTest()) { - EXPECT_TRUE(IsApproximatelySameColor( - SK_ColorBLACK, average_letterbox_rgb, max_color_diff)); - } - - if (testing::Test::HasFailure()) { - ADD_FAILURE() << "Test failure occurred at this frame; PNG dump: " + if (IsFixedAspectRatioTest() && + !IsApproximatelySameColor( + rgb_frame, gfx::Rect(frame_size), + ToSafeExcludeRect(content_in_frame_rect_f), SK_ColorBLACK, + max_color_diff)) { + // The letterboxed region should always be black for fixed aspect + // ratio tests, and not present otherwise. + ADD_FAILURE() << "Letterbox region is not black; PNG dump:\n" << cc::GetPNGDataUrl(rgb_frame); return; } - // Return if the content region(s) now has/have the expected color(s). - if (IsCrossSiteCaptureTest() && - IsApproximatelySameColor(color, average_iframe_rgb, - max_color_diff) && - IsApproximatelySameColor(SK_ColorWHITE, average_mainframe_rgb, - max_color_diff)) { + const SkColor expected_mainframe_color = + IsCrossSiteCaptureTest() ? SK_ColorWHITE : color; + const SkColor tolerated_mainframe_color = + IsCrossSiteCaptureTest() ? SK_ColorWHITE + : tolerate_color.value_or(SK_ColorWHITE); + + if (IsApproximatelySameColor(rgb_frame, + ToSafeIncludeRect(iframe_in_frame_rect_f), + gfx::Rect(), color, max_color_diff) && + IsApproximatelySameColor( + rgb_frame, ToSafeIncludeRect(content_in_frame_rect_f), + ToSafeExcludeRect(iframe_in_frame_rect_f), + expected_mainframe_color, max_color_diff)) { + // If we have a frame that matches all expectations, we can stop + // waiting. VLOG(1) << "Observed desired frame."; return; - } else if (!IsCrossSiteCaptureTest() && - IsApproximatelySameColor(color, average_iframe_rgb, - max_color_diff) && - IsApproximatelySameColor(color, average_mainframe_rgb, - max_color_diff)) { - VLOG(1) << "Observed desired frame."; - return; - } else { - VLOG(3) << "PNG dump of undesired frame: " - << cc::GetPNGDataUrl(rgb_frame); } + + if (tolerate_color && + IsApproximatelySameColor( + rgb_frame, ToSafeIncludeRect(iframe_in_frame_rect_f), + gfx::Rect(), *tolerate_color, max_color_diff) && + IsApproximatelySameColor( + rgb_frame, ToSafeIncludeRect(content_in_frame_rect_f), + ToSafeExcludeRect(iframe_in_frame_rect_f), + tolerated_mainframe_color, max_color_diff)) { + // Otherwise, if the frame matches a color that the caller told us to + // tolearate, we'll keep waiting for the frame. + VLOG(1) << "Observed frame with tolerated color. This is fine, keep " + "waiting."; + continue; // Skip requesting refreshed frame - the damage signal + // should propagate eventually and we should get a new + // frame. + } + + if (tolerate_color) { + // Otherwise, if the tolerated color was set and we reached this + // point, it means the frame we got did not match both expected and + // tolerated colors. + ADD_FAILURE() << "Observed frame that did not match both expected " + "and tolerated colors. PNG dump:\n" + << cc::GetPNGDataUrl(rgb_frame); + return; + } + + // Otherwise, we weren't told to tolerate colors other than the expected + // one, and the frame did not match. Keep waiting. } // Wait for at least the minimum capture period before checking for more @@ -411,7 +472,8 @@ class WebContentsVideoCaptureDeviceBrowserTestP : public WebContentsVideoCaptureDeviceBrowserTest, - public testing::WithParamInterface<std::tuple<bool, bool, bool>> { + public testing::WithParamInterface< + std::tuple<bool, bool, bool, media::VideoPixelFormat>> { public: bool IsSoftwareCompositingTest() const override { return std::get<0>(GetParam()); @@ -422,6 +484,26 @@ bool IsCrossSiteCaptureTest() const override { return std::get<2>(GetParam()); } + media::VideoPixelFormat GetVideoPixelFormat() const override { + return std::get<3>(GetParam()); + } + + // Returns human-readable description of the test based on test parameters. + // Currently unused due to CQ treating the tests as new and applying higher + // flakiness bar for them, which makes it impossible to land them (they + // flake ~1 in 20 times). + static std::string GetDescription( + const testing::TestParamInfo< + WebContentsVideoCaptureDeviceBrowserTestP::ParamType>& info) { + std::string name = base::StrCat( + {std::get<0>(info.param) ? "Software_" : "GPU_", + std::get<1>(info.param) ? "Fixed_" : "Variable_", + std::get<2>(info.param) ? "CrossSite_" : "Main_", + std::get<3>(info.param) == media::VideoPixelFormat::PIXEL_FORMAT_I420 + ? "I420" + : "Detect"}); + return name; + } }; #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID) @@ -434,7 +516,24 @@ testing::Values(false /* variable aspect ratio */, true /* fixed aspect ratio */), testing::Values(false /* page has only a main frame */, - true /* page contains a cross-site iframe */))); + true /* page contains a cross-site iframe */), + testing::Values(media::VideoPixelFormat::PIXEL_FORMAT_I420))); +#elif BUILDFLAG(IS_MAC) +// On MacOS, there is a newly added support for NV12-in-GMB. It relies on GPU +// acceleration, but has a feature detection built-in if the format is +// specified as media::VideoPixelFormat::PIXEL_FORMAT_UNKNOWN. +INSTANTIATE_TEST_SUITE_P( + All, + WebContentsVideoCaptureDeviceBrowserTestP, + testing::Combine( + testing::Values(false /* GPU-accelerated compositing */, + true /* software compositing */), + testing::Values(false /* variable aspect ratio */, + true /* fixed aspect ratio */), + testing::Values(false /* page has only a main frame */, + true /* page contains a cross-site iframe */), + testing::Values(media::VideoPixelFormat::PIXEL_FORMAT_I420, + media::VideoPixelFormat::PIXEL_FORMAT_UNKNOWN))); #else INSTANTIATE_TEST_SUITE_P( All, @@ -445,8 +544,9 @@ testing::Values(false /* variable aspect ratio */, true /* fixed aspect ratio */), testing::Values(false /* page has only a main frame */, - true /* page contains a cross-site iframe */))); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) + true /* page contains a cross-site iframe */), + testing::Values(media::VideoPixelFormat::PIXEL_FORMAT_I420))); +#endif // Tests that the device successfully captures a series of content changes, // whether the browser is running with software compositing or GPU-accelerated @@ -454,20 +554,41 @@ // and whether the main document contains a cross-site iframe. IN_PROC_BROWSER_TEST_P(WebContentsVideoCaptureDeviceBrowserTestP, CapturesContentChanges) { + media::VideoPixelFormat specified_format = GetVideoPixelFormat(); + media::VideoPixelFormat expected_format = specified_format; + if (specified_format == media::VideoPixelFormat::PIXEL_FORMAT_UNKNOWN) { + if (IsSoftwareCompositingTest()) { + expected_format = media::VideoPixelFormat::PIXEL_FORMAT_I420; + } else { + expected_format = media::VideoPixelFormat::PIXEL_FORMAT_NV12; + } + } + SCOPED_TRACE(testing::Message() << "Test parameters: " << (IsSoftwareCompositingTest() ? "Software Compositing" : "GPU Compositing") << " with " << (IsFixedAspectRatioTest() ? "Fixed Video Aspect Ratio" - : "Variable Video Aspect Ratio")); + : "Variable Video Aspect Ratio") + << ", specified format is " + << media::VideoPixelFormatToString(specified_format)); + + capture_stack()->SetFrameReceivedCallback(base::BindRepeating( + [](media::VideoPixelFormat expected_format, media::VideoFrame* frame) { + EXPECT_EQ(frame->format(), expected_format); + }, + expected_format)); NavigateToInitialDocument(); AllocateAndStartAndWaitForFirstFrame(); EXPECT_TRUE(shell()->web_contents()->IsBeingCaptured()); - for (int visilibilty_case = 0; visilibilty_case < 3; ++visilibilty_case) { - switch (visilibilty_case) { + // First frame is supposed to be black, store this as a previous color: + absl::optional<SkColor> previous_color = SK_ColorBLACK; + + for (int visibility_case = 0; visibility_case < 3; ++visibility_case) { + switch (visibility_case) { case 0: { SCOPED_TRACE(testing::Message() << "Visibility case: WebContents is showing."); @@ -505,9 +626,11 @@ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorWHITE, }; + for (SkColor color : kColorsToCycleThrough) { ChangePageContentColor(color); - WaitForFrameWithColor(color); + WaitForFrameWithColor(color, previous_color); + previous_color = color; } }
diff --git a/content/browser/net/socket_broker_impl.cc b/content/browser/net/socket_broker_impl.cc new file mode 100644 index 0000000..5ac6c4a5 --- /dev/null +++ b/content/browser/net/socket_broker_impl.cc
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/net/socket_broker_impl.h" + +#include "mojo/public/cpp/bindings/remote.h" +#include "net/base/net_errors.h" +#include "net/log/net_log_source.h" +#include "net/socket/socket_descriptor.h" +#include "net/socket/tcp_socket.h" + +namespace content { + +SocketBrokerImpl::SocketBrokerImpl() = default; + +SocketBrokerImpl::~SocketBrokerImpl() = default; + +void SocketBrokerImpl::CreateTcpSocket(net::AddressFamily address_family, + CreateTcpSocketCallback callback) { +// TODO(https://crbug.com/1311014): Open and release raw socket on Windows. +#if BUILDFLAG(IS_WIN) + std::move(callback).Run(mojo::PlatformHandle(), net::ERR_FAILED); +#else + net::SocketDescriptor socket; + int rv = + net::TCPSocket::OpenAndReleaseSocketDescriptor(address_family, &socket); + base::ScopedFD fd(socket); + + std::move(callback).Run(mojo::PlatformHandle(std::move(fd)), rv); +#endif +} + +} // namespace content
diff --git a/content/browser/net/socket_broker_impl.h b/content/browser/net/socket_broker_impl.h new file mode 100644 index 0000000..60d0e24 --- /dev/null +++ b/content/browser/net/socket_broker_impl.h
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_NET_SOCKET_BROKER_IMPL_H_ +#define CONTENT_BROWSER_NET_SOCKET_BROKER_IMPL_H_ + +#include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "net/base/address_family.h" +#include "services/network/public/mojom/socket_broker.mojom.h" + +namespace content { + +// Implementation of SocketBroker interface. Creates new sockets and sends them +// to the network sandbox via mojo. +class CONTENT_EXPORT SocketBrokerImpl : public network::mojom::SocketBroker { + public: + explicit SocketBrokerImpl(); + ~SocketBrokerImpl() override; + + SocketBrokerImpl(const SocketBrokerImpl&) = delete; + SocketBrokerImpl& operator=(const SocketBrokerImpl&) = delete; + + // mojom::SocketBroker implementation. + void CreateTcpSocket(net::AddressFamily address_family, + CreateTcpSocketCallback callback) override; + + private: + mojo::ReceiverSet<network::mojom::SocketBroker> receivers_; +}; + +} // namespace content +#endif // CONTENT_BROWSER_NET_SOCKET_BROKER_IMPL_H_
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc index b5ab4e3..5ef05e3 100644 --- a/content/browser/prerender/prerender_browsertest.cc +++ b/content/browser/prerender/prerender_browsertest.cc
@@ -21,6 +21,7 @@ #include "base/synchronization/lock.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" +#include "base/test/test_timeouts.h" #include "base/thread_annotations.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -730,6 +731,166 @@ PrerenderHost::FinalStatus::kLoginAuthRequested); } +IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, + CancelOnSpeculationCandidateRemoved) { + // Navigate to an initial page. + const GURL kInitialUrl = GetUrl("/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl)); + + // Start prerendering. + const GURL kPrerenderingUrl = GetUrl("/title2.html"); + test::PrerenderHostRegistryObserver registry_observer(*web_contents_impl()); + ASSERT_TRUE(ExecJs(web_contents_impl()->GetPrimaryMainFrame(), + JsReplace( + R"( + let sc = document.createElement('script'); + sc.type = 'speculationrules'; + sc.textContent = JSON.stringify({ + prerender: [ + {source: "list", urls: [$1]} + ] + }); + document.head.appendChild(sc); + )", + kPrerenderingUrl))); + registry_observer.WaitForTrigger(kPrerenderingUrl); + int host_id = GetHostForUrl(kPrerenderingUrl); + ASSERT_NE(host_id, RenderFrameHost::kNoFrameTreeNodeId); + + // Remove the rules and check that the prerender is cancelled with an + // appropriate final status. + test::PrerenderHostObserver host_observer(*web_contents_impl(), host_id); + ASSERT_TRUE(ExecJs( + web_contents_impl()->GetPrimaryMainFrame(), + "document.querySelector('script[type=speculationrules]').remove()")); + host_observer.WaitForDestroyed(); + EXPECT_EQ(GetHostForUrl(kPrerenderingUrl), + RenderFrameHost::kNoFrameTreeNodeId); + ExpectFinalStatusForSpeculationRule( + PrerenderHost::FinalStatus::kTriggerDestroyed); +} + +IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, + DontCancelOnSpeculationUpdateIfStillEligible) { + // Navigate to an initial page. + const GURL kInitialUrl = GetUrl("/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl)); + + // Start prerendering. + const GURL kPrerenderingUrl = GetUrl("/title2.html"); + test::PrerenderHostRegistryObserver registry_observer(*web_contents_impl()); + ASSERT_TRUE(ExecJs(web_contents_impl()->GetPrimaryMainFrame(), + JsReplace( + R"( + let sc = document.createElement('script'); + sc.type = 'speculationrules'; + sc.textContent = JSON.stringify({ + prerender: [ + {source: "list", urls: [$1]} + ] + }); + document.head.appendChild(sc); + )", + kPrerenderingUrl))); + registry_observer.WaitForTrigger(kPrerenderingUrl); + int host_id = GetHostForUrl(kPrerenderingUrl); + ASSERT_NE(host_id, RenderFrameHost::kNoFrameTreeNodeId); + + ASSERT_TRUE(ExecJs(web_contents_impl()->GetPrimaryMainFrame(), + JsReplace( + R"( + document.querySelector('script[type=speculationrules]') + .remove(); + let sc = document.createElement('script'); + sc.type = 'speculationrules'; + sc.textContent = JSON.stringify({ + prerender: [ + {source: "list", urls: ["/empty.html", $1]} + ] + }); + document.head.appendChild(sc); + )", + kPrerenderingUrl))); + + // Replace the rules. Even though the original rules are gone, the new ones + // still permit the prerender so it continues. + { + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout()); + run_loop.Run(); + ASSERT_NE(GetHostForUrl(kPrerenderingUrl), + RenderFrameHost::kNoFrameTreeNodeId); + } + + // Remove the rules and check that the prerender is cancelled. + test::PrerenderHostObserver host_observer(*web_contents_impl(), host_id); + ASSERT_TRUE(ExecJs( + web_contents_impl()->GetPrimaryMainFrame(), + "document.querySelector('script[type=speculationrules]').remove()")); + host_observer.WaitForDestroyed(); + EXPECT_EQ(GetHostForUrl(kPrerenderingUrl), + RenderFrameHost::kNoFrameTreeNodeId); +} + +IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, + CanStartSecondPrerenderWhenCancellingFirst) { + // Navigate to an initial page. + const GURL kInitialUrl = GetUrl("/title1.html"); + ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl)); + + // Start prerendering. + const GURL kPrerenderingUrl = GetUrl("/title2.html"); + test::PrerenderHostRegistryObserver registry_observer(*web_contents_impl()); + ASSERT_TRUE(ExecJs(web_contents_impl()->GetPrimaryMainFrame(), + JsReplace( + R"( + let sc = document.createElement('script'); + sc.type = 'speculationrules'; + sc.textContent = JSON.stringify({ + prerender: [ + {source: "list", urls: [$1]} + ] + }); + document.head.appendChild(sc); + )", + kPrerenderingUrl))); + registry_observer.WaitForTrigger(kPrerenderingUrl); + int host_id = GetHostForUrl(kPrerenderingUrl); + ASSERT_NE(host_id, RenderFrameHost::kNoFrameTreeNodeId); + + // Starting a different prerender still works. + // (For now, this works unconditionally. In the future this might depend on + // some other conditions.) + const GURL kPrerenderingUrl2 = GetUrl("/title3.html"); + test::PrerenderHostObserver host_observer(*web_contents_impl(), host_id); + ASSERT_TRUE(ExecJs(web_contents_impl()->GetPrimaryMainFrame(), + JsReplace( + R"( + document.querySelector('script[type=speculationrules]') + .remove(); + let sc = document.createElement('script'); + sc.type = 'speculationrules'; + sc.textContent = JSON.stringify({ + prerender: [ + {source: "list", urls: [$1]} + ] + }); + document.head.appendChild(sc); + )", + kPrerenderingUrl2))); + + // The original prerender should be cancelled. + host_observer.WaitForDestroyed(); + EXPECT_EQ(GetHostForUrl(kPrerenderingUrl), + RenderFrameHost::kNoFrameTreeNodeId); + + // And the new one should be discovered. + registry_observer.WaitForTrigger(kPrerenderingUrl2); + int second_host_id = GetHostForUrl(kPrerenderingUrl2); + EXPECT_NE(second_host_id, RenderFrameHost::kNoFrameTreeNodeId); +} + // Tests that prerendering triggered by prerendered pages is deferred until // activation. IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderChain) {
diff --git a/content/browser/prerender/prerender_host_registry_unittest.cc b/content/browser/prerender/prerender_host_registry_unittest.cc index 179eae5..7b78ae7 100644 --- a/content/browser/prerender/prerender_host_registry_unittest.cc +++ b/content/browser/prerender/prerender_host_registry_unittest.cc
@@ -35,14 +35,20 @@ return candidate; } -void SendCandidate(const GURL& url, - mojo::Remote<blink::mojom::SpeculationHost>& remote) { +void SendCandidates(const std::vector<GURL>& urls, + mojo::Remote<blink::mojom::SpeculationHost>& remote) { std::vector<blink::mojom::SpeculationCandidatePtr> candidates; - candidates.push_back(CreatePrerenderCandidate(url)); + candidates.resize(urls.size()); + base::ranges::transform(urls, candidates.begin(), &CreatePrerenderCandidate); remote->UpdateSpeculationCandidates(std::move(candidates)); remote.FlushForTesting(); } +void SendCandidate(const GURL& url, + mojo::Remote<blink::mojom::SpeculationHost>& remote) { + SendCandidates({url}, remote); +} + PrerenderAttributes GeneratePrerenderAttributes( const GURL& url, PrerenderTriggerType trigger_type, @@ -411,8 +417,7 @@ ASSERT_TRUE(remote1.is_connected()); const GURL kPrerenderingUrl1("https://example.com/next1"); const GURL kPrerenderingUrl2("https://example.com/next2"); - SendCandidate(kPrerenderingUrl1, remote1); - SendCandidate(kPrerenderingUrl2, remote1); + SendCandidates({kPrerenderingUrl1, kPrerenderingUrl2}, remote1); PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry(); // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1. @@ -455,8 +460,7 @@ ASSERT_TRUE(remote1.is_connected()); const GURL kPrerenderingUrl1("https://example.com/next1"); const GURL kPrerenderingUrl2("https://example.com/next2"); - SendCandidate(kPrerenderingUrl1, remote1); - SendCandidate(kPrerenderingUrl2, remote1); + SendCandidates({kPrerenderingUrl1, kPrerenderingUrl2}, remote1); PrerenderHostRegistry* registry = web_contents->GetPrerenderHostRegistry(); // PrerenderHostRegistry should only start prerendering for kPrerenderingUrl1.
diff --git a/content/browser/speculation_rules/speculation_host_impl.cc b/content/browser/speculation_rules/speculation_host_impl.cc index 41a9fa4..7d018aca 100644 --- a/content/browser/speculation_rules/speculation_host_impl.cc +++ b/content/browser/speculation_rules/speculation_host_impl.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "content/browser/speculation_rules/speculation_host_impl.h" +#include <functional> +#include "base/containers/span.h" #include "base/ranges/algorithm.h" #include "content/browser/prerender/prerender_attributes.h" #include "content/browser/prerender/prerender_host_registry.h" @@ -128,7 +130,7 @@ void SpeculationHostImpl::ProcessCandidatesForPrerender( const std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) { - if (!registry_ || candidates.empty()) + if (!registry_) return; DCHECK(blink::features::IsPrerender2Enabled()); @@ -142,19 +144,89 @@ return; } + // Extract only the candidates which apply to prerender, and sort them by URL + // so we can efficiently compare them to `started_prerenders_`. + std::vector<blink::mojom::SpeculationCandidatePtr> prerender_candidates; + for (const auto& candidate : candidates) { + if (candidate->action == blink::mojom::SpeculationAction::kPrerender) + prerender_candidates.push_back(candidate.Clone()); + } + base::ranges::sort(prerender_candidates, std::less<>(), + &blink::mojom::SpeculationCandidate::url); + std::vector<blink::mojom::SpeculationCandidatePtr> candidates_to_start; + + // Compare the sorted candidate and started prerender lists to one another. + // Since they are sorted, we process the lexicographically earlier of the two + // URLs pointed at by the iterators, and compare the range of entries in each + // that match that URL. + // + // URLs which are present in the prerender list but not the candidate list can + // no longer proceed and are cancelled. + // + // URLs which are present in the candidate list but not the prerender list + // could be started and are gathered in `candidates_to_start`. + auto candidate_it = prerender_candidates.begin(); + auto started_it = started_prerenders_.begin(); + while (candidate_it != prerender_candidates.end() || + started_it != started_prerenders_.end()) { + // Select the lesser of the two URLs to diff. + GURL url; + if (started_it == started_prerenders_.end()) + url = (*candidate_it)->url; + else if (candidate_it == prerender_candidates.end()) + url = started_it->url; + else + url = std::min((*candidate_it)->url, started_it->url); + + // Select the ranges from both that match the URL in question. + auto equal_prerender_end = base::ranges::find_if( + started_it, started_prerenders_.end(), + [&](const auto& started) { return started.url != url; }); + base::span<PrerenderInfo> matching_prerenders(started_it, + equal_prerender_end); + auto equal_candidate_end = base::ranges::find_if( + candidate_it, prerender_candidates.end(), + [&](const auto& candidate) { return candidate->url != url; }); + base::span<blink::mojom::SpeculationCandidatePtr> matching_candidates( + candidate_it, equal_candidate_end); + + // Decide what started prerenders to cancel. + for (PrerenderInfo& prerender : matching_prerenders) { + if (prerender.prerender_host_id == RenderFrameHost::kNoFrameTreeNodeId) + continue; + // TODO(jbroman): This doesn't currently care about other aspects, like + // the referrer. This doesn't presently matter, but in the future we might + // want to cancel if there are candidates which match by URL but none of + // which permit this prerender. + if (matching_candidates.empty()) { + registry_->OnTriggerDestroyed(prerender.prerender_host_id); + prerender.prerender_host_id = RenderFrameHost::kNoFrameTreeNodeId; + } + } + + // Decide what new candidates to start. + // For now, start the first candidate for a URL only if there are no + // matching prerenders. We could be cleverer in the future. + if (matching_prerenders.empty()) { + DCHECK_GT(matching_candidates.size(), 0u); + candidates_to_start.push_back(std::move(matching_candidates[0])); + } + + // Advance the iterators past all matching entries. + candidate_it = equal_candidate_end; + started_it = equal_prerender_end; + } + + // Actually start the candidates once the diffing is done. auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host()); - for (const auto& it : candidates) { - if (it->action != blink::mojom::SpeculationAction::kPrerender) - continue; + for (const auto& it : candidates_to_start) { + DCHECK_EQ(it->action, blink::mojom::SpeculationAction::kPrerender); auto [begin, end] = base::ranges::equal_range( started_prerenders_.begin(), started_prerenders_.end(), it->url, std::less<>(), &PrerenderInfo::url); - if (begin != end) { - // A prerender with this URL was previously triggered. - // At the moment there is no mechanism for cancelling these. - continue; - } + DCHECK(begin == end) + << "cannot currently start a second prerender with the same URL"; GetContentClient()->browser()->LogWebFeatureForCurrentPage( rfhi, blink::mojom::WebFeature::kSpeculationRulesPrerender);
diff --git a/content/test/data/attribution_reporting/register_attribution_src.js b/content/test/data/attribution_reporting/register_attribution_src.js index 06f87e2..0b880d5b 100644 --- a/content/test/data/attribution_reporting/register_attribution_src.js +++ b/content/test/data/attribution_reporting/register_attribution_src.js
@@ -7,11 +7,33 @@ img.attributionSrc = src; } +function createAttributionEligibleImgSrc(src) { + const img = document.createElement('img'); + img.setAttribute('attributionsrc', ''); + img.src = src; +} + function createAttributionSrcScript(src) { const script = document.createElement('script'); script.setAttribute('attributionsrc', src); } +function doAttributionEligibleFetch(url) { + const headers = { + 'Attribution-Reporting-Eligible': 'event-source' + }; + // Optionally set keepalive to ensure the request outlives the page. + window.fetch(url, + { headers, keepalive: true}); +} + +function doAttributionEligibleXHR(url) { + const req = new XMLHttpRequest(); + req.open('GET', url); + req.setRequestHeader('Attribution-Reporting-Eligible', 'event-source'); + req.send(); +} + function createAttributionSrcAnchor({ id, url,
diff --git a/content/test/data/attribution_reporting/register_source_headers.html.mock-http-headers b/content/test/data/attribution_reporting/register_source_headers.html.mock-http-headers index 4f64aab..54ba38a4 100644 --- a/content/test/data/attribution_reporting/register_source_headers.html.mock-http-headers +++ b/content/test/data/attribution_reporting/register_source_headers.html.mock-http-headers
@@ -1,2 +1,4 @@ HTTP/1.1 200 OK +Access-Control-Allow-Origin: * +Access-Control-Allow-Headers: * Attribution-Reporting-Register-Source:{"source_event_id":"5","destination":"https://d.test"}
diff --git a/content/test/data/attribution_reporting/register_source_trigger_redirect_chain.html.mock-http-headers b/content/test/data/attribution_reporting/register_source_trigger_redirect_chain.html.mock-http-headers index 2bdf55cb..e2a1878 100644 --- a/content/test/data/attribution_reporting/register_source_trigger_redirect_chain.html.mock-http-headers +++ b/content/test/data/attribution_reporting/register_source_trigger_redirect_chain.html.mock-http-headers
@@ -1,3 +1,6 @@ -HTTP/1.1 301 Yo +HTTP/1.1 301 Moved Permanently +Access-Control-Allow-Origin: * +Access-Control-Allow-Headers: * Attribution-Reporting-Register-Source:{"source_event_id":"5","destination":"https://d.test"} Location: /register_trigger_headers.html +
diff --git a/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers b/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers index be618df..39c13ff 100644 --- a/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers +++ b/content/test/data/attribution_reporting/register_trigger_headers.html.mock-http-headers
@@ -1,2 +1,4 @@ HTTP/1.1 200 OK +Access-Control-Allow-Origin: * +Access-Control-Allow-Headers: * Attribution-Reporting-Register-Trigger:{"event_trigger_data":[{"trigger_data": "7"}]}
diff --git a/content/test/data/attribution_reporting/register_trigger_source_trigger.html.mock-http-headers b/content/test/data/attribution_reporting/register_trigger_source_trigger.html.mock-http-headers index 10db407..97fd821 100644 --- a/content/test/data/attribution_reporting/register_trigger_source_trigger.html.mock-http-headers +++ b/content/test/data/attribution_reporting/register_trigger_source_trigger.html.mock-http-headers
@@ -1,3 +1,5 @@ -HTTP/1.1 301 Yo +HTTP/1.1 301 Moved Permanently +Access-Control-Allow-Origin: * +Access-Control-Allow-Headers: * Attribution-Reporting-Register-Trigger:{"event_trigger_data":[{"trigger_data": "5"}]} Location: /register_source_trigger_redirect_chain.html \ No newline at end of file
diff --git a/gpu/command_buffer/client/dawn_client_memory_transfer_service.h b/gpu/command_buffer/client/dawn_client_memory_transfer_service.h index 5fa10976a..2036070 100644 --- a/gpu/command_buffer/client/dawn_client_memory_transfer_service.h +++ b/gpu/command_buffer/client/dawn_client_memory_transfer_service.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_CLIENT_DAWN_CLIENT_MEMORY_TRANSFER_SERVICE_H_ #define GPU_COMMAND_BUFFER_CLIENT_DAWN_CLIENT_MEMORY_TRANSFER_SERVICE_H_ -#include <dawn_wire/WireClient.h> +#include <dawn/wire/WireClient.h> #include <vector> #include "base/memory/raw_ptr.h"
diff --git a/gpu/command_buffer/client/dawn_client_serializer.h b/gpu/command_buffer/client/dawn_client_serializer.h index 9e66fce0..fe6149b8 100644 --- a/gpu/command_buffer/client/dawn_client_serializer.h +++ b/gpu/command_buffer/client/dawn_client_serializer.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_CLIENT_DAWN_CLIENT_SERIALIZER_H_ #define GPU_COMMAND_BUFFER_CLIENT_DAWN_CLIENT_SERIALIZER_H_ -#include <dawn_wire/WireClient.h> +#include <dawn/wire/WireClient.h> #include <memory>
diff --git a/gpu/command_buffer/service/dawn_caching_interface.h b/gpu/command_buffer/service/dawn_caching_interface.h index f8b30bf..e797421 100644 --- a/gpu/command_buffer/service/dawn_caching_interface.h +++ b/gpu/command_buffer/service/dawn_caching_interface.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_DAWN_CACHING_INTERFACE_H_ #define GPU_COMMAND_BUFFER_SERVICE_DAWN_CACHING_INTERFACE_H_ -#include <dawn_platform/DawnPlatform.h> +#include <dawn/platform/DawnPlatform.h> #include <memory>
diff --git a/gpu/command_buffer/service/dawn_platform.h b/gpu/command_buffer/service/dawn_platform.h index db03d2b..62e9a5d 100644 --- a/gpu/command_buffer/service/dawn_platform.h +++ b/gpu/command_buffer/service/dawn_platform.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_DAWN_PLATFORM_H_ #define GPU_COMMAND_BUFFER_SERVICE_DAWN_PLATFORM_H_ -#include <dawn_platform/DawnPlatform.h> +#include <dawn/platform/DawnPlatform.h> namespace gpu { namespace webgpu {
diff --git a/gpu/command_buffer/service/dawn_service_memory_transfer_service.h b/gpu/command_buffer/service/dawn_service_memory_transfer_service.h index 85ecdb3..6fa41580 100644 --- a/gpu/command_buffer/service/dawn_service_memory_transfer_service.h +++ b/gpu/command_buffer/service/dawn_service_memory_transfer_service.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_MEMORY_TRANSFER_SERVICE_H_ #define GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_MEMORY_TRANSFER_SERVICE_H_ -#include <dawn_wire/WireServer.h> +#include <dawn/wire/WireServer.h> #include "base/memory/raw_ptr.h"
diff --git a/gpu/command_buffer/service/dawn_service_serializer.h b/gpu/command_buffer/service/dawn_service_serializer.h index 7536969d..a4492dac 100644 --- a/gpu/command_buffer/service/dawn_service_serializer.h +++ b/gpu/command_buffer/service/dawn_service_serializer.h
@@ -5,7 +5,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_SERIALIZER_H_ #define GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_SERIALIZER_H_ -#include <dawn_wire/WireClient.h> +#include <dawn/wire/WireClient.h> #include <memory> @@ -35,4 +35,4 @@ } // namespace webgpu } // namespace gpu -#endif // GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_SERIALIZER_H_ \ No newline at end of file +#endif // GPU_COMMAND_BUFFER_SERVICE_DAWN_SERVICE_SERIALIZER_H_
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index d465294..9d738f7 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -6,8 +6,8 @@ #include <dawn/native/DawnNative.h> #include <dawn/native/OpenGLBackend.h> -#include <dawn_platform/DawnPlatform.h> -#include <dawn_wire/WireServer.h> +#include <dawn/platform/DawnPlatform.h> +#include <dawn/wire/WireServer.h> #include <algorithm> #include <memory>
diff --git a/infra/config/generated/builders/ci/WebKit Win10/properties.json b/infra/config/generated/builders/ci/WebKit Win10/properties.json index c1c172d..2c5aae0c 100644 --- a/infra/config/generated/builders/ci/WebKit Win10/properties.json +++ b/infra/config/generated/builders/ci/WebKit Win10/properties.json
@@ -73,11 +73,10 @@ ] } }, - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git "a/infra/config/generated/builders/ci/Win 7 Tests x64 \0501\051/properties.json" "b/infra/config/generated/builders/ci/Win 7 Tests x64 \0501\051/properties.json" index 3d8e417..72cb0e0a 100644 --- "a/infra/config/generated/builders/ci/Win 7 Tests x64 \0501\051/properties.json" +++ "b/infra/config/generated/builders/ci/Win 7 Tests x64 \0501\051/properties.json"
@@ -76,11 +76,10 @@ ] } }, - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git "a/infra/config/generated/builders/ci/Win10 Tests x64 \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Win10 Tests x64 \050dbg\051/properties.json" index 1d20625a..2f79c4e7 100644 --- "a/infra/config/generated/builders/ci/Win10 Tests x64 \050dbg\051/properties.json" +++ "b/infra/config/generated/builders/ci/Win10 Tests x64 \050dbg\051/properties.json"
@@ -71,11 +71,10 @@ ] } }, - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/builders/ci/Win10 Tests x64/properties.json b/infra/config/generated/builders/ci/Win10 Tests x64/properties.json index 720e9e8..af4c8f6e 100644 --- a/infra/config/generated/builders/ci/Win10 Tests x64/properties.json +++ b/infra/config/generated/builders/ci/Win10 Tests x64/properties.json
@@ -83,11 +83,10 @@ ] } }, - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git "a/infra/config/generated/builders/ci/Win7 Tests \0501\051/properties.json" "b/infra/config/generated/builders/ci/Win7 Tests \0501\051/properties.json" index 876df5fa..b4e8ac6e 100644 --- "a/infra/config/generated/builders/ci/Win7 Tests \0501\051/properties.json" +++ "b/infra/config/generated/builders/ci/Win7 Tests \0501\051/properties.json"
@@ -77,11 +77,10 @@ ] } }, - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star index 3fda6bb0..d73d559a 100644 --- a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
@@ -15,7 +15,8 @@ cores = 8, executable = ci.DEFAULT_EXECUTABLE, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, - goma_backend = goma.backend.RBE_PROD, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.DEFAULT, os = os.LINUX_DEFAULT, pool = ci.DEFAULT_POOL, service_account = ci.DEFAULT_SERVICE_ACCOUNT, @@ -67,6 +68,8 @@ ], }, }, + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.builder( @@ -105,9 +108,7 @@ ], }, }, - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -139,9 +140,7 @@ short_name = "asn", ), main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -173,9 +172,7 @@ short_name = "cfi", ), main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -209,9 +206,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -246,9 +241,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -276,9 +269,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -310,9 +301,7 @@ short_name = "arm", ), main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -339,9 +328,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -367,6 +354,8 @@ short_name = "a64", ), main_console_view = "main", + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.builder( @@ -400,9 +389,7 @@ short_name = "kvn", ), main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -462,9 +449,7 @@ ], }, }, - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -502,9 +487,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -541,9 +524,7 @@ tree_closing = False, cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -573,9 +554,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -606,9 +585,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -638,9 +615,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.thin_tester( @@ -703,9 +678,7 @@ ), cq_mirrors_console_view = "mirrors", main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) # For Chromebox for meetings(CfM) @@ -734,7 +707,5 @@ short_name = "cfm", ), main_console_view = "main", - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, )
diff --git a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star index 0aebfe2..a3c9a60 100644 --- a/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.gpu.fyi.star
@@ -12,7 +12,8 @@ builder_group = "chromium.gpu.fyi", executable = ci.DEFAULT_EXECUTABLE, execution_timeout = 6 * time.hour, - goma_backend = goma.backend.RBE_PROD, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.DEFAULT, pool = ci.gpu.POOL, properties = { "perf_dashboard_machine_group": "ChromiumGPUFYI", @@ -122,9 +123,7 @@ category = "ChromeOS|LLVM", short_name = "gen", ), - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.linux_builder( @@ -134,6 +133,8 @@ short_name = "jcz", ), list_view = "chromium.gpu.experimental", + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.linux_builder( @@ -142,9 +143,7 @@ category = "ChromeOS|ARM", short_name = "kvn", ), - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.linux_builder( @@ -154,6 +153,8 @@ short_name = "oct", ), list_view = "chromium.gpu.experimental", + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.linux_builder( @@ -179,6 +180,8 @@ short_name = "zrk", ), list_view = "chromium.gpu.experimental", + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.linux_builder( @@ -187,9 +190,7 @@ category = "Android|Builder", short_name = "arm", ), - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.linux_builder( @@ -198,9 +199,7 @@ category = "Android|Builder", short_name = "arm64", ), - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.linux_builder( @@ -209,9 +208,7 @@ category = "Lacros|Builder", short_name = "rel", ), - goma_backend = None, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.linux_builder( @@ -220,8 +217,6 @@ category = "Linux|Builder", short_name = "rel", ), - goma_backend = None, - reclient_instance = rbe_instance.DEFAULT, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, ) @@ -231,8 +226,6 @@ category = "Linux|Builder", short_name = "dbg", ), - goma_backend = None, - reclient_instance = rbe_instance.DEFAULT, reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, ) @@ -242,9 +235,6 @@ category = "Linux", short_name = "tsn", ), - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, ) ci.gpu.mac_builder( @@ -253,6 +243,8 @@ category = "Mac|Builder", short_name = "rel", ), + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.mac_builder( @@ -261,6 +253,8 @@ category = "Mac|Builder", short_name = "asn", ), + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.mac_builder( @@ -269,6 +263,8 @@ category = "Mac|Builder", short_name = "dbg", ), + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.gpu.mac_builder( @@ -292,6 +288,8 @@ category = "Mac|Builder", short_name = "arm", ), + goma_backend = goma.backend.RBE_PROD, + reclient_instance = None, ) ci.thin_tester( @@ -649,9 +647,7 @@ category = "Windows|Builder|Release", short_name = "x86", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) gpu_fyi_windows_builder( @@ -660,9 +656,7 @@ category = "Windows|Builder|Release", short_name = "x64", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) gpu_fyi_windows_builder( @@ -671,9 +665,7 @@ category = "Windows|Builder|Debug", short_name = "x64", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) gpu_fyi_windows_builder( @@ -682,9 +674,7 @@ category = "Windows|Builder|dx12vk", short_name = "rel", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) gpu_fyi_windows_builder( @@ -693,9 +683,7 @@ category = "Windows|Builder|dx12vk", short_name = "dbg", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, ) gpu_fyi_windows_builder( @@ -704,7 +692,5 @@ category = "Windows|Builder|XR", short_name = "x64", ), - goma_backend = None, reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI, - reclient_instance = rbe_instance.DEFAULT, )
diff --git a/infra/config/subprojects/chromium/ci/chromium.win.star b/infra/config/subprojects/chromium/ci/chromium.win.star index 3215709..15bbe95 100644 --- a/infra/config/subprojects/chromium/ci/chromium.win.star +++ b/infra/config/subprojects/chromium/ci/chromium.win.star
@@ -6,7 +6,7 @@ load("//lib/args.star", "args") load("//lib/branches.star", "branches") load("//lib/builder_config.star", "builder_config") -load("//lib/builders.star", "goma", "os", "sheriff_rotations") +load("//lib/builders.star", "os", "sheriff_rotations") load("//lib/ci.star", "ci", "rbe_instance", "rbe_jobs") load("//lib/consoles.star", "consoles") @@ -15,7 +15,8 @@ cores = 8, executable = ci.DEFAULT_EXECUTABLE, execution_timeout = ci.DEFAULT_EXECUTION_TIMEOUT, - goma_backend = goma.backend.RBE_PROD, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.DEFAULT, main_console_view = "main", os = os.WINDOWS_DEFAULT, pool = ci.DEFAULT_POOL, @@ -86,9 +87,6 @@ ), cores = 32, os = os.WINDOWS_ANY, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -114,9 +112,6 @@ ), cores = 32, os = os.WINDOWS_ANY, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -252,9 +247,6 @@ cores = 32, cq_mirrors_console_view = "mirrors", os = os.WINDOWS_ANY, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -285,9 +277,6 @@ cores = 32, cq_mirrors_console_view = "mirrors", os = os.WINDOWS_ANY, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -359,7 +348,4 @@ ), executable = "recipe:swarming/deterministic_build", execution_timeout = 12 * time.hour, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, )
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm index a6919385..53d06687 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.mm
@@ -5,6 +5,8 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_module_container.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" +#include "ios/chrome/grit/ios_strings.h" +#include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -122,9 +124,11 @@ - (NSString*)titleString { switch (self.type) { case ContentSuggestionsModuleTypeShortcuts: - return @"Shortcuts"; + return l10n_util::GetNSString( + IDS_IOS_CONTENT_SUGGESTIONS_SHORTCUTS_MODULE_TITLE); case ContentSuggestionsModuleTypeMostVisited: - return @"Frequently Visited"; + return l10n_util::GetNSString( + IDS_IOS_CONTENT_SUGGESTIONS_MOST_VISITED_MODULE_TITLE); case ContentSuggestionsModuleTypeReturnToRecentTab: return @""; }
diff --git a/media/formats/hls/media_playlist.cc b/media/formats/hls/media_playlist.cc index 70f6e81..2dfa7d0 100644 --- a/media/formats/hls/media_playlist.cc +++ b/media/formats/hls/media_playlist.cc
@@ -39,6 +39,11 @@ bool end_list; bool i_frames_only; bool has_media_sequence_tag; + bool can_skip_dateranges; + bool can_block_reload; + absl::optional<base::TimeDelta> skip_boundary; + base::TimeDelta hold_back_distance; + absl::optional<base::TimeDelta> part_hold_back_distance; }; MediaPlaylist::MediaPlaylist(MediaPlaylist&&) = default; @@ -77,6 +82,7 @@ absl::optional<XEndListTag> end_list_tag; absl::optional<XIFramesOnlyTag> i_frames_only_tag; absl::optional<XPartInfTag> part_inf_tag; + absl::optional<XServerControlTag> server_control_tag; absl::optional<XMediaSequenceTag> media_sequence_tag; absl::optional<XDiscontinuitySequenceTag> discontinuity_sequence_tag; std::vector<MediaSegment> segments; @@ -193,6 +199,13 @@ } break; } + case MediaPlaylistTagName::kXServerControl: { + auto error = ParseUniqueTag(*tag, server_control_tag); + if (error.has_value()) { + return std::move(error).value(); + } + break; + } case MediaPlaylistTagName::kXMediaSequence: { // This tag must appear before any media segment if (!segments.empty()) { @@ -333,6 +346,52 @@ .target_duration = part_inf_tag->target_duration}; } + bool can_skip_dateranges = false; + bool can_block_reload = false; + absl::optional<base::TimeDelta> skip_boundary; + base::TimeDelta hold_back_distance = target_duration * 3; + absl::optional<base::TimeDelta> part_hold_back_distance; + if (server_control_tag.has_value()) { + can_skip_dateranges = server_control_tag->can_skip_dateranges; + can_block_reload = server_control_tag->can_block_reload; + + if (server_control_tag->skip_boundary.has_value()) { + skip_boundary = server_control_tag->skip_boundary.value(); + + // The skip boundary MUST be at least six times the target + // duration. + if (skip_boundary.value() < target_duration * 6) { + return ParseStatusCode::kSkipBoundaryTooLow; + } + } + + if (server_control_tag->hold_back.has_value()) { + hold_back_distance = server_control_tag->hold_back.value(); + + // The hold back distance MUST be at least three times the target + // duration. + if (hold_back_distance < target_duration * 3) { + return ParseStatusCode::kHoldBackDistanceTooLow; + } + } + + if (server_control_tag->part_hold_back.has_value()) { + part_hold_back_distance = server_control_tag->part_hold_back.value(); + + // The part hold back distance MUST be at least twice the part target + // duration. + if (partial_segment_info.has_value() && + part_hold_back_distance < partial_segment_info->target_duration * 2) { + return ParseStatusCode::kPartHoldBackDistanceTooLow; + } + } + } + + // PART-HOLD-BACK is required if the PART-INF tag appeared + if (part_inf_tag.has_value() && !part_hold_back_distance.has_value()) { + return ParseStatusCode::kPartInfTagWithoutPartHoldBack; + } + // Ensure that no segment exceeds the target duration base::TimeDelta total_duration; for (const auto& segment : segments) { @@ -374,7 +433,12 @@ .playlist_type = playlist_type, .end_list = end_list_tag.has_value(), .i_frames_only = i_frames_only_tag.has_value(), - .has_media_sequence_tag = media_sequence_tag.has_value()}); + .has_media_sequence_tag = media_sequence_tag.has_value(), + .can_skip_dateranges = can_skip_dateranges, + .can_block_reload = can_block_reload, + .skip_boundary = skip_boundary, + .hold_back_distance = hold_back_distance, + .part_hold_back_distance = part_hold_back_distance}); } MediaPlaylist::MediaPlaylist(CtorArgs args) @@ -386,6 +450,11 @@ playlist_type_(args.playlist_type), end_list_(args.end_list), i_frames_only_(args.i_frames_only), - has_media_sequence_tag_(args.has_media_sequence_tag) {} + has_media_sequence_tag_(args.has_media_sequence_tag), + can_skip_dateranges_(args.can_skip_dateranges), + can_block_reload_(args.can_block_reload), + skip_boundary_(args.skip_boundary), + hold_back_distance_(args.hold_back_distance), + part_hold_back_distance_(args.part_hold_back_distance) {} } // namespace media::hls
diff --git a/media/formats/hls/media_playlist.h b/media/formats/hls/media_playlist.h index 5369086..c369f735 100644 --- a/media/formats/hls/media_playlist.h +++ b/media/formats/hls/media_playlist.h
@@ -88,6 +88,37 @@ // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#:~:text=nominal%20playback%20rate).-,If,-the%20Media%20Playlist bool HasMediaSequenceTag() const { return has_media_sequence_tag_; } + // If present, this represents that the server can produce playlist delta + // updates. The value represents the distance from the end of the + // playlist beyond which media segments and their associated tags can be + // skipped. + // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.1 + absl::optional<base::TimeDelta> GetSkipBoundary() const { + return skip_boundary_; + } + + // Returns whether the server can produce playlist delta updates that skip + // EXT-X-DATERANGE tags. + // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.1 + bool CanSkipDateRanges() const { return can_skip_dateranges_; } + + // Returns the server-recommended minimum distance from the end + // of the playlist at which clients should begin live playback. + // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.8:~:text=SKIP%2DUNTIL%20attribute.-,HOLD%2DBACK,-The%20value%20is + base::TimeDelta GetHoldBackDistance() const { return hold_back_distance_; } + + // Returns the server-recommended minimum distance from the end + // of the playlist at which clients should begin live playback when playing in + // low-latency mode. + // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.8:~:text=any%20Media%20Playlist.-,PART%2DHOLD%2DBACK,-The%20value%20is + absl::optional<base::TimeDelta> GetPartHoldBackDistance() const { + return part_hold_back_distance_; + } + + // Returns whether the server supports blocking playlist reloads. + // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.2 + bool CanBlockReload() const { return can_block_reload_; } + // Attempts to parse the media playlist represented by `source`. `uri` must be // a valid, non-empty GURL referring to the URI of this playlist. If this // playlist was found through a multivariant playlist, `parent_playlist` must @@ -111,6 +142,11 @@ bool end_list_; bool i_frames_only_; bool has_media_sequence_tag_; + bool can_skip_dateranges_; + bool can_block_reload_; + absl::optional<base::TimeDelta> skip_boundary_; + base::TimeDelta hold_back_distance_; + absl::optional<base::TimeDelta> part_hold_back_distance_; }; } // namespace media::hls
diff --git a/media/formats/hls/media_playlist_test_builder.h b/media/formats/hls/media_playlist_test_builder.h index 37b8ef2..2d49c26 100644 --- a/media/formats/hls/media_playlist_test_builder.h +++ b/media/formats/hls/media_playlist_test_builder.h
@@ -127,6 +127,44 @@ EXPECT_EQ(playlist.HasMediaSequenceTag(), value) << from.ToString(); } +// Checks that the value of `GetSkipBoundary()` matches the given value. +inline void HasSkipBoundary(absl::optional<base::TimeDelta> value, + const base::Location& from, + const MediaPlaylist& playlist) { + EXPECT_TRUE(RoughlyEqual(playlist.GetSkipBoundary(), value)) + << from.ToString(); +} + +// Checks that the value of `CanSkipDateRanges()` matches the given value. +inline void CanSkipDateRanges(bool value, + const base::Location& from, + const MediaPlaylist& playlist) { + EXPECT_EQ(playlist.CanSkipDateRanges(), value) << from.ToString(); +} + +// Checks that the value of `GetHoldBackDistance()` matches the given value. +inline void HasHoldBackDistance(base::TimeDelta value, + const base::Location& from, + const MediaPlaylist& playlist) { + EXPECT_TRUE(RoughlyEqual(playlist.GetHoldBackDistance(), value)) + << from.ToString(); +} + +// Checks that the value of `GetPartHoldBackDistance()` matches the given value. +inline void HasPartHoldBackDistance(absl::optional<base::TimeDelta> value, + const base::Location& from, + const MediaPlaylist& playlist) { + EXPECT_TRUE(RoughlyEqual(playlist.GetPartHoldBackDistance(), value)) + << from.ToString(); +} + +// Checks that the value of `CanBlockReload()` matches the given value. +inline void CanBlockReload(bool value, + const base::Location& from, + const MediaPlaylist& playlist) { + EXPECT_EQ(playlist.CanBlockReload(), value) << from.ToString(); +} + // Checks that the latest media segment has the given duration. inline void HasDuration(base::TimeDelta duration, const base::Location& from,
diff --git a/media/formats/hls/media_playlist_unittest.cc b/media/formats/hls/media_playlist_unittest.cc index 9089e72c..2bab439d 100644 --- a/media/formats/hls/media_playlist_unittest.cc +++ b/media/formats/hls/media_playlist_unittest.cc
@@ -1096,6 +1096,7 @@ MediaPlaylistTestBuilder builder; builder.AppendLine("#EXTM3U"); builder.AppendLine("#EXT-X-TARGETDURATION:10"); + builder.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=500"); // EXT-X-PART-INF tag must be well-formed for (base::StringPiece x : {"", ":", ":TARGET=1", ":PART-TARGET=two"}) { @@ -1137,4 +1138,136 @@ fork.ExpectError(ParseStatusCode::kPlaylistHasDuplicateTags); } +TEST(HlsMediaPlaylistTest, XServerControlTag) { + MediaPlaylistTestBuilder builder; + builder.AppendLine("#EXTM3U"); + builder.AppendLine("#EXT-X-TARGETDURATION:6"); + builder.ExpectPlaylist(HasTargetDuration, base::Seconds(6)); + + // Without the EXT-X-SERVER-CONTROL tag, certain properties have default + // values + auto fork = builder; + fork.ExpectPlaylist(HasSkipBoundary, absl::nullopt); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(HasPartHoldBackDistance, absl::nullopt); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + // An empty EXT-X-SERVER-CONTROL tag shouldn't change these defaults + fork.AppendLine("#EXT-X-SERVER-CONTROL:"); + fork.ExpectOk(); + + // This tag may not appear twice + fork.AppendLine("#EXT-X-SERVER-CONTROL:"); + fork.ExpectError(ParseStatusCode::kPlaylistHasDuplicateTags); + + // If attributes are malformed, playlist should be rejected + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL={$foo}"); + fork.ExpectError(ParseStatusCode::kMalformedTag); + + // The CAN-SKIP-UNTIL attribute must be at least six times the target duration + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=35"); + fork.ExpectError(ParseStatusCode::kSkipBoundaryTooLow); + + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=36"); + fork.ExpectPlaylist(HasSkipBoundary, base::Seconds(36)); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(HasPartHoldBackDistance, absl::nullopt); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + // The CAN-SKIP-DATERANGES tag may not appear without CAN-SKIP-UNTIL + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:CAN-SKIP-DATERANGES=YES"); + fork.ExpectError(ParseStatusCode::kMalformedTag); + + fork = builder; + fork.AppendLine( + "#EXT-X-SERVER-CONTROL:CAN-SKIP-DATERANGES=YES,CAN-SKIP-UNTIL=40"); + fork.ExpectPlaylist(CanSkipDateRanges, true); + fork.ExpectPlaylist(HasSkipBoundary, base::Seconds(40)); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(HasPartHoldBackDistance, absl::nullopt); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + fork = builder; + fork.AppendLine( + "#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=40,CAN-SKIP-DATERANGES=YES"); + fork.ExpectPlaylist(CanSkipDateRanges, true); + fork.ExpectPlaylist(HasSkipBoundary, base::Seconds(40)); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(HasPartHoldBackDistance, absl::nullopt); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + // The 'EXT-X-PART-INF' tag requires the 'PART-HOLD-BACK' field + fork = builder; + fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=0.2"); + fork.ExpectError(ParseStatusCode::kPartInfTagWithoutPartHoldBack); + + fork = builder; + fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=0.2"); + fork.AppendLine("#EXT-X-SERVER-CONTROL:"); + fork.ExpectError(ParseStatusCode::kPartInfTagWithoutPartHoldBack); + + fork = builder; + fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=0.2"); + fork.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=0.5"); + fork.ExpectPlaylist( + HasPartialSegmentInfo, + MediaPlaylist::PartialSegmentInfo{.target_duration = base::Seconds(0.2)}); + fork.ExpectPlaylist(HasPartHoldBackDistance, base::Seconds(0.5)); + fork.ExpectPlaylist(HasSkipBoundary, absl::nullopt); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + // PART-HOLD-BACK must not be less than PART-TARGET * 2 (unless that tag + // doesn't exist) + fork = builder; + fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=0.2"); + fork.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=0.4"); + fork.ExpectPlaylist( + HasPartialSegmentInfo, + MediaPlaylist::PartialSegmentInfo{.target_duration = base::Seconds(0.2)}); + fork.ExpectPlaylist(HasPartHoldBackDistance, base::Seconds(0.4)); + fork.ExpectPlaylist(HasSkipBoundary, absl::nullopt); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + fork = builder; + fork.AppendLine("#EXT-X-PART-INF:PART-TARGET=0.2"); + fork.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=0.3"); + fork.ExpectError(ParseStatusCode::kPartHoldBackDistanceTooLow); + + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:PART-HOLD-BACK=0.3"); + fork.ExpectPlaylist(HasPartialSegmentInfo, absl::nullopt); + fork.ExpectPlaylist(HasPartHoldBackDistance, base::Seconds(0.3)); + fork.ExpectPlaylist(HasSkipBoundary, absl::nullopt); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectPlaylist(CanBlockReload, false); + fork.ExpectOk(); + + // Test the effect of the 'CAN-BLOCK-RELOAD' attribute + fork = builder; + fork.AppendLine("#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES"); + fork.ExpectPlaylist(CanBlockReload, true); + fork.ExpectPlaylist(HasPartialSegmentInfo, absl::nullopt); + fork.ExpectPlaylist(HasPartHoldBackDistance, absl::nullopt); + fork.ExpectPlaylist(HasSkipBoundary, absl::nullopt); + fork.ExpectPlaylist(CanSkipDateRanges, false); + fork.ExpectPlaylist(HasHoldBackDistance, base::Seconds(6) * 3); + fork.ExpectOk(); +} + } // namespace media::hls
diff --git a/media/formats/hls/parse_status.cc b/media/formats/hls/parse_status.cc index 86cb36ae..b877fd1 100644 --- a/media/formats/hls/parse_status.cc +++ b/media/formats/hls/parse_status.cc
@@ -51,6 +51,10 @@ PARSE_STATUS_CODE_CASE(kByteRangeInvalid); PARSE_STATUS_CODE_CASE(kValueOverflowsTimeDelta); PARSE_STATUS_CODE_CASE(kPlaylistOverflowsTimeDelta); + PARSE_STATUS_CODE_CASE(kSkipBoundaryTooLow); + PARSE_STATUS_CODE_CASE(kHoldBackDistanceTooLow); + PARSE_STATUS_CODE_CASE(kPartHoldBackDistanceTooLow); + PARSE_STATUS_CODE_CASE(kPartInfTagWithoutPartHoldBack); } NOTREACHED();
diff --git a/media/formats/hls/parse_status.h b/media/formats/hls/parse_status.h index 9280f3b..a0b0b63 100644 --- a/media/formats/hls/parse_status.h +++ b/media/formats/hls/parse_status.h
@@ -48,6 +48,10 @@ kByteRangeInvalid, kValueOverflowsTimeDelta, kPlaylistOverflowsTimeDelta, + kSkipBoundaryTooLow, + kHoldBackDistanceTooLow, + kPartHoldBackDistanceTooLow, + kPartInfTagWithoutPartHoldBack, }; struct ParseStatusTraits {
diff --git a/media/formats/hls/tag_name.cc b/media/formats/hls/tag_name.cc index 5494b573..12293a81 100644 --- a/media/formats/hls/tag_name.cc +++ b/media/formats/hls/tag_name.cc
@@ -69,6 +69,7 @@ TagNameEntry("EXT-X-MEDIA-SEQUENCE", MediaPlaylistTagName::kXMediaSequence), TagNameEntry("EXT-X-PART-INF", MediaPlaylistTagName::kXPartInf), TagNameEntry("EXT-X-PLAYLIST-TYPE", MediaPlaylistTagName::kXPlaylistType), + TagNameEntry("EXT-X-SERVER-CONTROL", MediaPlaylistTagName::kXServerControl), TagNameEntry("EXT-X-SESSION-DATA", MultivariantPlaylistTagName::kXSessionData), TagNameEntry("EXT-X-SESSION-KEY",
diff --git a/media/formats/hls/tag_name.h b/media/formats/hls/tag_name.h index df10628..6f6cdad 100644 --- a/media/formats/hls/tag_name.h +++ b/media/formats/hls/tag_name.h
@@ -58,6 +58,7 @@ kXGap, kXPlaylistType, kXPartInf, + kXServerControl, kXMediaSequence, kXDiscontinuitySequence, kXByteRange,
diff --git a/media/formats/hls/tags.cc b/media/formats/hls/tags.cc index c26ff19..7b04bb2 100644 --- a/media/formats/hls/tags.cc +++ b/media/formats/hls/tags.cc
@@ -121,6 +121,36 @@ return ""; } +// Attributes expected in `EXT-X-SERVER-CONTROL tag contents. +// These must remain sorted alphabetically. +enum class XServerControlTagAttribute { + kCanBlockReload, + kCanSkipDateRanges, + kCanSkipUntil, + kHoldBack, + kPartHoldBack, + kMaxValue = kPartHoldBack, +}; + +constexpr base::StringPiece GetAttributeName( + XServerControlTagAttribute attribute) { + switch (attribute) { + case XServerControlTagAttribute::kCanBlockReload: + return "CAN-BLOCK-RELOAD"; + case XServerControlTagAttribute::kCanSkipDateRanges: + return "CAN-SKIP-DATERANGES"; + case XServerControlTagAttribute::kCanSkipUntil: + return "CAN-SKIP-UNTIL"; + case XServerControlTagAttribute::kHoldBack: + return "HOLD-BACK"; + case XServerControlTagAttribute::kPartHoldBack: + return "PART-HOLD-BACK"; + } + + NOTREACHED(); + return ""; +} + template <typename T, size_t kLast> constexpr bool IsAttributeEnumSorted(std::index_sequence<kLast>) { return true; @@ -523,6 +553,109 @@ return XPartInfTag{.target_duration = part_target}; } +ParseStatus::Or<XServerControlTag> XServerControlTag::Parse(TagItem tag) { + DCHECK(tag.GetName() == ToTagName(XServerControlTag::kName)); + if (!tag.GetContent().has_value()) { + return ParseStatusCode::kMalformedTag; + } + + // Parse the attribute-list + TypedAttributeMap<XServerControlTagAttribute> map; + types::AttributeListIterator iter(*tag.GetContent()); + auto map_result = map.FillUntilError(&iter); + + if (map_result.code() != ParseStatusCode::kReachedEOF) { + return ParseStatus(ParseStatusCode::kMalformedTag) + .AddCause(std::move(map_result)); + } + + // Extract the 'CAN-SKIP-UNTIL' attribute + absl::optional<base::TimeDelta> can_skip_until; + if (map.HasValue(XServerControlTagAttribute::kCanSkipUntil)) { + auto result = types::ParseDecimalFloatingPoint( + map.GetValue(XServerControlTagAttribute::kCanSkipUntil)); + + if (result.has_error()) { + return ParseStatus(ParseStatusCode::kMalformedTag) + .AddCause(std::move(result).error()); + } + + can_skip_until = base::Seconds(std::move(result).value()); + + if (can_skip_until->is_max()) { + return ParseStatusCode::kValueOverflowsTimeDelta; + } + } + + // Extract the 'CAN-SKIP-DATERANGES' attribute + bool can_skip_dateranges = false; + if (map.HasValue(XServerControlTagAttribute::kCanSkipDateRanges)) { + if (map.GetValue(XServerControlTagAttribute::kCanSkipDateRanges).Str() == + "YES") { + // The existence of this attribute requires the 'CAN-SKIP-UNTIL' + // attribute. + if (!can_skip_until.has_value()) { + return ParseStatusCode::kMalformedTag; + } + + can_skip_dateranges = true; + } + } + + // Extract the 'HOLD-BACK' attribute + absl::optional<base::TimeDelta> hold_back; + if (map.HasValue(XServerControlTagAttribute::kHoldBack)) { + auto result = types::ParseDecimalFloatingPoint( + map.GetValue(XServerControlTagAttribute::kHoldBack)); + + if (result.has_error()) { + return ParseStatus(ParseStatusCode::kMalformedTag) + .AddCause(std::move(result).error()); + } + + hold_back = base::Seconds(std::move(result).value()); + + if (hold_back->is_max()) { + return ParseStatusCode::kValueOverflowsTimeDelta; + } + } + + // Extract the 'PART-HOLD-BACK' attribute + absl::optional<base::TimeDelta> part_hold_back; + if (map.HasValue(XServerControlTagAttribute::kPartHoldBack)) { + auto result = types::ParseDecimalFloatingPoint( + map.GetValue(XServerControlTagAttribute::kPartHoldBack)); + + if (result.has_error()) { + return ParseStatus(ParseStatusCode::kMalformedTag) + .AddCause(std::move(result).error()); + } + + part_hold_back = base::Seconds(std::move(result).value()); + + if (part_hold_back->is_max()) { + return ParseStatusCode::kValueOverflowsTimeDelta; + } + } + + // Extract the 'CAN-BLOCK-RELOAD' attribute + bool can_block_reload = false; + if (map.HasValue(XServerControlTagAttribute::kCanBlockReload)) { + if (map.GetValue(XServerControlTagAttribute::kCanBlockReload).Str() == + "YES") { + can_block_reload = true; + } + } + + return XServerControlTag{ + .skip_boundary = can_skip_until, + .can_skip_dateranges = can_skip_dateranges, + .hold_back = hold_back, + .part_hold_back = part_hold_back, + .can_block_reload = can_block_reload, + }; +} + ParseStatus::Or<XMediaSequenceTag> XMediaSequenceTag::Parse(TagItem tag) { return ParseDecimalIntegerTag(tag, &XMediaSequenceTag::number); }
diff --git a/media/formats/hls/tags.h b/media/formats/hls/tags.h index 720d81c..0b771a3f 100644 --- a/media/formats/hls/tags.h +++ b/media/formats/hls/tags.h
@@ -176,6 +176,35 @@ base::TimeDelta target_duration; }; +// Represents the contents of the #EXT-X-SERVER-CONTROL tag. +struct MEDIA_EXPORT XServerControlTag { + static constexpr auto kName = MediaPlaylistTagName::kXServerControl; + static ParseStatus::Or<XServerControlTag> Parse(TagItem); + + // This value (given by the 'CAN-SKIP-UNTIL' attribute) represents the + // distance from the last media segment that the server is able + // to produce a playlist delta update. + absl::optional<base::TimeDelta> skip_boundary; + + // This indicates whether the server supports skipping EXT-X-DATERANGE tags + // older than the skip boundary when producing playlist delta updates. + bool can_skip_dateranges = false; + + // This indicates the distance from the end of the playlist + // at which clients should begin playback. This MUST be at least three times + // the playlist's target duration. + absl::optional<base::TimeDelta> hold_back; + + // This indicates the distance from the end of the playlist + // at which clients should begin playback when playing in low-latency mode. + // This value MUST be at least twice the playlist's partial segment target + // duration, and SHOULD be at least three times that. + absl::optional<base::TimeDelta> part_hold_back; + + // This indicates whether the server supports blocking playlist reloads. + bool can_block_reload = false; +}; + // Represents the contents of the #EXT-X-MEDIA-SEQUENCE tag. struct MEDIA_EXPORT XMediaSequenceTag { static constexpr auto kName = MediaPlaylistTagName::kXMediaSequence;
diff --git a/media/formats/hls/tags_unittest.cc b/media/formats/hls/tags_unittest.cc index dbeefd5..4b666f34 100644 --- a/media/formats/hls/tags_unittest.cc +++ b/media/formats/hls/tags_unittest.cc
@@ -570,4 +570,147 @@ ParseStatusCode::kValueOverflowsTimeDelta); } +TEST(HlsTagsTest, ParseXServerControlTag) { + RunTagIdenficationTest<XServerControlTag>( + "#EXT-X-SERVER-CONTROL:SKIP-UNTIL=10\n", "SKIP-UNTIL=10"); + + // Tag requires content + ErrorTest<XServerControlTag>(absl::nullopt, ParseStatusCode::kMalformedTag); + + // Content is allowed to be empty + auto tag = OkTest<XServerControlTag>(""); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + + tag = OkTest<XServerControlTag>( + "CAN-SKIP-UNTIL=50,CAN-SKIP-DATERANGES=YES,HOLD-BACK=60,PART-HOLD-BACK=" + "40,CAN-BLOCK-RELOAD=YES,FUTURE-PROOF=YES"); + EXPECT_TRUE(RoughlyEqual(tag.skip_boundary, base::Seconds(50))); + EXPECT_EQ(tag.can_skip_dateranges, true); + EXPECT_TRUE(RoughlyEqual(tag.hold_back, base::Seconds(60))); + EXPECT_TRUE(RoughlyEqual(tag.part_hold_back, base::Seconds(40))); + EXPECT_EQ(tag.can_block_reload, true); + + ErrorTest<XServerControlTag>("CAN-SKIP-UNTIL=-5", + ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("CAN-SKIP-UNTIL={$B}", + ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("CAN-SKIP-UNTIL=\"5\"", + ParseStatusCode::kMalformedTag); + + tag = OkTest<XServerControlTag>("CAN-SKIP-UNTIL=5"); + EXPECT_TRUE(RoughlyEqual(tag.skip_boundary, base::Seconds(5))); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + + // Test max value + tag = OkTest<XServerControlTag>("CAN-SKIP-UNTIL=" + + base::NumberToString(MaxSeconds())); + EXPECT_TRUE(RoughlyEqual(tag.skip_boundary, base::Seconds(MaxSeconds()))); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + + ErrorTest<XServerControlTag>( + "CAN-SKIP-UNTIL=" + base::NumberToString(MaxSeconds() + 1), + ParseStatusCode::kValueOverflowsTimeDelta); + + // 'CAN-SKIP-DATERANGES' requires the presence of 'CAN-SKIP-UNTIL' + ErrorTest<XServerControlTag>("CAN-SKIP-DATERANGES=YES", + ParseStatusCode::kMalformedTag); + tag = OkTest<XServerControlTag>("CAN-SKIP-DATERANGES=YES,CAN-SKIP-UNTIL=50"); + EXPECT_TRUE(RoughlyEqual(tag.skip_boundary, base::Seconds(50))); + EXPECT_EQ(tag.can_skip_dateranges, true); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + + // The only value that results in `true` is "YES" + for (std::string x : {"NO", "Y", "TRUE", "1", "yes"}) { + tag = OkTest<XServerControlTag>("CAN-SKIP-DATERANGES=" + x + + ",CAN-SKIP-UNTIL=50"); + EXPECT_TRUE(RoughlyEqual(tag.skip_boundary, base::Seconds(50))); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + } + + // 'HOLD-BACK' must be a valid DecimalFloatingPoint + ErrorTest<XServerControlTag>("HOLD-BACK=-5", ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("HOLD-BACK={$B}", + ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("HOLD-BACK=\"5\"", + ParseStatusCode::kMalformedTag); + + tag = OkTest<XServerControlTag>("HOLD-BACK=50"); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_TRUE(RoughlyEqual(tag.hold_back, base::Seconds(50))); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + + // Test max value + tag = OkTest<XServerControlTag>("HOLD-BACK=" + + base::NumberToString(MaxSeconds())); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_TRUE(RoughlyEqual(tag.hold_back, base::Seconds(MaxSeconds()))); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + ErrorTest<XServerControlTag>( + "HOLD-BACK=" + base::NumberToString(MaxSeconds() + 1), + ParseStatusCode::kValueOverflowsTimeDelta); + + // 'PART-HOLD-BACK' must be a valid DecimalFloatingPoint + ErrorTest<XServerControlTag>("PART-HOLD-BACK=-5", + ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("PART-HOLD-BACK={$B}", + ParseStatusCode::kMalformedTag); + ErrorTest<XServerControlTag>("PART-HOLD-BACK=\"5\"", + ParseStatusCode::kMalformedTag); + + tag = OkTest<XServerControlTag>("PART-HOLD-BACK=50"); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, base::Seconds(50)); + EXPECT_EQ(tag.can_block_reload, false); + + // Test max value + tag = OkTest<XServerControlTag>("PART-HOLD-BACK=" + + base::NumberToString(MaxSeconds())); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_TRUE(RoughlyEqual(tag.part_hold_back, base::Seconds(MaxSeconds()))); + EXPECT_EQ(tag.can_block_reload, false); + ErrorTest<XServerControlTag>( + "PART-HOLD-BACK=" + base::NumberToString(MaxSeconds() + 1), + ParseStatusCode::kValueOverflowsTimeDelta); + + // The only value that results in `true` is "YES" + for (std::string x : {"NO", "Y", "TRUE", "1", "yes"}) { + tag = OkTest<XServerControlTag>("CAN-BLOCK-RELOAD=" + x); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, false); + } + + tag = OkTest<XServerControlTag>("CAN-BLOCK-RELOAD=YES"); + EXPECT_EQ(tag.skip_boundary, absl::nullopt); + EXPECT_EQ(tag.can_skip_dateranges, false); + EXPECT_EQ(tag.hold_back, absl::nullopt); + EXPECT_EQ(tag.part_hold_back, absl::nullopt); + EXPECT_EQ(tag.can_block_reload, true); +} + } // namespace media::hls
diff --git a/media/gpu/chromeos/mailbox_video_frame_converter.cc b/media/gpu/chromeos/mailbox_video_frame_converter.cc index 7f691e77..d965f8a 100644 --- a/media/gpu/chromeos/mailbox_video_frame_converter.cc +++ b/media/gpu/chromeos/mailbox_video_frame_converter.cc
@@ -49,17 +49,20 @@ void Reset(const gpu::Mailbox& mailbox, const gfx::Size& size, + const gfx::ColorSpace& color_space, DestroySharedImageCB destroy_shared_image_cb) { Destroy(); DCHECK(!mailbox.IsZero()); mailbox_ = mailbox; size_ = size; + color_space_ = color_space; destroy_shared_image_cb_ = std::move(destroy_shared_image_cb); } bool HasData() const { return !mailbox_.IsZero(); } const gpu::Mailbox& mailbox() const { return mailbox_; } const gfx::Size& size() const { return size_; } + const gfx::ColorSpace& color_space() const { return color_space_; } private: void Destroy() { @@ -76,6 +79,7 @@ gpu::Mailbox mailbox_; gfx::Size size_; + gfx::ColorSpace color_space_; DestroySharedImageCB destroy_shared_image_cb_; const scoped_refptr<base::SequencedTaskRunner> destruction_task_runner_; }; @@ -262,6 +266,7 @@ DCHECK(gpu_task_runner_->BelongsToCurrentThread()); TRACE_EVENT1("media,gpu", "ConvertFrameOnGPUThread", "VideoFrame id", origin_frame->unique_id()); + const gfx::ColorSpace src_color_space = frame->ColorSpace(); const gfx::Rect visible_rect = frame->visible_rect(); // |origin_frame| is kept alive by |frame|. @@ -275,13 +280,14 @@ if (stored_shared_image) { DCHECK(!stored_shared_image->mailbox().IsZero()); bool res; - if (stored_shared_image->size() == GetRectSizeFromOrigin(visible_rect)) { + if (stored_shared_image->size() == GetRectSizeFromOrigin(visible_rect) && + stored_shared_image->color_space() == src_color_space) { res = UpdateSharedImageOnGPUThread(stored_shared_image->mailbox()); } else { - // The existing shared image's size is no longer good enough, so let's - // create a new one. - res = GenerateSharedImageOnGPUThread(origin_frame, visible_rect, - stored_shared_image); + // Either the existing shared image's size is no longer good enough or the + // color space has changed. Let's create a new shared image. + res = GenerateSharedImageOnGPUThread(origin_frame, src_color_space, + visible_rect, stored_shared_image); } if (res) { DCHECK(stored_shared_image->HasData()); @@ -295,8 +301,8 @@ // There was no existing SharedImage: create a new one. auto new_shared_image = std::make_unique<ScopedSharedImage>(gpu_task_runner_); - if (!GenerateSharedImageOnGPUThread(origin_frame, visible_rect, - new_shared_image.get())) { + if (!GenerateSharedImageOnGPUThread(origin_frame, src_color_space, + visible_rect, new_shared_image.get())) { return; } DCHECK(new_shared_image->HasData()); @@ -317,6 +323,7 @@ bool MailboxVideoFrameConverter::GenerateSharedImageOnGPUThread( VideoFrame* video_frame, + const gfx::ColorSpace& src_color_space, const gfx::Rect& destination_visible_rect, ScopedSharedImage* shared_image) { DCHECK(gpu_task_runner_->BelongsToCurrentThread()); @@ -371,7 +378,7 @@ mailbox, gpu::kPlatformVideoFramePoolClientId, std::move(gpu_memory_buffer_handle), *buffer_format, gfx::BufferPlane::DEFAULT, gpu::kNullSurfaceHandle, shared_image_size, - video_frame->ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, + src_color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage); if (!success) { OnError(FROM_HERE, "Failed to create shared image."); @@ -380,7 +387,7 @@ // There's no need to UpdateSharedImage() after CreateSharedImage(). shared_image->Reset( - mailbox, shared_image_size, + mailbox, shared_image_size, src_color_space, shared_image_stub->GetSharedImageDestructionCallback(mailbox)); return true; }
diff --git a/media/gpu/chromeos/mailbox_video_frame_converter.h b/media/gpu/chromeos/mailbox_video_frame_converter.h index 6a28456..54f3697 100644 --- a/media/gpu/chromeos/mailbox_video_frame_converter.h +++ b/media/gpu/chromeos/mailbox_video_frame_converter.h
@@ -106,6 +106,7 @@ // method runs on |gpu_task_runner_|. Returns true if the SharedImage could be // created successfully; false otherwise (and OnError() is called). bool GenerateSharedImageOnGPUThread(VideoFrame* video_frame, + const gfx::ColorSpace& src_color_space, const gfx::Rect& destination_visible_rect, ScopedSharedImage* shared_image);
diff --git a/media/gpu/h265_decoder.cc b/media/gpu/h265_decoder.cc index 36a186e5..4280458 100644 --- a/media/gpu/h265_decoder.cc +++ b/media/gpu/h265_decoder.cc
@@ -329,6 +329,23 @@ if (par_res != H265Parser::kOk) SET_ERROR_AND_RETURN(); + // For ARC CTS tests they expect us to request the buffers after only + // processing the SPS/PPS, we can't wait until we get the first IDR. To + // resolve the problem that was created by originally doing that, only + // do it if we don't have an active PPS set yet so it won't disturb an + // active stream. + if (curr_pps_id_ == -1) { + bool need_new_buffers = false; + if (!ProcessPPS(pps_id, &need_new_buffers)) { + SET_ERROR_AND_RETURN(); + } + + if (need_new_buffers) { + curr_nalu_.reset(); + return kConfigChange; + } + } + break; case H265NALU::EOS_NUT: first_picture_ = true;
diff --git a/media/gpu/h265_decoder_unittest.cc b/media/gpu/h265_decoder_unittest.cc index 5b2c6ec..60b0e5e 100644 --- a/media/gpu/h265_decoder_unittest.cc +++ b/media/gpu/h265_decoder_unittest.cc
@@ -518,7 +518,7 @@ EXPECT_CALL(*accelerator_, SubmitDecode(HasPoc(0))).Times(1); EXPECT_CALL(*accelerator_, OutputPicture(HasPoc(0))).Times(1); } - EXPECT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode()); + EXPECT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, Decode(false)); EXPECT_TRUE(decoder_->Flush()); }
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc index 6b25b06..645d9b40 100644 --- a/net/socket/tcp_client_socket.cc +++ b/net/socket/tcp_client_socket.cc
@@ -58,6 +58,19 @@ nullptr /* network_quality_estimator */, NetworkChangeNotifier::kInvalidNetworkHandle) {} +TCPClientSocket::TCPClientSocket( + std::unique_ptr<TCPSocket> unconnected_socket, + const AddressList& addresses, + NetworkQualityEstimator* network_quality_estimator) + : TCPClientSocket( + std::move(unconnected_socket), + addresses, + -1 /* current_address_index */, + nullptr /* bind_address */, + network_quality_estimator, + // TODO(https://crbug.com/1295460): Pass through network handle + NetworkChangeNotifier::kInvalidNetworkHandle) {} + TCPClientSocket::~TCPClientSocket() { Disconnect(); #if defined(TCP_CLIENT_SOCKET_OBSERVES_SUSPEND) @@ -232,9 +245,7 @@ next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; - if (socket_->IsValid()) { - DCHECK(bind_address_); - } else { + if (!socket_->IsValid()) { int result = OpenSocket(endpoint.GetFamily()); if (result != OK) return result;
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h index 891f36b2..4b50732 100644 --- a/net/socket/tcp_client_socket.h +++ b/net/socket/tcp_client_socket.h
@@ -70,6 +70,12 @@ TCPClientSocket(std::unique_ptr<TCPSocket> connected_socket, const IPEndPoint& peer_address); + // Adopts an unconnected TCPSocket. This function is used by + // TCPClientSocketBrokered. + TCPClientSocket(std::unique_ptr<TCPSocket> unconnected_socket, + const AddressList& addresses, + NetworkQualityEstimator* network_quality_estimator); + // Creates a TCPClientSocket from a bound-but-not-connected socket. static std::unique_ptr<TCPClientSocket> CreateFromBoundSocket( std::unique_ptr<TCPSocket> bound_socket,
diff --git a/net/socket/transport_client_socket.cc b/net/socket/transport_client_socket.cc index 8b3e013..76e4514 100644 --- a/net/socket/transport_client_socket.cc +++ b/net/socket/transport_client_socket.cc
@@ -19,10 +19,4 @@ return false; } -void TransportClientSocket::SetSocketCreatorForTesting( - base::RepeatingCallback<std::unique_ptr<net::TransportClientSocket>(void)> - socket_creator) { - NOTIMPLEMENTED(); -} - } // namespace net
diff --git a/net/socket/transport_client_socket.h b/net/socket/transport_client_socket.h index 5ff1edd4..4bb5ec1c 100644 --- a/net/socket/transport_client_socket.h +++ b/net/socket/transport_client_socket.h
@@ -50,12 +50,6 @@ // should always be ready after successful connection or slightly earlier // during BeforeConnect handlers. virtual bool SetKeepAlive(bool enable, int delay_secs); - - // Sets a callback that returns a TransportClientSocket. Used in tests for - // TCPClientSocketBrokered to create a MockTCPClientSocket. - virtual void SetSocketCreatorForTesting( - base::RepeatingCallback<std::unique_ptr<net::TransportClientSocket>(void)> - socket_creator); }; } // namespace net
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn index d7b19a0e..cecd48a 100644 --- a/pdf/BUILD.gn +++ b/pdf/BUILD.gn
@@ -275,11 +275,13 @@ } source_set("pdf_test_utils") { - visibility = [ ":*" ] + visibility = [ "//pdf/*" ] testonly = true sources = [ + "test/mock_web_associated_url_loader.cc", + "test/mock_web_associated_url_loader.h", "test/test_client.cc", "test/test_client.h", "test/test_document_loader.cc", @@ -297,7 +299,7 @@ "//pdf/loader", "//testing/gmock", "//testing/gtest", - "//third_party/blink/public/common:headers", + "//third_party/blink/public:blink", "//ui/gfx/range", "//ui/latency:latency", ]
diff --git a/pdf/loader/BUILD.gn b/pdf/loader/BUILD.gn index 85e6e955..b0bf43e 100644 --- a/pdf/loader/BUILD.gn +++ b/pdf/loader/BUILD.gn
@@ -71,6 +71,7 @@ "//base/test:test_support", "//net", "//pdf:features", + "//pdf:pdf_test_utils", "//testing/gmock", "//testing/gtest", "//third_party/blink/public:blink",
diff --git a/pdf/loader/url_loader_unittest.cc b/pdf/loader/url_loader_unittest.cc index 6f0280b5..f2e5108 100644 --- a/pdf/loader/url_loader_unittest.cc +++ b/pdf/loader/url_loader_unittest.cc
@@ -23,6 +23,7 @@ #include "net/base/net_errors.h" #include "net/cookies/site_for_cookies.h" #include "pdf/loader/result_codes.h" +#include "pdf/test/mock_web_associated_url_loader.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h" @@ -74,22 +75,6 @@ return blink::WebURLError(reason, GURL()); } -class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader { - public: - // blink::WebAssociatedURLLoader: - MOCK_METHOD(void, - LoadAsynchronously, - (const blink::WebURLRequest&, - blink::WebAssociatedURLLoaderClient*), - (override)); - MOCK_METHOD(void, Cancel, (), (override)); - MOCK_METHOD(void, SetDefersLoading, (bool), (override)); - MOCK_METHOD(void, - SetLoadingTaskRunner, - (base::SingleThreadTaskRunner*), - (override)); -}; - class FakeUrlLoaderClient : public UrlLoader::Client { public: base::WeakPtr<FakeUrlLoaderClient> GetWeakPtr() {
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc index ecccb1c..914ed316 100644 --- a/pdf/pdf_view_web_plugin_unittest.cc +++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -36,6 +36,7 @@ #include "pdf/paint_ready_rect.h" #include "pdf/pdf_accessibility_data_handler.h" #include "pdf/pdf_view_plugin_base.h" +#include "pdf/test/mock_web_associated_url_loader.h" #include "pdf/test/test_helpers.h" #include "pdf/test/test_pdfium_engine.h" #include "printing/metafile_skia.h" @@ -174,32 +175,6 @@ (override)); }; -class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader { - public: - MockWebAssociatedURLLoader() { - ON_CALL(*this, LoadAsynchronously) - .WillByDefault([](const blink::WebURLRequest& /*request*/, - blink::WebAssociatedURLLoaderClient* client) { - // TODO(crbug.com/1322928): Must trigger callback to free `UrlLoader`. - client->DidReceiveResponse(blink::WebURLResponse()); - client->DidFinishLoading(); - }); - } - - // blink::WebAssociatedURLLoader: - MOCK_METHOD(void, - LoadAsynchronously, - (const blink::WebURLRequest&, - blink::WebAssociatedURLLoaderClient*), - (override)); - MOCK_METHOD(void, Cancel, (), (override)); - MOCK_METHOD(void, SetDefersLoading, (bool), (override)); - MOCK_METHOD(void, - SetLoadingTaskRunner, - (base::SingleThreadTaskRunner*), - (override)); -}; - class MockPdfAccessibilityDataHandler : public PdfAccessibilityDataHandler { public: // PdfAccessibilityDataHandler: @@ -224,7 +199,17 @@ public: FakePdfViewWebPluginClient() { ON_CALL(*this, CreateAssociatedURLLoader).WillByDefault([]() { - return std::make_unique<NiceMock<MockWebAssociatedURLLoader>>(); + auto associated_loader = + std::make_unique<NiceMock<MockWebAssociatedURLLoader>>(); + ON_CALL(*associated_loader, LoadAsynchronously) + .WillByDefault([](const blink::WebURLRequest& /*request*/, + blink::WebAssociatedURLLoaderClient* client) { + // TODO(crbug.com/1322928): Must trigger callback to free + // `UrlLoader`. + client->DidReceiveResponse(blink::WebURLResponse()); + client->DidFinishLoading(); + }); + return associated_loader; }); ON_CALL(*this, GetEmbedderOriginString) .WillByDefault(
diff --git a/pdf/test/mock_web_associated_url_loader.cc b/pdf/test/mock_web_associated_url_loader.cc new file mode 100644 index 0000000..82a5466a --- /dev/null +++ b/pdf/test/mock_web_associated_url_loader.cc
@@ -0,0 +1,12 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/test/mock_web_associated_url_loader.h" + +namespace chrome_pdf { + +MockWebAssociatedURLLoader::MockWebAssociatedURLLoader() = default; +MockWebAssociatedURLLoader::~MockWebAssociatedURLLoader() = default; + +} // namespace chrome_pdf
diff --git a/pdf/test/mock_web_associated_url_loader.h b/pdf/test/mock_web_associated_url_loader.h new file mode 100644 index 0000000..2c449ef --- /dev/null +++ b/pdf/test/mock_web_associated_url_loader.h
@@ -0,0 +1,36 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_TEST_MOCK_WEB_ASSOCIATED_URL_LOADER_H_ +#define PDF_TEST_MOCK_WEB_ASSOCIATED_URL_LOADER_H_ + +#include "testing/gmock/include/gmock/gmock.h" +#include "third_party/blink/public/web/web_associated_url_loader.h" + +namespace chrome_pdf { + +class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader { + public: + MockWebAssociatedURLLoader(); + MockWebAssociatedURLLoader(const MockWebAssociatedURLLoader&) = delete; + MockWebAssociatedURLLoader& operator=(const MockWebAssociatedURLLoader&) = + delete; + ~MockWebAssociatedURLLoader() override; + + MOCK_METHOD(void, + LoadAsynchronously, + (const blink::WebURLRequest&, + blink::WebAssociatedURLLoaderClient*), + (override)); + MOCK_METHOD(void, Cancel, (), (override)); + MOCK_METHOD(void, SetDefersLoading, (bool), (override)); + MOCK_METHOD(void, + SetLoadingTaskRunner, + (base::SingleThreadTaskRunner*), + (override)); +}; + +} // namespace chrome_pdf + +#endif // PDF_TEST_MOCK_WEB_ASSOCIATED_URL_LOADER_H_
diff --git a/remoting/codec/webrtc_video_encoder.h b/remoting/codec/webrtc_video_encoder.h index 395c23fb..c7d8aeb 100644 --- a/remoting/codec/webrtc_video_encoder.h +++ b/remoting/codec/webrtc_video_encoder.h
@@ -108,9 +108,11 @@ virtual ~WebrtcVideoEncoder() {} - // Request that the encoder provide lossless encoding, or color, if possible. + // Encoder configurable settings, may be provided via SDP or OOB via a + // proprietary message. virtual void SetLosslessEncode(bool want_lossless) {} virtual void SetLosslessColor(bool want_lossless) {} + virtual void SetEncoderSpeed(int encoder_speed) {} // Encode an image stored in |frame|. If frame.updated_region() is empty // then the encoder may return a frame (e.g. to top-off previously-encoded
diff --git a/remoting/codec/webrtc_video_encoder_vpx.cc b/remoting/codec/webrtc_video_encoder_vpx.cc index 3e440af..206d0fe3 100644 --- a/remoting/codec/webrtc_video_encoder_vpx.cc +++ b/remoting/codec/webrtc_video_encoder_vpx.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/system/sys_info.h" @@ -51,6 +52,11 @@ // TODO(zijiehe): This value is for VP8 only; reconsider the value for VP9. constexpr int kVp8MinimumTargetBitrateKbpsPerMegapixel = 2500; +// Default values for the encoder speed of the supported codecs. +constexpr int kVp9LosslessEncodeSpeed = 5; +constexpr int kVp9DefaultEncoderSpeed = 6; +constexpr int kVp9MaxEncoderSpeed = 9; + void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, const webrtc::DesktopSize& size) { // Use millisecond granularity time base. @@ -140,12 +146,12 @@ DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set noise sensitivity"; } -void SetVp9CodecOptions(vpx_codec_ctx_t* codec, bool lossless_encode) { - // Request the lowest-CPU usage that VP9 supports, which depends on whether - // we are encoding lossy or lossless. +void SetVp9CodecOptions(vpx_codec_ctx_t* codec, + bool lossless_encode, + int encoder_speed) { // Note that this knob uses the same parameter name as VP8. - int cpu_used = lossless_encode ? 5 : 6; - vpx_codec_err_t ret = vpx_codec_control(codec, VP8E_SET_CPUUSED, cpu_used); + vpx_codec_err_t ret = + vpx_codec_control(codec, VP8E_SET_CPUUSED, encoder_speed); DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set CPUUSED"; // Turn on row-based multi-threading if more than one thread is available. @@ -194,8 +200,13 @@ } void WebrtcVideoEncoderVpx::SetLosslessEncode(bool want_lossless) { - if (use_vp9_ && (want_lossless != lossless_encode_)) { + if (!use_vp9_) + return; + + if (want_lossless != lossless_encode_) { lossless_encode_ = want_lossless; + SetEncoderSpeed(lossless_encode_ ? kVp9LosslessEncodeSpeed + : kVp9DefaultEncoderSpeed); if (codec_) Configure(webrtc::DesktopSize(codec_->config.enc->g_w, codec_->config.enc->g_h)); @@ -203,7 +214,10 @@ } void WebrtcVideoEncoderVpx::SetLosslessColor(bool want_lossless) { - if (use_vp9_ && (want_lossless != lossless_color_)) { + if (!use_vp9_) + return; + + if (want_lossless != lossless_color_) { lossless_color_ = want_lossless; // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. // See https://code.google.com/p/webm/issues/detail?id=913. @@ -214,6 +228,14 @@ } } +void WebrtcVideoEncoderVpx::SetEncoderSpeed(int encoder_speed) { + if (!use_vp9_) + return; + + vp9_encoder_speed_ = base::clamp<int>(encoder_speed, kVp9LosslessEncodeSpeed, + kVp9MaxEncoderSpeed); +} + void WebrtcVideoEncoderVpx::Encode(std::unique_ptr<webrtc::DesktopFrame> frame, const FrameParams& params, EncodeCallback done) { @@ -340,6 +362,10 @@ bitrate_filter_(kVp8MinimumTargetBitrateKbpsPerMegapixel) { // Indicates config is still uninitialized. config_.g_timebase.den = 0; + + if (use_vp9_) { + SetEncoderSpeed(kVp9DefaultEncoderSpeed); + } } void WebrtcVideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { @@ -400,7 +426,7 @@ // Apply further customizations to the codec now it's initialized. if (use_vp9_) { - SetVp9CodecOptions(codec_.get(), lossless_encode_); + SetVp9CodecOptions(codec_.get(), lossless_encode_, vp9_encoder_speed_); } else { SetVp8CodecOptions(codec_.get()); }
diff --git a/remoting/codec/webrtc_video_encoder_vpx.h b/remoting/codec/webrtc_video_encoder_vpx.h index 1177bf6..a1e2ba82 100644 --- a/remoting/codec/webrtc_video_encoder_vpx.h +++ b/remoting/codec/webrtc_video_encoder_vpx.h
@@ -44,6 +44,7 @@ // WebrtcVideoEncoder interface. void SetLosslessEncode(bool want_lossless) override; void SetLosslessColor(bool want_lossless) override; + void SetEncoderSpeed(int encoder_speed) override; void Encode(std::unique_ptr<webrtc::DesktopFrame> frame, const FrameParams& params, EncodeCallback done) override; @@ -77,10 +78,11 @@ // True if the encoder is for VP9, false for VP8. const bool use_vp9_; - // Options controlling VP9 encode quantization and color space. - // These are always off (false) for VP8. + // Options controlling VP9 encode quantization, color space, and speed. + // These are not used when configuring VP8. bool lossless_encode_ = false; bool lossless_color_ = false; + int vp9_encoder_speed_ = -1; // Holds the initialized & configured codec. ScopedVpxCodec codec_;
diff --git a/remoting/protocol/webrtc_connection_to_client.cc b/remoting/protocol/webrtc_connection_to_client.cc index b6feb7c..7aed5dac 100644 --- a/remoting/protocol/webrtc_connection_to_client.cc +++ b/remoting/protocol/webrtc_connection_to_client.cc
@@ -137,6 +137,7 @@ session_options_ = options; DCHECK(transport_); transport_->ApplySessionOptions(options); + video_encoder_factory_->ApplySessionOptions(options); } PeerConnectionControls* WebrtcConnectionToClient::peer_connection_controls() {
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index 2760bc0c..7b95637 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -747,15 +747,11 @@ if (video_codec) { preferred_video_codec_ = *video_codec; } - absl::optional<std::string> video_frame_rate = - session_options().Get("Video-Frame-Rate"); - if (video_frame_rate) { - int frame_rate; - if (base::StringToInt(*video_frame_rate, &frame_rate)) { - // Clamp the range to prevent a bad experience in case of a client bug. - frame_rate = base::clamp<int>(frame_rate, kTargetFrameRate, 1000); - desired_video_frame_rate_ = frame_rate; - } + absl::optional<int> frame_rate = session_options().GetInt("Video-Frame-Rate"); + if (frame_rate) { + // Clamp the range to prevent a bad experience in case of a client bug. + frame_rate = base::clamp<int>(frame_rate.value(), kTargetFrameRate, 1000); + desired_video_frame_rate_ = frame_rate.value(); } }
diff --git a/remoting/protocol/webrtc_video_encoder_factory.cc b/remoting/protocol/webrtc_video_encoder_factory.cc index 8f08b6a4..71fcac8 100644 --- a/remoting/protocol/webrtc_video_encoder_factory.cc +++ b/remoting/protocol/webrtc_video_encoder_factory.cc
@@ -42,7 +42,8 @@ WebrtcVideoEncoderFactory::CreateVideoEncoder( const webrtc::SdpVideoFormat& format) { return std::make_unique<WebrtcVideoEncoderWrapper>( - format, main_task_runner_, video_channel_state_observer_); + format, session_options_, main_task_runner_, + video_channel_state_observer_); } std::vector<webrtc::SdpVideoFormat> @@ -56,4 +57,10 @@ video_channel_state_observer_ = video_channel_state_observer; } +void WebrtcVideoEncoderFactory::ApplySessionOptions( + const SessionOptions& options) { + DCHECK(main_task_runner_->BelongsToCurrentThread()); + session_options_ = options; +} + } // namespace remoting::protocol
diff --git a/remoting/protocol/webrtc_video_encoder_factory.h b/remoting/protocol/webrtc_video_encoder_factory.h index ec5d001..1a00675 100644 --- a/remoting/protocol/webrtc_video_encoder_factory.h +++ b/remoting/protocol/webrtc_video_encoder_factory.h
@@ -11,11 +11,11 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/task/single_thread_task_runner.h" +#include "remoting/base/session_options.h" #include "third_party/webrtc/api/video_codecs/video_encoder_factory.h" #include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h" -namespace remoting { -namespace protocol { +namespace remoting::protocol { class VideoChannelStateObserver; @@ -35,15 +35,18 @@ void SetVideoChannelStateObserver( base::WeakPtr<VideoChannelStateObserver> video_channel_state_observer); + void ApplySessionOptions(const SessionOptions& options); + private: scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; std::vector<webrtc::SdpVideoFormat> formats_; + SessionOptions session_options_; + base::WeakPtr<VideoChannelStateObserver> video_channel_state_observer_; }; -} // namespace protocol -} // namespace remoting +} // namespace remoting::protocol #endif // REMOTING_PROTOCOL_WEBRTC_VIDEO_ENCODER_FACTORY_H_
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper.cc b/remoting/protocol/webrtc_video_encoder_wrapper.cc index c50432b5..be6263c 100644 --- a/remoting/protocol/webrtc_video_encoder_wrapper.cc +++ b/remoting/protocol/webrtc_video_encoder_wrapper.cc
@@ -11,6 +11,7 @@ #include <vector> #include "base/bind.h" +#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/task/bind_post_task.h" @@ -18,6 +19,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "remoting/base/constants.h" +#include "remoting/base/session_options.h" #include "remoting/codec/webrtc_video_encoder_av1.h" #include "remoting/codec/webrtc_video_encoder_vpx.h" #include "remoting/protocol/video_channel_state_observer.h" @@ -36,9 +38,6 @@ namespace { -constexpr base::TimeDelta kTargetFrameInterval = - base::Milliseconds(1000 / kTargetFrameRate); - // Maximum quantizer at which to encode frames. Lowering this value will // improve image quality (in cases of low-bandwidth or large frames) at the // cost of latency. Increasing the value will improve latency (in these cases) @@ -91,10 +90,20 @@ WebrtcVideoEncoderWrapper::WebrtcVideoEncoderWrapper( const webrtc::SdpVideoFormat& format, + const SessionOptions& session_options, scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, base::WeakPtr<VideoChannelStateObserver> video_channel_state_observer) : main_task_runner_(main_task_runner), video_channel_state_observer_(video_channel_state_observer) { + // Set the target frame rate based on the session options. + absl::optional<int> frame_rate = session_options.GetInt("Video-Frame-Rate"); + if (frame_rate) { + // Clamp the range to prevent a bad experience in case of a client bug. + frame_rate = base::clamp<int>(frame_rate.value(), kTargetFrameRate, 1000); + target_frame_rate_ = frame_rate.value(); + } + target_frame_interval_ = base::Milliseconds(1000 / target_frame_rate_); + codec_type_ = webrtc::PayloadStringToCodecType(format.name); switch (codec_type_) { case webrtc::kVideoCodecVP8: @@ -110,6 +119,12 @@ << (lossless_color ? "true" : "false"); encoder_ = WebrtcVideoEncoderVpx::CreateForVP9(); encoder_->SetLosslessColor(lossless_color); + absl::optional<int> encoder_speed = + session_options.GetInt("Vp9-Encoder-Speed"); + if (encoder_speed) { + VLOG(0) << "Setting VP9 encoder speed to " << encoder_speed.value(); + encoder_->SetEncoderSpeed(encoder_speed.value()); + } break; } case webrtc::kVideoCodecH264: @@ -285,11 +300,11 @@ // SetRates() must be called prior to Encode(), with a non-zero bitrate. DCHECK_NE(0, bitrate_kbps_); frame_params.bitrate_kbps = bitrate_kbps_; - frame_params.duration = kTargetFrameInterval; + frame_params.duration = target_frame_interval_; // TODO(crbug.com/1192865): Copy the FPS estimator from the scheduler, // instead of hard-coding this value here. - frame_params.fps = kTargetFrameRate; + frame_params.fps = target_frame_rate_; frame_params.vpx_min_quantizer = ShouldDropQualityForLargeFrame(*desktop_frame) ? kMaxQuantizer @@ -495,7 +510,7 @@ updated_area * kEstimatedBytesPerMegapixel / kPixelsPerMegapixel; base::TimeDelta expected_send_delay = base::Seconds(expected_frame_size * 8 / (bitrate_kbps_ * 1000.0)); - if (expected_send_delay > kTargetFrameInterval) { + if (expected_send_delay > target_frame_interval_) { should_drop_quality = true; } }
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper.h b/remoting/protocol/webrtc_video_encoder_wrapper.h index d26a11eb..c6d82a71 100644 --- a/remoting/protocol/webrtc_video_encoder_wrapper.h +++ b/remoting/protocol/webrtc_video_encoder_wrapper.h
@@ -12,14 +12,15 @@ #include "base/sequence_checker.h" #include "base/task/single_thread_task_runner.h" #include "base/thread_annotations.h" +#include "remoting/base/constants.h" #include "remoting/base/running_samples.h" +#include "remoting/base/session_options.h" #include "remoting/codec/webrtc_video_encoder.h" #include "third_party/webrtc/api/video/video_codec_type.h" #include "third_party/webrtc/api/video_codecs/sdp_video_format.h" #include "third_party/webrtc/api/video_codecs/video_encoder.h" -namespace remoting { -namespace protocol { +namespace remoting::protocol { class VideoChannelStateObserver; @@ -33,6 +34,7 @@ // notified of important events on the |main_task_runner| thread. WebrtcVideoEncoderWrapper( const webrtc::SdpVideoFormat& format, + const SessionOptions& session_options, scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, base::WeakPtr<VideoChannelStateObserver> video_channel_state_observer); ~WebrtcVideoEncoderWrapper() override; @@ -147,6 +149,12 @@ // TaskRunner used for notifying |video_channel_state_observer_|. scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + // Stores the taret frame rate used for capture and encode scheduling. May be + // overridden by the client via SessionOptions. This value is applied to all + // codecs and cannot be changed during a session. + int target_frame_rate_ = kTargetFrameRate; + base::TimeDelta target_frame_interval_; + base::WeakPtr<VideoChannelStateObserver> video_channel_state_observer_; // This class lives on WebRTC's encoding thread. All methods (including ctor @@ -156,7 +164,6 @@ base::WeakPtrFactory<WebrtcVideoEncoderWrapper> weak_factory_{this}; }; -} // namespace protocol -} // namespace remoting +} // namespace remoting::protocol #endif // REMOTING_PROTOCOL_WEBRTC_VIDEO_ENCODER_WRAPPER_H_
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper_unittest.cc b/remoting/protocol/webrtc_video_encoder_wrapper_unittest.cc index 8f269e8..cf6968d 100644 --- a/remoting/protocol/webrtc_video_encoder_wrapper_unittest.cc +++ b/remoting/protocol/webrtc_video_encoder_wrapper_unittest.cc
@@ -5,6 +5,7 @@ #include "remoting/protocol/webrtc_video_encoder_wrapper.h" #include "base/test/task_environment.h" +#include "remoting/base/session_options.h" #include "remoting/protocol/video_channel_state_observer.h" #include "remoting/protocol/webrtc_video_frame_adapter.h" #include "testing/gmock/include/gmock/gmock.h" @@ -202,7 +203,7 @@ std::unique_ptr<WebrtcVideoEncoderWrapper> InitEncoder(SdpVideoFormat sdp, VideoCodec codec) { auto encoder = std::make_unique<WebrtcVideoEncoderWrapper>( - sdp, task_environment_.GetMainThreadTaskRunner(), + sdp, SessionOptions(), task_environment_.GetMainThreadTaskRunner(), observer_.GetWeakPtr()); encoder->InitEncode(&codec, kVideoEncoderSettings); encoder->RegisterEncodeCompleteCallback(&callback_);
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn index 3011d07..bffd7b6da 100644 --- a/services/network/BUILD.gn +++ b/services/network/BUILD.gn
@@ -524,6 +524,8 @@ "test/test_resource_scheduler.h", "test/test_shared_url_loader_factory.cc", "test/test_shared_url_loader_factory.h", + "test/test_socket_broker_impl.cc", + "test/test_socket_broker_impl.h", "test/test_udp_socket.cc", "test/test_udp_socket.h", "test/test_url_loader_client.cc",
diff --git a/services/network/brokered_client_socket_factory.cc b/services/network/brokered_client_socket_factory.cc index 5bd917b..7a36c71b 100644 --- a/services/network/brokered_client_socket_factory.cc +++ b/services/network/brokered_client_socket_factory.cc
@@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <memory> -#include <string> - #include "services/network/brokered_client_socket_factory.h" #include "build/build_config.h" @@ -27,7 +24,9 @@ namespace network { -BrokeredClientSocketFactory::BrokeredClientSocketFactory() = default; +BrokeredClientSocketFactory::BrokeredClientSocketFactory( + mojo::PendingRemote<mojom::SocketBroker> pending_remote) + : socket_broker_(std::move(pending_remote)) {} BrokeredClientSocketFactory::~BrokeredClientSocketFactory() = default; std::unique_ptr<net::DatagramClientSocket> @@ -48,7 +47,7 @@ const net::NetLogSource& source) { return std::make_unique<TCPClientSocketBrokered>( addresses, std::move(socket_performance_watcher), - network_quality_estimator, net_log, source); + network_quality_estimator, net_log, source, this); } std::unique_ptr<net::SSLClientSocket> @@ -61,4 +60,10 @@ return nullptr; } +void BrokeredClientSocketFactory::BrokerCreateTcpSocket( + net::AddressFamily address_family, + mojom::SocketBroker::CreateTcpSocketCallback callback) { + socket_broker_->CreateTcpSocket(address_family, std::move(callback)); +} + } // namespace network
diff --git a/services/network/brokered_client_socket_factory.h b/services/network/brokered_client_socket_factory.h index 2f33be0..dc083d2 100644 --- a/services/network/brokered_client_socket_factory.h +++ b/services/network/brokered_client_socket_factory.h
@@ -5,15 +5,14 @@ #ifndef SERVICES_NETWORK_BROKERED_CLIENT_SOCKET_FACTORY_H_ #define SERVICES_NETWORK_BROKERED_CLIENT_SOCKET_FACTORY_H_ -#include <memory> -#include <string> - #include "base/component_export.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/socket/client_socket_factory.h" #include "net/socket/datagram_socket.h" #include "net/socket/socket_performance_watcher.h" #include "net/socket/transport_client_socket.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/mojom/socket_broker.mojom.h" namespace net { @@ -35,7 +34,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) BrokeredClientSocketFactory : public net::ClientSocketFactory { public: - BrokeredClientSocketFactory(); + explicit BrokeredClientSocketFactory( + mojo::PendingRemote<mojom::SocketBroker> pending_remote); ~BrokeredClientSocketFactory() override; BrokeredClientSocketFactory(const BrokeredClientSocketFactory&) = delete; @@ -58,6 +58,14 @@ std::unique_ptr<net::StreamSocket> stream_socket, const net::HostPortPair& host_and_port, const net::SSLConfig& ssl_config) override; + + // Sends an IPC to the SocketBroker to create a new TCP socket. + void BrokerCreateTcpSocket( + net::AddressFamily address_family, + mojom::SocketBroker::CreateTcpSocketCallback callback); + + private: + mojo::Remote<mojom::SocketBroker> socket_broker_; }; } // namespace network
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 89bbba49..872f6c2 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1266,18 +1266,6 @@ std::move(callback).Run(); } -void NetworkContext::GetDomainReliabilityJSON( - GetDomainReliabilityJSONCallback callback) { - if (!domain_reliability_monitor_) { - base::Value data(base::Value::Type::DICTIONARY); - data.SetStringKey("error", "no_service"); - std::move(callback).Run(std::move(data)); - return; - } - - std::move(callback).Run(domain_reliability_monitor_->GetWebUIData()); -} - void NetworkContext::CloseAllConnections(CloseAllConnectionsCallback callback) { net::HttpNetworkSession* http_session = url_request_context_->http_transaction_factory()->GetSession();
diff --git a/services/network/network_context.h b/services/network/network_context.h index f253552..4da0446b 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h
@@ -290,8 +290,6 @@ void ClearDomainReliability(mojom::ClearDataFilterPtr filter, DomainReliabilityClearMode mode, ClearDomainReliabilityCallback callback) override; - void GetDomainReliabilityJSON( - GetDomainReliabilityJSONCallback callback) override; void CloseAllConnections(CloseAllConnectionsCallback callback) override; void CloseIdleConnections(CloseIdleConnectionsCallback callback) override; void SetNetworkConditions(const base::UnguessableToken& throttling_profile_id,
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn index bc88840..c386c265 100644 --- a/services/network/public/mojom/BUILD.gn +++ b/services/network/public/mojom/BUILD.gn
@@ -907,6 +907,7 @@ "proxy_lookup_client.mojom", "proxy_resolving_socket.mojom", "reporting_service.mojom", + "socket_broker.mojom", "ssl_config.mojom", "supports_loading_mode.mojom", "tcp_socket.mojom",
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 7f1c4dd..9428fe14 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -1004,9 +1004,6 @@ ClearDomainReliability(ClearDataFilter? filter, DomainReliabilityClearMode mode) => (); - // Returns a JSON value containing data for displaying on a debugging page. - GetDomainReliabilityJSON() => (mojo_base.mojom.Value data); - // Configures per-resource reporting endpoints set with the // Reporting-Endpoints header. // |reporting_source| is a token which identifies the document or worker with
diff --git a/services/network/public/mojom/socket_broker.mojom b/services/network/public/mojom/socket_broker.mojom new file mode 100644 index 0000000..14fafb6 --- /dev/null +++ b/services/network/public/mojom/socket_broker.mojom
@@ -0,0 +1,17 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module network.mojom; + +import "services/network/public/mojom/address_family.mojom"; + +// Interface to broker socket creation in the browser. +// Used on Windows and Android as a sandboxed network service +// cannot directly create sockets. +interface SocketBroker { + // Creates an unconnected TCP socket. Returns the + // SocketDescriptor and the net::Error. + CreateTcpSocket(AddressFamily address_family) + => (handle<platform>? created_socket, int32 rv); +};
diff --git a/services/network/tcp_client_socket_brokered.cc b/services/network/tcp_client_socket_brokered.cc index 28306bb8..9458fd5 100644 --- a/services/network/tcp_client_socket_brokered.cc +++ b/services/network/tcp_client_socket_brokered.cc
@@ -11,6 +11,7 @@ #include "net/base/completion_once_callback.h" #include "net/socket/tcp_client_socket.h" #include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/brokered_client_socket_factory.h" namespace network { @@ -19,12 +20,14 @@ std::unique_ptr<net::SocketPerformanceWatcher> socket_performance_watcher, net::NetworkQualityEstimator* network_quality_estimator, net::NetLog* net_log, - const net::NetLogSource& source) + const net::NetLogSource& source, + BrokeredClientSocketFactory* client_socket_factory) : addresses_(addresses), socket_performance_watcher_(std::move(socket_performance_watcher)), network_quality_estimator_(network_quality_estimator), net_log_(net_log), - source_(source) {} + source_(source), + client_socket_factory_(client_socket_factory) {} TCPClientSocketBrokered::~TCPClientSocketBrokered() { Disconnect(); @@ -50,12 +53,6 @@ return brokered_socket_->SetNoDelay(no_delay); } -void TCPClientSocketBrokered::SetSocketCreatorForTesting( - base::RepeatingCallback<std::unique_ptr<net::TransportClientSocket>(void)> - socket_creator) { - socket_creator_for_testing_ = std::move(socket_creator); -} - void TCPClientSocketBrokered::SetBeforeConnectCallback( const BeforeConnectCallback& before_connect_callback) { // TODO(liza): Implement this. @@ -71,19 +68,15 @@ return net::OK; is_connect_in_progress_ = true; - // TODO(liza): Add a mojo call that creates a TCPClientSocket and calls - // Connect. - if (socket_creator_for_testing_) { - brokered_socket_ = socket_creator_for_testing_.Run(); - } else { - brokered_socket_ = std::make_unique<net::TCPClientSocket>( - addresses_, std::move(socket_performance_watcher_), - network_quality_estimator_, net_log_, source_); - } - brokered_socket_->ApplySocketTag(tag_); - return brokered_socket_->Connect(base::BindOnce( - &TCPClientSocketBrokered::DidCompleteConnect, - brokered_weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + + // TODO(https://crbug.com/1321274): Pass in AddressFamily of single IPEndPoint + client_socket_factory_->BrokerCreateTcpSocket( + addresses_.begin()->GetFamily(), + base::BindOnce(&TCPClientSocketBrokered::DidCompleteCreate, + brokered_weak_ptr_factory_.GetWeakPtr(), + std::move(callback))); + + return net::ERR_IO_PENDING; } int TCPClientSocketBrokered::OpenSocketForBind(const net::IPEndPoint& address) { @@ -109,6 +102,35 @@ is_connect_in_progress_ = false; } +void TCPClientSocketBrokered ::DidCompleteCreate( + net::CompletionOnceCallback callback, + mojo::PlatformHandle fd, + int result) { + if (result != net::OK) { + std::move(callback).Run(result); + return; + } + + // Create an unconnected TCPSocket with the socket fd that was opened in the + // browser process. + std::unique_ptr<net::TCPSocket> tcp_socket = std::make_unique<net::TCPSocket>( + std::move(socket_performance_watcher_), net_log_, source_); +// TODO(https://crbug.com/1311014): call TCPSocketWin::AdoptUnconnectedSocket +#if BUILDFLAG(IS_WIN) + tcp_socket->Open(addresses_.begin()->GetFamily()); +#else + tcp_socket->AdoptUnconnectedSocket(fd.ReleaseFD()); +#endif + + // TODO(liza): Pass through the NetworkHandle. + brokered_socket_ = std::make_unique<net::TCPClientSocket>( + std::move(tcp_socket), addresses_, network_quality_estimator_); + brokered_socket_->ApplySocketTag(tag_); + brokered_socket_->Connect(base::BindOnce( + &TCPClientSocketBrokered::DidCompleteConnect, + brokered_weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + void TCPClientSocketBrokered::Disconnect() { if (brokered_socket_) { brokered_socket_->Disconnect();
diff --git a/services/network/tcp_client_socket_brokered.h b/services/network/tcp_client_socket_brokered.h index f564a5e8..958ce30 100644 --- a/services/network/tcp_client_socket_brokered.h +++ b/services/network/tcp_client_socket_brokered.h
@@ -9,6 +9,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" +#include "mojo/public/cpp/platform/platform_handle.h" #include "net/base/address_list.h" #include "net/base/completion_once_callback.h" #include "net/nqe/network_quality_estimator.h" @@ -27,6 +28,8 @@ namespace network { +class BrokeredClientSocketFactory; + // A client socket used exclusively with a socket broker. Currently intended for // Windows and Android only. Not intended to be used by non-brokered // connections. Generally, all calls pass through to an underlying @@ -43,7 +46,8 @@ brokered_socket_performance_watcher, net::NetworkQualityEstimator* network_quality_estimator, net::NetLog* net_log, - const net::NetLogSource& source); + const net::NetLogSource& source, + BrokeredClientSocketFactory* client_socket_factory); ~TCPClientSocketBrokered() override; @@ -54,9 +58,6 @@ int Bind(const net::IPEndPoint& address) override; bool SetKeepAlive(bool enable, int delay) override; bool SetNoDelay(bool no_delay) override; - void SetSocketCreatorForTesting( - base::RepeatingCallback<std::unique_ptr<net::TransportClientSocket>(void)> - socket_creator) override; // StreamSocket implementation. void SetBeforeConnectCallback( @@ -102,6 +103,10 @@ void DidCompleteConnect(net::CompletionOnceCallback callback, int result); + void DidCompleteCreate(net::CompletionOnceCallback callback, + mojo::PlatformHandle fd, + int result); + // The list of addresses we should try in order to establish a connection. net::AddressList addresses_; @@ -120,10 +125,13 @@ // Need to store the tag in case ApplySocketTag() is called before Connect(). net::SocketTag tag_; + // The underlying brokered socket. Created when the socket is created for + // Connect(). std::unique_ptr<net::TransportClientSocket> brokered_socket_; - base::RepeatingCallback<std::unique_ptr<net::TransportClientSocket>(void)> - socket_creator_for_testing_; + // The ClientSocketFactory that created this socket. Used to send IPCs to the + // remote SocketBroker. + const raw_ptr<BrokeredClientSocketFactory> client_socket_factory_; base::WeakPtrFactory<TCPClientSocketBrokered> brokered_weak_ptr_factory_{ this};
diff --git a/services/network/tcp_client_socket_brokered_unittest.cc b/services/network/tcp_client_socket_brokered_unittest.cc index 81fa9d3..68e5fde 100644 --- a/services/network/tcp_client_socket_brokered_unittest.cc +++ b/services/network/tcp_client_socket_brokered_unittest.cc
@@ -25,6 +25,7 @@ #include "net/test/test_with_task_environment.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/brokered_client_socket_factory.h" +#include "services/network/test/test_socket_broker_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -37,7 +38,11 @@ class TCPClientSocketBrokeredTest : public testing::Test, public net::WithTaskEnvironment { public: - TCPClientSocketBrokeredTest() {} + TCPClientSocketBrokeredTest() + : receiver_(&socket_broker_impl_), + client_socket_factory_( + BrokeredClientSocketFactory(receiver_.BindNewPipeAndPassRemote())) { + } ~TCPClientSocketBrokeredTest() override = default; @@ -52,6 +57,7 @@ listen_socket->Accept(&server_socket_, server_callback_.callback()); net::AddressList addr = net::AddressList::CreateFromIPAddress( net::IPAddress::IPv4Localhost(), local_address.port()); + socket_ = client_socket_factory_.CreateTransportClientSocket( addr, nullptr, nullptr, net::NetLog::Get(), net::NetLogSource()); @@ -86,27 +92,19 @@ EXPECT_THAT(socket_->SetSendBufferSize(256), IsOk()); } - std::unique_ptr<net::TransportClientSocket> FinishCreatingMockSocket() { - data_.set_connect_data( - net::MockConnect(net::ASYNC, net::ERR_CONNECTION_FAILED)); - mock_client_socket_factory_.AddTcpSocketDataProvider(&data_); - - return mock_client_socket_factory_.CreateTransportClientSocket( - net::AddressList::CreateFromIPAddress(net::IPAddress::IPv4Localhost(), - 0), - nullptr, nullptr, net::NetLog::Get(), net::NetLogSource()); - } - protected: std::unique_ptr<net::TransportClientSocket> socket_; std::unique_ptr<net::TCPServerSocket> listen_socket; std::unique_ptr<net::StreamSocket> server_socket_; + mojo::Receiver<mojom::SocketBroker> receiver_; BrokeredClientSocketFactory client_socket_factory_; net::TestCompletionCallback server_callback_; net::MockClientSocketFactory mock_client_socket_factory_; net::StaticSocketDataProvider data_; + TestSocketBrokerImpl socket_broker_impl_; + bool close_server_socket_on_next_send_; }; @@ -114,9 +112,8 @@ net::TestCompletionCallback callback; base::test::ScopedDisableRunLoopTimeout disable_timeout; - socket_->SetSocketCreatorForTesting(base::BindRepeating( - &TCPClientSocketBrokeredTest::FinishCreatingMockSocket, - base::Unretained(this))); + socket_broker_impl_.SetMockSocketTest(true); + int result = socket_->Connect(callback.callback()); ASSERT_EQ(result, net::ERR_IO_PENDING); @@ -421,7 +418,8 @@ ASSERT_TRUE(test_server.GetAddressList(&addr_list)); TCPClientSocketBrokered client_socket(addr_list, nullptr, nullptr, nullptr, - net::NetLogSource()); + net::NetLogSource(), + &client_socket_factory_); // Verify TCP connect packets are tagged and counted properly. int32_t tag_val1 = 0x12345678;
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h index 9326104..e1598a29 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h
@@ -112,8 +112,6 @@ ClearDomainReliabilityCallback callback) override {} void ClearTrustTokenData(mojom::ClearDataFilterPtr filter, ClearTrustTokenDataCallback callback) override {} - void GetDomainReliabilityJSON( - GetDomainReliabilityJSONCallback callback) override {} void SetDocumentReportingEndpoints( const base::UnguessableToken& reporting_source, const url::Origin& origin,
diff --git a/services/network/test/test_socket_broker_impl.cc b/services/network/test/test_socket_broker_impl.cc new file mode 100644 index 0000000..14b123e --- /dev/null +++ b/services/network/test/test_socket_broker_impl.cc
@@ -0,0 +1,43 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/test/test_socket_broker_impl.h" + +#include "mojo/public/cpp/bindings/remote.h" +#include "net/base/net_errors.h" +#include "net/log/net_log_source.h" +#include "net/socket/socket_descriptor.h" +#include "net/socket/tcp_socket.h" + +#if !BUILDFLAG(IS_WIN) +#include "base/files/scoped_file.h" +#endif + +namespace network { + +TestSocketBrokerImpl::TestSocketBrokerImpl() = default; + +TestSocketBrokerImpl::~TestSocketBrokerImpl() = default; + +void TestSocketBrokerImpl::CreateTcpSocket(net::AddressFamily address_family, + CreateTcpSocketCallback callback) { + if (is_mock_socket_test_) { + std::move(callback).Run(mojo::PlatformHandle(), net::ERR_CONNECTION_FAILED); + return; + } + +// TODO(https://crbug.com/1311014): Open and release raw socket on Windows. +#if BUILDFLAG(IS_WIN) + std::move(callback).Run(mojo::PlatformHandle(), net::OK); +#else + net::SocketDescriptor socket; + int rv = + net::TCPSocket::OpenAndReleaseSocketDescriptor(address_family, &socket); + base::ScopedFD fd(socket); + + std::move(callback).Run(mojo::PlatformHandle(std::move(fd)), rv); +#endif +} + +} // namespace network
diff --git a/services/network/test/test_socket_broker_impl.h b/services/network/test/test_socket_broker_impl.h new file mode 100644 index 0000000..fc35d8d --- /dev/null +++ b/services/network/test/test_socket_broker_impl.h
@@ -0,0 +1,41 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_NETWORK_TEST_TEST_SOCKET_BROKER_IMPL_H_ +#define SERVICES_NETWORK_TEST_TEST_SOCKET_BROKER_IMPL_H_ + +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "net/base/address_family.h" +#include "services/network/public/mojom/socket_broker.mojom.h" + +namespace network { + +// Implementation of mojom::SocketBroker for use in tests within +// //services/network. +class TestSocketBrokerImpl : public network::mojom::SocketBroker { + public: + explicit TestSocketBrokerImpl(); + ~TestSocketBrokerImpl() override; + + TestSocketBrokerImpl(const TestSocketBrokerImpl&) = delete; + TestSocketBrokerImpl& operator=(const TestSocketBrokerImpl&) = delete; + + // mojom::SocketBroker implementation. + void CreateTcpSocket(net::AddressFamily address_family, + CreateTcpSocketCallback callback) override; + + void SetMockSocketTest(bool is_mock_socket_test) { + is_mock_socket_test_ = is_mock_socket_test; + } + + private: + mojo::ReceiverSet<network::mojom::SocketBroker> receivers_; + + // When true, CreateTcpSocket returns ERR_CONNECTION_FAILED to test a failed + // connection. + bool is_mock_socket_test_ = false; +}; + +} // namespace network +#endif // SERVICES_NETWORK_TEST_TEST_SOCKET_BROKER_IMPL_H_
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 663fd1f..050dc1b6 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -1388,7 +1388,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -3781,7 +3782,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -8325,15 +8327,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -8359,7 +8361,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -8835,15 +8837,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--test-expectations", - "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--implementation-outdir", "../../weblayer_instrumentation_test_M103/out/Release", + "--test-expectations", + "../../weblayer/browser/android/javatests/skew/expectations.txt", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -8869,7 +8871,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 8b59a0d..84e6e52c 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -11665,7 +11665,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -16355,7 +16356,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -32714,7 +32716,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -42651,7 +42654,8 @@ "name": "shard #${SHARD_INDEX} logcats" } ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 }, "test": "chrome_public_unit_test_apk", "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" @@ -46453,15 +46457,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -46487,7 +46491,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -46963,15 +46967,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--test-expectations", - "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--implementation-outdir", "../../weblayer_instrumentation_test_M103/out/Release", + "--test-expectations", + "../../weblayer/browser/android/javatests/skew/expectations.txt", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -46997,7 +47001,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -47477,15 +47481,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -47511,7 +47515,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -47987,15 +47991,15 @@ { "args": [ "--additional-apk=apks/ChromePublic.apk", + "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--test-expectations", - "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/AOSP_SystemWebView.apk", "--implementation-outdir", "../../weblayer_instrumentation_test_M103/out/Release", + "--test-expectations", + "../../weblayer/browser/android/javatests/skew/expectations.txt", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48021,7 +48025,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -48569,15 +48573,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -48603,7 +48607,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49079,15 +49083,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--test-expectations", - "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", "--implementation-outdir", "../../weblayer_instrumentation_test_M103/out/Release", + "--test-expectations", + "../../weblayer/browser/android/javatests/skew/expectations.txt", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -49113,7 +49117,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -49661,15 +49665,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", + "--client-outdir", + "../../weblayer_instrumentation_test_M103/out/Release", "--implementation-outdir", ".", "--test-expectations", "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", - "--client-outdir", - "../../weblayer_instrumentation_test_M103/out/Release", "--client-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -49695,7 +49699,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}", @@ -50171,15 +50175,15 @@ { "args": [ "--additional-apk=apks/WebLayerShellSystemWebView.apk", + "--webview-apk-path=apks/SystemWebView.apk", "--test-runner-outdir", ".", "--client-outdir", ".", - "--test-expectations", - "../../weblayer/browser/android/javatests/skew/expectations.txt", - "--webview-apk-path=apks/SystemWebView.apk", "--implementation-outdir", "../../weblayer_instrumentation_test_M103/out/Release", + "--test-expectations", + "../../weblayer/browser/android/javatests/skew/expectations.txt", "--impl-version=103", "--gs-results-bucket=chromium-result-details", "--recover-devices", @@ -50205,7 +50209,7 @@ { "cipd_package": "chromium/testing/weblayer-x86", "location": "weblayer_instrumentation_test_M103", - "revision": "version:103.0.5060.56" + "revision": "version:103.0.5060.57" }, { "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index f803635c..6e94dd60 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -107036,48 +107036,5 @@ "test_id_prefix": "ninja://:blink_web_tests/" } ] - }, - "win11-blink-rel-dummy": { - "isolated_scripts": [ - { - "args": [ - "--num-retries=3", - "--fuzzy-diff", - "--git-revision=${got_revision}", - "--target", - "Release_x64" - ], - "check_flakiness_for_new_tests": false, - "isolate_name": "blink_web_tests", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "blink_web_tests", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true - }, - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Windows-11-22000" - } - ], - "hard_timeout": 1200, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 12 - }, - "test_id_prefix": "ninja://:blink_web_tests/" - } - ] } }
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py index 1af0e5e..1abb766 100755 --- a/testing/buildbot/generate_buildbot_json.py +++ b/testing/buildbot/generate_buildbot_json.py
@@ -1605,7 +1605,6 @@ 'mac11.0-blink-rel-dummy', 'mac11.0.arm64-blink-rel-dummy', 'win10.20h2-blink-rel-dummy', - 'win11-blink-rel-dummy', ] def get_internal_waterfalls(self):
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 30702e5..de1dbbb 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -502,16 +502,7 @@ '--target', 'Release_x64', ], - }, - 'win11-blink-rel-dummy': { - 'swarming': { - 'hard_timeout': 1200, - }, - 'args': [ - '--target', - 'Release_x64', - ], - }, + } }, }, 'breakpad_unittests': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index c5cca02..c79e4c8 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -99,6 +99,9 @@ 'test': 'chrome_public_test_apk', }, 'chrome_public_unit_test_apk': { + 'swarming': { + 'shards': 4, + }, 'mixins': [ 'skia_gold_test', ],
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 8c535e2..5c8aa18 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -517,16 +517,16 @@ }, 'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ + '--webview-apk-path=apks/AOSP_SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--test-expectations', - '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--webview-apk-path=apks/AOSP_SystemWebView.apk', '--implementation-outdir', '../../weblayer_instrumentation_test_M103/out/Release', - '--impl-version=103' + '--test-expectations', + '../../weblayer/browser/android/javatests/skew/expectations.txt', + '--impl-version=103', ], 'identifier': 'with_impl_from_103', 'swarming': { @@ -534,10 +534,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.56' + 'revision': 'version:103.0.5060.57', } - ] - } + ], + }, }, 'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [ @@ -661,16 +661,16 @@ }, 'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ + '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', '--client-outdir', '.', - '--test-expectations', - '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--webview-apk-path=apks/SystemWebView.apk', '--implementation-outdir', '../../weblayer_instrumentation_test_M103/out/Release', - '--impl-version=103' + '--test-expectations', + '../../weblayer/browser/android/javatests/skew/expectations.txt', + '--impl-version=103', ], 'identifier': 'with_impl_from_103', 'swarming': { @@ -678,10 +678,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.56' + 'revision': 'version:103.0.5060.57', } - ] - } + ], + }, }, 'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [ @@ -805,16 +805,16 @@ }, 'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': { 'args': [ + '--webview-apk-path=apks/SystemWebView.apk', '--test-runner-outdir', '.', + '--client-outdir', + '../../weblayer_instrumentation_test_M103/out/Release', '--implementation-outdir', '.', '--test-expectations', '../../weblayer/browser/android/javatests/skew/expectations.txt', - '--webview-apk-path=apks/SystemWebView.apk', - '--client-outdir', - '../../weblayer_instrumentation_test_M103/out/Release', - '--client-version=103' + '--client-version=103', ], 'identifier': 'with_client_from_103', 'swarming': { @@ -822,10 +822,10 @@ { 'cipd_package': 'chromium/testing/weblayer-x86', 'location': 'weblayer_instrumentation_test_M103', - 'revision': 'version:103.0.5060.56' + 'revision': 'version:103.0.5060.57', } - ] - } + ], + }, }, 'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': { 'args': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 343535fd..d1afb14 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -3803,18 +3803,7 @@ 'test_suites': { 'isolated_scripts': 'chromium_webkit_isolated_scripts', }, - }, - 'win11-blink-rel-dummy': { - 'mixins': [ - 'win11', - ], - 'swarming': { - 'hard_timeout': 900, - }, - 'test_suites': { - 'isolated_scripts': 'chromium_webkit_isolated_scripts', - }, - }, + } }, }, {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index af7c17e4..14e80c8 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3407,12 +3407,12 @@ "params": { "UseDnsHttpsSvcbEnableInsecure": "true", "UseDnsHttpsSvcbHttpUpgrade": "true", - "UseDnsHttpsSvcbInsecureExtraTimeMax": "500ms", - "UseDnsHttpsSvcbInsecureExtraTimeMin": "300ms", - "UseDnsHttpsSvcbInsecureExtraTimePercent": "50", - "UseDnsHttpsSvcbSecureExtraTimeMax": "500ms", - "UseDnsHttpsSvcbSecureExtraTimeMin": "300ms", - "UseDnsHttpsSvcbSecureExtraTimePercent": "50" + "UseDnsHttpsSvcbInsecureExtraTimeMax": "50ms", + "UseDnsHttpsSvcbInsecureExtraTimeMin": "5ms", + "UseDnsHttpsSvcbInsecureExtraTimePercent": "20", + "UseDnsHttpsSvcbSecureExtraTimeMax": "50ms", + "UseDnsHttpsSvcbSecureExtraTimeMin": "5ms", + "UseDnsHttpsSvcbSecureExtraTimePercent": "20" }, "enable_features": [ "UseDnsHttpsSvcb" @@ -3421,33 +3421,6 @@ ] } ], - "DnsHttpssvc": [ - { - "platforms": [ - "windows", - "mac", - "chromeos", - "android" - ], - "experiments": [ - { - "name": "DnsHttpssvcStudy", - "params": { - "DnsHttpssvcControlDomainWildcard": "true", - "DnsHttpssvcEnableQueryOverInsecure": "true", - "DnsHttpssvcExperimentDomains": "youtube.com.au", - "DnsHttpssvcExtraTimeMs": "50", - "DnsHttpssvcExtraTimePercent": "20", - "DnsHttpssvcUseHttpssvc": "true", - "DnsHttpssvcUseIntegrity": "true" - }, - "enable_features": [ - "DnsHttpssvc" - ] - } - ] - } - ], "DnsOverHttpsCox": [ { "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 9058f30..3e939f7 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -1543,5 +1543,8 @@ "DisableArrayBufferSizeLimitsForTesting", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kTimedHTMLParserBudget{"TimedHTMLParserBudget", + 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 11d4b4ab7..380fc324 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -791,6 +791,10 @@ BLINK_COMMON_EXPORT extern const base::Feature kDisableArrayBufferSizeLimitsForTesting; +// If enabled, the HTMLDocumentParser will use a budget based on elapsed time +// rather than token count. +BLINK_COMMON_EXPORT extern const base::Feature kTimedHTMLParserBudget; + } // namespace features } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 69b27dca..5438d68 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -5858,28 +5858,32 @@ dom_window_->GetSecurityOrigin()->Port() == 0 ? WebFeature::kDocumentDomainSetWithDefaultPort : WebFeature::kDocumentDomainSetWithNonDefaultPort); - bool was_cross_origin_to_main_frame = - GetFrame()->IsCrossOriginToMainFrame(); + bool was_cross_origin_to_nearest_main_frame = + GetFrame()->IsCrossOriginToNearestMainFrame(); bool was_cross_origin_to_parent_frame = GetFrame()->IsCrossOriginToParentOrOuterDocument(); dom_window_->GetMutableSecurityOrigin()->SetDomainFromDOM(new_domain); - bool is_cross_origin_to_main_frame = GetFrame()->IsCrossOriginToMainFrame(); - if (FrameScheduler* frame_scheduler = GetFrame()->GetFrameScheduler()) - frame_scheduler->SetCrossOriginToMainFrame(is_cross_origin_to_main_frame); - if (View() && - (was_cross_origin_to_main_frame != is_cross_origin_to_main_frame)) { - View()->CrossOriginToMainFrameChanged(); + bool is_cross_origin_to_nearest_main_frame = + GetFrame()->IsCrossOriginToNearestMainFrame(); + if (FrameScheduler* frame_scheduler = GetFrame()->GetFrameScheduler()) { + frame_scheduler->SetCrossOriginToNearestMainFrame( + is_cross_origin_to_nearest_main_frame); + } + if (View() && (was_cross_origin_to_nearest_main_frame != + is_cross_origin_to_nearest_main_frame)) { + View()->CrossOriginToNearestMainFrameChanged(); } if (GetFrame()->IsMainFrame()) { // Notify descendants if their cross-origin-to-main-frame status changed. - // TODO(pdr): This will notify even if |Frame::IsCrossOriginToMainFrame| - // is the same. Track whether each child was cross-origin to main before - // and after changing the domain, and only notify the changed ones. + // TODO(pdr): This will notify even if + // |Frame::IsCrossOriginToNearestMainFrame| is the same. Track whether + // each child was cross-origin to main before and after changing the + // domain, and only notify the changed ones. for (Frame* child = GetFrame()->Tree().FirstChild(); child; child = child->Tree().TraverseNext(GetFrame())) { auto* child_local_frame = DynamicTo<LocalFrame>(child); if (child_local_frame && child_local_frame->View()) - child_local_frame->View()->CrossOriginToMainFrameChanged(); + child_local_frame->View()->CrossOriginToNearestMainFrameChanged(); } }
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc index 9911df233..b31eaf0 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -13,6 +13,7 @@ #include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/http/structured_headers.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/navigation/impression.h" @@ -62,8 +63,67 @@ status); } +void MaybeLogAuditIssue(LocalFrame* frame, + AttributionReportingIssueType issue_type, + const absl::optional<String>& string, + HTMLElement* element, + absl::optional<uint64_t> request_id) { + if (!frame->IsAttached()) + return; + + absl::optional<String> id_string; + if (request_id) + id_string = IdentifiersFactory::SubresourceRequestId(*request_id); + + AuditsIssue::ReportAttributionIssue(frame->DomWindow(), issue_type, + frame->GetDevToolsFrameToken(), element, + id_string, string); +} + } // namespace +bool CanRegisterAttributionInContext( + LocalFrame* frame, + HTMLElement* element, + absl::optional<uint64_t> request_id, + AttributionSrcLoader::RegisterContext context, + bool log_issues) { + LocalDOMWindow* window = frame->DomWindow(); + DCHECK(window); + + if (!RuntimeEnabledFeatures::AttributionReportingEnabled(window)) + return false; + + const bool feature_policy_enabled = window->IsFeatureEnabled( + mojom::blink::PermissionsPolicyFeature::kAttributionReporting); + + if (!feature_policy_enabled) { + if (log_issues) { + MaybeLogAuditIssue( + frame, AttributionReportingIssueType::kPermissionPolicyDisabled, + /*string=*/absl::nullopt, element, request_id); + } + return false; + } + + // The API is only allowed in secure contexts. + if (!window->IsSecureContext()) { + if (log_issues) { + MaybeLogAuditIssue( + frame, + context == AttributionSrcLoader::RegisterContext::kAttributionSrc + ? AttributionReportingIssueType:: + kAttributionSourceUntrustworthyOrigin + : AttributionReportingIssueType::kAttributionUntrustworthyOrigin, + frame->GetSecurityContext()->GetSecurityOrigin()->ToString(), element, + request_id); + } + return false; + } + + return true; +} + class AttributionSrcLoader::ResourceClient : public GarbageCollected<AttributionSrcLoader::ResourceClient>, public RawResourceClient { @@ -112,9 +172,12 @@ return attribution_src_token_; } - private: + // Public, may be called if a response was received prior to the client being + // added to the resource. void HandleResponseHeaders(const ResourceResponse& response, uint64_t request_id); + + private: void HandleSourceRegistration(const ResourceResponse& response, uint64_t request_id); void HandleTriggerRegistration(const ResourceResponse& response); @@ -193,8 +256,8 @@ if (!src_url.ProtocolIsInHTTPFamily()) return nullptr; - if (!CanRegisterAttribution(RegisterContext::kAttributionSrc, src_url, - element, /*request_id=*/absl::nullopt)) { + if (!UrlCanRegisterAttribution(RegisterContext::kAttributionSrc, src_url, + element, /*request_id=*/absl::nullopt)) { return nullptr; } @@ -231,14 +294,14 @@ associated_with_navigation]() -> const char* { switch (src_type) { case SrcType::kSource: - return associated_with_navigation ? "navigation-source" - : "event-source"; + return associated_with_navigation ? kAttributionEligibleNavigationSource + : kAttributionEligibleEventSource; case SrcType::kTrigger: NOTREACHED(); return nullptr; case SrcType::kUndetermined: DCHECK(!associated_with_navigation); - return "event-source, trigger"; + return kAttributionEligibleEventSourceAndTrigger; } }(); @@ -260,7 +323,7 @@ return client; } -bool AttributionSrcLoader::CanRegisterAttribution( +bool AttributionSrcLoader::UrlCanRegisterAttribution( RegisterContext context, const KURL& url, HTMLElement* element, @@ -268,30 +331,11 @@ LocalDOMWindow* window = local_frame_->DomWindow(); DCHECK(window); - if (!RuntimeEnabledFeatures::AttributionReportingEnabled(window)) + if (!CanRegisterAttributionInContext(local_frame_, element, request_id, + context, + /*log_issues=*/true)) return false; - const bool feature_policy_enabled = window->IsFeatureEnabled( - mojom::blink::PermissionsPolicyFeature::kAttributionReporting); - - if (!feature_policy_enabled) { - LogAuditIssue(AttributionReportingIssueType::kPermissionPolicyDisabled, - /*string=*/absl::nullopt, element, request_id); - return false; - } - - // The API is only allowed in secure contexts. - if (!window->IsSecureContext()) { - LogAuditIssue( - context == RegisterContext::kAttributionSrc - ? AttributionReportingIssueType:: - kAttributionSourceUntrustworthyOrigin - : AttributionReportingIssueType::kAttributionUntrustworthyOrigin, - local_frame_->GetSecurityContext()->GetSecurityOrigin()->ToString(), - element, request_id); - return false; - } - scoped_refptr<const SecurityOrigin> reporting_origin = SecurityOrigin::Create(url); if (!reporting_origin->IsPotentiallyTrustworthy()) { @@ -314,43 +358,92 @@ return true; } -void AttributionSrcLoader::MaybeRegisterTrigger( +bool AttributionSrcLoader::MaybeRegisterAttributionHeaders( const ResourceRequest& request, - const ResourceResponse& response) { + const ResourceResponse& response, + const Resource* resource) { + DCHECK(resource); + + if (response.IsNull()) { + return false; + } + + // Attributionsrc requests will be serviced by the + // `AttributionSrcLoader::ResourceClient`. if (request.GetRequestContext() == mojom::blink::RequestContextType::ATTRIBUTION_SRC) { - return; + return false; } + // Only handle requests which are attempting to invoke the API. if (!response.HttpHeaderFields().Contains( + http_names::kAttributionReportingRegisterSource) && + !response.HttpHeaderFields().Contains( http_names::kAttributionReportingRegisterTrigger)) { - return; + return false; } - if (!CanRegisterAttribution(RegisterContext::kResourceTrigger, - response.CurrentRequestUrl(), - /*element=*/nullptr, request.InspectorId())) { - return; + if (!UrlCanRegisterAttribution(RegisterContext::kResource, + response.CurrentRequestUrl(), + /*element=*/nullptr, request.InspectorId())) { + return false; } - mojom::blink::AttributionTriggerDataPtr trigger_data = - attribution_response_parsing::ParseAttributionTriggerData(response); + SrcType src_type = SrcType::kUndetermined; - if (!trigger_data) - return; + // Determine eligibility for this registration by considering first request + // for a resource (even if `response` is for a redirect). This indicates + // whether the redirect chain was configured for eligibility. + // https://github.com/WICG/attribution-reporting-api/blob/main/EVENT.md#registering-attribution-sources + const AtomicString& header_value = + resource->GetResourceRequest().HttpHeaderField( + http_names::kAttributionReportingEligible); - LocalDOMWindow* window = local_frame_->DomWindow(); - DCHECK(window); - Document* document = window->document(); - DCHECK(document); - - if (document->IsPrerendering()) { - document->AddPostPrerenderingActivationStep( - WTF::Bind(&AttributionSrcLoader::RegisterTrigger, - WrapWeakPersistent(this), std::move(trigger_data))); + if (header_value.IsNull()) { + // All subresources are eligible to register triggers if they do *not* + // specify the header. + src_type = SrcType::kTrigger; } else { - RegisterTrigger(std::move(trigger_data)); + absl::optional<net::structured_headers::Dictionary> dict = + net::structured_headers::ParseDictionary( + StringUTF8Adaptor(header_value).AsStringPiece()); + if (!dict) + return false; + + const bool allows_event_source = + dict->contains(kAttributionEligibleEventSource); + const bool allows_navigation_source = + dict->contains(kAttributionEligibleNavigationSource); + const bool allows_trigger = dict->contains(kAttributionEligibleTrigger); + + // TODO(johnidel): Consider logging a devtools issue here for early exits. + if (allows_navigation_source) { + return false; + } else if (allows_event_source && allows_trigger) { + // We use an undetermined SrcType which indicates either a source or + // trigger may be registered. + src_type = SrcType::kUndetermined; + } else if (allows_event_source) { + src_type = SrcType::kSource; + } else if (allows_trigger) { + src_type = SrcType::kTrigger; + } else { + return false; + } } + + // TODO(johnidel): We should consider updating the eligibility header based on + // previously registered requests in the chain. + + // Create a client to mimic processing of attributionsrc requests. Note we do + // not share `AttributionDataHosts` for redirects chains. + // TODO(johnidel): Consider refactoring this such that we can share clients + // for redirect chain, or not create the client at all. + + auto* client = MakeGarbageCollected<ResourceClient>( + this, src_type, /*associated_with_navigation=*/false); + client->HandleResponseHeaders(response, resource->InspectorId()); + return true; } void AttributionSrcLoader::RegisterTrigger( @@ -475,16 +568,7 @@ const absl::optional<String>& string, HTMLElement* element, absl::optional<uint64_t> request_id) { - if (!local_frame_->IsAttached()) - return; - - absl::optional<String> id_string; - if (request_id) - id_string = IdentifiersFactory::SubresourceRequestId(*request_id); - - AuditsIssue::ReportAttributionIssue(local_frame_->DomWindow(), issue_type, - local_frame_->GetDevToolsFrameToken(), - element, id_string, string); + MaybeLogAuditIssue(local_frame_, issue_type, string, element, request_id); } } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.h b/third_party/blink/renderer/core/frame/attribution_src_loader.h index 51158df..a37805c2 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.h +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.h
@@ -22,6 +22,7 @@ class HTMLElement; class KURL; class LocalFrame; +class Resource; class ResourceRequest; class ResourceResponse; @@ -30,6 +31,18 @@ class CORE_EXPORT AttributionSrcLoader : public GarbageCollected<AttributionSrcLoader> { public: + enum class RegisterContext { + kAttributionSrc, + kResource, + }; + + static constexpr const char* kAttributionEligibleEventSource = "event-source"; + static constexpr const char* kAttributionEligibleNavigationSource = + "navigation-source"; + static constexpr const char* kAttributionEligibleTrigger = "trigger"; + static constexpr const char* kAttributionEligibleEventSourceAndTrigger = + "event-source, trigger"; + explicit AttributionSrcLoader(LocalFrame* frame); AttributionSrcLoader(const AttributionSrcLoader&) = delete; AttributionSrcLoader& operator=(const AttributionSrcLoader&) = delete; @@ -42,8 +55,13 @@ // if the frame is not attached. void Register(const KURL& attribution_src, HTMLElement* element); - void MaybeRegisterTrigger(const ResourceRequest& request, - const ResourceResponse& response); + // Registers an attribution resource client for the given resource if + // the request is eligible for attribution registration. Safe to call multiple + // times for the same `resource`. Returns whether a registration was + // successful. + bool MaybeRegisterAttributionHeaders(const ResourceRequest& request, + const ResourceResponse& response, + const Resource* resource); // Registers an attributionsrc which is associated with a top-level // navigation, for example a click on an anchor tag. Returns an Impression @@ -57,15 +75,10 @@ static constexpr size_t kMaxConcurrentRequests = 30; private: - // Represents what events are able to be registered from an attributionsrc. - enum class SrcType { kUndetermined, kSource, kTrigger }; - class ResourceClient; - enum class RegisterContext { - kAttributionSrc, - kResourceTrigger, - }; + // Represents what events are able to be registered from an attributionsrc. + enum class SrcType { kUndetermined, kSource, kTrigger }; ResourceClient* DoRegistration(const KURL& src_url, SrcType src_type, @@ -73,10 +86,10 @@ // Returns whether the attribution is allowed to be registered. Devtool issue // might be reported if it's not allowed. - bool CanRegisterAttribution(RegisterContext context, - const KURL& url, - HTMLElement* element, - absl::optional<uint64_t> request_id); + bool UrlCanRegisterAttribution(RegisterContext context, + const KURL& url, + HTMLElement* element, + absl::optional<uint64_t> request_id); void RegisterTrigger( mojom::blink::AttributionTriggerDataPtr trigger_data) const; @@ -95,6 +108,16 @@ size_t num_resource_clients_ = 0; }; +// Returns whether attribution is allowed, and logs devtools issues if +// registration was attempted in a context is not allowed and `log_issues` is +// set. `element` may be null. +CORE_EXPORT bool CanRegisterAttributionInContext( + LocalFrame* frame, + HTMLElement* element, + absl::optional<uint64_t> request_id, + AttributionSrcLoader::RegisterContext context, + bool log_issues); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_ATTRIBUTION_SRC_LOADER_H_
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc index 5e3dcbf1..b28bb3e 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader_test.cc
@@ -23,10 +23,12 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" +#include "third_party/blink/renderer/core/testing/fake_local_frame_host.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" +#include "third_party/blink/renderer/platform/loader/testing/mock_resource.h" #include "third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" @@ -75,16 +77,35 @@ ~MockDataHost() override = default; + const Vector<mojom::blink::AttributionSourceDataPtr>& source_data() const { + return source_data_; + } + + const Vector<mojom::blink::AttributionTriggerDataPtr>& trigger_data() const { + return trigger_data_; + } + size_t disconnects() const { return disconnects_; } + void Flush() { receiver_.FlushForTesting(); } + private: void OnDisconnect() { disconnects_++; } // mojom::blink::AttributionDataHost: void SourceDataAvailable( - mojom::blink::AttributionSourceDataPtr data) override {} + mojom::blink::AttributionSourceDataPtr data) override { + source_data_.push_back(std::move(data)); + } + void TriggerDataAvailable( - mojom::blink::AttributionTriggerDataPtr data) override {} + mojom::blink::AttributionTriggerDataPtr data) override { + trigger_data_.push_back(std::move(data)); + } + + Vector<mojom::blink::AttributionSourceDataPtr> source_data_; + + Vector<mojom::blink::AttributionTriggerDataPtr> trigger_data_; size_t disconnects_ = 0; mojo::Receiver<mojom::blink::AttributionDataHost> receiver_{this}; @@ -138,6 +159,10 @@ class AttributionSrcLoaderTest : public PageTestBase { public: + AttributionSrcLoaderTest() = default; + + ~AttributionSrcLoaderTest() override = default; + void SetUp() override { client_ = MakeGarbageCollected<AttributionSrcLocalFrameClient>(); PageTestBase::SetupPageWithClients(nullptr, client_); @@ -153,6 +178,11 @@ } void TearDown() override { + GetFrame() + .GetRemoteNavigationAssociatedInterfaces() + ->OverrideBinderForTesting( + mojom::blink::ConversionHost::Name_, + base::BindRepeating([](mojo::ScopedInterfaceEndpointHandle) {})); url_test_helpers::UnregisterAllURLsAndClearMemoryCache(); PageTestBase::TearDown(); } @@ -162,6 +192,120 @@ Persistent<AttributionSrcLoader> attribution_src_loader_; }; +TEST_F(AttributionSrcLoaderTest, RegisterTriggerWithoutEligibleHeader) { + KURL test_url = ToKURL("https://example1.com/foo.html"); + + ResourceRequest request(test_url); + auto* resource = MakeGarbageCollected<MockResource>(test_url); + ResourceResponse response(test_url); + response.SetHttpStatusCode(200); + response.SetHttpHeaderField( + http_names::kAttributionReportingRegisterTrigger, + R"({"event_trigger_data":[{"trigger_data": "7"}]})"); + + MockAttributionHost host( + GetFrame().GetRemoteNavigationAssociatedInterfaces()); + EXPECT_TRUE(attribution_src_loader_->MaybeRegisterAttributionHeaders( + request, response, resource)); + host.WaitUntilBoundAndFlush(); + + auto* mock_data_host = host.mock_data_host(); + ASSERT_TRUE(mock_data_host); + + mock_data_host->Flush(); + EXPECT_EQ(mock_data_host->trigger_data().size(), 1u); +} + +TEST_F(AttributionSrcLoaderTest, RegisterTriggerWithTriggerHeader) { + KURL test_url = ToKURL("https://example1.com/foo.html"); + + ResourceRequest request(test_url); + request.SetHttpHeaderField(http_names::kAttributionReportingEligible, + "trigger"); + auto* resource = MakeGarbageCollected<MockResource>(test_url); + ResourceResponse response(test_url); + response.SetHttpStatusCode(200); + response.SetHttpHeaderField( + http_names::kAttributionReportingRegisterTrigger, + R"({"event_trigger_data":[{"trigger_data": "7"}]})"); + + MockAttributionHost host( + GetFrame().GetRemoteNavigationAssociatedInterfaces()); + attribution_src_loader_->MaybeRegisterAttributionHeaders(request, response, + resource); + host.WaitUntilBoundAndFlush(); + + auto* mock_data_host = host.mock_data_host(); + ASSERT_TRUE(mock_data_host); + + mock_data_host->Flush(); + EXPECT_EQ(mock_data_host->trigger_data().size(), 1u); +} + +TEST_F(AttributionSrcLoaderTest, RegisterTriggerWithSourceTriggerHeader) { + KURL test_url = ToKURL("https://example1.com/foo.html"); + + ResourceRequest request(test_url); + request.SetHttpHeaderField(http_names::kAttributionReportingEligible, + "event-source, trigger"); + auto* resource = MakeGarbageCollected<MockResource>(test_url); + ResourceResponse response(test_url); + response.SetHttpStatusCode(200); + response.SetHttpHeaderField( + http_names::kAttributionReportingRegisterTrigger, + R"({"event_trigger_data":[{"trigger_data": "7"}]})"); + + MockAttributionHost host( + GetFrame().GetRemoteNavigationAssociatedInterfaces()); + attribution_src_loader_->MaybeRegisterAttributionHeaders(request, response, + resource); + host.WaitUntilBoundAndFlush(); + + auto* mock_data_host = host.mock_data_host(); + ASSERT_TRUE(mock_data_host); + + mock_data_host->Flush(); + EXPECT_EQ(mock_data_host->trigger_data().size(), 1u); +} + +TEST_F(AttributionSrcLoaderTest, AttributionSrcRequestsIgnored) { + KURL test_url = ToKURL("https://example1.com/foo.html"); + ResourceRequest request(test_url); + request.SetRequestContext(mojom::blink::RequestContextType::ATTRIBUTION_SRC); + + auto* resource = MakeGarbageCollected<MockResource>(test_url); + ResourceResponse response(test_url); + response.SetHttpStatusCode(200); + response.SetHttpHeaderField( + http_names::kAttributionReportingRegisterTrigger, + R"({"event_trigger_data":[{"trigger_data": "7"}]})"); + + EXPECT_FALSE(attribution_src_loader_->MaybeRegisterAttributionHeaders( + request, response, resource)); +} + +TEST_F(AttributionSrcLoaderTest, AttributionSrcRequestsInvalidEligibleHeaders) { + KURL test_url = ToKURL("https://example1.com/foo.html"); + ResourceRequest request(test_url); + request.SetRequestContext(mojom::blink::RequestContextType::ATTRIBUTION_SRC); + + auto* resource = MakeGarbageCollected<MockResource>(test_url); + ResourceResponse response(test_url); + response.SetHttpStatusCode(200); + + const char* header_values[] = {"navigation-source, event-source, trigger", + "!!!", ""}; + + for (const char* header : header_values) { + response.SetHttpHeaderField( + http_names::kAttributionReportingRegisterTrigger, header); + + EXPECT_FALSE(attribution_src_loader_->MaybeRegisterAttributionHeaders( + request, response, resource)) + << header; + } +} + TEST_F(AttributionSrcLoaderTest, AttributionSrcRequestStatusHistogram) { base::HistogramTester histograms;
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc index c2a2b41..2b490c6 100644 --- a/third_party/blink/renderer/core/frame/dom_window.cc +++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -589,7 +589,7 @@ return; // See https://crbug.com/1183571 - // We assumed accessing_frame->IsCrossOriginToMainFrame() implies + // We assumed accessing_frame->IsCrossOriginToNearestMainFrame() implies // accessing_frame->Tree().Top() to be a LocalFrame. This might not be the // case after all, some crashes are reported. This block speculatively returns // early to avoid crashing.
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index 7599354..80f4314d 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -199,7 +199,7 @@ return IsMainFrame() && !IsInFencedFrameTree(); } -bool Frame::IsCrossOriginToMainFrame() const { +bool Frame::IsCrossOriginToNearestMainFrame() const { DCHECK(GetSecurityContext()); const SecurityOrigin* security_origin = GetSecurityContext()->GetSecurityOrigin(); @@ -208,7 +208,7 @@ } bool Frame::IsCrossOriginToOutermostMainFrame() const { - return IsCrossOriginToMainFrame() || IsInFencedFrameTree(); + return IsCrossOriginToNearestMainFrame() || IsInFencedFrameTree(); } bool Frame::IsCrossOriginToParentOrOuterDocument() const {
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index 70dbaf12..c2e4d9a 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h
@@ -160,23 +160,20 @@ // returns true when the frame is detached. // TODO(dcheng): Move this to LocalDOMWindow and figure out the right // behavior for detached windows. - // TODO(crbug.com/1318055): this function should be renamed - // IsCrossOriginToNearestMainFrame and most current usages should be - // conrverted to IsCrossOriginToOutermostMainFrame. - bool IsCrossOriginToMainFrame() const; + bool IsCrossOriginToNearestMainFrame() const; // Returns true if and only if: // - this frame is an embedded frame (i.e., a subframe or embedded main frame) // - it is cross-origin to the outermost main frame. // - // The notes for |IsCrossOriginToMainFrame| apply here, but it's also + // The notes for |IsCrossOriginToNearestMainFrame| apply here, but it's also // important to note that any frame in a fenced frame tree is considered // cross-origin with respect to the outermost main frame. bool IsCrossOriginToOutermostMainFrame() const; // Returns true if this frame is a subframe and is cross-origin to the parent // frame or has an outer document in another frame tree. - // See |IsCrossOriginToMainFrame| for important notes. + // See |IsCrossOriginToNearestMainFrame| for important notes. bool IsCrossOriginToParentOrOuterDocument() const; FrameOwner* Owner() const;
diff --git a/third_party/blink/renderer/core/frame/frame_view.cc b/third_party/blink/renderer/core/frame/frame_view.cc index 8fc0628d..5e8f4bb 100644 --- a/third_party/blink/renderer/core/frame/frame_view.cc +++ b/third_party/blink/renderer/core/frame/frame_view.cc
@@ -34,7 +34,7 @@ if (CanThrottleRendering()) return true; Frame& frame = GetFrame(); - if (!frame.IsCrossOriginToMainFrame()) + if (!frame.IsCrossOriginToNearestMainFrame()) return false; if (frame.IsLocalFrame() && To<LocalFrame>(frame).IsHidden()) return true;
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index bb00559a..fd6118f 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -724,8 +724,8 @@ auto* frame_scheduler = GetFrame()->GetFrameScheduler(); frame_scheduler->TraceUrlChange(document_->Url().GetString()); - frame_scheduler->SetCrossOriginToMainFrame( - GetFrame()->IsCrossOriginToMainFrame()); + frame_scheduler->SetCrossOriginToNearestMainFrame( + GetFrame()->IsCrossOriginToNearestMainFrame()); GetFrame()->GetPage()->GetChromeClient().InstallSupplements(*GetFrame());
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 a8a1f6f..9efba1c 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -4354,7 +4354,7 @@ }); } -void LocalFrameView::CrossOriginToMainFrameChanged() { +void LocalFrameView::CrossOriginToNearestMainFrameChanged() { // If any of these conditions hold, then a change in cross-origin status does // not affect throttling. if (lifecycle_updates_throttled_ || IsSubtreeThrottled() || @@ -4554,7 +4554,7 @@ // cross-origin frames must already communicate with asynchronous messages, // so they should be able to tolerate some delay in receiving replies from a // throttled peer. - return IsHiddenForThrottling() && frame_->IsCrossOriginToMainFrame(); + return IsHiddenForThrottling() && frame_->IsCrossOriginToNearestMainFrame(); } void LocalFrameView::UpdateRenderThrottlingStatus(bool hidden_for_throttling,
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 cbc3650..ae4dcfc 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -710,7 +710,7 @@ void MapLocalToRemoteMainFrame(TransformState&); - void CrossOriginToMainFrameChanged(); + void CrossOriginToNearestMainFrameChanged(); void CrossOriginToParentFrameChanged(); void SetVisualViewportOrOverlayNeedsRepaint();
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 d8e1086..1157892 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -6555,9 +6555,14 @@ blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck( v8::Isolate::GetCurrent(), expected_result.Get(context, 0).ToLocalChecked()); - ASSERT_TRUE(layer_owner_node_for_start); - int start_layer_id = LayerIdFromNode(layer_tree_host->root_layer(), - layer_owner_node_for_start); + // Hidden selection does not always have a layer (might be hidden due to not + // having been painted. + ASSERT_TRUE(layer_owner_node_for_start || selection.start.hidden); + int start_layer_id = 0; + if (layer_owner_node_for_start) { + start_layer_id = LayerIdFromNode(layer_tree_host->root_layer(), + layer_owner_node_for_start); + } if (selection_is_caret) { // The selection data are recorded on the caret layer which is the next // layer for the current test cases. @@ -6579,9 +6584,15 @@ blink::Node* layer_owner_node_for_end = V8Node::ToImplWithTypeCheck( v8::Isolate::GetCurrent(), expected_result.Get(context, 5).ToLocalChecked()); - ASSERT_TRUE(layer_owner_node_for_end); - int end_layer_id = LayerIdFromNode(layer_tree_host->root_layer(), - layer_owner_node_for_end); + // Hidden selection does not always have a layer (might be hidden due to not + // having been painted. + ASSERT_TRUE(layer_owner_node_for_end || selection.end.hidden); + int end_layer_id = 0; + if (layer_owner_node_for_end) { + end_layer_id = LayerIdFromNode(layer_tree_host->root_layer(), + layer_owner_node_for_end); + } + if (selection_is_caret) { // The selection data are recorded on the caret layer which is the next // layer for the current test cases. @@ -6716,6 +6727,12 @@ TEST_F(CompositedSelectionBoundsTest, SVGTextWithFragments) { RunTest("composited_selection_bounds_svg_text_with_fragments.html"); } +TEST_F(CompositedSelectionBoundsTest, LargeSelectionScroll) { + RunTest("composited_selection_bounds_large_selection_scroll.html"); +} +TEST_F(CompositedSelectionBoundsTest, LargeSelectionNoScroll) { + RunTest("composited_selection_bounds_large_selection_noscroll.html"); +} #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #if !BUILDFLAG(IS_ANDROID) TEST_F(CompositedSelectionBoundsTest, Input) {
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc index 34a809f0..2116006 100644 --- a/third_party/blink/renderer/core/html/html_image_element.cc +++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -368,7 +368,7 @@ const AtomicString& attribution_src_value = FastGetAttribute(html_names::kAttributionsrcAttr); LocalDOMWindow* window = GetDocument().domWindow(); - if (!attribution_src_value.IsNull() && window && window->GetFrame()) { + if (!attribution_src_value.IsEmpty() && window && window->GetFrame()) { window->GetFrame()->GetAttributionSrcLoader()->Register( GetDocument().CompleteURL(attribution_src_value), this); }
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc index 4497f7f..fe081d2d 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -82,6 +82,7 @@ // the final page. This is the default value to use, if no Finch-provided // value exists. constexpr int kDefaultMaxTokenizationBudget = 250; +constexpr int kNumYieldsWithDefaultBudget = 2; class EndIfDelayedForbiddenScope; class ShouldCompleteScope; @@ -139,6 +140,36 @@ document->GetSettings()->GetDoHtmlPreloadScanning(); } +base::TimeDelta GetDefaultTimedBudget() { + static const base::FeatureParam<base::TimeDelta> kDefaultParserBudgetParam{ + &features::kTimedHTMLParserBudget, "default-parser-budget", + base::Milliseconds(10)}; + // Cache the value to avoid parsing the param string more than once. + static const base::TimeDelta kDefaultParserBudgetValue = + kDefaultParserBudgetParam.Get(); + return kDefaultParserBudgetValue; +} + +base::TimeDelta GetTimedBudget(int times_yielded) { + static const base::FeatureParam<int> kNumYieldsWithDefaultBudgetParam{ + &features::kTimedHTMLParserBudget, "num-yields-with-default-budget", + kNumYieldsWithDefaultBudget}; + // Cache the value to avoid parsing the param string more than once. + static const int kNumYieldsWithDefaultBudgetValue = + kNumYieldsWithDefaultBudgetParam.Get(); + + static const base::FeatureParam<base::TimeDelta> kLongParserBudgetParam{ + &features::kTimedHTMLParserBudget, "long-parser-budget", + base::Milliseconds(500)}; + // Cache the value to avoid parsing the param string more than once. + static const base::TimeDelta kLongParserBudgetValue = + kLongParserBudgetParam.Get(); + + if (times_yielded <= kNumYieldsWithDefaultBudgetValue) + return GetDefaultTimedBudget(); + return kLongParserBudgetValue; +} + // This class encapsulates the internal state needed for synchronous foreground // HTML parsing (e.g. if HTMLDocumentParser::PumpTokenizer yields, this class // tracks what should be done after the pump completes.) @@ -737,9 +768,14 @@ // number, to attempt to consume all available tokens in one go. This // heuristic is intended to allow a quick first contentful paint, followed by // a larger rendering lifecycle that processes the remainder of the page. - int budget = (task_runner_state_->TimesYielded() <= 2) - ? kDefaultMaxTokenizationBudget - : 1e7; + int budget = + (task_runner_state_->TimesYielded() <= kNumYieldsWithDefaultBudget) + ? kDefaultMaxTokenizationBudget + : 1e7; + + base::TimeDelta timed_budget; + if (timed_parser_budget_enabled_) + timed_budget = GetTimedBudget(task_runner_state_->TimesYielded()); base::ElapsedTimer chunk_parsing_timer_; unsigned tokens_parsed = 0; @@ -757,6 +793,10 @@ // to yield at some point soon, especially if we're in "extended budget" // mode. So reduce the budget back to at most the default. budget = std::min(budget, kDefaultMaxTokenizationBudget); + if (timed_parser_budget_enabled_) { + timed_budget = std::min(timed_budget, chunk_parsing_timer_.Elapsed() + + GetDefaultTimedBudget()); + } } { RUNTIME_CALL_TIMER_SCOPE( @@ -774,7 +814,10 @@ DCHECK(base::FeatureList::IsEnabled( features::kDeferBeginMainFrameDuringLoading) || scheduler_->DontDeferBeginMainFrame()); - should_yield = budget <= 0 && scheduler_->DontDeferBeginMainFrame(); + if (timed_parser_budget_enabled_) + should_yield = chunk_parsing_timer_.Elapsed() >= timed_budget; + else + should_yield = budget <= 0 && scheduler_->DontDeferBeginMainFrame(); should_yield |= scheduler_->ShouldYieldForHighPriorityWork(); should_yield &= task_runner_state_->HaveExitedHeader();
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.h b/third_party/blink/renderer/core/html/parser/html_document_parser.h index 8a5c182..e1cf872 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser.h +++ b/third_party/blink/renderer/core/html/parser/html_document_parser.h
@@ -246,6 +246,9 @@ Vector<std::unique_ptr<PendingPreloadData>> pending_preload_data_ GUARDED_BY(pending_preload_lock_); + const bool timed_parser_budget_enabled_ = + base::FeatureList::IsEnabled(features::kTimedHTMLParserBudget); + ThreadScheduler* scheduler_; };
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc index c5da5dc..73d752a9b 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc
@@ -373,6 +373,16 @@ } } +void GridItems::ReserveInitialCapacity(wtf_size_t initial_capacity) { + reordered_item_indices.ReserveInitialCapacity(initial_capacity); + item_data.ReserveInitialCapacity(initial_capacity); +} + +void GridItems::ReserveCapacity(wtf_size_t new_capacity) { + reordered_item_indices.ReserveCapacity(new_capacity); + item_data.ReserveCapacity(new_capacity); +} + void GridItems::RemoveSubgriddedItems() { wtf_size_t new_item_count = 0; for (const auto& grid_item : item_data) {
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h index 3ef5f72..4bfffc4 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
@@ -194,12 +194,14 @@ OutOfFlowItemPlacement row_placement; }; -using GridItemStorageVector = HeapVector<GridItemData, 4>; +using GridItemDataVector = Vector<GridItemData*, 16>; struct CORE_EXPORT GridItems { DISALLOW_NEW(); public: + using GridItemStorageVector = HeapVector<GridItemData, 16>; + class Iterator : public std::iterator<std::input_iterator_tag, GridItemData> { STACK_ALLOCATED(); @@ -241,11 +243,9 @@ reordered_item_indices.push_back(item_data.size()); item_data.emplace_back(new_item_data); } - void ReserveCapacity(const wtf_size_t capacity) { - reordered_item_indices.ReserveCapacity(capacity); - item_data.ReserveCapacity(capacity); - } + void ReserveInitialCapacity(wtf_size_t initial_capacity); + void ReserveCapacity(wtf_size_t new_capacity); void RemoveSubgriddedItems(); wtf_size_t Size() const { return item_data.size(); }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index c53f432..598d0f6 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -151,7 +151,7 @@ grid_item.SetTrackSpanProperty(property, track_direction); }; - Vector<GridItemData*, 16> grid_items_spanning_multiple_ranges; + GridItemDataVector grid_items_spanning_multiple_ranges; for (auto& grid_item : grid_items->item_data) { const auto& range_indices = grid_item.RangeIndices(track_direction); @@ -2002,25 +2002,26 @@ // potential must be able to increase its size by the same amount. if (growable_track_count || IsDistributionForGrowthLimits(contribution_type)) { - auto CompareSetsByGrowthPotential = [contribution_type](NGGridSet* a, - NGGridSet* b) { - LayoutUnit growth_potential_a = GrowthPotentialForSet( - *a, contribution_type, InfinitelyGrowableBehavior::kIgnore); - LayoutUnit growth_potential_b = GrowthPotentialForSet( - *b, contribution_type, InfinitelyGrowableBehavior::kIgnore); + auto CompareSetsByGrowthPotential = + [contribution_type](const NGGridSet* lhs, const NGGridSet* rhs) { + auto growth_potential_lhs = GrowthPotentialForSet( + *lhs, contribution_type, InfinitelyGrowableBehavior::kIgnore); + auto growth_potential_rhs = GrowthPotentialForSet( + *rhs, contribution_type, InfinitelyGrowableBehavior::kIgnore); - if (growth_potential_a == kIndefiniteSize || - growth_potential_b == kIndefiniteSize) { - // At this point we know that there is at least one set with infinite - // growth potential; if |a| has a definite value, then |b| must have - // infinite growth potential, and thus, |a| < |b|. - return growth_potential_a != kIndefiniteSize; - } - // Straightforward comparison of definite growth potentials. - return growth_potential_a < growth_potential_b; - }; - // If we only have flex growth potential, there's no need to sort because - // flex growth potentials are infinite. + if (growth_potential_lhs == kIndefiniteSize || + growth_potential_rhs == kIndefiniteSize) { + // At this point we know that there is at least one set with + // infinite growth potential; if |a| has a definite value, then |b| + // must have infinite growth potential, and thus, |a| < |b|. + return growth_potential_lhs != kIndefiniteSize; + } + // Straightforward comparison of definite growth potentials. + return growth_potential_lhs < growth_potential_rhs; + }; + + // Only sort for equal distributions; since the growth potential of any + // flexible set is infinite, they don't require comparing. if (AreEqual<double>(flex_factor_sum, 0)) { DCHECK(is_equal_distribution); std::sort(sets_to_grow->begin(), sets_to_grow->end(), @@ -2190,8 +2191,8 @@ } // namespace void NGGridLayoutAlgorithm::IncreaseTrackSizesToAccommodateGridItems( - GridItems::Iterator group_begin, - GridItems::Iterator group_end, + GridItemDataVector::iterator group_begin, + GridItemDataVector::iterator group_end, const NGGridLayoutData& layout_data, const bool is_group_spanning_flex_track, const SizingConstraint sizing_constraint, @@ -2207,27 +2208,22 @@ GridSetVector sets_to_grow; GridSetVector sets_to_grow_beyond_limit; - for (auto it = group_begin; it != group_end; ++it) { - GridItemData& grid_item = *it; + for (auto** it = group_begin; it != group_end; ++it) { + GridItemData& grid_item = **it; - // When the grid items of this group are not spanning a flexible track, we - // can skip the current item if it doesn't span an intrinsic track. - if (!grid_item.IsSpanningIntrinsicTrack(track_direction) && - !is_group_spanning_flex_track) { - continue; - } + DCHECK(grid_item.IsSpanningIntrinsicTrack(track_direction)); sets_to_grow.Shrink(0); sets_to_grow_beyond_limit.Shrink(0); + ClampedDouble flex_factor_sum = 0; LayoutUnit spanned_tracks_size = track_collection->GutterSize() * (grid_item.SpanSize(track_direction) - 1); - - ClampedDouble flex_factor_sum = 0; for (auto set_iterator = GetSetIteratorForItem(grid_item, *track_collection); !set_iterator.IsAtEnd(); set_iterator.MoveToNextSet()) { auto& current_set = set_iterator.CurrentSet(); + spanned_tracks_size += AffectedSizeForContribution(current_set, contribution_type); @@ -2312,6 +2308,14 @@ DCHECK(track_collection && grid_items); const auto track_direction = track_collection->Direction(); + GridItemDataVector reordered_grid_items; + reordered_grid_items.ReserveInitialCapacity(grid_items->Size()); + + for (auto& grid_item : grid_items->item_data) { + if (grid_item.IsSpanningIntrinsicTrack(track_direction)) + reordered_grid_items.push_back(&grid_item); + } + // Reorder grid items to process them as follows: // - First, consider items spanning a single non-flexible track. // - Next, consider items with span size of 2 not spanning a flexible track. @@ -2319,35 +2323,34 @@ // not spanning a flexible track have been considered. // - Finally, consider all items spanning a flexible track. auto CompareGridItemsForIntrinsicTrackResolution = - [grid_items, track_direction](wtf_size_t a, wtf_size_t b) -> bool { - if (grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction) || - grid_items->item_data[b].IsSpanningFlexibleTrack(track_direction)) { + [track_direction](const GridItemData* lhs, + const GridItemData* rhs) -> bool { + if (lhs->IsSpanningFlexibleTrack(track_direction) || + rhs->IsSpanningFlexibleTrack(track_direction)) { // Ignore span sizes if one of the items spans a track with a flexible // sizing function; items not spanning such tracks should come first. - return !grid_items->item_data[a].IsSpanningFlexibleTrack(track_direction); + return !lhs->IsSpanningFlexibleTrack(track_direction); } - return grid_items->item_data[a].SpanSize(track_direction) < - grid_items->item_data[b].SpanSize(track_direction); + return lhs->SpanSize(track_direction) < rhs->SpanSize(track_direction); }; - std::sort(grid_items->reordered_item_indices.begin(), - grid_items->reordered_item_indices.end(), + std::sort(reordered_grid_items.begin(), reordered_grid_items.end(), CompareGridItemsForIntrinsicTrackResolution); // First, process the items that don't span a flexible track. - auto current_group_begin = grid_items->begin(); - while (current_group_begin != grid_items->end() && - !current_group_begin->IsSpanningFlexibleTrack(track_direction)) { + auto** current_group_begin = reordered_grid_items.begin(); + while (current_group_begin != reordered_grid_items.end() && + !(*current_group_begin)->IsSpanningFlexibleTrack(track_direction)) { // Each iteration considers all items with the same span size. wtf_size_t current_group_span_size = - current_group_begin->SpanSize(track_direction); + (*current_group_begin)->SpanSize(track_direction); - auto current_group_end = current_group_begin; + auto** current_group_end = current_group_begin; do { - DCHECK(!current_group_end->IsSpanningFlexibleTrack(track_direction)); + DCHECK(!(*current_group_end)->IsSpanningFlexibleTrack(track_direction)); ++current_group_end; - } while (current_group_end != grid_items->end() && - !current_group_end->IsSpanningFlexibleTrack(track_direction) && - current_group_end->SpanSize(track_direction) == + } while (current_group_end != reordered_grid_items.end() && + !(*current_group_end)->IsSpanningFlexibleTrack(track_direction) && + (*current_group_end)->SpanSize(track_direction) == current_group_span_size); IncreaseTrackSizesToAccommodateGridItems( @@ -2382,24 +2385,24 @@ // sizing function... #if DCHECK_IS_ON() // Every grid item of the remaining group should span a flexible track. - for (auto it = current_group_begin; it != grid_items->end(); ++it) - DCHECK(it->IsSpanningFlexibleTrack(track_direction)); + for (auto** it = current_group_begin; it != reordered_grid_items.end(); ++it) + DCHECK((*it)->IsSpanningFlexibleTrack(track_direction)); #endif // Now, process items spanning flexible tracks (if any). - if (current_group_begin != grid_items->end()) { + if (current_group_begin != reordered_grid_items.end()) { // We can safely skip contributions for maximums since a <flex> definition // does not have an intrinsic max track sizing function. IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, grid_items->end(), layout_data, + current_group_begin, reordered_grid_items.end(), layout_data, /* is_group_spanning_flex_track */ true, sizing_constraint, GridItemContributionType::kForIntrinsicMinimums, track_collection); IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, grid_items->end(), layout_data, + current_group_begin, reordered_grid_items.end(), layout_data, /* is_group_spanning_flex_track */ true, sizing_constraint, GridItemContributionType::kForContentBasedMinimums, track_collection); IncreaseTrackSizesToAccommodateGridItems( - current_group_begin, grid_items->end(), layout_data, + current_group_begin, reordered_grid_items.end(), layout_data, /* is_group_spanning_flex_track */ true, sizing_constraint, GridItemContributionType::kForMaxContentMinimums, track_collection); } @@ -2564,20 +2567,20 @@ // Otherwise, determine which sets should be treated as inflexible, exclude // them from the leftover space and flex factor sum computation, and keep // checking the condition for sets with lesser ratios. - auto CompareSetsByBaseSizeFlexFactorRatio = [](NGGridSet* a, - NGGridSet* b) -> bool { + auto CompareSetsByBaseSizeFlexFactorRatio = [](NGGridSet* lhs, + NGGridSet* rhs) -> bool { // Avoid divisions by reordering the terms of the comparison. - return a->BaseSize().RawValue() * b->FlexFactor() > - b->BaseSize().RawValue() * a->FlexFactor(); + return lhs->BaseSize().RawValue() * rhs->FlexFactor() > + rhs->BaseSize().RawValue() * lhs->FlexFactor(); }; std::sort(flexible_sets.begin(), flexible_sets.end(), CompareSetsByBaseSizeFlexFactorRatio); - GridSetVector::iterator current_set = flexible_sets.begin(); + auto** current_set = flexible_sets.begin(); while (leftover_space > 0 && current_set != flexible_sets.end()) { flex_factor_sum = base::ClampMax(flex_factor_sum, 1); - GridSetVector::iterator next_set = current_set; + auto** next_set = current_set; while (next_set != flexible_sets.end() && (*next_set)->FlexFactor() * leftover_space.RawValue() < (*next_set)->BaseSize().RawValue() * flex_factor_sum) { @@ -2594,7 +2597,7 @@ // Otherwise, treat all those sets that does not receive a share of free // space of at least their base size as inflexible, effectively excluding // them from the leftover space and flex factor sum computation. - for (GridSetVector::iterator it = current_set; it != next_set; ++it) { + for (auto** it = current_set; it != next_set; ++it) { flex_factor_sum -= (*it)->FlexFactor(); leftover_space -= (*it)->BaseSize(); }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h index 109241f..dcbaa1e0 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -127,8 +127,8 @@ GridItems* grid_items) const; void IncreaseTrackSizesToAccommodateGridItems( - GridItems::Iterator group_begin, - GridItems::Iterator group_end, + GridItemDataVector::iterator group_begin, + GridItemDataVector::iterator group_end, const NGGridLayoutData& layout_data, const bool is_group_spanning_flex_track, const SizingConstraint sizing_constraint,
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc index b695ac8..96041df 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc
@@ -27,7 +27,7 @@ // Even if the cached placement data is incorrect, as long as the grid is // not marked as dirty, the grid item count should be the same. - grid_items.ReserveCapacity( + grid_items.ReserveInitialCapacity( cached_placement_data->grid_item_positions.size()); if (placement_data->column_auto_repetitions != @@ -109,7 +109,7 @@ if (!has_standalone_columns && !has_standalone_rows) return grid_items; - for (auto& grid_item : grid_items) { + for (auto& grid_item : grid_items.item_data) { grid_item.can_subgrid_items_in_column_direction = has_standalone_columns; grid_item.can_subgrid_items_in_row_direction = has_standalone_rows; } @@ -172,6 +172,7 @@ // described in https://drafts.csswg.org/css-grid-2/#auto-repeat. auto subgridded_items = subgrid.ConstructGridItems(&subgrid_placement_data); + grid_items.ReserveCapacity(grid_items.Size() + subgridded_items.Size()); const wtf_size_t column_start_line = current_item.StartLine(kForColumns); const wtf_size_t row_start_line = current_item.StartLine(kForRows);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h index 6190b31..d84adb4 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -38,8 +38,7 @@ adjust_inline_size_if_needed) { if (parent_space.ShouldPropagateChildBreakValues()) SetShouldPropagateChildBreakValues(); - if (parent_space.IsRepeatable()) - SetIsRepeatable(); + SetIsRepeatable(parent_space.IsRepeatable()); } // The setters on this builder are in the writing mode of parent_writing_mode. @@ -149,7 +148,9 @@ space_.EnsureRareData()->is_at_fragmentainer_start = true; } - void SetIsRepeatable() { space_.EnsureRareData()->is_repeatable = true; } + void SetIsRepeatable(bool is_repeatable) { + space_.EnsureRareData()->is_repeatable = is_repeatable; + } void SetIsFixedInlineSize(bool b) { if (LIKELY(is_in_parallel_flow_))
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.cc index e2ee2c3..97be41d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.cc
@@ -16,29 +16,6 @@ namespace { -const NGLayoutResult* GetClonableLayoutResult( - const LayoutBox& layout_box, - const NGPhysicalBoxFragment& fragment) { - if (const NGBlockBreakToken* break_token = fragment.BreakToken()) { - if (!break_token->IsRepeated()) - return layout_box.GetLayoutResult(break_token->SequenceNumber()); - } - // Cloned results may already have been added (so we can't just pick the last - // one), but the break tokens have not yet been updated. Look for the first - // result without a break token (or with a repeated break token, in case we've - // already been through this). This will actually be the very first result, - // unless there's a fragmentation context established inside the repeated - // root. - for (const NGLayoutResult* result : layout_box.GetLayoutResults()) { - const NGBlockBreakToken* break_token = - To<NGPhysicalBoxFragment>(result->PhysicalFragment()).BreakToken(); - if (!break_token || break_token->IsRepeated()) - return result; - } - NOTREACHED(); - return nullptr; -} - // Remove all cloned results, but keep the first original one(s). void RemoveClonedResults(LayoutBox& layout_box) { for (wtf_size_t idx = 0; idx < layout_box.PhysicalFragmentCount(); idx++) { @@ -149,7 +126,10 @@ child.fragment = &child_result->PhysicalFragment(); } else if (child_box->IsFragmentainerBox()) { child_box = NGPhysicalBoxFragment::Clone(*child_box); - CloneChildFragments(*child_box); + NGFragmentRepeater child_repeater( + is_first_clone_, is_last_fragment_, + /* is_inside_nested_fragmentainer */ true); + child_repeater.CloneChildFragments(*child_box); child.fragment = child_box; } } else if (child->IsLineBox()) { @@ -214,4 +194,29 @@ return cloned_result; } +const NGLayoutResult* NGFragmentRepeater::GetClonableLayoutResult( + const LayoutBox& layout_box, + const NGPhysicalBoxFragment& fragment) const { + if (const NGBlockBreakToken* break_token = fragment.BreakToken()) { + if (!break_token->IsRepeated()) + return layout_box.GetLayoutResult(break_token->SequenceNumber()); + } + // Cloned results may already have been added (so we can't just pick the last + // one), but the break tokens have not yet been updated. Look for the first + // result without a break token. Or look for the first result with a repeated + // break token (unless the repeated break token is the result of an inner + // fragmentation context), in case we've already been through this. This will + // actually be the very first result, unless there's a fragmentation context + // established inside the repeated root. + for (const NGLayoutResult* result : layout_box.GetLayoutResults()) { + const NGBlockBreakToken* break_token = + To<NGPhysicalBoxFragment>(result->PhysicalFragment()).BreakToken(); + if (!break_token || + (break_token->IsRepeated() && !is_inside_nested_fragmentainer_)) + return result; + } + NOTREACHED(); + return nullptr; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.h index 2a5f471..f9a0452f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_repeater.h
@@ -9,6 +9,7 @@ namespace blink { +class LayoutBox; class NGLayoutResult; class NGPhysicalBoxFragment; @@ -25,8 +26,12 @@ STACK_ALLOCATED(); public: - explicit NGFragmentRepeater(bool is_first_clone, bool is_last_fragment) - : is_first_clone_(is_first_clone), is_last_fragment_(is_last_fragment) {} + explicit NGFragmentRepeater(bool is_first_clone, + bool is_last_fragment, + bool is_inside_nested_fragmentainer = false) + : is_first_clone_(is_first_clone), + is_last_fragment_(is_last_fragment), + is_inside_nested_fragmentainer_(is_inside_nested_fragmentainer) {} // Deep-clone the subtree of an already shallowly cloned fragment. This will // also create new break tokens inside, in order to set unique sequence @@ -37,12 +42,20 @@ private: const NGLayoutResult* Repeat(const NGLayoutResult& other); + const NGLayoutResult* GetClonableLayoutResult( + const LayoutBox& layout_box, + const NGPhysicalBoxFragment& fragment) const; + // True when at the first cloned fragment. bool is_first_clone_; // True when at the last container fragment. No outgoing "repeat" break tokens // should be created then. bool is_last_fragment_; + + // True when we are cloning a subset of the tree in which an inner + // fragmentainer was found. + bool is_inside_nested_fragmentainer_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc index 9de9193..4be9128e 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -952,8 +952,7 @@ section_index); if (repeat_mode != kNotRepeated) { - if (repeat_mode == kMayRepeatAgain) - section_space_builder.SetIsRepeatable(); + section_space_builder.SetIsRepeatable(repeat_mode == kMayRepeatAgain); } else if (ConstraintSpace().HasBlockFragmentation()) { SetupSpaceBuilderForFragmentation( ConstraintSpace(), section, block_offset, §ion_space_builder,
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc index be938db..fa16c4e 100644 --- a/third_party/blink/renderer/core/loader/image_loader.cc +++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -38,6 +38,7 @@ #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/increment_load_event_delay_count.h" +#include "third_party/blink/renderer/core/frame/attribution_src_loader.h" #include "third_party/blink/renderer/core/frame/frame_owner.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" @@ -497,6 +498,20 @@ network::mojom::RequestDestination::kEmbed); } + DCHECK(document.GetFrame()); + auto* frame = document.GetFrame(); + + if (IsA<HTMLImageElement>(GetElement()) && + GetElement()->FastHasAttribute(html_names::kAttributionsrcAttr) && + CanRegisterAttributionInContext( + frame, To<HTMLImageElement>(GetElement()), absl::nullopt, + AttributionSrcLoader::RegisterContext::kResource, + /*log_issues=*/false)) { + resource_request.SetHttpHeaderField( + http_names::kAttributionReportingEligible, + AttributionSrcLoader::kAttributionEligibleEventSourceAndTrigger); + } + bool page_is_being_dismissed = document.PageDismissalEventBeingDispatched() != Document::kNoDismissal; if (page_is_being_dismissed) { @@ -517,9 +532,6 @@ resource_request.SetSkipServiceWorker(true); } - DCHECK(document.GetFrame()); - auto* frame = document.GetFrame(); - FetchParameters params(std::move(resource_request), resource_loader_options); ConfigureRequest(params, *element_, frame->GetClientHintsPreferences());
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc index c7d6ed6f..ed1d4081 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
@@ -144,7 +144,8 @@ const ResourceResponse& redirect_response, ResourceType resource_type, const ResourceLoaderOptions& options, - RenderBlockingBehavior render_blocking_behavior) { + RenderBlockingBehavior render_blocking_behavior, + const Resource* resource) { LocalFrame* frame = document_->GetFrame(); DCHECK(frame); if (redirect_response.IsNull()) { @@ -154,8 +155,8 @@ request.Priority()); } - frame->GetAttributionSrcLoader()->MaybeRegisterTrigger(request, - redirect_response); + frame->GetAttributionSrcLoader()->MaybeRegisterAttributionHeaders( + request, redirect_response, resource); probe::WillSendRequest( GetProbe(), document_loader_, @@ -307,7 +308,8 @@ resource->GetResourceRequest().IsAdResource()); } - frame->GetAttributionSrcLoader()->MaybeRegisterTrigger(request, response); + frame->GetAttributionSrcLoader()->MaybeRegisterAttributionHeaders( + request, response, resource); frame->Loader().Progress().IncrementProgress(identifier, response); probe::DidReceiveResourceResponse(GetProbe(), identifier, document_loader_,
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h index aa2f4bc..5a48140 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.h
@@ -35,7 +35,8 @@ const ResourceResponse& redirect_response, ResourceType, const ResourceLoaderOptions&, - RenderBlockingBehavior) override; + RenderBlockingBehavior, + const Resource*) override; void DidChangePriority(uint64_t identifier, ResourceLoadPriority, int intra_priority_value) override;
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc index 9d1fa51f..d51518f 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.cc
@@ -36,7 +36,8 @@ const ResourceResponse& redirect_response, ResourceType resource_type, const ResourceLoaderOptions& options, - RenderBlockingBehavior render_blocking_behavior) { + RenderBlockingBehavior render_blocking_behavior, + const Resource* resource) { probe::WillSendRequest( probe_, nullptr, fetcher_properties_->GetFetchClientSettingsObject().GlobalObjectUrl(),
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h index 2e4ee05b..ca6b92c 100644 --- a/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h +++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_worker.h
@@ -33,7 +33,8 @@ const ResourceResponse& redirect_response, ResourceType, const ResourceLoaderOptions&, - RenderBlockingBehavior) override; + RenderBlockingBehavior, + const Resource*) override; void DidChangePriority(uint64_t identifier, ResourceLoadPriority, int intra_priority_value) override;
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc index f3fb833..0daf5a8 100644 --- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc +++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -302,7 +302,7 @@ ASSERT_TRUE(iframe); iframe->contentDocument()->OverrideIsInitialEmptyDocument(); To<LocalFrame>(iframe->ContentFrame())->View()->BeginLifecycleUpdates(); - ASSERT_FALSE(iframe->ContentFrame()->IsCrossOriginToMainFrame()); + ASSERT_FALSE(iframe->ContentFrame()->IsCrossOriginToNearestMainFrame()); UpdateAllLifecyclePhasesForTest(); LayoutView* iframe_layout_view = To<LocalFrame>(iframe->ContentFrame())->ContentLayoutObject(); @@ -325,7 +325,7 @@ To<LocalFrame>(iframe->ContentFrame())->ContentLayoutObject(); iframe_layer = iframe_layout_view->Layer(); ASSERT_TRUE(iframe_layer); - ASSERT_TRUE(iframe->ContentFrame()->IsCrossOriginToMainFrame()); + ASSERT_TRUE(iframe->ContentFrame()->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE(iframe_layer->GetScrollableArea()->NeedsCompositedScrolling()); EXPECT_REASONS(CompositingReason::kIFrame, DirectReasonsForPaintProperties(*iframe_layout_view));
diff --git a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc index c1a1f87f..e545bfa 100644 --- a/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc +++ b/third_party/blink/renderer/core/paint/selection_bounds_recorder.cc
@@ -126,6 +126,11 @@ selection_layout_object_(layout_object) {} SelectionBoundsRecorder::~SelectionBoundsRecorder() { + paint_controller_.RecordAnySelectionWasPainted(); + + if (state_ == SelectionState::kInside) + return; + absl::optional<PaintedSelectionBound> start; absl::optional<PaintedSelectionBound> end; gfx::Rect selection_rect = ToPixelSnappedRect(selection_rect_); @@ -172,7 +177,7 @@ if (local_frame != focused_frame) return false; - if (state == SelectionState::kInside || state == SelectionState::kNone) + if (state == SelectionState::kNone) return false; return true;
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 5b7a377c..44b6aa0 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
@@ -733,8 +733,9 @@ CompositeFrame(); EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering()); - EXPECT_TRUE( - frame_element->contentDocument()->GetFrame()->IsCrossOriginToMainFrame()); + EXPECT_TRUE(frame_element->contentDocument() + ->GetFrame() + ->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE(frame_element->contentDocument() ->View() ->GetLayoutView() @@ -747,8 +748,9 @@ frame_element->contentDocument()->setDomain(String("example.com"), exception_state); - EXPECT_FALSE( - frame_element->contentDocument()->GetFrame()->IsCrossOriginToMainFrame()); + EXPECT_FALSE(frame_element->contentDocument() + ->GetFrame() + ->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE( frame_element->contentDocument()->View()->CanThrottleRendering()); EXPECT_TRUE(frame_element->contentDocument() @@ -774,7 +776,7 @@ To<HTMLIFrameElement>(GetDocument().getElementById("frame")); auto* frame_document = frame_element->contentDocument(); EXPECT_TRUE(frame_document->View()->CanThrottleRendering()); - EXPECT_TRUE(frame_document->GetFrame()->IsCrossOriginToMainFrame()); + EXPECT_TRUE(frame_document->GetFrame()->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE( frame_document->View()->GetLayoutView()->NeedsPaintPropertyUpdate()); @@ -784,14 +786,14 @@ frame_element->contentDocument()->setDomain(String("example.com"), exception_state); EXPECT_TRUE(frame_document->View()->CanThrottleRendering()); - EXPECT_TRUE(frame_document->GetFrame()->IsCrossOriginToMainFrame()); + EXPECT_TRUE(frame_document->GetFrame()->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE( frame_document->View()->GetLayoutView()->NeedsPaintPropertyUpdate()); // Then change the main frame origin which needs to invalidate the newly // cross-origin child. GetDocument().setDomain(String("example.com"), exception_state); - EXPECT_FALSE(frame_document->GetFrame()->IsCrossOriginToMainFrame()); + EXPECT_FALSE(frame_document->GetFrame()->IsCrossOriginToNearestMainFrame()); EXPECT_FALSE(frame_document->View()->CanThrottleRendering()); EXPECT_TRUE( frame_document->View()->GetLayoutView()->NeedsPaintPropertyUpdate());
diff --git a/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_noscroll.html b/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_noscroll.html new file mode 100644 index 0000000..608df3d --- /dev/null +++ b/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_noscroll.html
@@ -0,0 +1,33 @@ +<style> + @font-face { + font-family: ahem; + src: url(Ahem.ttf); + } + * { + font-family: ahem; + margin: 0; + padding: 0; + } + div.top { + + } + div.bottom { + position:absolute; + top: 10000px; + + } +</style> +<div class="top">top text</div> +<div class="bottom">bottom text</div> + +<script> + document.getSelection().selectAllChildren(document.documentElement); + + var expectEditable = false; + var expectEmptyTextFormControl = false; + var yBottomEpsilon = 2; + var startHidden = false; + var endHidden = true; + window.expectedResult = [document, 0, 0, 0, 12, null, 0, 0, 0, 0, expectEditable, expectEmptyTextFormControl, yBottomEpsilon, startHidden, endHidden]; +</script> +
diff --git a/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_scroll.html b/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_scroll.html new file mode 100644 index 0000000..9f6d1265 --- /dev/null +++ b/third_party/blink/renderer/core/testing/data/composited_selection_bounds_large_selection_scroll.html
@@ -0,0 +1,33 @@ +<style> + @font-face { + font-family: ahem; + src: url(Ahem.ttf); + } + * { + font-family: ahem; + margin: 0; + padding: 0; + } + div.top { + + } + div.bottom { + position:absolute; + top: 10000px; + + } +</style> +<div class="top">top text</div> +<div class="bottom">bottom text</div> + +<script> + document.getSelection().selectAllChildren(document.documentElement); + document.scrollingElement.scrollTop = 10000; + + var expectEditable = false; + var expectEmptyTextFormControl = false; + var yBottomEpsilon = 2; + var startHidden = true; + var endHidden = false; + window.expectedResult = [null, 0, 0, 0, 0, document, 132, 10000, 132, 10012, expectEditable, expectEmptyTextFormControl, yBottomEpsilon, startHidden, endHidden, 50, 10]; +</script>
diff --git a/third_party/blink/renderer/modules/vibration/vibration_controller.cc b/third_party/blink/renderer/modules/vibration/vibration_controller.cc index bc44cf5..8e62bb9 100644 --- a/third_party/blink/renderer/modules/vibration/vibration_controller.cc +++ b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
@@ -85,7 +85,7 @@ } else if (!window->GetFrame()->IsMainFrame()) { // TODO(crbug.com/1254770): Update for embedded portals. UseCounter::Count(window, WebFeature::kNavigatorVibrateSubFrame); - if (window->GetFrame()->IsCrossOriginToMainFrame()) { + if (window->GetFrame()->IsCrossOriginToNearestMainFrame()) { if (user_gesture) type = NavigatorVibrationType::kCrossOriginSubFrameWithUserGesture; else @@ -191,7 +191,7 @@ if (!frame->HasStickyUserActivation()) { String message; // TODO(crbug.com/1254770): Update for embedded portals. - if (frame->IsCrossOriginToMainFrame()) { + if (frame->IsCrossOriginToNearestMainFrame()) { message = "Blocked call to navigator.vibrate inside a cross-origin " "iframe because the frame has never been activated by the user: "
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc index db71e27f..f9d6662 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -1016,16 +1016,20 @@ return layer_bound; } -void PaintChunksToCcLayer::UpdateLayerSelection( +bool PaintChunksToCcLayer::UpdateLayerSelection( cc::Layer& layer, const PropertyTreeState& layer_state, const PaintChunkSubset& chunks, cc::LayerSelection& layer_selection) { gfx::Vector2dF layer_offset = layer.offset_to_transform_parent(); + bool any_selection_was_painted = false; for (const auto& chunk : chunks) { if (!chunk.layer_selection_data) continue; + any_selection_was_painted |= + chunk.layer_selection_data->any_selection_was_painted; + auto chunk_state = chunk.properties.GetPropertyTreeState().Unalias(); if (chunk.layer_selection_data->start) { const PaintedSelectionBound& bound = @@ -1043,6 +1047,8 @@ layer_selection.end.layer_id = layer.id(); } } + + return any_selection_was_painted; } void PaintChunksToCcLayer::UpdateLayerProperties(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h index 9bf9ee82..e1d5148 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h
@@ -68,7 +68,8 @@ cc::DisplayItemList::UsageHint, RasterUnderInvalidationCheckingParams* = nullptr); - static void UpdateLayerSelection(cc::Layer& layer, + // Returns true if any selection was painted in the provided PaintChunkSubset. + static bool UpdateLayerSelection(cc::Layer& layer, const PropertyTreeState& layer_state, const PaintChunkSubset&, cc::LayerSelection& layer_selection);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/pending_layer.cc b/third_party/blink/renderer/platform/graphics/compositing/pending_layer.cc index a610484..b3b6ff1 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/pending_layer.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/pending_layer.cc
@@ -650,8 +650,22 @@ // Foreign layers cannot contain selection. if (compositing_type_ == PendingLayer::kForeignLayer) return; - PaintChunksToCcLayer::UpdateLayerSelection(CcLayer(), GetPropertyTreeState(), - Chunks(), layer_selection); + bool any_selection_was_painted = PaintChunksToCcLayer::UpdateLayerSelection( + CcLayer(), GetPropertyTreeState(), Chunks(), layer_selection); + if (any_selection_was_painted) { + // If any selection was painted, but we didn't see the start or end bound + // recorded, it could have been outside of the painting cull rect thus + // invisible. Mark the bound as such if this is the case. + if (layer_selection.start.type == gfx::SelectionBound::EMPTY) { + layer_selection.start.type = gfx::SelectionBound::LEFT; + layer_selection.start.hidden = true; + } + + if (layer_selection.end.type == gfx::SelectionBound::EMPTY) { + layer_selection.end.type = gfx::SelectionBound::RIGHT; + layer_selection.end.hidden = true; + } + } } bool PendingLayer::IsSolidColor() const {
diff --git a/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h b/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h index 2d9cf08..d33ad2ac 100644 --- a/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h +++ b/third_party/blink/renderer/platform/graphics/paint/layer_selection_data.h
@@ -22,6 +22,7 @@ struct PLATFORM_EXPORT LayerSelectionData { absl::optional<PaintedSelectionBound> start; absl::optional<PaintedSelectionBound> end; + bool any_selection_was_painted = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc index eaff961..f73448ba 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc +++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
@@ -233,6 +233,15 @@ } } +void PaintChunker::RecordAnySelectionWasPainted() { + DCHECK(chunks_); + DCHECK(!chunks_->IsEmpty()); + + auto& chunk = chunks_->back(); + LayerSelectionData& selection_data = chunk.EnsureLayerSelectionData(); + selection_data.any_selection_was_painted = true; +} + void PaintChunker::CreateScrollHitTestChunk( const PaintChunk::Id& id, const DisplayItemClient& client,
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h index 06adbe36..f9863c6 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.h
@@ -92,6 +92,7 @@ // Otherwise it's ignored. Returns true if a new chunk is added. void AddSelectionToCurrentChunk(absl::optional<PaintedSelectionBound> start, absl::optional<PaintedSelectionBound> end); + void RecordAnySelectionWasPainted(); // Returns true if a new chunk is created. bool EnsureChunk() {
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h index a1cec14..883fabc 100644 --- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h +++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -132,6 +132,9 @@ void RecordSelection(absl::optional<PaintedSelectionBound> start, absl::optional<PaintedSelectionBound> end); + void RecordAnySelectionWasPainted() { + paint_chunker_.RecordAnySelectionWasPainted(); + } wtf_size_t NumNewChunks() const { return new_paint_artifact_->PaintChunks().size();
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 d92668a5..4a6b4a2 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -604,7 +604,7 @@ resource_load_observer_->WillSendRequest( request, ResourceResponse() /* redirects */, resource->GetType(), - resource->Options(), render_blocking_behavior); + resource->Options(), render_blocking_behavior, resource); resource_load_observer_->DidReceiveResponse( request.InspectorId(), request, resource->GetResponse(), resource, ResourceLoadObserver::ResponseSource::kFromMemoryCache); @@ -2067,7 +2067,7 @@ ResourceResponse response; resource_load_observer_->WillSendRequest( request, response, resource->GetType(), resource->Options(), - render_blocking_behavior); + render_blocking_behavior, resource); } using QuotaType = decltype(inflight_keepalive_bytes_);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc index 3fe4c19..ef244c3 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -124,7 +124,8 @@ const ResourceResponse& redirect_response, ResourceType, const ResourceLoaderOptions&, - RenderBlockingBehavior) override { + RenderBlockingBehavior, + const Resource*) override { request_ = PartialResourceRequest(request); } void DidChangePriority(uint64_t identifier,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h b/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h index a075fbe..38c27b8 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_observer.h
@@ -50,7 +50,8 @@ const ResourceResponse& redirect_response, ResourceType, const ResourceLoaderOptions&, - RenderBlockingBehavior) = 0; + RenderBlockingBehavior, + const Resource*) = 0; // Called when the priority of the request changes. virtual void DidChangePriority(uint64_t identifier,
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 ff63b3d0..dd6c2bb 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -911,9 +911,9 @@ unused_virtual_time_pauser, resource_->GetType()); DCHECK(!new_request->HttpBody()); if (auto* observer = fetcher_->GetResourceLoadObserver()) { - observer->WillSendRequest(*new_request, redirect_response, - resource_->GetType(), options, - initial_request.GetRenderBlockingBehavior()); + observer->WillSendRequest( + *new_request, redirect_response, resource_->GetType(), options, + initial_request.GetRenderBlockingBehavior(), resource_); } // First-party cookie logic moved from DocumentLoader in Blink to
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc index 10b1111..44cc7c5 100644 --- a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc +++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader_unittest.cc
@@ -147,12 +147,13 @@ class MockResourceLoadObserver : public ResourceLoadObserver { public: MOCK_METHOD2(DidStartRequest, void(const FetchParameters&, ResourceType)); - MOCK_METHOD5(WillSendRequest, + MOCK_METHOD6(WillSendRequest, void(const ResourceRequest&, const ResourceResponse& redirect_response, ResourceType, const ResourceLoaderOptions&, - RenderBlockingBehavior)); + RenderBlockingBehavior, + const Resource*)); MOCK_METHOD3(DidChangePriority, void(uint64_t identifier, ResourceLoadPriority,
diff --git a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc index 159565f..15b0c28e 100644 --- a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc +++ b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
@@ -49,8 +49,8 @@ bool IsPageVisible() const override { return true; } void SetPaused(bool) override {} void SetShouldReportPostedTasksWhenDisabled(bool) override {} - void SetCrossOriginToMainFrame(bool) override {} - bool IsCrossOriginToMainFrame() const override { return false; } + void SetCrossOriginToNearestMainFrame(bool) override {} + bool IsCrossOriginToNearestMainFrame() const override { return false; } void SetIsAdFrame(bool is_ad_frame) override {} bool IsAdFrame() const override { return false; } bool IsInEmbeddedFrameTree() const override { return false; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.cc index ca7405a..08f0204 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.cc
@@ -15,7 +15,7 @@ if (scheduler->GetFrameType() == FrameScheduler::FrameType::kMainFrame) return FrameOriginType::kMainFrame; - if (scheduler->IsCrossOriginToMainFrame()) { + if (scheduler->IsCrossOriginToNearestMainFrame()) { return FrameOriginType::kCrossOriginToMainFrame; } else { return FrameOriginType::kSameOriginToMainFrame;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index ea896b1e..aa09642 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -320,7 +320,7 @@ return frame_visible_; } -void FrameSchedulerImpl::SetCrossOriginToMainFrame(bool cross_origin) { +void FrameSchedulerImpl::SetCrossOriginToNearestMainFrame(bool cross_origin) { DCHECK(parent_page_scheduler_); if (frame_origin_type_ == FrameOriginType::kMainFrame) { DCHECK(!cross_origin); @@ -350,7 +350,7 @@ return is_in_embedded_frame_tree_; } -bool FrameSchedulerImpl::IsCrossOriginToMainFrame() const { +bool FrameSchedulerImpl::IsCrossOriginToNearestMainFrame() const { return frame_origin_type_ == FrameOriginType::kCrossOriginToMainFrame; } @@ -746,7 +746,7 @@ auto dict = std::move(context).WriteDictionary(); dict.Add("frame_visible", frame_visible_); dict.Add("page_visible", parent_page_scheduler_->IsPageVisible()); - dict.Add("cross_origin_to_main_frame", IsCrossOriginToMainFrame()); + dict.Add("cross_origin_to_main_frame", IsCrossOriginToNearestMainFrame()); dict.Add("frame_type", frame_type_ == FrameScheduler::FrameType::kMainFrame ? "MainFrame" : "Subframe"); @@ -768,10 +768,9 @@ proto->set_frame_type( frame_type_ == FrameScheduler::FrameType::kMainFrame ? RendererMainThreadTaskExecution::FRAME_TYPE_MAIN_FRAME - : IsCrossOriginToMainFrame() ? RendererMainThreadTaskExecution:: - FRAME_TYPE_CROSS_ORIGIN_SUBFRAME - : RendererMainThreadTaskExecution:: - FRAME_TYPE_SAME_ORIGIN_SUBFRAME); + : IsCrossOriginToNearestMainFrame() + ? RendererMainThreadTaskExecution::FRAME_TYPE_CROSS_ORIGIN_SUBFRAME + : RendererMainThreadTaskExecution::FRAME_TYPE_SAME_ORIGIN_SUBFRAME); proto->set_is_ad_frame(is_ad_frame_); } @@ -957,7 +956,7 @@ return false; if (!parent_page_scheduler_->IsPageVisible()) return true; - return !frame_visible_ && IsCrossOriginToMainFrame(); + return !frame_visible_ && IsCrossOriginToNearestMainFrame(); } bool FrameSchedulerImpl::IsExemptFromBudgetBasedThrottling() const { @@ -1079,7 +1078,7 @@ } // Frame origin type experiment. - if (IsCrossOriginToMainFrame()) { + if (IsCrossOriginToNearestMainFrame()) { if (main_thread_scheduler_->scheduling_settings() .low_priority_cross_origin || (main_thread_scheduler_->scheduling_settings()
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h index 3227de0..c5a92703 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -95,8 +95,8 @@ void SetPaused(bool frame_paused) override; void SetShouldReportPostedTasksWhenDisabled(bool should_report) override; - void SetCrossOriginToMainFrame(bool cross_origin) override; - bool IsCrossOriginToMainFrame() const override; + void SetCrossOriginToNearestMainFrame(bool cross_origin) override; + bool IsCrossOriginToNearestMainFrame() const override; void SetIsAdFrame(bool is_ad_frame) override; bool IsAdFrame() const override;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index e7dc407..053686f 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -758,10 +758,10 @@ LazyInitThrottleableTaskQueue(); EXPECT_FALSE(IsThrottled()); frame_scheduler_->SetFrameVisible(false); - frame_scheduler_->SetCrossOriginToMainFrame(true); - frame_scheduler_->SetCrossOriginToMainFrame(false); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(false); EXPECT_FALSE(IsThrottled()); - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); EXPECT_TRUE(IsThrottled()); frame_scheduler_->SetFrameVisible(true); EXPECT_FALSE(IsThrottled()); @@ -771,7 +771,7 @@ TEST_F(FrameSchedulerImplTest, FrameHidden_CrossOrigin_LazyInit) { frame_scheduler_->SetFrameVisible(false); - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); LazyInitThrottleableTaskQueue(); EXPECT_TRUE(IsThrottled()); } @@ -795,13 +795,13 @@ EXPECT_TRUE(throttleable_task_queue()); frame_scheduler_->SetFrameVisible(true); EXPECT_FALSE(IsThrottled()); - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); EXPECT_FALSE(IsThrottled()); } TEST_F(FrameSchedulerImplTest, FrameVisible_CrossOrigin_LazyInit) { frame_scheduler_->SetFrameVisible(true); - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); LazyInitThrottleableTaskQueue(); EXPECT_FALSE(IsThrottled()); } @@ -2336,7 +2336,7 @@ }; TEST_F(LowPriorityCrossOriginTaskExperimentTest, FrameQueuesPriorities) { - EXPECT_FALSE(frame_scheduler_->IsCrossOriginToMainFrame()); + EXPECT_FALSE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); // Same Origin Task Queues. EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(), @@ -2352,8 +2352,8 @@ EXPECT_EQ(UnpausableTaskQueue()->GetQueuePriority(), TaskQueue::QueuePriority::kNormalPriority); - frame_scheduler_->SetCrossOriginToMainFrame(true); - EXPECT_TRUE(frame_scheduler_->IsCrossOriginToMainFrame()); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); + EXPECT_TRUE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(), TaskQueue::QueuePriority::kLowPriority); @@ -2402,8 +2402,8 @@ EXPECT_EQ(UnpausableTaskQueue()->GetQueuePriority(), TaskQueue::QueuePriority::kNormalPriority); - frame_scheduler_->SetCrossOriginToMainFrame(true); - EXPECT_TRUE(frame_scheduler_->IsCrossOriginToMainFrame()); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); + EXPECT_TRUE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(), TaskQueue::QueuePriority::kLowPriority); @@ -3017,7 +3017,7 @@ // the main frame with intensive wake up throttling. TEST_P(FrameSchedulerImplTestWithIntensiveWakeUpThrottling, TaskExecutionSameOriginFrame) { - ASSERT_FALSE(frame_scheduler_->IsCrossOriginToMainFrame()); + ASSERT_FALSE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); // Throttled TaskRunner to which tasks are posted in this test. const scoped_refptr<base::SingleThreadTaskRunner> task_runner = @@ -3188,7 +3188,7 @@ // with the main frame with intensive wake up throttling. TEST_P(FrameSchedulerImplTestWithIntensiveWakeUpThrottling, TaskExecutionCrossOriginFrame) { - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); // Throttled TaskRunner to which tasks are posted in this test. const scoped_refptr<base::SingleThreadTaskRunner> task_runner = @@ -3359,7 +3359,7 @@ // frame run at the expected time. TEST_P(FrameSchedulerImplTestWithIntensiveWakeUpThrottling, ManySameOriginFrames) { - ASSERT_FALSE(frame_scheduler_->IsCrossOriginToMainFrame()); + ASSERT_FALSE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); const scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetTaskRunner(); @@ -3370,7 +3370,7 @@ frame_scheduler_delegate_.get(), nullptr, /*is_in_embedded_frame_tree=*/false, FrameScheduler::FrameType::kSubframe); - ASSERT_FALSE(other_frame_scheduler->IsCrossOriginToMainFrame()); + ASSERT_FALSE(other_frame_scheduler->IsCrossOriginToNearestMainFrame()); const scoped_refptr<base::SingleThreadTaskRunner> other_task_runner = GetTaskRunner(other_frame_scheduler.get()); @@ -3542,7 +3542,7 @@ // same-origin and cross-origin with the main frame. TEST_P(FrameSchedulerImplTestWithIntensiveWakeUpThrottling, FrameChangesOriginType) { - EXPECT_FALSE(frame_scheduler_->IsCrossOriginToMainFrame()); + EXPECT_FALSE(frame_scheduler_->IsCrossOriginToNearestMainFrame()); const scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetTaskRunner(); @@ -3553,7 +3553,7 @@ frame_scheduler_delegate_.get(), nullptr, /*is_in_embedded_frame_tree=*/false, FrameScheduler::FrameType::kSubframe); - cross_origin_frame_scheduler->SetCrossOriginToMainFrame(true); + cross_origin_frame_scheduler->SetCrossOriginToNearestMainFrame(true); const scoped_refptr<base::SingleThreadTaskRunner> cross_origin_task_runner = GetTaskRunner(cross_origin_frame_scheduler.get()); @@ -3586,7 +3586,7 @@ // Make the |frame_scheduler_| cross-origin. Its task must now run at an // aligned time. - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); task_environment_.FastForwardBy(kDefaultThrottledWakeUpInterval); if (IsIntensiveThrottlingExpected()) { @@ -3621,7 +3621,7 @@ // Make the |frame_scheduler_| same-origin. Its task can now run at a // 1-second aligned time, since there was no wake up in the last minute. - frame_scheduler_->SetCrossOriginToMainFrame(false); + frame_scheduler_->SetCrossOriginToNearestMainFrame(false); task_environment_.FastForwardBy(kLongUnalignedDelay); if (IsIntensiveThrottlingExpected()) { @@ -4066,7 +4066,7 @@ /*is_in_embedded_frame_tree=*/false, FrameScheduler::FrameType::kSubframe); page_scheduler_->SetPageVisible(true); - cross_origin_frame_scheduler->SetCrossOriginToMainFrame(true); + cross_origin_frame_scheduler->SetCrossOriginToNearestMainFrame(true); const scoped_refptr<base::SingleThreadTaskRunner> cross_origin_task_runner = cross_origin_frame_scheduler->GetTaskRunner( TaskType::kJavascriptTimerDelayedLowNesting); @@ -4101,7 +4101,7 @@ /*is_in_embedded_frame_tree=*/false, FrameScheduler::FrameType::kSubframe); page_scheduler_->SetPageVisible(true); - cross_origin_frame_scheduler->SetCrossOriginToMainFrame(true); + cross_origin_frame_scheduler->SetCrossOriginToNearestMainFrame(true); const scoped_refptr<base::SingleThreadTaskRunner> cross_origin_task_runner = cross_origin_frame_scheduler->GetTaskRunner( TaskType::kJavascriptTimerDelayedLowNesting);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc index d8a1c92..7432d1c9 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc
@@ -61,7 +61,7 @@ if (frame_scheduler.GetFrameType() == FrameScheduler::FrameType::kMainFrame) { return FrameOriginState::kMainFrame; } - if (frame_scheduler.IsCrossOriginToMainFrame()) + if (frame_scheduler.IsCrossOriginToNearestMainFrame()) return FrameOriginState::kCrossOriginToMainFrame; return FrameOriginState::kSameOriginToMainFrame; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc index a6988a1..e024be7 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
@@ -179,38 +179,38 @@ break; case FrameStatus::kCrossOriginVisible: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetIsPageVisible(true) .SetIsFrameVisible(true); break; case FrameStatus::kCrossOriginVisibleService: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetPageScheduler(playing_view_.get()) .SetIsFrameVisible(true); break; case FrameStatus::kCrossOriginHidden: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetIsPageVisible(true); break; case FrameStatus::kCrossOriginHiddenService: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetPageScheduler(playing_view_.get()); break; case FrameStatus::kCrossOriginBackground: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true); + .SetIsCrossOriginToNearestMainFrame(true); break; case FrameStatus::kCrossOriginBackgroundExemptSelf: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetIsExemptFromThrottling(true); break; case FrameStatus::kCrossOriginBackgroundExemptOther: builder.SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetPageScheduler(throtting_exempt_view_.get()); break; case FrameStatus::kCount:
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h index 777a379..9ff0059 100644 --- a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h +++ b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
@@ -82,8 +82,8 @@ // Set whether this frame is cross origin w.r.t. the top level frame. Cross // origin frames may use a different scheduling policy from same origin // frames. - virtual void SetCrossOriginToMainFrame(bool) = 0; - virtual bool IsCrossOriginToMainFrame() const = 0; + virtual void SetCrossOriginToNearestMainFrame(bool) = 0; + virtual bool IsCrossOriginToNearestMainFrame() const = 0; virtual void SetIsAdFrame(bool is_ad_frame) = 0; virtual bool IsAdFrame() const = 0;
diff --git a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h index 66785fed..f9fe067 100644 --- a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h +++ b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h
@@ -46,14 +46,14 @@ is_page_visible_(false), is_frame_visible_(false), frame_type_(FrameScheduler::FrameType::kSubframe), - is_cross_origin_to_main_frame_(false), + is_cross_origin_to_nearest_main_frame_(false), is_exempt_from_throttling_(false) {} FakeFrameScheduler(PageScheduler* page_scheduler, bool is_page_visible, bool is_frame_visible, FrameScheduler::FrameType frame_type, - bool is_cross_origin_to_main_frame, + bool is_cross_origin_to_nearest_main_frame, bool is_exempt_from_throttling, FrameScheduler::Delegate* delegate) : FrameSchedulerImpl(/*main_thread_scheduler=*/nullptr, @@ -66,10 +66,10 @@ is_page_visible_(is_page_visible), is_frame_visible_(is_frame_visible), frame_type_(frame_type), - is_cross_origin_to_main_frame_(is_cross_origin_to_main_frame), + is_cross_origin_to_nearest_main_frame_(is_cross_origin_to_nearest_main_frame), is_exempt_from_throttling_(is_exempt_from_throttling) { DCHECK(frame_type_ != FrameType::kMainFrame || - !is_cross_origin_to_main_frame); + !is_cross_origin_to_nearest_main_frame); } FakeFrameScheduler(const FakeFrameScheduler&) = delete; FakeFrameScheduler& operator=(const FakeFrameScheduler&) = delete; @@ -84,7 +84,7 @@ std::unique_ptr<FakeFrameScheduler> Build() { return std::make_unique<FakeFrameScheduler>( page_scheduler_, is_page_visible_, is_frame_visible_, frame_type_, - is_cross_origin_to_main_frame_, is_exempt_from_throttling_, + is_cross_origin_to_nearest_main_frame_, is_exempt_from_throttling_, delegate_); } @@ -108,8 +108,9 @@ return *this; } - Builder& SetIsCrossOriginToMainFrame(bool is_cross_origin_to_main_frame) { - is_cross_origin_to_main_frame_ = is_cross_origin_to_main_frame; + Builder& SetIsCrossOriginToNearestMainFrame( + bool is_cross_origin_to_nearest_main_frame) { + is_cross_origin_to_nearest_main_frame_ = is_cross_origin_to_nearest_main_frame; return *this; } @@ -129,7 +130,7 @@ bool is_frame_visible_ = false; FrameScheduler::FrameType frame_type_ = FrameScheduler::FrameType::kMainFrame; - bool is_cross_origin_to_main_frame_ = false; + bool is_cross_origin_to_nearest_main_frame_ = false; bool is_exempt_from_throttling_ = false; FrameScheduler::Delegate* delegate_ = nullptr; }; @@ -139,9 +140,9 @@ bool IsFrameVisible() const override { return is_frame_visible_; } bool IsPageVisible() const override { return is_page_visible_; } void SetPaused(bool) override {} - void SetCrossOriginToMainFrame(bool) override {} - bool IsCrossOriginToMainFrame() const override { - return is_cross_origin_to_main_frame_; + void SetCrossOriginToNearestMainFrame(bool) override {} + bool IsCrossOriginToNearestMainFrame() const override { + return is_cross_origin_to_nearest_main_frame_; } void TraceUrlChange(const String&) override {} FrameScheduler::FrameType GetFrameType() const override { @@ -182,7 +183,7 @@ bool is_page_visible_; bool is_frame_visible_; FrameScheduler::FrameType frame_type_; - bool is_cross_origin_to_main_frame_; + bool is_cross_origin_to_nearest_main_frame_; bool is_exempt_from_throttling_; };
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc index 6f7dc7e..e1c71af0 100644 --- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
@@ -492,10 +492,10 @@ frame_scheduler_ = FakeFrameScheduler::Builder() .SetIsPageVisible(false) .SetFrameType(FrameScheduler::FrameType::kSubframe) - .SetIsCrossOriginToMainFrame(true) + .SetIsCrossOriginToNearestMainFrame(true) .SetDelegate(frame_scheduler_delegate_.get()) .Build(); - frame_scheduler_->SetCrossOriginToMainFrame(true); + frame_scheduler_->SetCrossOriginToNearestMainFrame(true); worker_scheduler_proxy_ = std::make_unique<WorkerSchedulerProxy>(frame_scheduler_.get());
diff --git a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py deleted file mode 100644 index 9dc929fb..0000000 --- a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater.py +++ /dev/null
@@ -1,297 +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. -"""Updates expectations for Android WPT bots. - -Specifically, this class fetches results from try bots for the current CL, then -(1) updates browser specific expectation files for Androids browsers like Weblayer. - -We needed an Android flavour of the WPTExpectationsUpdater class because -(1) Android bots don't currently produce output that can be baselined, therefore - we only update expectations in the class below. -(2) For Android we write test expectations to browser specific expectation files, - not the regular web test's TestExpectation and NeverFixTests file. -(3) WPTExpectationsUpdater can only update expectations for the blink_web_tests - and webdriver_test_suite steps. Android bots may run several WPT steps, so - the script needs to be able to update expectations for multiple steps. -""" - -import logging -from collections import defaultdict, namedtuple -import six - -if six.PY3: - from functools import reduce - -from blinkpy.common.host import Host -from blinkpy.common.memoized import memoized -from blinkpy.common.system.executive import ScriptError -from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater -from blinkpy.web_tests.models.test_expectations import TestExpectations -from blinkpy.web_tests.models.typ_types import Expectation, ResultType -from blinkpy.web_tests.port.android import ( - PRODUCTS, PRODUCTS_TO_STEPNAMES, PRODUCTS_TO_BROWSER_TAGS, - PRODUCTS_TO_EXPECTATION_FILE_PATHS, ANDROID_DISABLED_TESTS, - ANDROID_WEBLAYER, ANDROID_WEBVIEW, CHROME_ANDROID) - -_log = logging.getLogger(__name__) - -AndroidConfig = namedtuple('AndroidConfig', ['port_name', 'browser']) - - -class AndroidWPTExpectationsUpdater(WPTExpectationsUpdater): - MARKER_COMMENT = '# Add untriaged failures in this block' - NEVER_FIX_MARKER_COMMENT = '# Add untriaged disabled tests in this block' - UMBRELLA_BUG = 'crbug.com/1050754' - - def __init__(self, host, args=None, wpt_manifests=None): - super(AndroidWPTExpectationsUpdater, self).__init__(host, args, wpt_manifests) - self._never_fix_expectations = TestExpectations( - self.port, { - ANDROID_DISABLED_TESTS: - host.filesystem.read_text_file(ANDROID_DISABLED_TESTS)}) - self._baseline_expectations = TestExpectations(self.port) - assert(len(self.options.android_product) == 1) - product = self.options.android_product[0] - if product == ANDROID_WEBLAYER: - self.testid_prefix = "ninja://weblayer/shell/android:weblayer_shell_wpt/" - self.test_suite = "weblayer_shell_wpt" - elif product == ANDROID_WEBVIEW: - self.testid_prefix = "ninja://android_webview/test:system_webview_wpt/" - self.test_suite = "system_webview_wpt" - elif product == CHROME_ANDROID: - self.testid_prefix = "ninja://chrome/android:chrome_public_wpt/" - self.test_suite = "chrome_public_wpt" - - def expectations_files(self): - # We need to put all the Android expectation files in - # the _test_expectations member variable so that the - # files get cleaned in cleanup_test_expectations_files() - return (list(PRODUCTS_TO_EXPECTATION_FILE_PATHS.values()) + - [ANDROID_DISABLED_TESTS]) - - def _get_web_test_results(self, build): - """Gets web tests results for Android builders. We need to - bypass the step which gets the step names for the builder - since it does not currently work for Android. - - Args: - build: Named tuple containing builder name and number - - Returns: - returns: List of web tests results for each web test step - in build. - """ - results_sets = [] - build_specifiers = self._get_build_specifiers(build) - for product in self.options.android_product: - if product in build_specifiers: - step_name = PRODUCTS_TO_STEPNAMES[product] - results_sets.append(self.host.results_fetcher.fetch_results( - build, True, '%s (with patch)' % step_name)) - return filter(None, results_sets) - - def get_builder_configs(self, build, results_set=None): - """Gets step name from WebTestResults instance and uses - that to create AndroidConfig instances. It also only - returns valid configs for the android products passed - through the --android-product command line argument. - - Args: - build: Build object that contains the builder name and - build number. - results_set: WebTestResults instance. If this variable - then it will return a list of android configs for - each product passed through the --android-product - command line argument. - - Returns: - List of valid android configs for products passed through - the --android-product command line argument.""" - configs = [] - if not results_set: - build_specifiers = self._get_build_specifiers(build) - products = build_specifiers & { - s.lower() for s in self.options.android_product} - else: - step_name = results_set.step_name() - step_name = step_name[: step_name.index(' (with patch)')] - product = {s: p for p, s in PRODUCTS_TO_STEPNAMES.items()}[step_name] - products = {product} - - for product in products: - browser = PRODUCTS_TO_BROWSER_TAGS[product] - configs.append( - AndroidConfig(port_name=self.port_name(build), browser=browser)) - return configs - - @memoized - def _get_build_specifiers(self, build): - return {s.lower() for s in - self.host.builders.specifiers_for_builder(build.builder_name)} - - def can_rebaseline(self, *_): - """Return False since we cannot rebaseline tests for - Android at the moment.""" - return False - - @staticmethod - @memoized - def _get_marker_line_number(test_expectations, path, marker_comment): - for line in test_expectations.get_updated_lines(path): - if line.to_string() == marker_comment: - return line.lineno - raise ScriptError('Marker comment does not exist in %s' % path) - - def _get_untriaged_test_expectations( - self, test_expectations, paths, marker_comment): - untriaged_exps = defaultdict(dict) - for path in paths: - marker_lineno = self._get_marker_line_number( - test_expectations, path, marker_comment) - exp_lines = test_expectations.get_updated_lines(path) - for i in range(marker_lineno, len(exp_lines)): - if (not exp_lines[i].to_string().strip() or - exp_lines[i].to_string().startswith('#')): - break - untriaged_exps[path].setdefault( - exp_lines[i].test, []).append(exp_lines[i]) - return untriaged_exps - - def _maybe_create_never_fix_expectation( - self, path, test, test_skipped, tags): - if test_skipped: - exps = self._test_expectations.get_expectations_from_file( - path, test) - wontfix = self._never_fix_expectations.matches_an_expected_result( - test, ResultType.Skip) - temporary_skip = any(ResultType.Skip in exp.results for exp in exps) - if not (wontfix or temporary_skip): - return Expectation( - test=test, reason=self.UMBRELLA_BUG, - results={ResultType.Skip}, tags=tags, raw_tags=tags) - - def _get_expectations_from_baseline(self, exps_test_name): - expectation_line = self._baseline_expectations.get_expectations( - exps_test_name) - results_from_expectation = expectation_line.results - if expectation_line.is_default_pass: - # Expectation is default pass, also check baseline expectation - if self.port.expected_subtest_failure(exps_test_name): - results_from_expectation = set([ResultType.Failure]) - return results_from_expectation - - def write_to_test_expectations(self, test_to_results): - """Each expectations file is browser specific, and currently only - runs on pie. Therefore we do not need any configuration specifiers - to anotate expectations for certain builds. - - Args: - test_to_results: A dictionary that maps test names to another - dictionary which maps a tuple of build configurations and to - a test result. - Returns: - Dictionary mapping test names to lists of expectation strings. - """ - browser_to_product = { - browser: product - for product, browser in PRODUCTS_TO_BROWSER_TAGS.items()} - browser_to_exp_path = { - browser: PRODUCTS_TO_EXPECTATION_FILE_PATHS[product] - for product, browser in PRODUCTS_TO_BROWSER_TAGS.items()} - product_exp_paths = {PRODUCTS_TO_EXPECTATION_FILE_PATHS[prod] - for prod in self.options.android_product} - untriaged_exps = self._get_untriaged_test_expectations( - self._test_expectations, product_exp_paths, self.MARKER_COMMENT) - neverfix_tests = self._get_untriaged_test_expectations( - self._never_fix_expectations, [ANDROID_DISABLED_TESTS], - self.NEVER_FIX_MARKER_COMMENT)[ANDROID_DISABLED_TESTS] - - for path, test_exps in untriaged_exps.items(): - self._test_expectations.remove_expectations( - path, reduce(lambda x, y: x + y, list(test_exps.values()))) - - if neverfix_tests: - self._never_fix_expectations.remove_expectations( - ANDROID_DISABLED_TESTS, - reduce(lambda x, y: x + y, list(neverfix_tests.values()))) - - exp_lines_dict_by_product = defaultdict(dict) - for results_test_name, platform_results in test_to_results.items(): - exps_test_name = results_test_name - for configs, test_results in platform_results.items(): - for config in configs: - path = browser_to_exp_path[config.browser] - neverfix_exp = self._maybe_create_never_fix_expectation( - path, exps_test_name, - ResultType.Skip in test_results.actual, - {config.browser.lower()}) - if neverfix_exp: - neverfix_tests.setdefault(exps_test_name, []).append( - neverfix_exp) - else: - # no system specifiers are necessary because we are - # writing to browser specific expectations files for - # only one Android version. - unexpected_results = { - r for r in test_results.actual.split() - if r not in test_results.expected.split()} - - # as we are using override expectations for Android - # side, do not create override expectations if it is a - # subset of default expectations or baseline - default_expectation = \ - self._get_expectations_from_baseline(results_test_name) - if unexpected_results.issubset(default_expectation): - continue - - # Test expectations for modified test cases are already - # deleted, so all tests should be new test - expectation = Expectation( - test=exps_test_name, reason=self.UMBRELLA_BUG, - results=unexpected_results) - product = browser_to_product[config.browser] - exp_lines_dict_by_product[product][exps_test_name] = \ - expectation.to_string() - untriaged_exps[path].setdefault( - exps_test_name, []).append(expectation) - - for path in untriaged_exps: - marker_lineno = self._get_marker_line_number( - self._test_expectations, path, self.MARKER_COMMENT) - self._test_expectations.add_expectations( - path, - sorted([exps[0] for exps in untriaged_exps[path].values()], - key=lambda e: e.test), - marker_lineno) - - disabled_tests_marker_lineno = self._get_marker_line_number( - self._never_fix_expectations, - ANDROID_DISABLED_TESTS, - self.NEVER_FIX_MARKER_COMMENT) - - if neverfix_tests: - self._never_fix_expectations.add_expectations( - ANDROID_DISABLED_TESTS, - sorted(reduce(lambda x, y: x + y, list(neverfix_tests.values())), - key=lambda e: e.test), - disabled_tests_marker_lineno) - - self._test_expectations.commit_changes() - self._never_fix_expectations.commit_changes() - - # returns dictionary mapping product to dictionary that maps test names - # to test expectation strings. - return exp_lines_dict_by_product - - def _is_wpt_test(self, _): - """On Android we use the wpt executable. The test results do not include - the external/wpt prefix. Therefore we need to override this function for - Android and return True for all tests since we only run WPT on Android. - """ - return True - - @memoized - def _get_try_bots(self): - return self.host.builders.filter_builders( - is_try=True, include_specifiers=self.options.android_product)
diff --git a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py deleted file mode 100644 index 653571b6..0000000 --- a/third_party/blink/tools/blinkpy/w3c/android_wpt_expectations_updater_unittest.py +++ /dev/null
@@ -1,253 +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. - -import json -import logging - -from blinkpy.common.host_mock import MockHost -from blinkpy.common.net.git_cl import TryJobStatus -from blinkpy.common.net.git_cl_mock import MockGitCL -from blinkpy.common.net.results_fetcher import Build -from blinkpy.common.net.web_test_results import WebTestResults -from blinkpy.common.system.log_testing import LoggingTestCase -from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME -from blinkpy.web_tests.builder_list import BuilderList -from blinkpy.web_tests.port.factory_mock import MockPortFactory -from blinkpy.web_tests.port.android import ( - PRODUCTS_TO_EXPECTATION_FILE_PATHS, ANDROID_DISABLED_TESTS, - ANDROID_WEBLAYER, ANDROID_WEBVIEW, CHROME_ANDROID, - PRODUCTS_TO_STEPNAMES) -from blinkpy.w3c.android_wpt_expectations_updater import ( - AndroidWPTExpectationsUpdater) - -WEBLAYER_WPT_STEP = PRODUCTS_TO_STEPNAMES[ANDROID_WEBLAYER] -WEBVIEW_WPT_STEP = PRODUCTS_TO_STEPNAMES[ANDROID_WEBVIEW] -CHROME_ANDROID_WPT_STEP = PRODUCTS_TO_STEPNAMES[CHROME_ANDROID] - -class AndroidWPTExpectationsUpdaterTest(LoggingTestCase): - _raw_baseline_expectations = ( - '# results: [ Failure Crash Timeout]\n' - '\n' - 'crbug.com/1111111 external/wpt/new1.html [ Failure Timeout ]\n') - - # baseline for external/wpt/new2.html - _raw_expected_text = ( - 'This is a testharness.js-based test.\n' - 'FAIL a failed subtest\n' - 'Harness: the test ran to completion.\n') - - _raw_android_never_fix_tests = ( - '# tags: [ android-weblayer android-webview chrome-android ]\n' - '# results: [ Skip ]\n' - '\n' - '# Add untriaged disabled tests in this block\n' - 'crbug.com/1050754 [ android-webview ] external/wpt/disabled.html [ Skip ]\n') - - def _setup_host(self, raw_android_expectations): - """Returns a mock host with fake values set up for testing.""" - self.set_logging_level(logging.DEBUG) - host = MockHost() - host.port_factory = MockPortFactory(host) - host.executive._output = '' - - # Set up a fake list of try builders. - host.builders = BuilderList({ - 'MOCK Android Weblayer - Pie': { - 'port_name': 'test-android-pie', - 'specifiers': ['Precise', 'Release', - 'anDroid', 'android_Weblayer'], - 'is_try_builder': True, - }, - }) - - host.filesystem.write_text_file( - host.port_factory.get().web_tests_dir() + '/external/' + - BASE_MANIFEST_NAME, - json.dumps({ - 'items': { - 'testharness': { - 'foo1.html': ['abcdef123', [None, {}]], - 'foo2.html': ['abcdef123', [None, {}]], - 'bar.html': ['abcdef123', [None, {}]], - }, - }, - })) - - # Write dummy expectations - path = host.port_factory.get().web_tests_dir() + '/TestExpectations' - host.filesystem.write_text_file( - path, self._raw_baseline_expectations) - path = host.port_factory.get().web_tests_dir() + '/platform/generic/external/wpt/new2-expected.txt' - host.filesystem.write_text_file( - path, self._raw_expected_text) - - for path in PRODUCTS_TO_EXPECTATION_FILE_PATHS.values(): - host.filesystem.write_text_file( - path, raw_android_expectations) - - host.filesystem.write_text_file( - ANDROID_DISABLED_TESTS, self._raw_android_never_fix_tests) - return host - - def testUpdateTestExpectationsForWeblayer(self): - raw_android_expectations = ( - '# results: [ Failure Crash Timeout]\n' - '\n' - 'crbug.com/1000754 external/wpt/foo.html [ Failure ]\n' - '\n' - '# Add untriaged failures in this block\n' - 'crbug.com/1050754 external/wpt/bar.html [ Failure ]\n' - '\n' - '# This comment will not be deleted\n') - host = self._setup_host(raw_android_expectations) - # Add results for Weblayer - # new1.html is covered by default expectations - # new2.html is covered by baseline - # new3.html is a new test. We should create WebLayer expectation for it. - result = """ - [{ - "testId": "ninja://weblayer/shell/android:weblayer_shell_wpt/external/wpt/new1.html", - "variant": { - "def": { - "builder": "android-weblayer-pie-x86-wpt-fyi-rel", - "os": "Ubuntu-16.04", - "test_suite": "weblayer_shell_wpt" - } - }, - "status": "FAIL" - }, - { - "testId": "ninja://weblayer/shell/android:weblayer_shell_wpt/external/wpt/new2.html", - "variant": { - "def": { - "builder": "android-weblayer-pie-x86-wpt-fyi-rel", - "os": "Ubuntu-16.04", - "test_suite": "weblayer_shell_wpt" - } - }, - "status": "FAIL" - }, - { - "testId": "ninja://weblayer/shell/android:weblayer_shell_wpt/external/wpt/new3.html", - "variant": { - "def": { - "builder": "android-weblayer-pie-x86-wpt-fyi-rel", - "os": "Ubuntu-16.04", - "test_suite": "weblayer_shell_wpt" - } - }, - "status": "CRASH" - }, - { - "testId": "ninja://weblayer/shell/android:weblayer_shell_wpt/external/wpt/new3.html", - "variant": { - "def": { - "builder": "android-weblayer-pie-x86-wpt-fyi-rel", - "os": "Ubuntu-16.04", - "test_suite": "weblayer_shell_wpt" - } - }, - "status": "FAIL" - }]""" - host.results_fetcher.set_results_to_resultdb( - Build('MOCK Android Weblayer - Pie', 123, '123'), - json.loads(result) * 3) - - updater = AndroidWPTExpectationsUpdater( - host, ['-vvv', '--android-product', ANDROID_WEBLAYER, - '--include-unexpected-pass']) - updater.git_cl = MockGitCL(host, { - Build('MOCK Android Weblayer - Pie', 123, '123'): - TryJobStatus('COMPLETED', 'FAILURE')}) - # Run command - updater.run() - # Get new expectations - content = host.filesystem.read_text_file( - PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBLAYER]) - _new_expectations = ( - '# results: [ Failure Crash Timeout]\n' - '\n' - 'crbug.com/1000754 external/wpt/foo.html [ Failure ]\n' - '\n' - '# Add untriaged failures in this block\n' - 'crbug.com/1050754 external/wpt/bar.html [ Failure ]\n' - 'crbug.com/1050754 external/wpt/new3.html [ Crash Failure ]\n' - '\n' - '# This comment will not be deleted\n') - self.assertEqual(content, _new_expectations) - - # Check that ANDROID_DISABLED_TESTS expectation files were not changed - self.assertEqual( - self._raw_android_never_fix_tests, - host.filesystem.read_text_file(ANDROID_DISABLED_TESTS)) - - def testCleanupAndUpdateTestExpectationsForAll(self): - # Full integration test for expectations cleanup and update - # using builder results. - raw_android_expectations = ( - '# results: [ Failure Crash Timeout]\n' - '\n' - 'crbug.com/1000754 external/wpt/foo1.html [ Failure ]\n' - 'crbug.com/1000754 external/wpt/foo2.html [ Failure ]\n' - 'crbug.com/1000754 external/wpt/bar.html [ Failure ]\n' - '\n' - '# Add untriaged failures in this block\n' - '\n' - '# This comment will not be deleted\n') - host = self._setup_host(raw_android_expectations) - # Add results for Weblayer - result = """ - { - "testId": "ninja://weblayer/shell/android:weblayer_shell_wpt/external/wpt/bar.html", - "variant": { - "def": { - "builder": "android-weblayer-pie-x86-wpt-fyi-rel", - "os": "Ubuntu-16.04", - "test_suite": "weblayer_shell_wpt" - } - }, - "status": "CRASH" - }""" - host.results_fetcher.set_results_to_resultdb( - Build('MOCK Android Weblayer - Pie', 123, '123'), - [json.loads(result)] * 3) - updater = AndroidWPTExpectationsUpdater( - host, ['-vvv', - '--clean-up-test-expectations', - '--clean-up-affected-tests-only', - '--include-unexpected-pass', - '--android-product', ANDROID_WEBLAYER]) - - def _git_command_return_val(cmd): - if '--diff-filter=D' in cmd: - return 'external/wpt/foo2.html' - if '--diff-filter=R' in cmd: - return 'C\texternal/wpt/foo1.html\texternal/wpt/foo3.html' - if '--diff-filter=M' in cmd: - return 'external/wpt/bar.html' - return '' - - updater.git_cl = MockGitCL(host, { - Build('MOCK Android Weblayer - Pie', 123, '123'): - TryJobStatus('COMPLETED', 'FAILURE')}) - - updater.git.run = _git_command_return_val - updater._relative_to_web_test_dir = lambda test_path: test_path - - # Run command - updater.run() - - # Check expectations for weblayer - content = host.filesystem.read_text_file( - PRODUCTS_TO_EXPECTATION_FILE_PATHS[ANDROID_WEBLAYER]) - _new_expectations = ( - '# results: [ Failure Crash Timeout]\n' - '\n' - 'crbug.com/1000754 external/wpt/foo3.html [ Failure ]\n' - '\n' - '# Add untriaged failures in this block\n' - 'crbug.com/1050754 external/wpt/bar.html [ Crash ]\n' - '\n' - '# This comment will not be deleted\n') - self.assertEqual(content, _new_expectations)
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py index f15d5d8..4e32e8e 100644 --- a/third_party/blink/tools/blinkpy/w3c/test_importer.py +++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -21,7 +21,6 @@ from blinkpy.common.path_finder import PathFinder from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.log_utils import configure_logging -from blinkpy.w3c.android_wpt_expectations_updater import AndroidWPTExpectationsUpdater from blinkpy.w3c.chromium_exportable_commits import exportable_commits_over_last_n_commits from blinkpy.w3c.common import read_credentials, is_testharness_baseline, is_file_exportable, WPT_GH_URL from blinkpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor @@ -80,13 +79,6 @@ self._expectations_updater = WPTExpectationsUpdater( self.host, args, wpt_manifests) - args = [ - '--android-product', - 'android_weblayer' - ] - self._android_expectations_updater = AndroidWPTExpectationsUpdater( - self.host, args, wpt_manifests) - def main(self, argv=None): # TODO(robertma): Test this method! Split it to make it easier to test # if necessary. @@ -256,7 +248,6 @@ if try_results and self.git_cl.some_failed(try_results): self.fetch_new_expectations_and_baselines() - self.fetch_wpt_override_expectations() if self.chromium_git.has_working_directory_changes(): # Skip slow and timeout tests so that presubmit check passes port = self.host.port_factory.get() @@ -686,19 +677,6 @@ _log.info('Adding test expectations lines for disable-site-isolation-trials') self._expectations_updater.update_expectations_for_flag_specific('disable-site-isolation-trials') - def fetch_wpt_override_expectations(self): - """Modifies WPT Override expectations based on try job results. - - Assuming that there are some try job results available, this - adds new expectation lines to WPT Override Expectation files, - e.g. WebLayerWPTOverrideExpectations - - This is the same as invoking the `wpt-update-expectations` script. - """ - _log.info('Adding test expectations lines to Override Expectations.') - _, self.new_override_expectations = ( - self._android_expectations_updater.update_expectations()) - def _get_last_imported_wpt_revision(self): """Finds the last imported WPT revision.""" # TODO(robertma): Only match commit subjects.
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py index d2aa7bcc..633d6de 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -96,11 +96,6 @@ log_level = logging.DEBUG if self.options.verbose else logging.INFO configure_logging(logging_level=log_level, include_time=True) - if not (self.options.android_product - or self.options.update_android_expectations_only): - assert not self.options.include_unexpected_pass, ( - 'Command line argument --include-unexpected-pass is not ' - 'supported in desktop mode.') self.patchset = self.options.patchset if (self.options.clean_up_test_expectations or @@ -139,17 +134,6 @@ help='Only cleanup expectations deleted or renamed in current CL. ' 'If flag is not used then a full cleanup of deleted or ' 'renamed tests will be done in expectations.') - # TODO(rmhasan): Move below arguments to the - # AndroidWPTExpectationsUpdater add_arguments implementation. - # Also look into using sub parsers to separate android and - # desktop specific arguments. - parser.add_argument( - '--update-android-expectations-only', action='store_true', - help='Update and clean up only Android test expectations.') - parser.add_argument( - '--android-product', action='append', default=[], - help='Android products whose baselines will be updated.', - choices=PRODUCTS) parser.add_argument( '--include-unexpected-pass', action='store_true',
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py index 0e89ac6..c48deedd 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -168,17 +168,6 @@ 'crbug.com/626703 [ Mac10.10 ] external/wpt/test/path.html [ Timeout ]\n' ) - def test_cmd_arg_include_unexpected_pass_raieses_exception(self): - host = self.mock_host() - expectations_path = \ - host.port_factory.get().path_to_generic_test_expectations_file() - host.filesystem.write_text_file(expectations_path, - WPTExpectationsUpdater.MARKER_COMMENT + '\n') - updater = WPTExpectationsUpdater(host, args=['--include-unexpected-pass']) - with self.assertRaises(AssertionError) as ctx: - updater.run() - self.assertIn('--include-unexpected-pass', str(ctx.exception)) - def test_get_failing_results_dict_only_passing_results(self): host = self.mock_host() result = """
diff --git a/third_party/blink/tools/wpt_update_expectations.py b/third_party/blink/tools/wpt_update_expectations.py index c7c40c2..3acac28d 100755 --- a/third_party/blink/tools/wpt_update_expectations.py +++ b/third_party/blink/tools/wpt_update_expectations.py
@@ -7,18 +7,12 @@ from blinkpy.common.host import Host from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater -from blinkpy.w3c.android_wpt_expectations_updater import ( - AndroidWPTExpectationsUpdater) def get_updater(host=None, args=None): host = host or Host() args = args or [] - if ('--update-android-expectations-only' in args or - any(arg.startswith('--android-product') for arg in args)): - return AndroidWPTExpectationsUpdater(host, args) - else: - return WPTExpectationsUpdater(host, args) + return WPTExpectationsUpdater(host, args) def main(args):
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 4a60281..2796ae1 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -414,8 +414,6 @@ crbug.com/1004547 external/wpt/intersection-observer/cross-origin-iframe.sub.html [ Failure Pass ] crbug.com/1007229 external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html [ Failure Pass ] -crbug.com/849459 fragmentation/repeating-thead-under-repeating-thead.html [ Failure ] - # These fail when device_scale_factor is changed, but only for anti-aliasing: crbug.com/968791 [ Mac ] virtual/scalefactor200/css3/filters/effect-blur-hw.html [ Failure Pass ] crbug.com/968791 virtual/scalefactor200/css3/filters/filterRegions.html [ Failure ] @@ -1625,6 +1623,7 @@ virtual/layout_ng_table_frag/external/wpt/css/css-break/table/table-row-paint-vlr-rtl.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/table-row-paint-vrl-rtl.html [ Pass ] virtual/layout_ng_table_frag/external/wpt/css/css-break/table/table-section-paint-vrl-rtl.html [ Pass ] +virtual/layout_ng_table_frag/fragmentation/repeating-thead-under-repeating-thead.html [ Pass ] virtual/layout_ng_table_frag/fragmentation/single-line-cells-repeating-thead-cell-straddles-page-unsplittable-div.html [ Pass ] ### Tests failing with LayoutNGTableFragmentation enabled: @@ -1669,7 +1668,6 @@ crbug.com/1078927 virtual/layout_ng_table_frag/fragmentation/table-row-dimensions-break-freely.html [ Failure ] crbug.com/1078927 virtual/layout_ng_table_frag/fragmentation/table-row-dimensions-with-thead.html [ Failure ] crbug.com/1078927 virtual/layout_ng_table_frag/fragmentation/table-row-page-break-collapsed-border.html [ Crash Failure ] -crbug.com/1078927 virtual/layout_ng_table_frag/fragmentation/thead-under-repeating-thead.html [ Failure ] ### With LayoutNGPrinting enabled: @@ -4029,6 +4027,7 @@ crbug.com/481431 external/wpt/css/css-multicol/multicol-zero-height-003.html [ Failure ] crbug.com/1191124 external/wpt/css/css-multicol/spanner-fragmentation-012.html [ Failure ] crbug.com/1224888 external/wpt/css/css-multicol/spanner-in-opacity.html [ Failure ] +crbug.com/849459 fragmentation/repeating-thead-under-repeating-thead.html [ Failure ] crbug.com/1078927 fragmentation/single-line-cells-repeating-thead-cell-straddles-page-unsplittable-div.html [ Failure ] crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-007.tentative.html [ Failure ] @@ -7079,3 +7078,6 @@ # Flaky on Windows crbug.com/1316343 [ Win ] external/wpt/web-bundle/subresource-loading/script-reuse-web-bundle-resource.https.tentative.html [ Failure ] + +# Manual test fails when run under automation due to lack of pop-up blocking. https://github.com/web-platform-tests/wpt/issues/3867 +crbug.com/1337125 external/wpt/window-placement/fullscreen-companion-window-manual.tentative.https.html [ Failure ]
diff --git a/third_party/blink/web_tests/WebDriverExpectations b/third_party/blink/web_tests/WebDriverExpectations index 42c9cb3..ddf9e41 100644 --- a/third_party/blink/web_tests/WebDriverExpectations +++ b/third_party/blink/web_tests/WebDriverExpectations
@@ -85,6 +85,11 @@ crbug.com/1167321 [ Linux ] external/wpt/webdriver/tests/find_element_from_shadow_root/find.py>>test_find_element[xpath-//a] [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_computed_label/get.py>>test_stale_element_reference[child_context] [ Failure ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_computed_label/get.py>>test_stale_element_reference[top_context] [ Failure ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_computed_role/get.py>>test_no_browsing_context [ Failure ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_computed_role/get.py>>test_stale_element_reference[child_context] [ Failure ] +crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_computed_role/get.py>>test_stale_element_reference[top_context] [ Failure ] crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/get_current_url/file.py>>test_get_current_url_file_protocol [ Failure ] crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/navigate_to/file.py>>test_file_protocol [ Failure ] crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/back/back.py>>test_data_urls [ Failure ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index 8ca897c..0cfc0eb 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: 61d1201b0719c18b4bd2992a4bd6de54dedcda1a +Version: 73380548ab5f7f6fe47ece278005b500e45f8c4d
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 198acd9..2afe2f5 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
@@ -723,6 +723,13 @@ {} ] ], + "nested-float-in-multicol-crash.html": [ + "6878d384e54b0f3262cbbfb0552b9d19e707140d", + [ + null, + {} + ] + ], "nested-multicol-with-spanners-and-oofs-crash.html": [ "d2e8ebb62196e2217e3e0594edb05618650e7aca", [ @@ -793,6 +800,17 @@ {} ] ], + "table": { + "repeated-section": { + "nested-repeated-header-crash.html": [ + "1dffcf821a113b6afe6c4205cee892007f83eb30", + [ + null, + {} + ] + ] + } + }, "uncontained-oof-in-inline-after-break-000-crash.html": [ "4d301e497749ddf0d2bfca3a5976a9877b45cff8", [ @@ -140835,6 +140853,19 @@ {} ] ], + "multicol-fill-balance-024.html": [ + "c31f0770678ba054ff652ac08ee0322dab92a89f", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "multicol-fill-balance-nested-000.html": [ "5e466df8077545b4d6474389d296bc26c5b28b86", [ @@ -143578,6 +143609,19 @@ {} ] ], + "resize-multicol-with-fixed-size-children.html": [ + "47c041b994eb79a7cf82eafdfb386e37142a852c", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "spanner-fragmentation-000.html": [ "f700235621a5833a53185ef2ab12d31343c3d35c", [ @@ -332897,13 +332941,13 @@ }, "execute_async_script": { "__init__.py": [ - "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "9cd37ecdca13921d71b70c9ce335e93fc0e0d799", [] ] }, "execute_script": { "__init__.py": [ - "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "1ab36eb054143df81bd41140f844916d9e2949c1", [] ] }, @@ -332925,7 +332969,7 @@ [] ], "conftest.py": [ - "b8fc93319f43a9f427ab9ce25fd863620559c4a6", + "5fd5f8a065cec7a8f3b612e23ab26e706afc7097", [] ] }, @@ -332947,7 +332991,7 @@ [] ], "conftest.py": [ - "b8fc93319f43a9f427ab9ce25fd863620559c4a6", + "5fd5f8a065cec7a8f3b612e23ab26e706afc7097", [] ] }, @@ -333027,7 +333071,7 @@ [] ], "conftest.py": [ - "afc0c91c3d3f2fcfe237e845bd1375124f8ebc56", + "4ca71025d69184d5f6edac66f700f5c6e71d5998", [] ] }, @@ -333281,7 +333325,7 @@ [] ], "fixtures_http.py": [ - "8c9c82bbadf49056d38e2d5ed9a282ecb45ba114", + "c0683dd7cc1ae03962f75d94023e3dc05383698b", [] ], "helpers.py": [ @@ -373557,6 +373601,13 @@ {} ] ], + "column-spanner-in-container.html": [ + "d494e28504fb6be56fb79b53f68507071f39ce72", + [ + null, + {} + ] + ], "conditional-container-status.html": [ "e9762f93239ac674897827aff1bd6eb5727abdab", [ @@ -373816,6 +373867,20 @@ {} ] ], + "grid-container.html": [ + "60278e09c69f3fb5718e75ebaebcf04da1e146de", + [ + null, + {} + ] + ], + "grid-item-container.html": [ + "f1c66efc26d9f96db833c17900852b1ffeb69991", + [ + null, + {} + ] + ], "idlharness.html": [ "ac1a677bb94d045d9aa6ce8b49bb85cbff51cc92", [ @@ -379643,6 +379708,34 @@ {} ] ], + "grid-template-columns-neutral-keyframe-001.html": [ + "070539e2c0eda9cbc8585f8bd1fc4217485d97e4", + [ + null, + {} + ] + ], + "grid-template-columns-neutral-keyframe-002.html": [ + "6cd163711ee599366280b352dcb808e83ea2899f", + [ + null, + {} + ] + ], + "grid-template-columns-neutral-keyframe-003.html": [ + "80187cf68487bf3af4d39a0799b30886600e61f3", + [ + null, + {} + ] + ], + "grid-template-columns-neutral-keyframe-004.html": [ + "a207aa713c971cda94052dc8abf810f1e1cb29fd", + [ + null, + {} + ] + ], "grid-template-rows-composition.html": [ "42f9c92e9ad6d2042553e7e4b440adeeddf09bab", [ @@ -379656,6 +379749,34 @@ null, {} ] + ], + "grid-template-rows-neutral-keyframe-001.html": [ + "ecbe0481eded5ede38ab482b9175555258f82861", + [ + null, + {} + ] + ], + "grid-template-rows-neutral-keyframe-002.html": [ + "f63d45b4a71929ae703bd1dc51b875c0c843b12e", + [ + null, + {} + ] + ], + "grid-template-rows-neutral-keyframe-003.html": [ + "5ffd67528ca91f27ae801fe8930745a27c61df0b", + [ + null, + {} + ] + ], + "grid-template-rows-neutral-keyframe-004.html": [ + "941e843624837b16506b9900cc0736f3ca8a5a5f", + [ + null, + {} + ] ] }, "chrome-crash-001.html": [ @@ -399831,6 +399952,13 @@ {} ] ], + "has-error-recovery.html": [ + "143638c9e325f13576a02e19151a42eec4684408", + [ + null, + {} + ] + ], "has-matches-to-uninserted-elements.html": [ "4d6c8cf2e35f4421b1232b2720184a61a26cb9f9", [ @@ -587962,7 +588090,7 @@ ] ], "click.py": [ - "b1b10162e4d62b3bf22867c6543d84a16d5c4ac1", + "8abcfe789d4e9b721f824a37b3f6873783a6c420", [ null, {} @@ -588010,13 +588138,6 @@ {} ] ], - "stale.py": [ - "8d2ae348ef4f774d972ab5f36f3ed312357179bc", - [ - null, - {} - ] - ], "user_prompts.py": [ "140aceb3cedfe84ec8f9a3ac0285497b6e670285", [ @@ -588071,7 +588192,7 @@ ] ], "send_keys.py": [ - "aa393e16d814dbdc2f6db16fe1d22d963073e2a7", + "3cb1c7469d8a81855716d3109ee039e80b5ef84f", [ null, {} @@ -588089,35 +588210,35 @@ }, "execute_async_script": { "collections.py": [ - "49657711e28cbc51e7bad7671031e93d73739d60", + "38b7c260161ed9afff9e891287e4ae152abaa8d4", [ null, {} ] ], "execute_async.py": [ - "5746ed6f05f37d7329308a5f46d47550c8a78164", + "49e8675ba0aea791b893e21bd1b80bccb4ea5970", [ null, {} ] ], "promise.py": [ - "8b6d7d9157b28570e7984491e02e42f6a64ce15c", + "d726d0d71283033086b1ca8851b444968654876b", [ null, {} ] ], "properties.py": [ - "e51b3e3ea579019e8b9e29ff3ccd4a375a0a39d9", + "b9592e7edd40a5d4225fc0fc7d2c6bbade01307e", [ null, {} ] ], "user_prompts.py": [ - "5c873935519716a3f4933b710828118218f7220c", + "e39574fd4ac1b734006614c4ab6caf0a9542676b", [ null, { @@ -588128,49 +588249,49 @@ }, "execute_script": { "collections.py": [ - "4d88d497060480043682df29298387d150bf9055", + "60b7797d5219e4e42a3a69b97b69998a39a03524", [ null, {} ] ], "cyclic.py": [ - "e3094f89f3b7e0d5305a9a1726a2f424f38717f3", + "3bcc73890c9a044658ee0b1fb78cd8c20941ce26", [ null, {} ] ], "execute.py": [ - "0f934cbb4450107c70f268762bac7036db4f1fb8", + "31397cb176195fb659c8f62ea1278c87c3bdd930", [ null, {} ] ], "json_serialize_windowproxy.py": [ - "9864227374e328514d54596f611c474c6f0fe3f3", + "8e76feda23809bf65a77c6bcd3994209aaba40e0", [ null, {} ] ], "promise.py": [ - "8bb637853ccd789f128a8293a678f58cfe030912", + "c206674baefc75d23443fb5b7999ef465b09a3e2", [ null, {} ] ], "properties.py": [ - "51999936e71aae5584f73ba661d5e355cf0a732e", + "c3b01dea29b5a160cda24ea82d0135cb1761032b", [ null, {} ] ], "user_prompts.py": [ - "ec6895b74f8e110120f2e3067e2c35b94d2a532d", + "48d735ea754c0f74726d5a89f43eabb245b8bc5a", [ null, { @@ -588203,7 +588324,7 @@ }, "find_element_from_shadow_root": { "user_prompts.py": [ - "e1326cf599a4affe3c269f205bdbd4e791b8f346", + "ee79ed79f479a9bc5daee016a44c0ea453f3393e", [ null, { @@ -588236,7 +588357,7 @@ }, "find_elements_from_shadow_root": { "user_prompts.py": [ - "9950999226debc864f66e2096e8d2108c620f022", + "8ec381b3870dda9651b144ed628e9a0bbc1fe104", [ null, { @@ -588319,7 +588440,7 @@ }, "get_computed_label": { "get.py": [ - "f27f3d7093aa7a12c46bd95b9b4be79f42921597", + "d10ccf7f24b36eb784bf09e4e10f3a8d094102c3", [ null, {} @@ -588328,7 +588449,7 @@ }, "get_computed_role": { "get.py": [ - "2a7053d640bb35c0a0c8fc3ca622e46b9342863d", + "bc4be6efd658fce26771aca8f047d91c75e766be", [ null, {} @@ -588369,7 +588490,7 @@ }, "get_element_attribute": { "get.py": [ - "528cbd29f020cafa60cdd20fc5047fc4ac9c1e65", + "5119949fedb3e1663f7a4610b11ef1a71d562278", [ null, {} @@ -588387,7 +588508,7 @@ }, "get_element_css_value": { "get.py": [ - "369ca9c699f883ba59dab171c4f6d7b80e35164d", + "5ab0b3b58dc7b332beeeb989cb2f65c0f9db8e53", [ null, {} @@ -588405,7 +588526,7 @@ }, "get_element_property": { "get.py": [ - "10f7a08ae73e92b94cde668e71275fda3e35379d", + "6c15545b26589ccb05870c9b197390c555a14a80", [ null, {} @@ -588423,7 +588544,7 @@ }, "get_element_rect": { "get.py": [ - "9ab4db4c604ff93a22a88ae3917db7cd8a47d396", + "a12b8d4e4f6b13c938b6d145d7667e9965e77802", [ null, {} @@ -588441,14 +588562,14 @@ }, "get_element_shadow_root": { "get.py": [ - "82e52420a2c0bdbae4680a54bafbbd4e7cf17e1d", + "3cf3c6521daed9e5053202af3d2144c8b1bb7fde", [ null, {} ] ], "user_prompts.py": [ - "32671b95a535a9fc14e4881a47f4c7c8031c485c", + "b94650a6f0b7271c8098b93078cab7fd8f8e3974", [ null, { @@ -588459,7 +588580,7 @@ }, "get_element_tag_name": { "get.py": [ - "cfc63bd788de2e38d7c092aeaea61a78411f1b65", + "b163a58b71a7be3a264021e0c978d76986e1b706", [ null, {} @@ -588477,7 +588598,7 @@ }, "get_element_text": { "get.py": [ - "72dc0cf735e51aeeb0a098497c5793cbc59493e1", + "d2a1f180eeea436441940cd2dee0172bd1a5d831", [ null, {} @@ -588628,7 +588749,7 @@ }, "is_element_enabled": { "enabled.py": [ - "4a5a92ba5e912d1120a0a2fc1732eeaba7b901ac", + "5e8548ba827060ed68e21366293c574ae4e8ecbd", [ null, {} @@ -588646,7 +588767,7 @@ }, "is_element_selected": { "selected.py": [ - "6c8e8155cab17be937b1e259ed6ec67ac38d4235", + "4dbc7974d22501f394e0d5682d5772507a70d1ba", [ null, {} @@ -588889,7 +589010,7 @@ ] ], "pointer.py": [ - "674d46d7b610294b6cadabb4e1e46d79cab8940d", + "53e1535019bc4366746cef979e444e0d7d25c529", [ null, { @@ -589107,7 +589228,7 @@ ] ], "switch_webelement.py": [ - "a30d2d8d339cfc4aeca83460942bb78f640850c3", + "465efb76e01d42819f502cf7c5d3e2a764e31507", [ null, {} @@ -589148,7 +589269,7 @@ ] ], "screenshot.py": [ - "4d3bfb0e5c68b4a73253010e199606866f90ee03", + "79ffa15b7461ac6e2ae7087090fafc0ae91cd4fe", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/nested-repeated-header-crash.html b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/nested-repeated-header-crash.html new file mode 100644 index 0000000..1dffcf8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/table/repeated-section/nested-repeated-header-crash.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1336683"> +<style> + thead { break-inside: avoid; } + td { padding: 0; } + table { border-spacing: 0; } +</style> +<p>PASS if no freeze.</p> +<div style="columns:2; column-fill:auto; height:700px;"> + <table> + <thead> + <tr> + <td> + <div style="columns:2; column-fill:auto; height:120px; background:yellow;"> + <table> + <thead> + <tr> + <td> + <div style="width:50px; height:20px; background:hotpink;"></div> + </td> + </tr> + </thead> + <tr><td style="height:100px;"></td></tr> + <tr><td style="height:100px;"></td></tr> + </table> + </div> + </td> + </tr> + </thead> + <tr><td style="height:400px; background:blue;"></td></tr> + <tr><td style="height:400px; background:orange;"></td></tr> + </table> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/has-error-recovery.html b/third_party/blink/web_tests/external/wpt/css/selectors/has-error-recovery.html new file mode 100644 index 0000000..143638c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/has-error-recovery.html
@@ -0,0 +1,53 @@ +<!doctype html> +<title>CSS Selectors: :has() error recovery</title> +<link rel="help" href="https://drafts.csswg.org/selectors/#relational"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#typedef-forgiving-selector-list"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style id="test-sheet"> + random-selector { color: blue; } +</style> +<div id="test-div"> + <div id="test-descendant"> + </div> +</div> +<script> + let rule = document.getElementById("test-sheet").sheet.cssRules[0]; + test(function() { + rule.selectorText = "random-selector"; + let invalidSelector = `:has(:total-nonsense)`; + rule.selectorText = invalidSelector; + assert_not_equals( + rule.selectorText, + "random-selector", + "Should've parsed", + ); + assert_not_equals( + rule.selectorText, + invalidSelector, + "Should not be considered valid and parsed as-is", + ); + let emptyList = `:has()`; + assert_equals( + rule.selectorText, + emptyList, + "Should be serialized as an empty selector-list", + ); + assert_equals(document.querySelector(emptyList), null, "Should never match, but should parse"); + for (let mixedList of [ + `:has(:total-nonsense, #test-descendant)`, + `:has(:total-nonsense and-more-stuff, #test-descendant)`, + `:has(weird-token || and-more-stuff, #test-descendant)`, + ]) { + rule.selectorText = mixedList; + assert_equals( + rule.selectorText, + `:has(#test-descendant)`, + `${mixedList}: Should ignore invalid selectors`, + ); + let testDiv = document.getElementById("test-div"); + assert_equals(document.querySelector(mixedList), testDiv, "Should correctly match"); + assert_equals(getComputedStyle(testDiv).color, "rgb(0, 0, 255)", "test element should be blue"); + } + }); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/click.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/click.py index b1b10162..8abcfe7 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/click.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/click.py
@@ -1,3 +1,4 @@ +import pytest from webdriver import Element from tests.support.asserts import assert_error, assert_success @@ -38,3 +39,11 @@ response = element_click(session, element) assert_error(response, "no such window") + + +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<div>", "div", as_frame=as_frame) + + response = element_click(session, element) + assert_error(response, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/stale.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/stale.py deleted file mode 100644 index 8d2ae34..0000000 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_click/stale.py +++ /dev/null
@@ -1,17 +0,0 @@ -from tests.support.asserts import assert_error - - -def element_click(session, element): - return session.transport.send( - "POST", "/session/{session_id}/element/{element_id}/click".format( - session_id=session.session_id, - element_id=element.id)) - - -def test_is_stale(session, inline): - session.url = inline("<button>foo</button>") - button = session.find.css("button", all=False) - session.url = inline("<button>bar</button>") - - response = element_click(session, button) - assert_error(response, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_send_keys/send_keys.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_send_keys/send_keys.py index aa393e16..3cb1c74 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/element_send_keys/send_keys.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/element_send_keys/send_keys.py
@@ -54,6 +54,14 @@ assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + + response = element_send_keys(session, element, "foo") + assert_error(response, "stale element reference") + + @pytest.mark.parametrize("value", [True, None, 1, [], {}]) def test_invalid_text_type(session, inline, value): session.url = inline("<input>") @@ -61,13 +69,3 @@ response = element_send_keys(session, element, value) assert_error(response, "invalid argument") - - -def test_stale_element(session, inline): - session.url = inline("<input>") - element = session.find.css("input", all=False) - - session.refresh() - - response = element_send_keys(session, element, "foo") - assert_error(response, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/__init__.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/__init__.py index e69de29..9cd37ec 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/__init__.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/__init__.py
@@ -0,0 +1,16 @@ +import webdriver.protocol as protocol + + +def execute_async_script(session, script, args=None): + if args is None: + args = [] + body = {"script": script, "args": args} + + return session.transport.send( + "POST", + "/session/{session_id}/execute/async".format(**vars(session)), + body, + encoder=protocol.Encoder, + decoder=protocol.Decoder, + session=session, + )
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/collections.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/collections.py index 4965771..38b7c26 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/collections.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/collections.py
@@ -1,16 +1,9 @@ import os +from webdriver.client import ShadowRoot + from tests.support.asserts import assert_same_element, assert_success - - -def execute_async_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/async".format(**vars(session)), - body) +from . import execute_async_script def test_arguments(session): @@ -185,6 +178,5 @@ resolve(document.querySelector('custom-checkbox-element').shadowRoot); """) value = assert_success(response) - assert isinstance(value, dict) - assert "shadow-6066-11e4-a52e-4f735466cecf" in value - assert value["shadow-6066-11e4-a52e-4f735466cecf"] == expected.id + assert isinstance(value, ShadowRoot) + assert value.id == expected.id
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/execute_async.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/execute_async.py index 5746ed6..49e8675b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/execute_async.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/execute_async.py
@@ -5,16 +5,7 @@ from tests.support.asserts import assert_error, assert_success from tests.support.sync import Poll - - -def execute_async_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/async".format(**vars(session)), - body) +from . import execute_async_script def test_null_parameter_value(session, http): @@ -33,6 +24,33 @@ assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference_as_argument(session, stale_element, as_frame): + element = stale_element("<div>", "div", as_frame=as_frame) + + result = execute_async_script(session, "arguments[0](1);", args=[element]) + assert_error(result, "stale element reference") + + +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference_as_returned_value(session, iframe, inline, as_frame): + if as_frame: + session.url = inline(iframe("<div>")) + frame = session.find.css("iframe", all=False) + session.switch_frame(frame) + else: + session.url = inline("<div>") + + element = session.find.css("div", all=False) + + result = execute_async_script(session, """ + const [elem, resolve] = arguments; + elem.remove(); + resolve(elem); + """, args=[element]) + assert_error(result, "stale element reference") + + @pytest.mark.parametrize("dialog_type", ["alert", "confirm", "prompt"]) def test_abort_by_user_prompt(session, dialog_type): response = execute_async_script(
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/promise.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/promise.py index 8b6d7d915..d726d0d 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/promise.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/promise.py
@@ -1,14 +1,5 @@ from tests.support.asserts import assert_error, assert_success - - -def execute_async_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/async".format(**vars(session)), - body) +from . import execute_async_script def test_promise_resolve(session):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/properties.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/properties.py index e51b3e3..b9592e7 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/properties.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/properties.py
@@ -1,13 +1,5 @@ from tests.support.asserts import assert_same_element, assert_success - - -def execute_async_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - return session.transport.send( - "POST", "/session/{session_id}/execute/async".format(**vars(session)), - body) +from . import execute_async_script def test_content_attribute(session, inline):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/user_prompts.py index 5c87393..e39574fd 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_async_script/user_prompts.py
@@ -3,16 +3,7 @@ import pytest from tests.support.asserts import assert_dialog_handled, assert_error, assert_success - - -def execute_async_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/async".format(**vars(session)), - body) +from . import execute_async_script @pytest.fixture
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/__init__.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/__init__.py index e69de29..1ab36eb 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/__init__.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/__init__.py
@@ -0,0 +1,16 @@ +import webdriver.protocol as protocol + + +def execute_script(session, script, args=None): + if args is None: + args = [] + body = {"script": script, "args": args} + + return session.transport.send( + "POST", + "/session/{session_id}/execute/sync".format(**vars(session)), + body, + encoder=protocol.Encoder, + decoder=protocol.Decoder, + session=session, + )
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/collections.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/collections.py index 4d88d497..60b7797 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/collections.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/collections.py
@@ -1,16 +1,9 @@ import os +from webdriver.client import ShadowRoot + from tests.support.asserts import assert_same_element, assert_success - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format(**vars(session)), - body) +from . import execute_script def test_arguments(session): @@ -161,6 +154,5 @@ response = execute_script(session, "return document.querySelector('custom-checkbox-element').shadowRoot") value = assert_success(response) - assert isinstance(value, dict) - assert "shadow-6066-11e4-a52e-4f735466cecf" in value - assert value["shadow-6066-11e4-a52e-4f735466cecf"] == expected.id + assert isinstance(value, ShadowRoot) + assert value.id == expected.id
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/cyclic.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/cyclic.py index e3094f8..3bcc738 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/cyclic.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/cyclic.py
@@ -1,15 +1,5 @@ from tests.support.asserts import assert_error, assert_same_element, assert_success - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format( - session_id=session.session_id), - body) +from . import execute_script def test_array(session):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/execute.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/execute.py index 0f934cbb..31397cb 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/execute.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/execute.py
@@ -1,21 +1,10 @@ import pytest - from webdriver.error import NoSuchAlertException from webdriver.transport import Response from tests.support.asserts import assert_error, assert_success from tests.support.sync import Poll - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format( - session_id=session.session_id), - body) +from . import execute_script def test_null_parameter_value(session, http): @@ -34,6 +23,33 @@ assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference_as_argument(session, stale_element, as_frame): + element = stale_element("<div>", "div", as_frame=as_frame) + + result = execute_script(session, "return 1;", args=[element]) + assert_error(result, "stale element reference") + + +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference_as_returned_value(session, iframe, inline, as_frame): + if as_frame: + session.url = inline(iframe("<div>")) + frame = session.find.css("iframe", all=False) + session.switch_frame(frame) + else: + session.url = inline("<div>") + + element = session.find.css("div", all=False) + + result = execute_script(session, """ + const elem = arguments[0]; + elem.remove(); + return elem; + """, args=[element]) + assert_error(result, "stale element reference") + + def test_opening_new_window_keeps_current_window_handle(session, inline): original_handle = session.window_handle original_handles = session.handles
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/json_serialize_windowproxy.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/json_serialize_windowproxy.py index 9864227..8e76feda 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/json_serialize_windowproxy.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/json_serialize_windowproxy.py
@@ -1,22 +1,12 @@ import json from tests.support.asserts import assert_success - +from . import execute_script _window_id = "window-fcc6-11e5-b4f8-330a88ab9d7f" _frame_id = "frame-075b-4da1-b6ba-e579c2d3230a" -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format(**vars(session)), - body) - - def test_initial_window(session): # non-auxiliary top-level browsing context response = execute_script(session, "return window;")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/promise.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/promise.py index 8bb6378..c206674 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/promise.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/promise.py
@@ -1,15 +1,5 @@ from tests.support.asserts import assert_error, assert_success - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format( - session_id=session.session_id), - body) +from . import execute_script def test_promise_resolve(session):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/properties.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/properties.py index 51999936..c3b01de 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/properties.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/properties.py
@@ -1,13 +1,5 @@ from tests.support.asserts import assert_same_element, assert_success - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format(**vars(session)), - body) +from . import execute_script def test_content_attribute(session, inline):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/user_prompts.py index ec6895b7..48d735e 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/execute_script/user_prompts.py
@@ -3,17 +3,7 @@ import pytest from tests.support.asserts import assert_dialog_handled, assert_error, assert_success - - -def execute_script(session, script, args=None): - if args is None: - args = [] - body = {"script": script, "args": args} - - return session.transport.send( - "POST", "/session/{session_id}/execute/sync".format( - session_id=session.session_id), - body) +from . import execute_script @pytest.fixture
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/conftest.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/conftest.py index b8fc9331..5fd5f8a0 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/conftest.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/conftest.py
@@ -1,9 +1,9 @@ import pytest @pytest.fixture -def get_shadow_page(inline): +def get_shadow_page(): def get_shadow_page(shadow_content): - return inline(""" + return """ <custom-shadow-element></custom-shadow-element> <script> customElements.define('custom-shadow-element', @@ -15,5 +15,5 @@ `; }} }}); - </script>""".format(shadow_content)) + </script>""".format(shadow_content) return get_shadow_page
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/user_prompts.py index e1326cf..ee79ed7 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_element_from_shadow_root/user_prompts.py
@@ -19,9 +19,9 @@ @pytest.fixture -def check_user_prompt_closed_without_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_closed_without_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_closed_without_exception(dialog_type, retval): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root inner_element = session.execute_script("return arguments[0].shadowRoot.querySelector('p')", @@ -40,9 +40,9 @@ @pytest.fixture -def check_user_prompt_closed_with_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_closed_with_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_closed_with_exception(dialog_type, retval): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root @@ -57,9 +57,9 @@ @pytest.fixture -def check_user_prompt_not_closed_but_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_not_closed_but_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_not_closed_but_exception(dialog_type): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/conftest.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/conftest.py index b8fc9331..5fd5f8a0 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/conftest.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/conftest.py
@@ -1,9 +1,9 @@ import pytest @pytest.fixture -def get_shadow_page(inline): +def get_shadow_page(): def get_shadow_page(shadow_content): - return inline(""" + return """ <custom-shadow-element></custom-shadow-element> <script> customElements.define('custom-shadow-element', @@ -15,5 +15,5 @@ `; }} }}); - </script>""".format(shadow_content)) + </script>""".format(shadow_content) return get_shadow_page
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/user_prompts.py index 9950999..8ec381b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/find_elements_from_shadow_root/user_prompts.py
@@ -19,9 +19,9 @@ @pytest.fixture -def check_user_prompt_closed_without_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_closed_without_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_closed_without_exception(dialog_type, retval): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root inner_element = session.execute_script("return arguments[0].shadowRoot.querySelector('p')", @@ -42,9 +42,9 @@ @pytest.fixture -def check_user_prompt_closed_with_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_closed_with_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_closed_with_exception(dialog_type, retval): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root @@ -59,9 +59,9 @@ @pytest.fixture -def check_user_prompt_not_closed_but_exception(session, create_dialog, get_shadow_page): +def check_user_prompt_not_closed_but_exception(session, create_dialog, inline, get_shadow_page): def check_user_prompt_not_closed_but_exception(dialog_type): - session.url = get_shadow_page("<div><p>bar</p><div>") + session.url = inline(get_shadow_page("<div><p>bar</p><div>")) outer_element = session.find.css("custom-shadow-element", all=False) shadow_root = outer_element.shadow_root
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_label/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_label/get.py index f27f3d7..d10ccf7f 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_label/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_label/get.py
@@ -5,20 +5,28 @@ from tests.support.asserts import assert_error, assert_success -def get_computed_label(session, element): +def get_computed_label(session, element_id): return session.transport.send( "GET", "session/{session_id}/element/{element_id}/computedlabel".format( session_id=session.session_id, - element_id=element)) + element_id=element_id)) -def test_no_browsing_context(session, closed_window): - response = get_computed_label(session) +def test_no_browsing_context(session, closed_frame): + response = get_computed_label(session, "foo") assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + + response = get_computed_label(session, element.id) + assert_error(response, "stale element reference") + + def test_no_user_prompt(session): - response = get_computed_label(session) + response = get_computed_label(session, "foo") assert_error(response, "no such alert")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_role/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_role/get.py index 2a7053d..bc4be6e 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_role/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_computed_role/get.py
@@ -5,20 +5,28 @@ from tests.support.asserts import assert_error, assert_success -def get_computed_role(session, element): +def get_computed_role(session, element_id): return session.transport.send( "GET", "session/{session_id}/element/{element_id}/computedrole".format( session_id=session.session_id, - element_id=element)) + element_id=element_id)) -def test_no_browsing_context(session, closed_window): - response = get_computed_role(session, "id") +def test_no_browsing_context(session, closed_frame): + response = get_computed_role(session, "foo") assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + + response = get_computed_role(session, element.id) + assert_error(response, "stale element reference") + + def test_no_user_prompt(session): - response = get_computed_role(session, "id") + response = get_computed_role(session, "foo") assert_error(response, "no such alert")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_attribute/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_attribute/get.py index 528cbd2..5119949 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_attribute/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_attribute/get.py
@@ -33,10 +33,10 @@ assert_error(result, "no such element") -def test_element_stale(session, inline): - session.url = inline("<input id=foo>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + result = get_element_attribute(session, element.id, "id") assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_css_value/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_css_value/get.py index 369ca9c..5ab0b3b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_css_value/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_css_value/get.py
@@ -1,3 +1,5 @@ +import pytest + from tests.support.asserts import assert_error, assert_success @@ -34,10 +36,9 @@ assert_error(result, "no such element") -def test_element_stale(session, inline): - session.url = inline("<input>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) result = get_element_css_value(session, element.id, "display") assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_property/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_property/get.py index 10f7a08..6c15545 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_property/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_property/get.py
@@ -33,13 +33,12 @@ assert_error(response, "no such element") -def test_element_stale(session, inline): - session.url = inline("<input id=foobar>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) - response = get_element_property(session, element.id, "id") - assert_error(response, "stale element reference") + result = get_element_property(session, element.id, "id") + assert_error(result, "stale element reference") def test_property_non_existent(session, inline):
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_rect/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_rect/get.py index 9ab4db4..a12b8d4 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_rect/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_rect/get.py
@@ -1,3 +1,5 @@ +import pytest + from tests.support.asserts import assert_error, assert_success from tests.support.helpers import element_rect @@ -34,10 +36,9 @@ assert_error(result, "no such element") -def test_element_stale(session, inline): - session.url = inline("<input>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) result = get_element_rect(session, element.id) assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/conftest.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/conftest.py index afc0c91c..4ca7102 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/conftest.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/conftest.py
@@ -2,7 +2,7 @@ @pytest.fixture def checkbox_dom(inline): - return inline(""" + return """ <style> custom-checkbox-element { display:block; width:20px; height:20px; @@ -19,4 +19,4 @@ `; } }); - </script>""") + </script>"""
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/get.py index 82e5242..3cf3c65 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/get.py
@@ -32,17 +32,16 @@ assert_error(result, "no such element") -def test_element_stale(session, checkbox_dom): - session.url = checkbox_dom - element = session.find.css("custom-checkbox-element", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, checkbox_dom, as_frame): + element = stale_element(checkbox_dom, "custom-checkbox-element", as_frame=as_frame) result = get_shadow_root(session, element.id) assert_error(result, "stale element reference") -def test_get_shadow_root(session, checkbox_dom): - session.url = checkbox_dom +def test_get_shadow_root(session, inline, checkbox_dom): + session.url = inline(checkbox_dom) expected = session.execute_script( "return document.querySelector('custom-checkbox-element').shadowRoot.host") custom_element = session.find.css("custom-checkbox-element", all=False)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/user_prompts.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/user_prompts.py index 32671b95..b94650a 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/user_prompts.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_shadow_root/user_prompts.py
@@ -13,9 +13,9 @@ @pytest.fixture -def check_user_prompt_closed_without_exception(session, create_dialog, checkbox_dom): +def check_user_prompt_closed_without_exception(session, create_dialog, inline, checkbox_dom): def check_user_prompt_closed_without_exception(dialog_type, retval): - session.url = checkbox_dom + session.url = inline(checkbox_dom) element = session.find.css("custom-checkbox-element", all=False) create_dialog(dialog_type, text=dialog_type) @@ -30,9 +30,9 @@ @pytest.fixture -def check_user_prompt_closed_with_exception(session, create_dialog, checkbox_dom): +def check_user_prompt_closed_with_exception(session, create_dialog, inline, checkbox_dom): def check_user_prompt_closed_with_exception(dialog_type, retval): - session.url = checkbox_dom + session.url = inline(checkbox_dom) element = session.find.css("custom-checkbox-element", all=False) create_dialog(dialog_type, text=dialog_type) @@ -46,9 +46,9 @@ @pytest.fixture -def check_user_prompt_not_closed_but_exception(session, create_dialog, checkbox_dom): +def check_user_prompt_not_closed_but_exception(session, create_dialog, inline, checkbox_dom): def check_user_prompt_not_closed_but_exception(dialog_type): - session.url = checkbox_dom + session.url = inline(checkbox_dom) element = session.find.css("custom-checkbox-element", all=False) create_dialog(dialog_type, text=dialog_type)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_tag_name/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_tag_name/get.py index cfc63bd78..b163a58 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_tag_name/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_tag_name/get.py
@@ -1,3 +1,5 @@ +import pytest + from tests.support.asserts import assert_error, assert_success @@ -30,10 +32,9 @@ assert_error(result, "no such element") -def test_element_stale(session, inline): - session.url = inline("<input id=foo>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) result = get_element_tag_name(session, element.id) assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_text/get.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_text/get.py index 72dc0cf7..d2a1f18 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_text/get.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/get_element_text/get.py
@@ -1,3 +1,5 @@ +import pytest + from tests.support.asserts import assert_error, assert_success @@ -25,6 +27,14 @@ assert_error(response, "no such window") +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + + response = get_element_text(session, element.id) + assert_error(response, "stale element reference") + + def test_getting_text_of_a_non_existant_element_is_an_error(session, inline): session.url = inline("""<body>Hello world</body>""")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_enabled/enabled.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_enabled/enabled.py index 4a5a92b..5e8548b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_enabled/enabled.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_enabled/enabled.py
@@ -30,10 +30,9 @@ assert_error(response, "no such window") -def test_element_stale(session, inline): - session.url = inline("<input>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) result = is_element_enabled(session, element.id) assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_selected/selected.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_selected/selected.py index 6c8e815..4dbc7974d 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_selected/selected.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/is_element_selected/selected.py
@@ -1,23 +1,24 @@ import pytest + from tests.support.asserts import assert_error, assert_success @pytest.fixture -def check_doc(inline): - return inline(""" +def check_doc(): + return """ <input id=checked type=checkbox checked> <input id=notChecked type=checkbox> - """) + """ @pytest.fixture -def option_doc(inline): - return inline(""" +def option_doc(): + return """ <select> <option id=notSelected>r- <option id=selected selected>r+ </select> - """) + """ def is_element_selected(session, element_id): @@ -45,41 +46,40 @@ assert_error(response, "no such window") -def test_element_stale(session, check_doc): - session.url = check_doc - element = session.find.css("#checked", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, check_doc, as_frame): + element = stale_element(check_doc, "#checked", as_frame=as_frame) result = is_element_selected(session, element.id) assert_error(result, "stale element reference") -def test_element_checked(session, check_doc): - session.url = check_doc +def test_element_checked(session, inline, check_doc): + session.url = inline(check_doc) element = session.find.css("#checked", all=False) result = is_element_selected(session, element.id) assert_success(result, True) -def test_checkbox_not_selected(session, check_doc): - session.url = check_doc +def test_checkbox_not_selected(session, inline, check_doc): + session.url = inline(check_doc) element = session.find.css("#notChecked", all=False) result = is_element_selected(session, element.id) assert_success(result, False) -def test_element_selected(session, option_doc): - session.url = option_doc +def test_element_selected(session, inline, option_doc): + session.url = inline(option_doc) element = session.find.css("#selected", all=False) result = is_element_selected(session, element.id) assert_success(result, True) -def test_element_not_selected(session, option_doc): - session.url = option_doc +def test_element_not_selected(session, inline, option_doc): + session.url = inline(option_doc) element = session.find.css("#notSelected", all=False) result = is_element_selected(session, element.id)
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py index 674d46d..53e1535 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/perform_actions/pointer.py
@@ -2,7 +2,7 @@ import pytest -from webdriver.error import NoSuchWindowException +from webdriver.error import NoSuchWindowException, StaleElementReferenceException from tests.perform_actions.support.mouse import get_inview_center, get_viewport_rect from tests.perform_actions.support.refine import get_events @@ -26,6 +26,14 @@ mouse_chain.click().perform() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, mouse_chain, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) + + with pytest.raises(StaleElementReferenceException): + mouse_chain.click(element=element).perform() + + def test_click_at_coordinates(session, test_actions_page, mouse_chain): div_point = { "x": 82,
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_http.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_http.py index 8c9c82b..c0683dd7 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_http.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures_http.py
@@ -163,3 +163,27 @@ return current_session.execute_script("return Date.now();") return _timestamp + + +@pytest.fixture +def stale_element(current_session, iframe, inline): + """Create a stale element reference + + The given document will be loaded in the top-level or child browsing context. + Before the requested element is returned it is removed from the document's DOM. + """ + def stale_element(doc, css_value, as_frame=False): + if as_frame: + current_session.url = inline(iframe(doc)) + frame = current_session.find.css("iframe", all=False) + current_session.switch_frame(frame) + else: + current_session.url = inline(doc) + + element = current_session.find.css(css_value, all=False) + + current_session.execute_script("arguments[0].remove();", args=[element]) + + return element + + return stale_element
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/switch_to_frame/switch_webelement.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/switch_to_frame/switch_webelement.py index a30d2d8..465efb7 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/switch_to_frame/switch_webelement.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/switch_to_frame/switch_webelement.py
@@ -18,6 +18,31 @@ return "<frameset rows='{}'>\n{}</frameset>".format(len(frames) * "*,", "\n".join(frames)) +def test_frame_id_webelement_no_element_reference(session, inline, iframe): + session.url = inline(iframe("<p>foo")) + frame = session.find.css("iframe", all=False) + frame.id = "bar" + + response = switch_to_frame(session, frame) + assert_error(response, "no such element") + + +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, iframe, stale_element, as_frame): + frame = stale_element(iframe("<div>"), "iframe", as_frame=as_frame) + + result = switch_to_frame(session, frame) + assert_error(result, "stale element reference") + + +def test_frame_id_webelement_no_frame_element(session, inline): + session.url = inline("<p>foo") + no_frame = session.find.css("p", all=False) + + response = switch_to_frame(session, no_frame) + assert_error(response, "no such frame") + + @pytest.mark.parametrize("index, value", [[0, "foo"], [1, "bar"]]) def test_frame_id_webelement_frame(session, inline, index, value): session.url = inline(frameset(inline, "<p>foo", "<p>bar")) @@ -57,33 +82,6 @@ assert element.text == expected_text[i] -def test_frame_id_webelement_no_element_reference(session, inline, iframe): - session.url = inline(iframe("<p>foo")) - frame = session.find.css("iframe", all=False) - frame.id = "bar" - - response = switch_to_frame(session, frame) - assert_error(response, "no such element") - - -def test_frame_id_webelement_stale_reference(session, inline, iframe): - session.url = inline(iframe("<p>foo")) - frame = session.find.css("iframe", all=False) - - session.refresh() - - response = switch_to_frame(session, frame) - assert_error(response, "stale element reference") - - -def test_frame_id_webelement_no_frame_element(session, inline): - session.url = inline("<p>foo") - no_frame = session.find.css("p", all=False) - - response = switch_to_frame(session, no_frame) - assert_error(response, "no such frame") - - def test_frame_id_webelement_cloned_into_iframe(session, inline, iframe): session.url = inline(iframe("<body><p>hello world</p></body>"))
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/take_element_screenshot/screenshot.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/take_element_screenshot/screenshot.py index 4d3bfb0..79ffa15b 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/take_element_screenshot/screenshot.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/take_element_screenshot/screenshot.py
@@ -1,6 +1,7 @@ +import pytest + from tests.support.asserts import assert_error, assert_success from tests.support.image import png_dimensions - from . import element_dimensions @@ -29,10 +30,9 @@ assert png_dimensions(screenshot) == element_dimensions(session, element) -def test_stale(session, inline): - session.url = inline("<input>") - element = session.find.css("input", all=False) - session.refresh() +@pytest.mark.parametrize("as_frame", [False, True], ids=["top_context", "child_context"]) +def test_stale_element_reference(session, stale_element, as_frame): + element = stale_element("<input>", "input", as_frame=as_frame) result = take_element_screenshot(session, element.id) assert_error(result, "stale element reference")
diff --git a/third_party/blink/web_tests/external/wpt/window-placement/fullscreen-companion-window-manual.tentative.https.html b/third_party/blink/web_tests/external/wpt/window-placement/fullscreen-companion-window-manual.tentative.https.html new file mode 100644 index 0000000..fe82916 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/window-placement/fullscreen-companion-window-manual.tentative.https.html
@@ -0,0 +1,83 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<!-- user agents are not required to support open features other than `noopener` + and on some platforms position and size features don't make sense --> +<meta name="flags" content="may"> +<title>Multi-Screen Window Placement test: Fullscreen Companion Window</title> +<link rel="help" href="https://w3c.github.io/window-placement"> +This test uses multi-screen details to request fullscreen and open a pop-up<br> +(companion window) in the same user activation.<br> +It runs automated or manually with `wpt serve` and a compatible browser.<br><br> +<button id="setUpButton">Request screen details</button> +<ul id="popupButtons"></ul> +<button id="cleanUpButton">Close any open popups</button><br> +<input id="autoCleanUp" type="checkbox" checked=true>Auto-close popups</input> +<ul id="logger"></ul> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/helpers.js"></script> + +<script> +'use strict'; +let popups = []; + +cleanUpButton.addEventListener('click', async () => { + popups.forEach(p => p.close()); +}); + +// expectPopup should be true if the test should expect the pop-up to be +// created, or false if the popup is not expected to be created (blocked). +async function testPopupOnScreen(popupTest, screen, expectPopup) { + // Show a popup child window on the associated screen. + const left = screen.availLeft + Math.floor(screen.availWidth / 2) - 150; + const top = screen.availTop + Math.floor(screen.availHeight / 2) - 50; + log(`Opening a popup on '${screen.label}' at (${left}, ${top})`); + let popup = window.open( + '/resources/blank.html', '', + `left=${left},top=${top},width=300,height=100`); + assert_equals(!!popup, expectPopup, 'Popup reference'); + if (popup === null) + return; + assert_equals(!popup.closed, expectPopup, 'Popup open'); + popups.push(popup); + if (autoCleanUp.checked) + popupTest.add_cleanup(popup.close); +} + +promise_test(async setUpTest => { + await setUpWindowPlacement(setUpTest, setUpButton); + const screenDetails = await getScreenDetails(); + assert_true(!!screenDetails, 'Error getting screen details'); + for (const [i, fullscreenScreen] of screenDetails.screens.entries()) { + const popupScreen = + screenDetails.screens[(i + 1) % screenDetails.screens.length]; + // Fullscreen and popup are the same in single screen environments. + if (popupScreen === undefined) popupScreen = fullscreenScreen; + let testName = + `Fullscreen on '${fullscreenScreen.label}' and open popup on '${popupScreen.label}'`; + promise_test(async popupTest => { + const button = document.createElement('button'); + button.innerHTML = testName; + const entry = document.createElement('li'); + entry.appendChild(button); + popupButtons.appendChild(entry); + const popupWatcher = new EventWatcher(popupTest, button, ['click']); + const popupClick = popupWatcher.wait_for('click'); + try { // Support manual testing where test_driver is not running. + await test_driver.click(button); + } catch { + } + await popupClick; + button.disabled = true; + await document.documentElement.requestFullscreen( + { screen: fullscreenScreen } + ); + await testPopupOnScreen(popupTest, popupScreen, + /*expectPopup=*/fullscreenScreen !== popupScreen); + }, testName); + } +}, 'Use multi-screen details to request fullscreen and open a pop-up in the same user activation.'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/window-placement/multi-screen-window-open.tentative.https.html b/third_party/blink/web_tests/external/wpt/window-placement/multi-screen-window-open.tentative.https.html index 00c00d90..c9973fc 100644 --- a/third_party/blink/web_tests/external/wpt/window-placement/multi-screen-window-open.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/window-placement/multi-screen-window-open.tentative.https.html
@@ -5,7 +5,7 @@ and on some platforms position and size features don't make sense --> <meta name="flags" content="may"> <title>Multi-Screen Window Placement test: window.open()</title> -<link rel="help" href="https://webscreens.github.io/window-placement/"> +<link rel="help" href="https://w3c.github.io/window-placement"> This test uses multi-screen details to open a popup window on each screen.<br> It runs automated or manually with `wpt serve` and a compatible browser.<br><br> <button id="setUpButton">Request screen details</button> @@ -17,18 +17,12 @@ <script src="/resources/testharnessreport.js"></script> <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="resources/helpers.js"></script> <script> 'use strict'; let popups = []; -function log(str) { - const entry = document.createElement('li'); - entry.innerHTML = str; - logger.appendChild(entry); - return entry; -} - cleanUpButton.addEventListener('click', async () => { popups.forEach(p => p.close()); }); @@ -89,27 +83,7 @@ } promise_test(async setUpTest => { - assert_true( - 'getScreenDetails' in self && 'isExtended' in screen, - `API not supported; use Chromium (not content_shell) and enable - chrome://flags/#enable-experimental-web-platform-features`); - if (!screen.isExtended) - log(`WARNING: Use multiple screens for full test coverage`); - if (window.location.href.startsWith('file')) - log(`WARNING: Run via 'wpt serve'; file URLs lack permission support`); - - try { // Support manual testing where test_driver is not running. - await test_driver.set_permission({name: 'window-placement'}, 'granted'); - } catch { - } - const setUpWatcher = new EventWatcher(setUpTest, setUpButton, ['click']); - const setUpClick = setUpWatcher.wait_for('click'); - try { // Support manual testing where test_driver is not running. - await test_driver.click(setUpButton); - } catch { - } - await setUpClick; - setUpButton.disabled = true; + await setUpWindowPlacement(setUpTest, setUpButton); const screenDetails = await getScreenDetails(); assert_true(!!screenDetails, 'Error getting screen details'); assert_greater_than(screenDetails.screens.length, 0, 'Connect a screen');
diff --git a/third_party/blink/web_tests/external/wpt/window-placement/resources/helpers.js b/third_party/blink/web_tests/external/wpt/window-placement/resources/helpers.js new file mode 100644 index 0000000..88609892 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/window-placement/resources/helpers.js
@@ -0,0 +1,38 @@ +// Logs (append) an HTML string to the document in a list format. +function log(str) { + const entry = document.createElement('li'); + entry.innerHTML = str; + logger.appendChild(entry); + return entry; +} + +// Common setup for window placement tests. Performs some basic assertions, and +// then waits for a click on the `setUpButton` element (for manual tests). +// Example usage: +// promise_test(async setUpTest => { +// await setUpWindowPlacement(setUpTest, setUpButton); +// ... +// }); +async function setUpWindowPlacement(setUpTest, setUpButton) { + assert_true( + 'getScreenDetails' in self && 'isExtended' in screen, + `API not supported; use Chromium (not content_shell) and enable + chrome://flags/#enable-experimental-web-platform-features`); + if (!screen.isExtended) + log(`WARNING: Use multiple screens for full test coverage`); + if (window.location.href.startsWith('file')) + log(`WARNING: Run via 'wpt serve'; file URLs lack permission support`); + + try { // Support manual testing where test_driver is not running. + await test_driver.set_permission({ name: 'window-placement' }, 'granted'); + } catch { + } + const setUpWatcher = new EventWatcher(setUpTest, setUpButton, ['click']); + const setUpClick = setUpWatcher.wait_for('click'); + try { // Support manual testing where test_driver is not running. + await test_driver.click(setUpButton); + } catch { + } + await setUpClick; + setUpButton.disabled = true; +}
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/selectors/has-error-recovery-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/selectors/has-error-recovery-expected.txt new file mode 100644 index 0000000..6fba3e49 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/selectors/has-error-recovery-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL CSS Selectors: :has() error recovery assert_equals: Should correctly match expected Element node <div id="test-div"> + <div id="test-descendant"> + </div>... but got Element node <html><head><title>CSS Selectors: :has() error recovery</... +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/css/selectors/has-error-recovery-expected.txt b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/css/selectors/has-error-recovery-expected.txt new file mode 100644 index 0000000..6fba3e49 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/disable-site-isolation-trials/external/wpt/css/selectors/has-error-recovery-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL CSS Selectors: :has() error recovery assert_equals: Should correctly match expected Element node <div id="test-div"> + <div id="test-descendant"> + </div>... but got Element node <html><head><title>CSS Selectors: :has() error recovery</... +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead-expected.html b/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead-expected.html index fae6fca..2007cfa 100644 --- a/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead-expected.html +++ b/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead-expected.html
@@ -17,7 +17,7 @@ </div> </td></tr> </thead> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> <thead> <tr><td> <div style="columns: 2"> @@ -30,6 +30,6 @@ </div> </td></tr> </thead> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> </table> </div>
diff --git a/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead.html b/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead.html index b590edf0..40b0c2a46 100644 --- a/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead.html +++ b/third_party/blink/web_tests/fragmentation/repeating-thead-under-repeating-thead.html
@@ -17,7 +17,7 @@ </div> </td></tr> </thead> - <tr><td style="height: 400px"></td></tr> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> + <tr><td style="height: 600px"></td></tr> </table> </div>
diff --git a/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead-expected.html b/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead-expected.html index 6630379..be8625b 100644 --- a/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead-expected.html +++ b/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead-expected.html
@@ -11,13 +11,13 @@ <tr><td style="height: 100px"></td></tr> </table> </td></tr> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> <tr><td> <table> <tr><td>Inner</td></tr> <tr><td style="height: 100px"></td></tr> </table> </td></tr> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> </table> </div>
diff --git a/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead.html b/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead.html index 2defff1..ca4c9d1 100644 --- a/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead.html +++ b/third_party/blink/web_tests/fragmentation/thead-under-repeating-thead.html
@@ -14,7 +14,7 @@ </table> </td></tr> </thead> - <tr><td style="height: 400px"></td></tr> - <tr><td style="height: 400px"></td></tr> + <tr><td style="height: 600px"></td></tr> + <tr><td style="height: 600px"></td></tr> </table> </div>
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/selectors/has-error-recovery-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/selectors/has-error-recovery-expected.txt new file mode 100644 index 0000000..6fba3e49 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/selectors/has-error-recovery-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL CSS Selectors: :has() error recovery assert_equals: Should correctly match expected Element node <div id="test-div"> + <div id="test-descendant"> + </div>... but got Element node <html><head><title>CSS Selectors: :has() error recovery</... +Harness: the test ran to completion. +
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 5e95eae..4519093 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -544,8 +544,6 @@ 'GPU FYI Win x64 DX12 Vulkan Builder (dbg)': 'gpu_fyi_tests_dx12vk_debug_trybot_reclient', 'GPU FYI XR Win x64 Builder': 'gpu_fyi_tests_release_trybot_reclient', 'Linux FYI GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan_reclient', - 'Optional Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64', - 'Optional Android Release (Pixel 4)': 'gpu_tests_android_release_trybot', 'gpu-fyi-chromeos-jacuzzi-exp': 'gpu_tests_chromeos_jacuzzi_release_trybot', 'gpu-fyi-chromeos-octopus-exp': 'gpu_tests_chromeos_octopus_release_trybot', 'gpu-fyi-chromeos-zork-exp': 'gpu_tests_chromeos_zork_release_trybot',
diff --git a/tools/mb/mb_config_expectations/chromium.gpu.fyi.json b/tools/mb/mb_config_expectations/chromium.gpu.fyi.json index 221222d..9f54e1b 100644 --- a/tools/mb/mb_config_expectations/chromium.gpu.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.gpu.fyi.json
@@ -227,33 +227,6 @@ "use_remoteexec": true } }, - "Optional Android Release (Nexus 5X)": { - "gn_args": { - "dcheck_always_on": true, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 1, - "target_cpu": "arm64", - "target_os": "android", - "use_goma": true, - "use_static_angle": true - } - }, - "Optional Android Release (Pixel 4)": { - "gn_args": { - "dcheck_always_on": true, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "symbol_level": 1, - "target_os": "android", - "use_goma": true, - "use_static_angle": true - } - }, "gpu-fyi-chromeos-jacuzzi-exp": { "args_file": "//build/args/chromeos/jacuzzi.gni", "gn_args": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index a72be7d..e2e1b6cd 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -55477,6 +55477,7 @@ <int value="-1775842908" label="EnableOAuthIpp:disabled"/> <int value="-1774818943" label="VrWebInputEditing:enabled"/> <int value="-1774290918" label="webview-shadow-dom-fenced-frames"/> + <int value="-1773925297" label="TimedHtmlParserBudget:disabled"/> <int value="-1772942854" label="LongPressBackForHistory:enabled"/> <int value="-1772905637" label="RunVideoCaptureServiceInBrowserProcess:enabled"/> @@ -61447,6 +61448,7 @@ <int value="2133594095" label="CryptAuthV2DeviceActivityStatus:disabled"/> <int value="2133647636" label="ClipboardFilenames:disabled"/> <int value="2134480727" label="MediaSessionAccelerators:disabled"/> + <int value="2135378598" label="TimedHtmlParserBudget:enabled"/> <int value="2135408204" label="OverscrollHistoryNavigation:disabled"/> <int value="2137113620" label="ProcessSharingWithStrictSiteInstances:enabled"/>
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml index ba5a32d..9b10a8a 100644 --- a/tools/metrics/histograms/metadata/commerce/histograms.xml +++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -218,7 +218,7 @@ </histogram> <histogram name="Commerce.PriceDrop.AnnotationsEnabled" enum="Boolean" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -231,7 +231,7 @@ </histogram> <histogram name="Commerce.PriceDrop.NotificationChannelBlocked" enum="Boolean" - expires_after="2022-10-04"> + expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> @@ -243,7 +243,7 @@ </histogram> <histogram name="Commerce.PriceDrop.NotificationChannelCreated" enum="Boolean" - expires_after="2022-12-04"> + expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> @@ -255,7 +255,7 @@ </histogram> <histogram name="Commerce.PriceDrop.SystemNotificationEnabled" enum="Boolean" - expires_after="2022-12-04"> + expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> @@ -267,7 +267,7 @@ </histogram> <histogram name="Commerce.PriceDrops.{ManagementType}.NotificationCount" - units="notifications" expires_after="2022-10-01"> + units="notifications" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -281,7 +281,7 @@ </histogram> <histogram name="Commerce.PriceDrops.{ManagementType}.NotificationReachedCap" - enum="Boolean" expires_after="2022-10-01"> + enum="Boolean" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -344,7 +344,7 @@ </histogram> <histogram name="Commerce.SignIn.AccountWaaStatus" - enum="AccountWaaStatusForCommerce" expires_after="2022-12-04"> + enum="AccountWaaStatusForCommerce" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -356,7 +356,7 @@ </histogram> <histogram name="Commerce.Subscriptions.TabEligible" enum="Boolean" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -370,7 +370,7 @@ </histogram> <histogram name="Commerce.Subscriptions.{ManagementType}.Count" - units="subscriptions" expires_after="2022-10-01"> + units="subscriptions" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -384,8 +384,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.CloseReason" - enum="BottomSheet.StateChangeReason" expires_after="2022-10-01"> + enum="BottomSheet.StateChangeReason" expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the reason that the merchant trust bottom sheet is closed. Recorded @@ -394,8 +395,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.DurationFullyOpened" units="ms" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the duration in milliseconds that the merchant trust bottom sheet is @@ -404,8 +406,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.DurationHalfOpened" units="ms" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the duration in milliseconds that the merchant trust bottom sheet is @@ -414,8 +417,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.DurationPeeked" units="ms" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the duration in milliseconds that the merchant trust bottom sheet is @@ -424,8 +428,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.IsFullyViewed" enum="Boolean" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records whether the merchant trust bottom sheet is fully expanded. Recorded @@ -434,8 +439,9 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.IsHalfViewed" enum="Boolean" - expires_after="2022-10-01"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records whether the merchant trust bottom sheet is half expanded. Recorded @@ -444,7 +450,7 @@ </histogram> <histogram name="MerchantTrust.BottomSheet.OpenSource" - enum="MerchantTrustBottomSheetOpenedSource" expires_after="2022-10-01"> + enum="MerchantTrustBottomSheetOpenedSource" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> @@ -454,8 +460,9 @@ </histogram> <histogram name="MerchantTrust.Message.ClearReason" - enum="MerchantTrustMessageClearReason" expires_after="2022-11-20"> + enum="MerchantTrustMessageClearReason" expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records why the prepared merchant trust message is cleared. Recorded when @@ -466,8 +473,9 @@ </histogram> <histogram name="MerchantTrust.Message.DismissReason" - enum="MessageDismissReason" expires_after="2022-11-20"> + enum="MessageDismissReason" expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the reason that the merchant trust message is dismissed. Implemented @@ -476,8 +484,9 @@ </histogram> <histogram name="MerchantTrust.Message.DurationPrepared" units="ms" - expires_after="2022-11-20"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the duration in milliseconds from the merchant trust message being @@ -486,8 +495,9 @@ </histogram> <histogram name="MerchantTrust.Message.DurationShown" units="ms" - expires_after="2022-11-20"> + expires_after="2023-04-25"> <owner>ayman@chromium.org</owner> + <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary> Records the duration in milliseconds that the merchant trust message is @@ -496,7 +506,7 @@ </histogram> <histogram name="MerchantTrust.MessageImpact.BrowsingTime" units="ms" - expires_after="2022-12-11"> + expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -509,7 +519,7 @@ <histogram name="MerchantTrust.MessageImpact.BrowsingTime.Rating{MessageStarRating}" - units="ms" expires_after="M105"> + units="ms" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -523,7 +533,7 @@ </histogram> <histogram name="MerchantTrust.MessageImpact.NavigationCount" - units="navigations" expires_after="2022-12-11"> + units="navigations" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -536,7 +546,7 @@ <histogram name="MerchantTrust.MessageImpact.NavigationCount.Rating{MessageStarRating}" - units="navigations" expires_after="M105"> + units="navigations" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>ayman@chromium.org</owner> <owner>chrome-shopping@google.com</owner> @@ -550,7 +560,7 @@ </histogram> <histogram name="MerchantTrust.PageInfo.IsStoreInfoVisible" - enum="BooleanVisible" expires_after="2022-11-13"> + enum="BooleanVisible" expires_after="2023-04-25"> <owner>zhiyuancai@chromium.org</owner> <owner>chrome-shopping@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index 622232a..720e00f 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -622,17 +622,19 @@ </histogram> <histogram name="Network.Cellular.Pin.{SimPinOperation}" - enum="SimPinOperationResult" expires_after="2022-09-01"> + enum="SimPinOperationResult" expires_after="2023-06-01"> <owner>azeemarshad@chromium.org</owner> - <owner>cros-connectivity@google.com</owner> <owner>hsuregan@chromium.org</owner> + <owner>cros-connectivity@google.com</owner> <summary> Tracks the rate of success of various pin operations. Note: This histogram was expired from 2022-03-01 to 2022-03-23; data may be missing. </summary> <token key="SimPinOperation"> <variant name="ChangeSuccess"/> - <variant name="LockSuccess"/> + <variant name="LockSuccess" summary="Deprecated on 2022-07-16."/> + <variant name="RemoveLockSuccess"/> + <variant name="RequireLockSuccess"/> <variant name="UnblockSuccess"/> <variant name="UnlockSuccess"/> </token>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml index 13fb19d..0e5762de 100644 --- a/tools/metrics/histograms/metadata/power/histograms.xml +++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -527,8 +527,9 @@ </token> </histogram> -<histogram name="Power.AdaptiveChargingMinutesDelta.{AdaptiveChargingState}" - units="minutes" expires_after="2023-03-19"> +<histogram + name="Power.AdaptiveChargingMinutesDelta.{AdaptiveChargingState}.{OnTimeStatus}" + units="minutes" expires_after="2023-06-13"> <owner>dbasehore@chromium.org</owner> <owner>chromeos-platform-power@google.com</owner> <summary> @@ -545,6 +546,11 @@ metric if the feature is not supported, since we may backport support to older systems, and we'd like to know how well the ML model does before enabling support. + + Since metrics don't work with negative values, this is additionally split + across Late and Early variants. The absolute values of negatives are + reported under the Late variant. Positive and 0 values are reported under + the Early variant. </summary> <token key="AdaptiveChargingState"> <variant name="Active"/> @@ -553,6 +559,10 @@ <variant name="UserCanceled"/> <variant name="UserDisabled"/> </token> + <token key="OnTimeStatus"> + <variant name="Early"/> + <variant name="Late"/> + </token> </histogram> <histogram name="Power.AdaptiveChargingMinutesToFull" units="minutes"
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 2be007d0..7347644 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@ "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "win": { - "hash": "ee579d0b0de45910c16a149ad0ae2955512fc7ff", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/0fc854399d1b817841aaa2e6362452ac16d01d8b/trace_processor_shell.exe" + "hash": "7057b12bfb48ded7f4f64ac0010c4df624a8a5ed", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/faa478c7878b2b0dae9d2dad346cbaee6712a628/trace_processor_shell.exe" }, "linux_arm": { "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893", "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "mac": { - "hash": "2a02892e088a5b55c04f79aad1ac20b88a6980ab", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/b9f4805cadbde30a1bc094e6c55a4084a0dc4f44/trace_processor_shell" + "hash": "81754e8eb6f10e3aa872e95f3e44f3f574c23b1b", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/faa478c7878b2b0dae9d2dad346cbaee6712a628/trace_processor_shell" }, "mac_arm64": { "hash": "e1ad4861384b06d911a65f035317914b8cc975c6", "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "186699dc75360a57f6d1be5e8145f745f740b523", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/0fc854399d1b817841aaa2e6362452ac16d01d8b/trace_processor_shell" + "hash": "64aef20cc1e600f42ce493e1efab4d68d32c54c2", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/faa478c7878b2b0dae9d2dad346cbaee6712a628/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 3a51d2ad..5713bbd 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -600,6 +600,8 @@ crbug.com/1211795 [ mac ] v8.browsing_desktop-future/browse:social:facebook_infinite_scroll:2018 [ Skip ] crbug.com/1302694 [ mac ] v8.browsing_desktop-future/browse:tools:photoshop:2021 [ Skip ] crbug.com/1302694 [ mac ] v8.browsing_desktop-future/browse:tools:photoshop_warm:2021 [ Skip ] +crbug.com/1337469 [ linux ] v8.browsing_desktop-future/browse:news:reddit:2020 [ Skip ] +crbug.com/1337469 [ win ] v8.browsing_desktop-future/browse:news:reddit:2020 [ Skip ] # Benchmark: v8.browsing_mobile (keep in sync with v8.browsing_mobile-future below) crbug.com/958034 [ android-go android-webview ] v8.browsing_mobile/* [ Skip ] @@ -641,6 +643,7 @@ crbug.com/1302665 [ android ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll:2021 [ Skip ] crbug.com/1321927 [ android-pixel-2 ] v8.browsing_mobile-future/browse:media:googleplaystore:2019 [ Skip ] crbug.com/1321927 [ android-pixel-4 ] v8.browsing_mobile-future/browse:media:googleplaystore:2019 [ Skip ] +crbug.com/1337452 [ android-pixel-4 ] v8.browsing_mobile-future/browse:media:imgur:2019 [ Skip ] # Benchmark: v8.runtime_stats.top_25 crbug.com/954229 [ mac ] v8.runtime_stats.top_25/* [ Skip ]
diff --git a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java index 83972dab..1900561 100644 --- a/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java +++ b/ui/android/java/src/org/chromium/ui/dragdrop/DragAndDropDelegateImpl.java
@@ -435,4 +435,14 @@ String suffix = result ? "Success" : "Canceled"; RecordHistogram.recordMediumTimesHistogram(histogramPrefix + suffix, duration); } + + @VisibleForTesting + float getDragStartXDp() { + return mDragStartXDp; + } + + @VisibleForTesting + float getDragStartYDp() { + return mDragStartYDp; + } }
diff --git a/ui/android/junit/src/org/chromium/ui/dragdrop/DragAndDropDelegateImplUnitTest.java b/ui/android/junit/src/org/chromium/ui/dragdrop/DragAndDropDelegateImplUnitTest.java index d22c0de..03f0ded 100644 --- a/ui/android/junit/src/org/chromium/ui/dragdrop/DragAndDropDelegateImplUnitTest.java +++ b/ui/android/junit/src/org/chromium/ui/dragdrop/DragAndDropDelegateImplUnitTest.java
@@ -5,6 +5,8 @@ package org.chromium.ui.dragdrop; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.ClipData; import android.content.ClipDescription; @@ -29,7 +31,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -52,8 +56,14 @@ private static final int WINDOW_WIDTH = 1000; private static final int WINDOW_HEIGHT = 600; + private static final float DRAG_START_X_DP = 1.0f; + private static final float DRAG_START_Y_DP = 1.0f; + private static final String IMAGE_FILENAME = "image.png"; + @Mock + private DragAndDropPermissions mDragAndDropPermissions; + /** Helper shadow class to make sure #startDragAndDrop is accepted by Android. */ @Implements(ApiHelperForN.class) static class ShadowApiHelperForN { @@ -73,6 +83,8 @@ @Before public void setup() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); mDragAndDropDelegateImpl = new DragAndDropDelegateImpl(); @@ -188,6 +200,14 @@ } @Test + public void testStartDragAndDrop_InvalidDropData() { + final DropDataAndroid dropData = DropDataAndroid.create(null, null, null, null, null); + + Assert.assertFalse("Drag and drop should not start.", + mDragAndDropDelegateImpl.startDragAndDrop(mContainerView, null, dropData)); + } + + @Test @Config(shadows = {ShadowApiHelperForN.class}) public void testDragImage_ShadowPlaceholder() { final Bitmap shadowImage = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); @@ -254,6 +274,21 @@ } @Test + public void testDragStartedFromContainerView() { + final Bitmap shadowImage = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8); + final DropDataAndroid imageDropData = + DropDataAndroid.create("", null, new byte[] {1, 2, 3, 4}, "png", IMAGE_FILENAME); + mDragAndDropDelegateImpl.startDragAndDrop(mContainerView, shadowImage, imageDropData); + + mDragAndDropDelegateImpl.onDrag( + mContainerView, mockDragEvent(DragEvent.ACTION_DRAG_STARTED)); + Assert.assertEquals("Recorded drag start X dp should match.", DRAG_START_X_DP, + mDragAndDropDelegateImpl.getDragStartXDp(), 0.0f); + Assert.assertEquals("Recorded drag start Y dp should match.", DRAG_START_Y_DP, + mDragAndDropDelegateImpl.getDragStartYDp(), 0.0f); + } + + @Test public void testResizeShadowImage_ScaleDownWithRatio() { doTestResizeShadowImage("Resize 60%", /*width=*/100, /*height=*/100, @@ -330,7 +365,7 @@ @Test @Config(sdk = VERSION_CODES.O) - public void testClipData_ImageWithUrl() { + public void testClipData_ImageWithUrl_PostO() { final DropDataAndroid dropData = DropDataAndroid.create("", JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), new byte[] {1, 2, 3, 4}, "png", IMAGE_FILENAME); @@ -343,25 +378,23 @@ } @Test - public void testClipData_TextLink() { + @Config(sdk = VERSION_CODES.N_MR1) + public void testClipData_ImageWithUrl_PreO() { + final DropDataAndroid dropData = + DropDataAndroid.create("", JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), + new byte[] {1, 2, 3, 4}, "png", IMAGE_FILENAME); + + ClipData clipData = mDragAndDropDelegateImpl.buildClipData(dropData); + Assert.assertEquals( + "Image ClipData should include only image info.", 1, clipData.getItemCount()); + } + + @Test + public void testClipData_TextLink_NonNullIntent() { final DropDataAndroid dropData = DropDataAndroid.create( "", JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), null, null, null); - mDragAndDropDelegateImpl.setDragAndDropBrowserDelegate(new DragAndDropBrowserDelegate() { - @Override - public boolean getSupportDropInChrome() { - return false; - } - - @Override - public DragAndDropPermissions getDragAndDropPermissions(DragEvent dropEvent) { - return null; - } - - @Override - public Intent createLinkIntent(String urlString) { - return new Intent(); - } - }); + mDragAndDropDelegateImpl.setDragAndDropBrowserDelegate( + createDragAndDropBrowserDelegate(false, null, new Intent())); ClipData clipData = mDragAndDropDelegateImpl.buildClipData(dropData); Assert.assertTrue("Link ClipData should include plaintext MIME type.", clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)); @@ -373,6 +406,30 @@ "ClipData intent should not be null.", clipData.getItemAt(0).getIntent()); } + @Test + public void testClipData_TextLink_NullIntent() { + final DropDataAndroid dropData = DropDataAndroid.create( + "", JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), null, null, null); + mDragAndDropDelegateImpl.setDragAndDropBrowserDelegate( + createDragAndDropBrowserDelegate(false, null, null)); + ClipData clipData = mDragAndDropDelegateImpl.buildClipData(dropData); + Assert.assertTrue("Link ClipData should include plaintext MIME type.", + clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)); + Assert.assertFalse("Link ClipData should not include intent MIME type.", + clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)); + Assert.assertEquals("Dragged link text should match.", JUnitTestGURLs.EXAMPLE_URL, + clipData.getItemAt(0).getText()); + } + + @Test + public void testDropInChromeFromOutside() { + mDragAndDropDelegateImpl.setDragAndDropBrowserDelegate( + createDragAndDropBrowserDelegate(true, mDragAndDropPermissions, null)); + // Assume that data is dragged from outside Chrome. + mDragAndDropDelegateImpl.onDrag(mContainerView, mockDragEvent(DragEvent.ACTION_DROP)); + verify(mDragAndDropPermissions).release(); + } + private void doTestResizeShadowImage( String testcase, int width, int height, int expectedWidth, int expectedHeight) { Pair<Integer, Integer> widthHeight = @@ -392,6 +449,8 @@ private DragEvent mockDragEvent(int action) { DragEvent event = Mockito.mock(DragEvent.class); + when(event.getX()).thenReturn(DRAG_START_X_DP); + when(event.getY()).thenReturn(DRAG_START_Y_DP); doReturn(action).when(event).getAction(); return event; } @@ -440,4 +499,24 @@ recorded ? 1 : 0, ShadowRecordHistogram.getHistogramTotalCountForTesting(histogram)); } + + private DragAndDropBrowserDelegate createDragAndDropBrowserDelegate( + boolean supportDropInChrome, DragAndDropPermissions permissions, Intent intent) { + return new DragAndDropBrowserDelegate() { + @Override + public boolean getSupportDropInChrome() { + return supportDropInChrome; + } + + @Override + public DragAndDropPermissions getDragAndDropPermissions(DragEvent dropEvent) { + return permissions; + } + + @Override + public Intent createLinkIntent(String urlString) { + return intent; + } + }; + } }
diff --git a/ui/gfx/render_text_api_fuzzer.cc b/ui/gfx/render_text_api_fuzzer.cc index 02a238b..ae8e1855 100644 --- a/ui/gfx/render_text_api_fuzzer.cc +++ b/ui/gfx/render_text_api_fuzzer.cc
@@ -164,24 +164,44 @@ } } -gfx::ElideBehavior ConsumeElideBehavior(FuzzedDataProvider* fdp) { - switch (fdp->ConsumeIntegralInRange(0, 7)) { - case 0: - return gfx::NO_ELIDE; - case 1: - return gfx::TRUNCATE; - case 2: - return gfx::ELIDE_HEAD; - case 3: - return gfx::ELIDE_MIDDLE; - case 4: - return gfx::ELIDE_TAIL; - case 5: - return gfx::ELIDE_EMAIL; - case 6: - return gfx::FADE_TAIL; - default: - return gfx::NO_ELIDE; +gfx::ElideBehavior ConsumeElideBehavior(FuzzedDataProvider* fdp, + bool generate_only_homogeneous_styles) { + if (generate_only_homogeneous_styles) { + // The styles are guaranteed to be homogenous and it is safe to generate + // any eliding behavior. + switch (fdp->ConsumeIntegralInRange(0, 7)) { + case 0: + return gfx::NO_ELIDE; + case 1: + return gfx::TRUNCATE; + case 2: + return gfx::ELIDE_HEAD; + case 3: + return gfx::ELIDE_MIDDLE; + case 4: + return gfx::ELIDE_TAIL; + case 5: + return gfx::ELIDE_EMAIL; + case 6: + return gfx::FADE_TAIL; + default: + return gfx::NO_ELIDE; + } + } else { + // Only generate eliding behaviors that are compatible with non homogeneous + // text. Remove this when http://crbug.com/1085014 is fixed. + switch (fdp->ConsumeIntegralInRange(0, 4)) { + case 0: + return gfx::NO_ELIDE; + case 1: + return gfx::TRUNCATE; + case 2: + return gfx::ELIDE_TAIL; + case 3: + return gfx::FADE_TAIL; + default: + return gfx::NO_ELIDE; + } } } @@ -211,6 +231,16 @@ return gfx::Range(start, end); } +// Eliding behaviors are not all fully supported by RenderText. Ignore +// unsupported cases. This is causing clusterfuzz to fail with invalid +// tests (http://crbug.com/1185542). Remove when https://crbug.com/1085014 is +// fixed. +bool DoesDisplayRangeSupportElideBehavior(const gfx::RenderText* render_text) { + const gfx::ElideBehavior behavior = render_text->elide_behavior(); + return behavior != gfx::ELIDE_HEAD && behavior != gfx::ELIDE_MIDDLE && + behavior != gfx::ELIDE_EMAIL; +} + const int kMaxStringLength = 128; } // anonymous namespace @@ -223,6 +253,14 @@ gfx::Canvas canvas; FuzzedDataProvider fdp(data, size); + if (size == 0) + return 0; + + // Eliding and Styles are not well supported by RenderText. DCHECKs are + // present in RenderText code to avoid any incorrect uses but the fuzzer + // should not generate them until full support (http://crbug.com/1283159). + const bool generate_only_homogeneous_styles = fdp.ConsumeBool(); + while (fdp.remaining_bytes() != 0) { const RenderTextAPI command = fdp.ConsumeEnum<RenderTextAPI>(); switch (command) { @@ -283,7 +321,9 @@ break; case RenderTextAPI::kSetMultiline: - render_text->SetMultiline(fdp.ConsumeBool()); + if (generate_only_homogeneous_styles) { + render_text->SetMultiline(fdp.ConsumeBool()); + } break; case RenderTextAPI::kSetMaxLines: @@ -307,9 +347,11 @@ break; case RenderTextAPI::kApplyColor: - render_text->ApplyColor( - ConsumeSkColor(&fdp), - ConsumeRange(&fdp, render_text->text().length())); + if (generate_only_homogeneous_styles) { + render_text->ApplyColor( + ConsumeSkColor(&fdp), + ConsumeRange(&fdp, render_text->text().length())); + } break; case RenderTextAPI::kSetStyle: @@ -317,9 +359,11 @@ break; case RenderTextAPI::kApplyStyle: - render_text->ApplyStyle( - ConsumeStyle(&fdp), fdp.ConsumeBool(), - ConsumeRange(&fdp, render_text->text().length())); + if (generate_only_homogeneous_styles) { + render_text->ApplyStyle( + ConsumeStyle(&fdp), fdp.ConsumeBool(), + ConsumeRange(&fdp, render_text->text().length())); + } break; case RenderTextAPI::kSetWeight: @@ -327,9 +371,11 @@ break; case RenderTextAPI::kApplyWeight: - render_text->ApplyWeight( - ConsumeWeight(&fdp), - ConsumeRange(&fdp, render_text->text().length())); + if (generate_only_homogeneous_styles) { + render_text->ApplyWeight( + ConsumeWeight(&fdp), + ConsumeRange(&fdp, render_text->text().length())); + } break; case RenderTextAPI::kSetDirectionalityMode: @@ -337,7 +383,8 @@ break; case RenderTextAPI::kSetElideBehavior: - render_text->SetElideBehavior(ConsumeElideBehavior(&fdp)); + render_text->SetElideBehavior( + ConsumeElideBehavior(&fdp, generate_only_homogeneous_styles)); break; case RenderTextAPI::kIsGraphemeBoundary: @@ -365,10 +412,18 @@ fdp.ConsumeIntegralInRange<int>(0, 30))); break; case RenderTextAPI::kGetSubstringBounds: + // RenderText doesn't support that case (https://crbug.com/1085014). + if (!DoesDisplayRangeSupportElideBehavior(render_text.get())) + break; + render_text->GetSubstringBounds( ConsumeRange(&fdp, render_text->text().length())); break; case RenderTextAPI::kGetCursorSpan: + // RenderText doesn't support that case (https://crbug.com/1085014). + if (!DoesDisplayRangeSupportElideBehavior(render_text.get())) + break; + render_text->GetCursorSpan( ConsumeRange(&fdp, render_text->text().length())); break;
diff --git a/ui/webui/resources/cr_components/localized_link/localized_link.ts b/ui/webui/resources/cr_components/localized_link/localized_link.ts index 2b323dad..4c0cfc0a 100644 --- a/ui/webui/resources/cr_components/localized_link/localized_link.ts +++ b/ui/webui/resources/cr_components/localized_link/localized_link.ts
@@ -28,13 +28,13 @@ import {getTemplate} from './localized_link.html.js'; -interface LocalizedLinkElement { +export interface LocalizedLinkElement { $: { container: HTMLElement, }; } -class LocalizedLinkElement extends PolymerElement { +export class LocalizedLinkElement extends PolymerElement { static get is() { return 'localized-link'; }
diff --git a/ui/webui/resources/html/BUILD.gn b/ui/webui/resources/html/BUILD.gn index 51d2e8d..8f77ffb 100644 --- a/ui/webui/resources/html/BUILD.gn +++ b/ui/webui/resources/html/BUILD.gn
@@ -12,26 +12,23 @@ out_grd = "$target_gen_dir/resources.grdp" resource_path_prefix = "html" input_files = [ - "action_link.html", "assert.html", - "cr/event_target.html", - "cr.html", - "cr/ui/focus_outline_manager.html", - "cr/ui.html", - "event_tracker.html", "load_time_data.html", "parse_html_subset.html", - "promise_resolver.html", "test_loader.html", - "util.html", ] if (is_chromeos_ash) { input_files += [ + "action_link.html", + "cr.html", + "cr/event_target.html", + "cr/ui.html", "cr/ui/array_data_model.html", "cr/ui/command.html", "cr/ui/context_menu_handler.html", "cr/ui/focus_manager.html", + "cr/ui/focus_outline_manager.html", "cr/ui/focus_row.html", "cr/ui/keyboard_shortcut_list.html", "cr/ui/list.html", @@ -42,17 +39,18 @@ "cr/ui/menu.html", "cr/ui/menu_item.html", "cr/ui/position_util.html", + "event_tracker.html", + "promise_resolver.html", + "util.html", ] } if (include_polymer) { - input_files += [ - "cr/ui/focus_without_ink.html", - "polymer.html", - ] + input_files += [ "polymer.html" ] if (is_chromeos_ash) { input_files += [ + "cr/ui/focus_without_ink.html", "cr/ui/focus_row_behavior.html", "i18n_behavior.html", "list_property_update_behavior.html",
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn index 6a96181..57c131f 100644 --- a/ui/webui/resources/js/BUILD.gn +++ b/ui/webui/resources/js/BUILD.gn
@@ -71,6 +71,8 @@ "search_highlight_utils.js", "test_loader.js", "test_loader_util.js", + + # Used by security interstitials and ios inspect UI "util.js", "webui_resource_test.js", "webview_manager.js",
diff --git a/ui/webui/resources/js/cr/ui/BUILD.gn b/ui/webui/resources/js/cr/ui/BUILD.gn index 0c8b357..1bc6988 100644 --- a/ui/webui/resources/js/cr/ui/BUILD.gn +++ b/ui/webui/resources/js/cr/ui/BUILD.gn
@@ -38,7 +38,6 @@ in_files = [ "drag_wrapper.js", "focus_grid.js", - "focus_outline_manager.js", "store.js", ] @@ -48,6 +47,7 @@ "command.js", "context_menu_handler.js", "focus_manager.js", + "focus_outline_manager.js", "focus_row.js", "focus_row_behavior.js", "focus_without_ink.js",
diff --git a/ui/webui/resources/mojo/BUILD.gn b/ui/webui/resources/mojo/BUILD.gn index 918e11a6..be2fcb4f 100644 --- a/ui/webui/resources/mojo/BUILD.gn +++ b/ui/webui/resources/mojo/BUILD.gn
@@ -16,6 +16,7 @@ in_files = [ "mojo/public/mojom/base/big_buffer.mojom-webui.js", "mojo/public/mojom/base/file_path.mojom-webui.js", + "mojo/public/mojom/base/process_id.mojom-webui.js", "mojo/public/mojom/base/safe_base_name.mojom-webui.js", "mojo/public/mojom/base/string16.mojom-webui.js", "mojo/public/mojom/base/text_direction.mojom-webui.js",