diff --git a/DEPS b/DEPS index dd981f1..533d932 100644 --- a/DEPS +++ b/DEPS
@@ -299,7 +299,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '07afa62babe959ab4e6759263490db189e2195c2', + 'skia_revision': 'c408daec0f9a46d5ed2f698a172ede3fd9f78551', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -307,7 +307,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'f6b40bc8397af944cb09ecb606b2d809466a5f02', + 'angle_revision': 'db9624073324a2e5b485df7ba24c4cd45d9dceab', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -331,7 +331,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling googletest # and whatever else without interference from each other. - 'googletest_revision': 'e9092b12dc3cf617d47578f13a1f64285cfa5b2f', + 'googletest_revision': '7e2c425db2c2e024b2807bfe6d386f4ff068d0d6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling lighttpd # and whatever else without interference from each other. @@ -371,11 +371,11 @@ # 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': 'ea769d2a2a7bedc43ac1baec43fdf7423047184e', + 'catapult_revision': 'aa341ec41f6d475102eee85ddec60d403ef575cd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. - 'crossbench_revision': '675d2d63880904c537f03a76f021c2c13e20e355', + 'crossbench_revision': '0d4bbb09c3901288772039f71f071897432d77b8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -391,7 +391,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': '9520a835b578aa11db9df1cf6651dbe5c3376887', + 'devtools_frontend_revision': 'd8f563509959c9132c81f22536bff9edd4325093', # 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. @@ -415,11 +415,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'ba5fbf6ca75113fc554651f2cd601ce911f3e6a1', + 'dawn_revision': '4d33621217632e25d8e88e2f0dd2544596d129ac', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '35b5350ab0afe83a60dbf23ac0f4585e901db7f8', + 'quiche_revision': 'f0a8dcea08196573119875267b4f8303241a24d9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ink # and whatever else without interference from each other. @@ -527,7 +527,7 @@ # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. - 'libcxx_revision': '0e242589e53523da3fc2df7ee965f9534550dec5', + 'libcxx_revision': 'cdae0b78c315e58661273c8cd9119b460e68f98b', # GN CIPD package version. 'gn_version': 'git_revision:e5c4d1881b85b82789b7013233a944cf1a46370f', @@ -1521,7 +1521,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '9d5f4e3ec164804c21a8a7c92eed98c1e0094c13', + '4d4ffc26471ca1d5eb0d122765d87b359956f635', 'condition': 'checkout_android and checkout_src_internal', }, @@ -2013,7 +2013,7 @@ 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '749b3f1960ffd7575f6e7d5ecf1e90d6b9db673a', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd255a8d41e7a2fdc6b50fee69e70014f875d47ef', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -2934,7 +2934,7 @@ Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '2ce86c46cefa1c8e62951f54c812b6faf69860ef', + Var('webrtc_git') + '/src.git' + '@' + 'e37b3246716888f66e859f17931f2cc7caedbbfd', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -2980,7 +2980,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': '292Pn0vLgzx9408oFYJWgwBQOo-DbERMVgSoEJ6UfwAC', + 'version': 'lkxqvhJtv-45S0zRCu7Z3er-IcDc6t931-7jM1lN-RMC', }, ], 'dep_type': 'cipd', @@ -2990,7 +2990,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'gPfWQkZSNWaJpihXXBc7SCvVDlFrPBXvtdq2BSa6OIoC', + 'version': '1pUE-hNBek5om-0mUbI4sJSEt4-m1AwEGnVNuEfMFOIC', }, ], 'dep_type': 'cipd', @@ -3001,7 +3001,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'v4HGLZ-ir5Y-4pZMGKYMAgJ7yAEv5Y5Kj-cdpYfzlgoC', + 'version': 'r2LyNXR63hRBteBs8GN14Otjpbnu_VQvVOvDVUFjeV4C', }, ], 'dep_type': 'cipd', @@ -3012,7 +3012,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-arm64', - 'version': 'i6y9edid-Os3HU7qmVuxE-DH00jNj4Pbl6td-HnHYnYC', + 'version': 'tJUKq9z8lfdk4KydEare4F1gdGAXnTVuC5W3k8mBQBMC', }, ], 'dep_type': 'cipd',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 938ed884..0a0498c 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -67,7 +67,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool/thread_pool_instance.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "components/crash/content/browser/crash_handler_host_linux.h" #include "components/embedder_support/origin_trials/origin_trials_settings_storage.h"
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc index af0f37d..bb73748 100644 --- a/android_webview/browser/aw_contents_io_thread_client.cc +++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -30,7 +30,7 @@ #include "base/synchronization/lock.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/embedder_support/android/util/features.h" #include "components/embedder_support/android/util/input_stream.h" #include "components/embedder_support/android/util/web_resource_response.h"
diff --git a/android_webview/browser/aw_cookie_access_policy.cc b/android_webview/browser/aw_cookie_access_policy.cc index d3d8ed3..7f5f939 100644 --- a/android_webview/browser/aw_cookie_access_policy.cc +++ b/android_webview/browser/aw_cookie_access_policy.cc
@@ -9,7 +9,7 @@ #include "android_webview/browser/aw_contents_io_thread_client.h" #include "base/check_op.h" #include "base/no_destructor.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/global_routing_id.h" #include "content/public/browser/render_frame_host.h"
diff --git a/android_webview/browser/aw_field_trials.cc b/android_webview/browser/aw_field_trials.cc index 4b8ce8ff..69be6d3 100644 --- a/android_webview/browser/aw_field_trials.cc +++ b/android_webview/browser/aw_field_trials.cc
@@ -263,4 +263,9 @@ // Disable draw cutout edge-to-edge on WebView. Safe area insets are not // handled correctly when WebView is drawing edge-to-edge. aw_feature_overrides.DisableFeature(features::kDrawCutoutEdgeToEdge); + + // This is enabled for WebView to improve crbug.com/418159642. + // TODO(crbug.com/422161917): Revert this for the ablation study. + aw_feature_overrides.EnableFeature( + features::kServiceWorkerBackgroundUpdateForRegisteredStorageKeys); }
diff --git a/android_webview/browser/gfx/display_webview.cc b/android_webview/browser/gfx/display_webview.cc index d51c67e..2567936 100644 --- a/android_webview/browser/gfx/display_webview.cc +++ b/android_webview/browser/gfx/display_webview.cc
@@ -7,6 +7,7 @@ #include "android_webview/browser/gfx/overlay_processor_webview.h" #include "android_webview/browser/gfx/root_frame_sink.h" #include "base/memory/ptr_util.h" +#include "base/trace_event/trace_id_helper.h" #include "components/viz/common/features.h" #include "components/viz/service/display/overlay_processor_stub.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc index 5b9cfe5..72291e0 100644 --- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -40,7 +40,7 @@ #include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/embedder_support/android/util/input_stream.h" #include "components/embedder_support/android/util/response_delegate_impl.h" #include "components/embedder_support/android/util/web_resource_response.h"
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 fc8242e..1474993 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
@@ -1073,7 +1073,7 @@ "PrefetchServiceWorker", "Enables SpeculationRules prefetch to ServiceWorker-controlled URLs."), Flag.baseFeature("TimedHTMLParserBudget"), - Flag.baseFeature("BackgroundUpdateForRegisteredStorageKeys"), + Flag.baseFeature("ServiceWorkerBackgroundUpdateForRegisteredStorageKeys"), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/ash/app_list/quick_app_access_model.h b/ash/app_list/quick_app_access_model.h index d293e4c..657011d 100644 --- a/ash/app_list/quick_app_access_model.h +++ b/ash/app_list/quick_app_access_model.h
@@ -12,10 +12,7 @@ #include "ash/public/cpp/app_list/app_list_controller_observer.h" #include "base/observer_list.h" #include "base/scoped_observation.h" - -namespace base { -class TimeTicks; -} // namespace base +#include "base/time/time.h" namespace gfx { class ImageSkia; @@ -43,11 +40,10 @@ // Called when the default icon for the quick app icon changes. virtual void OnQuickAppIconChanged() = 0; }; - QuickAppAccessModel(); + QuickAppAccessModel(); QuickAppAccessModel(const QuickAppAccessModel&) = delete; QuickAppAccessModel& operator=(const QuickAppAccessModel&) = delete; - ~QuickAppAccessModel() override; void AddObserver(Observer* observer); @@ -67,8 +63,10 @@ // Returns the quick app's display name. const std::u16string GetAppName() const; - const std::string& quick_app_id() { return quick_app_id_; } - bool quick_app_should_show_state() { return quick_app_should_show_state_; } + const std::string& quick_app_id() const { return quick_app_id_; } + bool quick_app_should_show_state() const { + return quick_app_should_show_state_; + } private: // AppListItemObserver:
diff --git a/ash/public/cpp/holding_space/holding_space_progress.cc b/ash/public/cpp/holding_space/holding_space_progress.cc index 94febf0..607e2962 100644 --- a/ash/public/cpp/holding_space/holding_space_progress.cc +++ b/ash/public/cpp/holding_space/holding_space_progress.cc
@@ -5,6 +5,7 @@ #include "ash/public/cpp/holding_space/holding_space_progress.h" #include <limits> +#include <tuple> #include "base/check_op.h"
diff --git a/ash/public/cpp/holding_space/holding_space_progress.h b/ash/public/cpp/holding_space/holding_space_progress.h index d903481..b5bd973 100644 --- a/ash/public/cpp/holding_space/holding_space_progress.h +++ b/ash/public/cpp/holding_space/holding_space_progress.h
@@ -5,6 +5,8 @@ #ifndef ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_PROGRESS_H_ #define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_PROGRESS_H_ +#include <stdint.h> + #include <optional> #include "ash/public/cpp/ash_public_export.h"
diff --git a/ash/public/cpp/system_tray.h b/ash/public/cpp/system_tray.h index 1304cbe..ac000dda 100644 --- a/ash/public/cpp/system_tray.h +++ b/ash/public/cpp/system_tray.h
@@ -6,9 +6,9 @@ #define ASH_PUBLIC_CPP_SYSTEM_TRAY_H_ #include <string> +#include <vector> #include "ash/ash_export.h" - #include "base/memory/raw_ptr.h" namespace ash {
diff --git a/ash/public/cpp/tab_cluster/correlation_clusterer.h b/ash/public/cpp/tab_cluster/correlation_clusterer.h index 50f3787b..33fe4ab 100644 --- a/ash/public/cpp/tab_cluster/correlation_clusterer.h +++ b/ash/public/cpp/tab_cluster/correlation_clusterer.h
@@ -5,6 +5,8 @@ #ifndef ASH_PUBLIC_CPP_TAB_CLUSTER_CORRELATION_CLUSTERER_H_ #define ASH_PUBLIC_CPP_TAB_CLUSTER_CORRELATION_CLUSTERER_H_ +#include <stdint.h> + #include <map> #include <optional> #include <set>
diff --git a/ash/public/cpp/wallpaper/sea_pen_image.h b/ash/public/cpp/wallpaper/sea_pen_image.h index 55d9d2a..085a3ef 100644 --- a/ash/public/cpp/wallpaper/sea_pen_image.h +++ b/ash/public/cpp/wallpaper/sea_pen_image.h
@@ -5,6 +5,8 @@ #ifndef ASH_PUBLIC_CPP_WALLPAPER_SEA_PEN_IMAGE_H_ #define ASH_PUBLIC_CPP_WALLPAPER_SEA_PEN_IMAGE_H_ +#include <stdint.h> + #include <string> #include "ash/public/cpp/ash_public_export.h"
diff --git a/ash/quick_pair/common/fast_pair/fast_pair_decoder.h b/ash/quick_pair/common/fast_pair/fast_pair_decoder.h index 412ba979..8fd91cf 100644 --- a/ash/quick_pair/common/fast_pair/fast_pair_decoder.h +++ b/ash/quick_pair/common/fast_pair/fast_pair_decoder.h
@@ -7,6 +7,7 @@ #include <cstdint> #include <optional> +#include <string> #include <vector> #include "base/component_export.h"
diff --git a/ash/user_education/user_education_delegate.h b/ash/user_education/user_education_delegate.h index 9ba2f05..3f48016e 100644 --- a/ash/user_education/user_education_delegate.h +++ b/ash/user_education/user_education_delegate.h
@@ -5,6 +5,8 @@ #ifndef ASH_USER_EDUCATION_USER_EDUCATION_DELEGATE_H_ #define ASH_USER_EDUCATION_USER_EDUCATION_DELEGATE_H_ +#include <stdint.h> + #include <memory> #include <optional> #include <string>
diff --git a/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts b/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts index 2c8121e..a6b0ca66 100644 --- a/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts +++ b/ash/webui/recorder_app_ui/resources/platforms/swa/on_device_model.ts
@@ -120,12 +120,18 @@ const size = await this.getInputTokenSize(text, session); if (size < MIN_TOKEN_LENGTH) { + console.warn( + `Skip GenAI model execution: too small token size: ${size}.`, + ); return { kind: 'error', error: ModelExecutionError.UNSUPPORTED_TRANSCRIPTION_IS_TOO_SHORT, }; } if (size > this.modelInfo.inputTokenLimit) { + console.warn( + `Skip GenAI model execution: too large token size: ${size}.`, + ); return { kind: 'error', error: ModelExecutionError.UNSUPPORTED_TRANSCRIPTION_IS_TOO_LONG, @@ -168,6 +174,7 @@ // When the model returns the canned response, show the same UI as // unsafe content for now. if (isCannedResponse(result)) { + console.warn('Invalid GenAI result: canned response.'); return {kind: 'error', error: ModelExecutionError.UNSAFE}; } @@ -177,6 +184,7 @@ parsedResult, expectedBulletPointCount, )) { + console.warn('Invalid GenAI result: invalid format.'); return {kind: 'error', error: ModelExecutionError.UNSAFE}; } @@ -189,6 +197,7 @@ // Show unsafe content if no valid bullet point. if (finalBulletPoints.length === 0) { + console.warn('Invalid GenAI result: no valid bullet point.'); return {kind: 'error', error: ModelExecutionError.UNSAFE}; } @@ -264,6 +273,7 @@ return {kind: 'error', error: ModelExecutionError.GENERAL}; } if (await this.contentIsUnsafe(prompt, requestSafetyFeature, language)) { + console.warn('Unsafe GenAI prompt.'); return {kind: 'error', error: ModelExecutionError.UNSAFE}; } const response = await this.executeRaw( @@ -280,6 +290,7 @@ responseSafetyFeature, language, )) { + console.warn('Unsafe GenAI result.'); return {kind: 'error', error: ModelExecutionError.UNSAFE}; } return {kind: 'success', result: response.result}; @@ -508,6 +519,9 @@ override async loadAndExecute(content: string, language: LanguageCode): Promise<ModelResponse<T>> { if (!this.platformHandler.getLangPackInfo(language).isGenAiSupported) { + console.warn( + `Skip GenAI model execution: unsupported language: ${language}.`, + ); return {kind: 'error', error: ModelExecutionError.UNSUPPORTED_LANGUAGE}; }
diff --git a/base/BUILD.gn b/base/BUILD.gn index 9ea4ead..3e8c3be 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -885,7 +885,6 @@ "timer/wall_clock_timer.h", "token.cc", "token.h", - "trace_event/base_tracing.h", "trace_event/base_tracing_forward.h", "trace_event/common/trace_event_common.h", "trace_event/heap_profiler_allocation_context.cc",
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc index b2942fc..352530e3 100644 --- a/base/allocator/partition_alloc_features.cc +++ b/base/allocator/partition_alloc_features.cc
@@ -480,10 +480,6 @@ FEATURE_DISABLED_BY_DEFAULT); #endif -BASE_FEATURE(kPartitionAllocUseSmallSingleSlotSpans, - "PartitionAllocUseSmallSingleSlotSpans", - FEATURE_ENABLED_BY_DEFAULT); - #if PA_CONFIG(ENABLE_SHADOW_METADATA) BASE_FEATURE(kPartitionAllocShadowMetadata, "PartitionAllocShadowMetadata",
diff --git a/base/allocator/partition_alloc_support.cc b/base/allocator/partition_alloc_support.cc index 59ed4e2..abb7274 100644 --- a/base/allocator/partition_alloc_support.cc +++ b/base/allocator/partition_alloc_support.cc
@@ -41,7 +41,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "partition_alloc/allocation_guard.h" #include "partition_alloc/buildflags.h" @@ -1183,10 +1183,6 @@ #endif // PA_BUILDFLAG(ENABLE_PARTITION_LOCK_PRIORITY_INHERITANCE) && // PA_BUILDFLAG(IS_ANDROID) - allocator_shim::UseSmallSingleSlotSpans use_small_single_slot_spans( - base::FeatureList::IsEnabled( - features::kPartitionAllocUseSmallSingleSlotSpans)); - allocator_shim::ConfigurePartitions( allocator_shim::EnableBrp(brp_config.enable_brp), brp_config.extra_extras_size, @@ -1195,8 +1191,7 @@ scheduler_loop_quarantine_global_config, scheduler_loop_quarantine_thread_local_config, allocator_shim::EventuallyZeroFreedMemory(eventually_zero_freed_memory), - allocator_shim::FewerMemoryRegions(fewer_memory_regions), - use_small_single_slot_spans); + allocator_shim::FewerMemoryRegions(fewer_memory_regions)); const uint32_t extras_size = allocator_shim::GetMainPartitionRootExtrasSize(); // As per description, extras are optional and are expected not to
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc index cc0d1ef..56b8c54 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc
@@ -6022,7 +6022,7 @@ TEST_P(PartitionAllocTest, SortActiveSlotSpans) { auto run_test = [this](size_t count) { PartitionBucket bucket; - bucket.Init(16, /*use_small_single_slot_spans=*/false); + bucket.Init(16); bucket.active_slot_spans_head = nullptr; #if PA_CONFIG(ENABLE_SHADOW_METADATA)
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc index 80e056f..80a353d 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc
@@ -605,8 +605,7 @@ return ComputeSystemPagesPerSlotSpanInternal(slot_size); } -void PartitionBucket::Init(uint32_t new_slot_size, - bool use_small_single_slot_spans) { +void PartitionBucket::Init(uint32_t new_slot_size) { slot_size = new_slot_size; slot_size_reciprocal = kReciprocalMask / new_slot_size + 1; active_slot_spans_head = SlotSpanMetadata< @@ -625,7 +624,7 @@ ComputeSystemPagesPerSlotSpan(slot_size, prefer_smaller_slot_spans); PA_CHECK(num_system_pages_per_slot_span > 0); - InitCanStoreRawSize(use_small_single_slot_spans); + InitCanStoreRawSize(); } PA_ALWAYS_INLINE SlotSpanMetadata<MetadataKind::kReadOnly>* @@ -710,7 +709,7 @@ return slot_span; } -void PartitionBucket::InitCanStoreRawSize(bool use_small_single_slot_spans) { +void PartitionBucket::InitCanStoreRawSize() { // By definition, direct map buckets can store the raw size. The value // of `can_store_raw_size` is set explicitly in that code path (see // `PartitionDirectMap()`), bypassing this method. @@ -726,8 +725,7 @@ if (slot_size <= MaxRegularSlotSpanSize()) [[likely]] { // Even when the slot size is below the standard floor for single // slot spans, there exist spans that happen to have exactly one - // slot per. If `use_small_single_slot_spans` is true, we use more - // nuanced criteria for determining if a span is "single-slot." + // slot per. // // The conditions are all of: // * Don't deal with slots trafficked by the thread cache [1]. @@ -744,9 +742,9 @@ // [2] ../../PartitionAlloc.md#layout-in-memory const bool not_handled_by_thread_cache = slot_size > kThreadCacheLargeSizeThreshold; - can_store_raw_size = - use_small_single_slot_spans && not_handled_by_thread_cache && - get_slots_per_span() == 1u && get_pages_per_slot_span() > 1u; + can_store_raw_size = not_handled_by_thread_cache && + get_slots_per_span() == 1u && + get_pages_per_slot_span() > 1u; return; }
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.h b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.h index 6dfc34bf..6c3841dc 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.h +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.h
@@ -66,7 +66,7 @@ // Public API. PA_COMPONENT_EXPORT(PARTITION_ALLOC) - void Init(uint32_t new_slot_size, bool use_small_single_slot_spans); + void Init(uint32_t new_slot_size); // Sets |is_already_zeroed| to true if the allocation was satisfied by // requesting (a) new page(s) from the operating system, or false otherwise. @@ -176,7 +176,7 @@ private: // Sets `this->can_store_raw_size`. - void InitCanStoreRawSize(bool use_small_single_slot_spans); + void InitCanStoreRawSize(); // Allocates several consecutive super pages. Returns the address of the first // super page.
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc index 7715637..4a97575f 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
@@ -1191,14 +1191,11 @@ // This is a "magic" value so we can test if a root pointer is valid. inverted_self = ~reinterpret_cast<uintptr_t>(this); - const bool use_small_single_slot_spans = - opts.use_small_single_slot_spans == PartitionOptions::kEnabled; - // Set up the actual usable buckets first. for (size_t bucket_index = 0; bucket_index < BucketIndexLookup::kNumBuckets; ++bucket_index) { const size_t slot_size = BucketIndexLookup::GetBucketSize(bucket_index); - buckets[bucket_index].Init(slot_size, use_small_single_slot_spans); + buckets[bucket_index].Init(slot_size); } #if !PA_CONFIG(THREAD_CACHE_SUPPORTED)
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h index 997940d..899099c 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h +++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
@@ -198,8 +198,6 @@ #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION) ThreadIsolationOption thread_isolation; #endif - - EnableToggle use_small_single_slot_spans = kDisabled; }; constexpr PartitionOptions::PartitionOptions() = default;
diff --git a/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_unittest.cc b/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_unittest.cc index 8fdda5e2..f02743f 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_unittest.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_unittest.cc
@@ -1620,7 +1620,7 @@ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) void HandleOOM(size_t unused_size) { - LOG(FATAL) << "Out of memory"; + PA_LOG(FATAL) << "Out of memory"; } class BackupRefPtrTest : public testing::Test {
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h index dd18e49..d43a9fff 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim.h
@@ -149,9 +149,6 @@ using FewerMemoryRegions = partition_alloc::internal::base::StrongAlias<class FewerMemoryRegionsTag, bool>; -using UseSmallSingleSlotSpans = partition_alloc::internal::base:: - StrongAlias<class UseSmallSingleSlotSpansTag, bool>; - // If |thread_cache_on_non_quarantinable_partition| is specified, the // thread-cache will be enabled on the non-quarantinable partition. The // thread-cache on the main (malloc) partition will be disabled. @@ -167,8 +164,7 @@ partition_alloc::internal::SchedulerLoopQuarantineConfig scheduler_loop_quarantine_thread_local_config, EventuallyZeroFreedMemory eventually_zero_freed_memory, - FewerMemoryRegions fewer_memory_regions, - UseSmallSingleSlotSpans use_small_single_slot_spans); + FewerMemoryRegions fewer_memory_regions); PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) uint32_t GetMainPartitionRootExtrasSize();
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc index bf13d4a2..b7e026b 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -639,8 +639,7 @@ partition_alloc::internal::SchedulerLoopQuarantineConfig scheduler_loop_quarantine_thread_local_config, EventuallyZeroFreedMemory eventually_zero_freed_memory, - FewerMemoryRegions fewer_memory_regions, - UseSmallSingleSlotSpans use_small_single_slot_spans) { + FewerMemoryRegions fewer_memory_regions) { // Calling Get() is actually important, even if the return value isn't // used, because it has a side effect of initializing the variable, if it // wasn't already. @@ -680,10 +679,6 @@ ? partition_alloc::PartitionOptions::kEnabled : partition_alloc::PartitionOptions::kDisabled, .reporting_mode = memory_tagging_reporting_mode}; - opts.use_small_single_slot_spans = - use_small_single_slot_spans - ? partition_alloc::PartitionOptions::kEnabled - : partition_alloc::PartitionOptions::kDisabled; return opts; }()); partition_alloc::PartitionRoot* new_root = new_main_allocator->root();
diff --git a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h index 29206a5..d969bc9 100644 --- a/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h +++ b/base/allocator/partition_allocator/src/partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h
@@ -189,14 +189,12 @@ auto eventually_zero_freed_memory = EventuallyZeroFreedMemory(false); auto fewer_memory_regions = FewerMemoryRegions(false); - auto use_small_single_slot_spans = UseSmallSingleSlotSpans(true); ConfigurePartitions(enable_brp, brp_extra_extras_size, enable_memory_tagging, memory_tagging_reporting_mode, distribution, scheduler_loop_quarantine_global_config, scheduler_loop_quarantine_thread_local_config, - eventually_zero_freed_memory, fewer_memory_regions, - use_small_single_slot_spans); + eventually_zero_freed_memory, fewer_memory_regions); } #endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
diff --git a/base/android/application_status_listener.cc b/base/android/application_status_listener.cc index 45b191d..6efdf26 100644 --- a/base/android/application_status_listener.cc +++ b/base/android/application_status_listener.cc
@@ -11,7 +11,7 @@ #include "base/metrics/user_metrics.h" #include "base/observer_list_threadsafe.h" #include "base/trace_event/application_state_proto_android.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" // Must come after all headers that specialize FromJniType() / ToJniType(). #include "base/tasks_jni/ApplicationStatus_jni.h"
diff --git a/base/android/early_trace_event_binding.cc b/base/android/early_trace_event_binding.cc index 4b28b29..c6b471a 100644 --- a/base/android/early_trace_event_binding.cc +++ b/base/android/early_trace_event_binding.cc
@@ -9,7 +9,7 @@ #include "base/android/jni_string.h" #include "base/android/trace_event_binding.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" // Must come after all headers that specialize FromJniType() / ToJniType().
diff --git a/base/android/jank_metric_uma_recorder.cc b/base/android/jank_metric_uma_recorder.cc index a7bb1f9..ebb362b 100644 --- a/base/android/jank_metric_uma_recorder.cc +++ b/base/android/jank_metric_uma_recorder.cc
@@ -11,7 +11,7 @@ #include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "jank_metric_uma_recorder.h" // Must come after all headers that specialize FromJniType() / ToJniType().
diff --git a/base/android/jni_registrar.cc b/base/android/jni_registrar.cc index 9172a93..827a33f 100644 --- a/base/android/jni_registrar.cc +++ b/base/android/jni_registrar.cc
@@ -11,7 +11,7 @@ #include "base/android/jni_android.h" #include "base/logging.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base { namespace android {
diff --git a/base/android/meminfo_dump_provider.cc b/base/android/meminfo_dump_provider.cc index 20637d3..4f77e01 100644 --- a/base/android/meminfo_dump_provider.cc +++ b/base/android/meminfo_dump_provider.cc
@@ -8,9 +8,10 @@ #include "base/android/jni_android.h" #include "base/logging.h" -#include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/memory_jni/MemoryInfoBridge_jni.h" +#include "base/time/time.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/trace_event.h" namespace base::android {
diff --git a/base/android/meminfo_dump_provider.h b/base/android/meminfo_dump_provider.h index 582ac37..8549281 100644 --- a/base/android/meminfo_dump_provider.h +++ b/base/android/meminfo_dump_provider.h
@@ -8,7 +8,8 @@ #include "base/base_export.h" #include "base/no_destructor.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/memory_dump_provider.h" +#include "base/trace_event/trace_event.h" namespace base::android {
diff --git a/base/android/meminfo_dump_provider_unittest.cc b/base/android/meminfo_dump_provider_unittest.cc index f587355..7cab734 100644 --- a/base/android/meminfo_dump_provider_unittest.cc +++ b/base/android/meminfo_dump_provider_unittest.cc
@@ -9,7 +9,9 @@ #include <string> #include "base/android/build_info.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/process_memory_dump.h" +#include "base/trace_event/trace_event.h" #include "testing/gtest/include/gtest/gtest.h" namespace base::android {
diff --git a/base/android/pre_freeze_background_memory_trimmer.cc b/base/android/pre_freeze_background_memory_trimmer.cc index a7b8c6f..0c36746 100644 --- a/base/android/pre_freeze_background_memory_trimmer.cc +++ b/base/android/pre_freeze_background_memory_trimmer.cc
@@ -27,8 +27,8 @@ #include "base/task/thread_pool.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/named_trigger.h" // no-presubmit-check +#include "base/trace_event/trace_event.h" namespace base::android { BASE_FEATURE(kShouldFreezeSelf, "ShouldFreezeSelf", FEATURE_ENABLED_BY_DEFAULT);
diff --git a/base/android/scoped_input_event.h b/base/android/scoped_input_event.h index 9ad8be70..12709ba5 100644 --- a/base/android/scoped_input_event.h +++ b/base/android/scoped_input_event.h
@@ -9,7 +9,7 @@ #include "base/base_export.h" #include "base/memory/raw_ptr.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/typed_macros.h" namespace base::android {
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc index 7e2a006..3d003bc 100644 --- a/base/android/sys_utils.cc +++ b/base/android/sys_utils.cc
@@ -10,7 +10,7 @@ #include "base/feature_list.h" #include "base/process/process_metrics.h" #include "base/system/sys_info.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" // Must come after all headers that specialize FromJniType() / ToJniType(). #include "base/sys_utils_jni/SysUtils_jni.h"
diff --git a/base/android/task_scheduler/task_runner_android.cc b/base/android/task_scheduler/task_runner_android.cc index 0347d550..a38220f 100644 --- a/base/android/task_scheduler/task_runner_android.cc +++ b/base/android/task_scheduler/task_runner_android.cc
@@ -20,7 +20,7 @@ #include "base/task/thread_pool/thread_pool_impl.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" // Must come after all headers that specialize FromJniType() / ToJniType(). #include "base/android_runtime_jni_headers/Runnable_jni.h"
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc index 9c1377b5..cf659b08 100644 --- a/base/android/trace_event_binding.cc +++ b/base/android/trace_event_binding.cc
@@ -11,10 +11,10 @@ #include "base/android/jni_string.h" #include "base/compiler_specific.h" #include "base/metrics/histogram_macros.h" -#include "base/trace_event/base_tracing.h" -#include "base/tracing_buildflags.h" - #include "base/trace_event/trace_event_impl.h" // no-presubmit-check +#include "base/trace_event/trace_id_helper.h" +#include "base/trace_event/typed_macros.h" +#include "base/tracing_buildflags.h" #include "third_party/perfetto/include/perfetto/tracing/track.h" // no-presubmit-check nogncheck #include "third_party/perfetto/protos/perfetto/config/chrome/chrome_config.gen.h" // nogncheck
diff --git a/base/debug/dump_without_crashing.cc b/base/debug/dump_without_crashing.cc index 7862bc1..22dc925b 100644 --- a/base/debug/dump_without_crashing.cc +++ b/base/debug/dump_without_crashing.cc
@@ -12,7 +12,7 @@ #include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/synchronization/lock.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/buildflag.h" namespace {
diff --git a/base/files/file.cc b/base/files/file.cc index e62d6d40..d9e2b9f 100644 --- a/base/files/file.cc +++ b/base/files/file.cc
@@ -13,7 +13,7 @@ #include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
diff --git a/base/files/file_path.cc b/base/files/file_path.cc index 878a15e..8a97119 100644 --- a/base/files/file_path.cc +++ b/base/files/file_path.cc
@@ -25,7 +25,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_ostream_operators.h" #include "base/strings/utf_string_conversions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #if BUILDFLAG(IS_APPLE) #include "base/apple/scoped_cftyperef.h"
diff --git a/base/files/file_path_watcher_inotify.cc b/base/files/file_path_watcher_inotify.cc index 43b97b0..85d70a0 100644 --- a/base/files/file_path_watcher_inotify.cc +++ b/base/files/file_path_watcher_inotify.cc
@@ -43,7 +43,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/threading/platform_thread.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc index 69953e5..c0d6315a 100644 --- a/base/files/file_tracing.cc +++ b/base/files/file_tracing.cc
@@ -7,7 +7,7 @@ #include <atomic> #include "base/files/file.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/location.cc b/base/location.cc index 931758a0..f4ce271 100644 --- a/base/location.cc +++ b/base/location.cc
@@ -7,7 +7,7 @@ #include "base/compiler_specific.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #if defined(COMPILER_MSVC) #include <intrin.h>
diff --git a/base/location_unittest.cc b/base/location_unittest.cc index 2e3c25e5..bb06f734 100644 --- a/base/location_unittest.cc +++ b/base/location_unittest.cc
@@ -4,7 +4,7 @@ #include "base/location.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/perfetto/include/perfetto/test/traced_value_test_support.h"
diff --git a/base/logging.cc b/base/logging.cc index b8eee13..3a470897 100644 --- a/base/logging.cc +++ b/base/logging.cc
@@ -47,11 +47,13 @@ #include "base/task/common/task_annotator.h" #include "base/test/scoped_logging_settings.h" #include "base/threading/platform_thread.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/typed_macros.h" #include "base/vlog.h" #include "build/build_config.h" #include "third_party/abseil-cpp/absl/base/internal/raw_logging.h" #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h" #if !BUILDFLAG(IS_NACL) #include "base/auto_reset.h"
diff --git a/base/memory/madv_free_discardable_memory_allocator_posix.h b/base/memory/madv_free_discardable_memory_allocator_posix.h index 3e12720f..e0a1fc6 100644 --- a/base/memory/madv_free_discardable_memory_allocator_posix.h +++ b/base/memory/madv_free_discardable_memory_allocator_posix.h
@@ -16,7 +16,8 @@ #include "base/memory/discardable_memory.h" #include "base/memory/discardable_memory_allocator.h" #include "base/memory/madv_free_discardable_memory_posix.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/memory_dump_provider.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc index d536066..7846d75 100644 --- a/base/memory/memory_pressure_listener.cc +++ b/base/memory/memory_pressure_listener.cc
@@ -9,8 +9,10 @@ #include "base/observer_list.h" #include "base/observer_list_threadsafe.h" #include "base/task/sequenced_task_runner.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/memory_pressure_level_proto.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" namespace base {
diff --git a/base/memory/shared_memory_tracker.cc b/base/memory/shared_memory_tracker.cc index c7609cc..d9d883c 100644 --- a/base/memory/shared_memory_tracker.cc +++ b/base/memory/shared_memory_tracker.cc
@@ -8,9 +8,9 @@ #include "base/check.h" #include "base/strings/string_number_conversions.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/process_memory_dump.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" namespace base {
diff --git a/base/memory/shared_memory_tracker.h b/base/memory/shared_memory_tracker.h index 1a3bb251..45d88e3 100644 --- a/base/memory/shared_memory_tracker.h +++ b/base/memory/shared_memory_tracker.h
@@ -11,7 +11,7 @@ #include "base/base_export.h" #include "base/memory/shared_memory_mapping.h" #include "base/synchronization/lock.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/memory_dump_provider.h" namespace base {
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc index 10358797..f61747c9 100644 --- a/base/message_loop/message_pump_default.cc +++ b/base/message_loop/message_pump_default.cc
@@ -8,7 +8,7 @@ #include "base/logging.h" #include "base/synchronization/waitable_event.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_APPLE)
diff --git a/base/message_loop/message_pump_epoll.cc b/base/message_loop/message_pump_epoll.cc index 008728bb5..48c7f5f 100644 --- a/base/message_loop/message_pump_epoll.cc +++ b/base/message_loop/message_pump_epoll.cc
@@ -27,7 +27,8 @@ #include "base/posix/eintr_wrapper.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/heap_profiler.h" +#include "base/trace_event/trace_event.h" #if DCHECK_IS_ON() #include <iomanip>
diff --git a/base/message_loop/message_pump_fuchsia.cc b/base/message_loop/message_pump_fuchsia.cc index adc3986b..5e758b2 100644 --- a/base/message_loop/message_pump_fuchsia.cc +++ b/base/message_loop/message_pump_fuchsia.cc
@@ -15,7 +15,7 @@ #include "base/check.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc index d33f686f..4e20010 100644 --- a/base/message_loop/message_pump_win.cc +++ b/base/message_loop/message_pump_win.cc
@@ -25,7 +25,8 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/task/task_features.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/typed_macros.h" #include "base/tracing_buildflags.h" #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_message_pump.pbzero.h"
diff --git a/base/metrics/user_metrics.cc b/base/metrics/user_metrics.cc index 07325827..aa9f052 100644 --- a/base/metrics/user_metrics.cc +++ b/base/metrics/user_metrics.cc
@@ -14,7 +14,7 @@ #include "base/location.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base { namespace {
diff --git a/base/power_monitor/cpu_frequency_utils.cc b/base/power_monitor/cpu_frequency_utils.cc index 9c16dfa..4885ccb 100644 --- a/base/power_monitor/cpu_frequency_utils.cc +++ b/base/power_monitor/cpu_frequency_utils.cc
@@ -8,7 +8,7 @@ #include "base/system/sys_info.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_WIN)
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc index df28a48..68a7441 100644 --- a/base/power_monitor/power_monitor.cc +++ b/base/power_monitor/power_monitor.cc
@@ -9,7 +9,7 @@ #include "base/logging.h" #include "base/no_destructor.h" #include "base/power_monitor/power_monitor_source.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "power_observer.h"
diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h index 6213ed7..c8f7efd 100644 --- a/base/power_monitor/power_monitor.h +++ b/base/power_monitor/power_monitor.h
@@ -12,7 +12,7 @@ #include "base/observer_list_threadsafe.h" #include "base/power_monitor/power_observer.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/power_monitor/speed_limit_observer_win.cc b/base/power_monitor/speed_limit_observer_win.cc index 70782b11..c2e2f790 100644 --- a/base/power_monitor/speed_limit_observer_win.cc +++ b/base/power_monitor/speed_limit_observer_win.cc
@@ -18,7 +18,7 @@ #include "base/power_monitor/cpu_frequency_utils.h" #include "base/system/sys_info.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace {
diff --git a/base/process/current_process.h b/base/process/current_process.h index be41d24..9773afe 100644 --- a/base/process/current_process.h +++ b/base/process/current_process.h
@@ -13,8 +13,8 @@ #include "base/no_destructor.h" #include "base/process/process_handle.h" #include "base/synchronization/lock.h" -#include "base/trace_event/base_tracing.h" #include "build/buildflag.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h" namespace tracing { class TraceEventDataSource;
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc index ced30570..79ee18b 100644 --- a/base/process/launch_fuchsia.cc +++ b/base/process/launch_fuchsia.cc
@@ -24,7 +24,7 @@ #include "base/process/environment_internal.h" #include "base/scoped_generic.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc index 29e6d750..116f4b86 100644 --- a/base/process/launch_mac.cc +++ b/base/process/launch_mac.cc
@@ -20,7 +20,7 @@ #include "base/process/environment_internal.h" #include "base/threading/scoped_blocking_call.h" #include "base/threading/thread_restrictions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #if BUILDFLAG(IS_MAC) #include "base/apple/mach_port_rendezvous_mac.h"
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc index 6433a7e..7b1d5f9 100644 --- a/base/process/launch_posix.cc +++ b/base/process/launch_posix.cc
@@ -41,7 +41,7 @@ #include "base/threading/platform_thread.h" #include "base/threading/platform_thread_internal_posix.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_AIX)
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index 3399c0e8..1dd6a6da 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc
@@ -37,7 +37,7 @@ #include "base/threading/scoped_thread_priority.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/scoped_handle.h" #include "base/win/scoped_process_information.h" #include "base/win/startup_information.h"
diff --git a/base/process/process_fuchsia.cc b/base/process/process_fuchsia.cc index 14ce8ca..75c509e 100644 --- a/base/process/process_fuchsia.cc +++ b/base/process/process_fuchsia.cc
@@ -14,7 +14,7 @@ #include "base/fuchsia/default_job.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/threading/thread_restrictions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #if BUILDFLAG(CLANG_PROFILING) #include "base/test/clang_profiling.h"
diff --git a/base/process/process_metrics_apple.mm b/base/process/process_metrics_apple.mm index 6375b63d..a4fe040b 100644 --- a/base/process/process_metrics_apple.mm +++ b/base/process/process_metrics_apple.mm
@@ -24,7 +24,7 @@ #include "base/numerics/safe_math.h" #include "base/system/sys_info.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected.h" #include "build/build_config.h"
diff --git a/base/process/process_metrics_fuchsia.cc b/base/process/process_metrics_fuchsia.cc index 4b5dfd5..f14d8c5 100644 --- a/base/process/process_metrics_fuchsia.cc +++ b/base/process/process_metrics_fuchsia.cc
@@ -9,7 +9,7 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/memory/ptr_util.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc index f2110ea..d327b12 100644 --- a/base/process/process_metrics_linux.cc +++ b/base/process/process_metrics_linux.cc
@@ -38,7 +38,7 @@ #include "base/strings/string_util.h" #include "base/system/sys_info.h" #include "base/threading/thread_restrictions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected.h" #include "base/values.h" #include "build/build_config.h"
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc index 113c58f6..4d2ba62 100644 --- a/base/process/process_metrics_win.cc +++ b/base/process/process_metrics_win.cc
@@ -19,7 +19,7 @@ #include "base/notreached.h" #include "base/system/sys_info.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/values.h" #include "build/build_config.h"
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc index d19747e..8e8c6acda 100644 --- a/base/process/process_posix.cc +++ b/base/process/process_posix.cc
@@ -22,7 +22,7 @@ #include "base/process/kill.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_MAC)
diff --git a/base/process/process_win.cc b/base/process/process_win.cc index 1dbf497..34020ce3d 100644 --- a/base/process/process_win.cc +++ b/base/process/process_win.cc
@@ -11,7 +11,7 @@ #include "base/numerics/safe_conversions.h" #include "base/process/kill.h" #include "base/threading/thread_restrictions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/win_util.h" #include "base/win/windows_version.h"
diff --git a/base/profiler/libunwindstack_unwinder_android.cc b/base/profiler/libunwindstack_unwinder_android.cc index 531b533..c13916c 100644 --- a/base/profiler/libunwindstack_unwinder_android.cc +++ b/base/profiler/libunwindstack_unwinder_android.cc
@@ -15,7 +15,7 @@ #include "base/profiler/module_cache.h" #include "base/profiler/native_unwinder_android.h" #include "base/profiler/profile_builder.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/typed_macros.h" #include "build/build_config.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Elf.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Error.h"
diff --git a/base/profiler/stack_copier_signal.cc b/base/profiler/stack_copier_signal.cc index 46009f7..ce877e2 100644 --- a/base/profiler/stack_copier_signal.cc +++ b/base/profiler/stack_copier_signal.cc
@@ -29,7 +29,7 @@ #include "base/profiler/stack_buffer.h" #include "base/profiler/suspendable_thread_delegate.h" #include "base/time/time_override.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc index c44dc12..5450d925 100644 --- a/base/profiler/stack_sampling_profiler.cc +++ b/base/profiler/stack_sampling_profiler.cc
@@ -29,7 +29,7 @@ #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_WIN)
diff --git a/base/run_loop.cc b/base/run_loop.cc index 35056c0..d135ee7e 100644 --- a/base/run_loop.cc +++ b/base/run_loop.cc
@@ -11,7 +11,7 @@ #include "base/functional/callback.h" #include "base/observer_list.h" #include "base/task/single_thread_task_runner.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/synchronization/cancelable_event.cc b/base/synchronization/cancelable_event.cc index f34bf20..d3c3d2b1f 100644 --- a/base/synchronization/cancelable_event.cc +++ b/base/synchronization/cancelable_event.cc
@@ -6,7 +6,7 @@ #include "base/notreached.h" #include "base/synchronization/waitable_event.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/synchronization/waitable_event.cc b/base/synchronization/waitable_event.cc index 79581c14..de226a0 100644 --- a/base/synchronization/waitable_event.cc +++ b/base/synchronization/waitable_event.cc
@@ -11,7 +11,7 @@ #include "base/check.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" namespace base {
diff --git a/base/task/common/task_annotator.cc b/base/task/common/task_annotator.cc index 5654417b..135db033 100644 --- a/base/task/common/task_annotator.cc +++ b/base/task/common/task_annotator.cc
@@ -19,9 +19,13 @@ #include "base/logging.h" #include "base/metrics/metrics_hashes.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/heap_profiler.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/trace_event.h" +#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "base/tracing_buildflags.h" #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_mojo_event_info.pbzero.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/task_execution.pbzero.h" namespace base {
diff --git a/base/task/common/task_annotator.h b/base/task/common/task_annotator.h index e7ed932f..7922462b 100644 --- a/base/task/common/task_annotator.h +++ b/base/task/common/task_annotator.h
@@ -14,7 +14,7 @@ #include "base/memory/raw_ptr_exclusion.h" #include "base/pending_task.h" #include "base/time/tick_clock.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/pass_key.h" namespace base {
diff --git a/base/task/current_thread.cc b/base/task/current_thread.cc index 53a6213a..0f5ac15e4 100644 --- a/base/task/current_thread.cc +++ b/base/task/current_thread.cc
@@ -14,7 +14,7 @@ #include "base/message_loop/message_pump_type.h" #include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/threading/thread_local.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc index 7b1f2b0c..04539c9e 100644 --- a/base/task/sequence_manager/sequence_manager_impl.cc +++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -43,7 +43,7 @@ #include "base/threading/thread_id_name_manager.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/blink_buildflags.h" #include "build/build_config.h"
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc index fd30aa7..f025b981c 100644 --- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc +++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -67,7 +67,7 @@ #include "base/threading/sequence_local_storage_slot.h" #include "base/threading/thread.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" #include "build/build_config.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc index cd41040..c9bcab39 100644 --- a/base/task/sequence_manager/task_queue.cc +++ b/base/task/sequence_manager/task_queue.cc
@@ -19,7 +19,7 @@ #include "base/threading/thread_checker.h" #include "base/threading/thread_checker_impl.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base::sequence_manager {
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h index b87c189..8a5389a 100644 --- a/base/task/sequence_manager/task_queue.h +++ b/base/task/sequence_manager/task_queue.h
@@ -20,8 +20,8 @@ #include "base/task/task_observer.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/base_tracing_forward.h" +#include "base/tracing/protos/chrome_track_event.pbzero.h" namespace perfetto { class EventContext;
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc index 21a00bf..933fc9e 100644 --- a/base/task/sequence_manager/task_queue_impl.cc +++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -36,7 +36,8 @@ #include "base/task/task_observer.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "third_party/abseil-cpp/absl/container/inlined_vector.h"
diff --git a/base/task/sequence_manager/task_queue_selector.cc b/base/task/sequence_manager/task_queue_selector.cc index cc552427..4d6c8610 100644 --- a/base/task/sequence_manager/task_queue_selector.cc +++ b/base/task/sequence_manager/task_queue_selector.cc
@@ -14,7 +14,7 @@ #include "base/task/sequence_manager/work_queue.h" #include "base/task/task_features.h" #include "base/threading/thread_checker.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base::sequence_manager::internal {
diff --git a/base/task/sequence_manager/thread_controller.cc b/base/task/sequence_manager/thread_controller.cc index e22c5df..87a9eb1 100644 --- a/base/task/sequence_manager/thread_controller.cc +++ b/base/task/sequence_manager/thread_controller.cc
@@ -18,7 +18,7 @@ #include "base/strings/string_util.h" #include "base/time/tick_clock.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base::sequence_manager::internal {
diff --git a/base/task/sequence_manager/thread_controller.h b/base/task/sequence_manager/thread_controller.h index ffa65fa..2ad391a5 100644 --- a/base/task/sequence_manager/thread_controller.h +++ b/base/task/sequence_manager/thread_controller.h
@@ -28,7 +28,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/thread_annotations.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" #include "build/build_config.h"
diff --git a/base/task/sequence_manager/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc index 0c2f3a9..8ca3ec03 100644 --- a/base/task/sequence_manager/thread_controller_impl.cc +++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -14,7 +14,7 @@ #include "base/task/common/lazy_now.h" #include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/sequenced_task_source.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base::sequence_manager::internal {
diff --git a/base/task/sequence_manager/thread_controller_power_monitor.cc b/base/task/sequence_manager/thread_controller_power_monitor.cc index ad7abc2..fd250b27 100644 --- a/base/task/sequence_manager/thread_controller_power_monitor.cc +++ b/base/task/sequence_manager/thread_controller_power_monitor.cc
@@ -6,7 +6,7 @@ #include "base/feature_list.h" #include "base/power_monitor/power_monitor.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base::sequence_manager::internal {
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc index 8fa6327e..f6f5ca48 100644 --- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc +++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -22,7 +22,7 @@ #include "base/threading/hang_watcher.h" #include "base/time/tick_clock.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #if BUILDFLAG(IS_IOS)
diff --git a/base/task/thread_pool/job_task_source.cc b/base/task/thread_pool/job_task_source.cc index e7ef71b..417d6e6 100644 --- a/base/task/thread_pool/job_task_source.cc +++ b/base/task/thread_pool/job_task_source.cc
@@ -19,7 +19,7 @@ #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/time/time_override.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base::internal {
diff --git a/base/task/thread_pool/task_tracker.cc b/base/task/thread_pool/task_tracker.cc index df19d8c..96231a9 100644 --- a/base/task/thread_pool/task_tracker.cc +++ b/base/task/thread_pool/task_tracker.cc
@@ -31,7 +31,8 @@ #include "base/threading/sequence_local_storage_map.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" +#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "base/values.h" #include "build/build_config.h"
diff --git a/base/task/thread_pool/thread_group_impl.cc b/base/task/thread_pool/thread_group_impl.cc index cad8c8e..bc8fa19 100644 --- a/base/task/thread_pool/thread_group_impl.cc +++ b/base/task/thread_pool/thread_group_impl.cc
@@ -17,7 +17,7 @@ #include "base/threading/scoped_blocking_call_internal.h" #include "base/threading/thread_checker.h" #include "base/time/time_override.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "third_party/abseil-cpp/absl/container/inlined_vector.h" namespace base::internal {
diff --git a/base/task/thread_pool/worker_thread.cc b/base/task/thread_pool/worker_thread.cc index cdd5e2c..fb60dd3 100644 --- a/base/task/thread_pool/worker_thread.cc +++ b/base/task/thread_pool/worker_thread.cc
@@ -21,7 +21,7 @@ #include "base/threading/hang_watcher.h" #include "base/time/time.h" #include "base/time/time_override.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "partition_alloc/buildflags.h"
diff --git a/base/test/launcher/test_launcher_unittest.cc b/base/test/launcher/test_launcher_unittest.cc index d594ca7..21b45c2 100644 --- a/base/test/launcher/test_launcher_unittest.cc +++ b/base/test/launcher/test_launcher_unittest.cc
@@ -21,6 +21,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/to_string.h" #include "base/test/gtest_xml_util.h" #include "base/test/launcher/test_launcher_test_utils.h" #include "base/test/launcher/unit_test_launcher.h"
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc index 54a56b6..ffff9d4 100644 --- a/base/test/test_pending_task.cc +++ b/base/test/test_pending_task.cc
@@ -7,7 +7,8 @@ #include <string> #include <utility> -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/traced_value.h" namespace base {
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc index 0345d9e..58050e4 100644 --- a/base/test/test_pending_task_unittest.cc +++ b/base/test/test_pending_task_unittest.cc
@@ -5,7 +5,8 @@ #include "base/test/test_pending_task.h" #include "base/functional/bind.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/traced_value.h" #include "base/tracing_buildflags.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest-spi.h"
diff --git a/base/test/test_trace_processor_example_unittest.cc b/base/test/test_trace_processor_example_unittest.cc index a61db72..a728ed65 100644 --- a/base/test/test_trace_processor_example_unittest.cc +++ b/base/test/test_trace_processor_example_unittest.cc
@@ -5,6 +5,7 @@ #include "base/test/task_environment.h" #include "base/test/test_trace_processor.h" #include "base/test/trace_test_utils.h" +#include "base/trace_event/trace_event.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/perfetto/include/perfetto/tracing/tracing.h"
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h index dad01f12..a2c53f1 100644 --- a/base/test/trace_event_analyzer.h +++ b/base/test/trace_event_analyzer.h
@@ -100,7 +100,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base { class Value;
diff --git a/base/threading/hang_watcher.cc b/base/threading/hang_watcher.cc index 3f52378..c62f44f 100644 --- a/base/threading/hang_watcher.cc +++ b/base/threading/hang_watcher.cc
@@ -28,7 +28,7 @@ #include "base/threading/threading_features.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/threading/platform_thread.cc b/base/threading/platform_thread.cc index abe6453..2e4f7d9 100644 --- a/base/threading/platform_thread.cc +++ b/base/threading/platform_thread.cc
@@ -6,7 +6,7 @@ #include "base/task/current_thread.h" #include "base/threading/thread_id_name_manager.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #if BUILDFLAG(IS_FUCHSIA) #include "base/fuchsia/scheduler.h"
diff --git a/base/threading/platform_thread_metrics_apple.mm b/base/threading/platform_thread_metrics_apple.mm index 62db5248..b9c9213 100644 --- a/base/threading/platform_thread_metrics_apple.mm +++ b/base/threading/platform_thread_metrics_apple.mm
@@ -13,7 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/threading/platform_thread_metrics_fuchsia.cc b/base/threading/platform_thread_metrics_fuchsia.cc index b1df0b7..429d4e6 100644 --- a/base/threading/platform_thread_metrics_fuchsia.cc +++ b/base/threading/platform_thread_metrics_fuchsia.cc
@@ -15,7 +15,7 @@ #include <optional> #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/threading/platform_thread_metrics_linux.cc b/base/threading/platform_thread_metrics_linux.cc index c49e2428..13f0eb30 100644 --- a/base/threading/platform_thread_metrics_linux.cc +++ b/base/threading/platform_thread_metrics_linux.cc
@@ -16,7 +16,7 @@ #include "base/process/internal_linux.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base {
diff --git a/base/threading/platform_thread_metrics_win.cc b/base/threading/platform_thread_metrics_win.cc index 73ab3797..e3ba14c 100644 --- a/base/threading/platform_thread_metrics_win.cc +++ b/base/threading/platform_thread_metrics_win.cc
@@ -13,7 +13,7 @@ #include "base/memory/ptr_util.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/scoped_handle.h" #include "build/build_config.h"
diff --git a/base/threading/scoped_blocking_call.cc b/base/threading/scoped_blocking_call.cc index eb253a2..b9901ca3 100644 --- a/base/threading/scoped_blocking_call.cc +++ b/base/threading/scoped_blocking_call.cc
@@ -8,7 +8,8 @@ #include "base/threading/thread_local.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/typed_macros.h" #include "base/tracing_buildflags.h" #include "build/build_config.h" #include "third_party/perfetto/protos/perfetto/trace/track_event/source_location.pbzero.h"
diff --git a/base/threading/scoped_thread_priority.cc b/base/threading/scoped_thread_priority.cc index 995f94d..caec5b8 100644 --- a/base/threading/scoped_thread_priority.cc +++ b/base/threading/scoped_thread_priority.cc
@@ -7,7 +7,8 @@ #include "base/check_op.h" #include "base/location.h" #include "base/threading/platform_thread.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" namespace base {
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc index 74e56c3..c5f793b6 100644 --- a/base/threading/thread_restrictions.cc +++ b/base/threading/thread_restrictions.cc
@@ -6,7 +6,8 @@ #include "base/check.h" #include "base/threading/hang_watcher.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/interned_args_helper.h" +#include "base/trace_event/typed_macros.h" #include "build/build_config.h" namespace base {
diff --git a/base/trace_event/base_tracing.h b/base/trace_event/base_tracing.h deleted file mode 100644 index ea24753..0000000 --- a/base/trace_event/base_tracing.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TRACE_EVENT_BASE_TRACING_H_ -#define BASE_TRACE_EVENT_BASE_TRACING_H_ - -// Proxy header that provides tracing instrumentation for //base code. When -// tracing support is disabled via the gn flag enable_base_tracing, this header -// provides a mock implementation of the relevant trace macros instead, which -// causes the instrumentation in //base to be compiled into no-ops. - -#include "base/tracing_buildflags.h" - -// TODO(crbug.com/42050015): Switch to perfetto for trace event implementation. -#include "base/trace_event/heap_profiler.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/interned_args_helper.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/memory_allocator_dump_guid.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/memory_dump_manager.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/memory_dump_provider.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/trace_event.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/trace_id_helper.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/traced_value.h" // IWYU pragma: export, nogncheck -#include "base/trace_event/typed_macros.h" // IWYU pragma: export, nogncheck -#include "third_party/perfetto/include/perfetto/tracing/traced_value.h" // IWYU pragma: export, nogncheck -#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h" // IWYU pragma: export, nogncheck -#include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h" // IWYU pragma: export, nogncheck -#include "third_party/perfetto/protos/perfetto/trace/track_event/task_execution.pbzero.h" // IWYU pragma: export, nogncheck - -#endif // BASE_TRACE_EVENT_BASE_TRACING_H_
diff --git a/base/trace_event/named_trigger.h b/base/trace_event/named_trigger.h index 7cbc9c7..17eebf5 100644 --- a/base/trace_event/named_trigger.h +++ b/base/trace_event/named_trigger.h
@@ -11,7 +11,6 @@ #include <string> #include "base/base_export.h" -#include "base/trace_event/base_tracing.h" namespace base::trace_event {
diff --git a/base/values.cc b/base/values.cc index 2400671..571d7be 100644 --- a/base/values.cc +++ b/base/values.cc
@@ -27,11 +27,11 @@ #include "base/notreached.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/memory_usage_estimator.h" // no-presubmit-check +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" #include "base/types/pass_key.h" #include "base/types/to_address.h" -#include "base/trace_event/memory_usage_estimator.h" // no-presubmit-check namespace base {
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc index 642e5510..bbbb6e6 100644 --- a/base/win/object_watcher.cc +++ b/base/win/object_watcher.cc
@@ -13,7 +13,7 @@ #include "base/synchronization/waitable_event.h" #include "base/task/sequenced_task_runner.h" #include "base/threading/thread_restrictions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace base { namespace win {
diff --git a/base/win/scoped_handle_verifier.cc b/base/win/scoped_handle_verifier.cc index 8eb96802..aa75354 100644 --- a/base/win/scoped_handle_verifier.cc +++ b/base/win/scoped_handle_verifier.cc
@@ -18,7 +18,7 @@ #include "base/memory/raw_ref.h" #include "base/notreached.h" #include "base/synchronization/lock_impl.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/base_win_buildflags.h" #include "base/win/current_module.h" #include "base/win/scoped_handle.h"
diff --git a/build/android/java/templates/BuildConfig.template b/build/android/java/templates/BuildConfig.template index c1465a6..3d06cb4 100644 --- a/build/android/java/templates/BuildConfig.template +++ b/build/android/java/templates/BuildConfig.template
@@ -110,6 +110,12 @@ public static boolean IS_DESKTOP_ANDROID; #endif +#if defined(_ENABLE_DESKTOP_ANDROID_EXTENSIONS) + public static boolean ENABLE_DESKTOP_ANDROID_EXTENSIONS = true; +#else + public static boolean ENABLE_DESKTOP_ANDROID_EXTENSIONS; +#endif + // Controls whether or not StrictModeContext is a no-op. #if defined(_DISABLE_STRICT_MODE_CONTEXT) public static boolean DISABLE_STRICT_MODE_CONTEXT = true;
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 05f947f4..159a1665 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -9,6 +9,7 @@ import("//build/config/rts.gni") import("//build/config/sanitizers/sanitizers.gni") import("//build_overrides/build.gni") +import("//extensions/buildflags/buildflags.gni") assert( is_android || is_robolectric, @@ -1998,6 +1999,10 @@ defines += [ "_IS_DESKTOP_ANDROID" ] } + if (enable_desktop_android_extensions) { + defines += [ "_ENABLE_DESKTOP_ANDROID_EXTENSIONS" ] + } + if (defined(invoker.write_clang_profiling_data) && invoker.write_clang_profiling_data) { defines += [ "_WRITE_CLANG_PROFILING_DATA" ]
diff --git a/build/config/mac/mac_sdk_overrides.gni b/build/config/mac/mac_sdk_overrides.gni index 15ddfd5c..8f8ac1c 100644 --- a/build/config/mac/mac_sdk_overrides.gni +++ b/build/config/mac/mac_sdk_overrides.gni
@@ -7,5 +7,5 @@ declare_args() { # Minimum supported version of the Mac SDK. - mac_sdk_min = "10.15" + mac_sdk_min = "15" }
diff --git a/build/install-build-deps.py b/build/install-build-deps.py index f699b9b..6b1236a5 100755 --- a/build/install-build-deps.py +++ b/build/install-build-deps.py
@@ -376,7 +376,6 @@ "libsqlite3-0", "libuuid1", "libwayland-egl1", - "libwayland-egl1-mesa", "libx11-6", "libx11-xcb1", "libxau6",
diff --git a/build/toolchain/nacl_toolchain.gni b/build/toolchain/nacl_toolchain.gni index fbaa65e..915716a 100644 --- a/build/toolchain/nacl_toolchain.gni +++ b/build/toolchain/nacl_toolchain.gni
@@ -54,6 +54,9 @@ use_clang_coverage = false coverage_instrumentation_input_file = "" + # NaCl doesn't work with Clang modules. + use_libcxx_modules = false + if (use_reclient) { if (is_win) { reclient_cc_cfg_file = rebase_path(reclient_cfg_dir, root_build_dir) +
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni index e4bb2359..4aa235a6 100644 --- a/buildtools/deps_revisions.gni +++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@ declare_args() { # Used to cause full rebuilds on libc++ rolls. This should be kept in sync # with the libcxx_revision var in //DEPS. - libcxx_revision = "0e242589e53523da3fc2df7ee965f9534550dec5" + libcxx_revision = "cdae0b78c315e58661273c8cd9119b460e68f98b" }
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn index d88764bb..48a85d7 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn
@@ -61,10 +61,7 @@ template("sysroot_modules") { source_set(target_name) { use_libcxx_modules = false - deps = [] - if (is_linux) { - sources = [ "//build/linux/amd64/module.modulemap" ] - } + sources = [ "//build/linux/amd64/module.modulemap" ] deps = [ ":copy_custom_headers", ":copy_libcxx_headers",
diff --git a/cc/raster/single_thread_task_graph_runner.cc b/cc/raster/single_thread_task_graph_runner.cc index 1a2c295..356ec6c 100644 --- a/cc/raster/single_thread_task_graph_runner.cc +++ b/cc/raster/single_thread_task_graph_runner.cc
@@ -12,8 +12,6 @@ #include <utility> #include "base/threading/simple_thread.h" -#include "base/trace_event/base_tracing.h" -#include "base/trace_event/trace_event.h" #include "base/trace_event/typed_macros.h" namespace cc {
diff --git a/chrome/VERSION b/chrome/VERSION index b47a6f8..496154cd 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=139 MINOR=0 -BUILD=7222 +BUILD=7223 PATCH=0
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml index ff274a2a..d982ebe 100644 --- a/chrome/android/java/res/values/ids.xml +++ b/chrome/android/java/res/values/ids.xml
@@ -38,6 +38,7 @@ <item type="id" name="open_recently_closed_tab" /> <item type="id" name="toggle_bookmark_bar" /> <item type="id" name="switch_keyboard_focus_row" /> + <item type="id" name="open_tab_strip_context_menu" /> <item type="id" name="focus_bookmarks" /> <item type="id" name="dev_tools" /> <item type="id" name="task_manager" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java index 524484e..6d624f1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
@@ -673,7 +673,7 @@ new KeyboardShortcutDefinition( KeyboardShortcutsSemanticMeaning .NOT_IMPLEMENTED_FOCUSED_TAB_STRIP_ITEM_OPEN_CONTEXT_MENU, - new KeyCombo(KeyEvent.KEYCODE_F7, KeyEvent.META_SHIFT_ON), + new KeyCombo(KeyEvent.KEYCODE_F10, KeyEvent.META_SHIFT_ON), /* resId= */ Resources.ID_NULL, /* groupId= */ Resources.ID_NULL); new KeyboardShortcutDefinition( @@ -1138,6 +1138,14 @@ } else { return false; } + case KeyboardShortcutsSemanticMeaning + .NOT_IMPLEMENTED_FOCUSED_TAB_STRIP_ITEM_OPEN_CONTEXT_MENU: + if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_KEYBOARD_A11Y)) { + return menuOrKeyboardActionController.onMenuOrKeyboardAction( + R.id.open_tab_strip_context_menu, /* fromMenu= */ false); + } else { + return false; + } case KeyboardShortcutsSemanticMeaning.KEYBOARD_FOCUS_TOOLBAR: if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_KEYBOARD_A11Y)) { toolbarManager.requestFocus();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java index fdad183..97e4cfe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java
@@ -82,6 +82,8 @@ static final String PREF_CARD_BENEFITS = "card_benefits"; private static final String PREF_PAYMENT_APPS = "payment_apps"; static final String PREF_LOYALTY_CARDS = "loyalty_cards"; + // The constant used to optionally scroll to the loyalty card management pref. + static final String EXTRA_FOCUS_LOYALTY_CARD_PREF = "focus_loyalty_card_pref"; @VisibleForTesting static final String PREF_FINANCIAL_ACCOUNTS_MANAGEMENT = "financial_accounts_management"; @@ -111,6 +113,11 @@ screen.setShouldUseGeneratedIds(false); setPreferenceScreen(screen); + + Bundle arguments = getArguments(); + if (arguments != null && arguments.keySet().contains(EXTRA_FOCUS_LOYALTY_CARD_PREF)) { + scrollToPreference(PREF_LOYALTY_CARDS); + } } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelper.java index a4274b4..ed3c636 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelper.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.autofill.settings; import android.content.Context; +import android.os.Bundle; import org.jni_zero.CalledByNative; @@ -50,6 +51,19 @@ return true; } + /** + * Shows the loyalty card management pref in the payments settings fragment. + * + * @param context The {@link Context} required to start the settings page. + */ + public static void showGoogleWalletSettings(Context context) { + // TODO: crbug.com/421839554 - Record user action for this scenario. + Bundle bundle = new Bundle(); + bundle.putBoolean(AutofillPaymentMethodsFragment.EXTRA_FOCUS_LOYALTY_CARD_PREF, true); + SettingsNavigationFactory.createSettingsNavigation() + .startSettings(context, AutofillPaymentMethodsFragment.class, bundle); + } + @CalledByNative private static void showAutofillProfileSettings(WebContents webContents) { WindowAndroid windowAndroid = webContents.getTopLevelNativeWindow();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java index 3ecb8b5..783cabd6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -2216,6 +2216,21 @@ mTabContextMenuCoordinator.showMenu(anchorRectProvider, tab.getTabId()); } + /** + * Opens the context menu for the keyboard-focused view, if applicable. + * + * @return Whether the context menu was successfully opened. + */ + public boolean openKeyboardFocusedContextMenu() { + List<VirtualView> virtualViews = new ArrayList<>(); + getVirtualViews(virtualViews); + for (VirtualView view : virtualViews) { + if (!view.isKeyboardFocused()) continue; + return showContextMenu((StripLayoutView) view); + } + return false; + } + /* package */ void showTabContextMenuForTesting(StripLayoutTab tab) { showTabContextMenu(tab); } @@ -2889,16 +2904,28 @@ mUpdateHost.requestUpdate(); } - private void showContextMenu(StripLayoutView clickedView) { + /** + * Show the context menu originating at {@param clickedView}, and returns true if a context menu + * was shown. (Note: this will return false if there is no context menu to be shown at {@param + * clickedView}. + * + * @param clickedView The view for which to show a context menu. + * @return Whether a context menu was shown. + */ + private boolean showContextMenu(StripLayoutView clickedView) { if (clickedView instanceof StripLayoutTab clickedTab && ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_STRIP_CONTEXT_MENU)) { showTabContextMenu(clickedTab); + return true; } else if (clickedView instanceof CompositorButton button && button.getType() == ButtonType.TAB_CLOSE) { showCloseButtonMenu((StripLayoutTab) button.getParentView()); + return true; } else if (clickedView instanceof StripLayoutGroupTitle groupTitle) { showTabGroupContextMenu(groupTitle, /* shouldWaitForUpdate= */ false); + return true; } + return false; } private void handleTabClick(StripLayoutTab tab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java index b8cc16ce..9e202bd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -1647,4 +1647,13 @@ public boolean containsKeyboardFocus() { return mManagerHost.containsKeyboardFocus(this); } + + /** + * Opens the context menu for the currently keyboard-focused item, if applicable. + * + * @return Whether the context menu was successfully opened. + */ + public boolean openKeyboardFocusedContextMenu() { + return getActiveStripLayoutHelper().openKeyboardFocusedContextMenu(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java index 49d068f..1b2b429 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabLoadIfNeededCaller; import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.media.capture.ScreenCapture; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -195,8 +196,12 @@ private void startAndroidCapturePrompt() { var fragment = MediaCapturePickerHeadlessFragment.getInstanceForCurrentActivity(); fragment.startAndroidCapturePrompt( - result -> { - switch (result) { + (action, result) -> { + if (action != CaptureAction.CAPTURE_CANCELLED) { + ScreenCapture.onPick(result); + } + + switch (action) { case CaptureAction.CAPTURE_CANCELLED: mDelegate.onCancel(); break;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerHeadlessFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerHeadlessFragment.java index 8b72a251..999111a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerHeadlessFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerHeadlessFragment.java
@@ -10,6 +10,7 @@ import android.media.projection.MediaProjectionManager; import android.os.Bundle; +import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.IntDef; @@ -19,7 +20,6 @@ import androidx.fragment.app.FragmentManager; import org.chromium.base.ApplicationStatus; -import org.chromium.base.Callback; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -47,9 +47,13 @@ int CAPTURE_SCREEN = 2; } + interface Delegate { + void onPicked(@CaptureAction int action, ActivityResult result); + } + private MediaProjectionManager mMediaProjectionManager; private ActivityResultLauncher<Intent> mLauncher; - private Callback<@CaptureAction Integer> mNextCallback; + private Delegate mNextDelegate; public static MediaCapturePickerHeadlessFragment getInstanceForCurrentActivity() { var activity = (FragmentActivity) ApplicationStatus.getLastTrackedFocusedActivity(); @@ -83,25 +87,25 @@ registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { - assert mNextCallback != null; + assert mNextDelegate != null; if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { // There is currently no way to differentiate between window and // screen sharing. - mNextCallback.onResult(CaptureAction.CAPTURE_WINDOW); + mNextDelegate.onPicked(CaptureAction.CAPTURE_WINDOW, result); } else { - mNextCallback.onResult(CaptureAction.CAPTURE_CANCELLED); + mNextDelegate.onPicked(CaptureAction.CAPTURE_CANCELLED, result); } - mNextCallback = null; + mNextDelegate = null; }); // This fragment has no UI so we can retain it. setRetainInstance(true); } - public void startAndroidCapturePrompt(Callback<@CaptureAction Integer> callback) { - assert mNextCallback == null; - mNextCallback = callback; + public void startAndroidCapturePrompt(Delegate delegate) { + assert mNextDelegate == null; + mNextDelegate = delegate; mLauncher.launch(mMediaProjectionManager.createScreenCaptureIntent()); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java index 3044b4c..462b1e81 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.multiwindow; +import static org.chromium.build.NullUtil.assumeNonNull; import static org.chromium.chrome.browser.tabwindow.TabWindowManager.INVALID_WINDOW_ID; import android.app.Activity; @@ -86,6 +87,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; class MultiInstanceManagerApi31 extends MultiInstanceManagerImpl implements ActivityStateListener { private static final String TAG = "MIMApi31"; @@ -640,6 +643,22 @@ ChromeSharedPreferences.getInstance().writeInt(taskMapKey(instanceId), taskId); } + static Set<Integer> getPersistedInstanceIds() { + Set<Integer> ids = new HashSet<>(); + Map<String, Long> lastAccessedTimeMap = + ChromeSharedPreferences.getInstance() + .readLongsWithPrefix( + ChromePreferenceKeys.MULTI_INSTANCE_LAST_ACCESSED_TIME); + for (String prefKey : lastAccessedTimeMap.keySet()) { + Pattern pattern = Pattern.compile("(\\d+)$"); + Matcher matcher = pattern.matcher(prefKey); + assert matcher.find() : "Key should be suffixed with the instance id."; + assumeNonNull(matcher.group(1)); + ids.add(Integer.parseInt(matcher.group(1))); + } + return ids; + } + private void removeInvalidInstanceData(boolean cleanupApplicationStatus) { // Remove tasks that do not exist any more from the task map ActivityManager activityManager =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java index b7e05575..13f9749 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -63,6 +63,7 @@ import java.lang.ref.WeakReference; import java.util.List; import java.util.Locale; +import java.util.Set; /** * Utilities for detecting multi-window/multi-instance support. @@ -406,8 +407,9 @@ public static int getInstanceCount() { if (sInstanceCountForTesting != null) return sInstanceCountForTesting; int count = 0; - for (int i = 0; i < getMaxInstances(); ++i) { - if (MultiInstanceManagerApi31.instanceEntryExists(i) && isRestorableInstance(i)) { + Set<Integer> ids = MultiInstanceManagerApi31.getPersistedInstanceIds(); + for (Integer id : ids) { + if (isRestorableInstance(id)) { count++; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index dd537d1..9c07946 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -70,6 +70,7 @@ import org.chromium.chrome.browser.collaboration.messaging.MessagingBackendServiceFactory; import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl; +import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager; import org.chromium.chrome.browser.crash.ChromePureJavaExceptionReporter; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.data_sharing.DataSharingNotificationManager; @@ -1811,6 +1812,12 @@ if (id == R.id.switch_keyboard_focus_row) { mKeyboardFocusRowManager.onKeyboardFocusRowSwitch(); return true; + } else if (id == R.id.open_tab_strip_context_menu) { + @Nullable + StripLayoutHelperManager stripLayoutHelperManager = + mLayoutManager.getStripLayoutHelperManager(); + if (stripLayoutHelperManager == null) return false; + return stripLayoutHelperManager.openKeyboardFocusedContextMenu(); } else if (id == R.id.focus_bookmarks) { if (mBookmarkBarCoordinator != null) mBookmarkBarCoordinator.requestFocus(); return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index d3817ad..f17c203 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1647,6 +1647,7 @@ ExtensionToolbarManager.maybeCreate( mActivity, extensionToolbarStub, + windowAndroid, profileSupplier, tabProvider, browsingModeThemeColorProvider);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerBridge.java index af2387f..5bdc71aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerBridge.java
@@ -15,6 +15,7 @@ import org.chromium.build.annotations.NullMarked; import org.chromium.chrome.browser.autofill.AutofillFallbackSurfaceLauncher; +import org.chromium.chrome.browser.autofill.settings.SettingsNavigationHelper; import org.chromium.ui.base.WindowAndroid; import java.lang.ref.WeakReference; @@ -74,6 +75,13 @@ } @Override + public void showGoogleWalletSettings() { + if (mContext.get() != null) { + SettingsNavigationHelper.showGoogleWalletSettings(mContext.get()); + } + } + + @Override public void creditCardSuggestionSelected(String uniqueId, boolean isVirtual) { if (mNativeTouchToFillPaymentMethodViewController != 0) { TouchToFillPaymentMethodControllerBridgeJni.get()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java index a73ddcb..e2dfa339 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java
@@ -342,6 +342,16 @@ /* id= */ eq(R.id.switch_keyboard_focus_row), /* fromMenu= */ eq(false)); } + @Test + @SmallTest + @EnableFeatures(ChromeFeatureList.ANDROID_KEYBOARD_A11Y) + public void testOpenStripContextMenu() { + keyDown(KeyEvent.KEYCODE_F10, KeyEvent.META_SHIFT_ON, true); + verify(mMenuOrKeyboardActionController, times(1)) + .onMenuOrKeyboardAction( + /* id= */ eq(R.id.open_tab_strip_context_menu), /* fromMenu= */ eq(false)); + } + private void testOpenBookmarks( boolean expectHandled, boolean isCurrentTabVisible, int metaState) { assertEquals(expectHandled, keyDown(KeyEvent.KEYCODE_O, metaState, isCurrentTabVisible));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelperTest.java index 30a6d64..e5d923e 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/settings/SettingsNavigationHelperTest.java
@@ -5,11 +5,14 @@ package org.chromium.chrome.browser.autofill.settings; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import android.content.Context; +import android.os.Bundle; import androidx.test.filters.SmallTest; @@ -18,6 +21,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -39,6 +44,7 @@ @Mock private SettingsNavigation mMockLauncher; @Mock private Context mMockContext; + @Captor private ArgumentCaptor<Bundle> mBundleCaptor; private final UserActionTester mActionTester = new UserActionTester(); @@ -62,6 +68,23 @@ @Test @SmallTest + public void testLaunchesGoogleWalletSettings() { + SettingsNavigationHelper.showGoogleWalletSettings(mMockContext); + verify(mMockLauncher) + .startSettings( + eq(mMockContext), + eq(AutofillPaymentMethodsFragment.class), + mBundleCaptor.capture()); + + Bundle bundle = mBundleCaptor.getValue(); + assertNotNull(bundle); + assertTrue( + bundle.keySet() + .contains(AutofillPaymentMethodsFragment.EXTRA_FOCUS_LOYALTY_CARD_PREF)); + } + + @Test + @SmallTest public void testRecordsActionThenLaunchesAddressesSettings() { assertTrue(SettingsNavigationHelper.showAutofillProfileSettings(mMockContext)); assertTrue(mActionTester.getActions().contains("AutofillAddressesViewed"));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java index ab4f825..057abf3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -6295,6 +6295,74 @@ /* expectedScrollDelta= */ StripLayoutHelper.SCROLL_SPEED_FACTOR); } + @EnableFeatures({ + ChromeFeatureList.ANDROID_KEYBOARD_A11Y, + ChromeFeatureList.TAB_STRIP_CONTEXT_MENU + }) + @Test + public void testOpenContextMenu_notApplicable() { + initializeTest(false, false, 0); + setupForIndividualTabContextMenu(); + assertFalse( + "If nothing is keyboard focused, expect context menu to not open", + mStripLayoutHelper.openKeyboardFocusedContextMenu()); + } + + @EnableFeatures({ + ChromeFeatureList.ANDROID_KEYBOARD_A11Y, + ChromeFeatureList.TAB_STRIP_CONTEXT_MENU + }) + @Test + public void testOpenContextMenu_tab() { + initializeTest(false, false, 0); + setupForIndividualTabContextMenu(); + StripLayoutTab tabToFocus = mStripLayoutHelper.getStripLayoutTabsForTesting()[0]; + tabToFocus.setKeyboardFocused(true); + assertTrue( + "Expected openKeyboardFocusedContextMenu to return true if tab context menu opened", + mStripLayoutHelper.openKeyboardFocusedContextMenu()); + verify(mTabContextMenuCoordinator, times(1)).showMenu(any(), anyInt()); + } + + @EnableFeatures({ + ChromeFeatureList.ANDROID_KEYBOARD_A11Y, + ChromeFeatureList.TAB_STRIP_CONTEXT_MENU + }) + @Test + public void testOpenContextMenu_tabGroup() { + initializeTest(false, false, 0); + groupTabs(0, 1); + setupForGroupContextMenu(); + StripLayoutGroupTitle groupTitle = + (StripLayoutGroupTitle) mStripLayoutHelper.getStripLayoutViewsForTesting()[0]; + groupTitle.setKeyboardFocused(true); + assertTrue( + "Expected openKeyboardFocusedContextMenu to return true if tab context menu opened", + mStripLayoutHelper.openKeyboardFocusedContextMenu()); + verify(mTabGroupContextMenuCoordinator, times(1)).showMenu(any(), any()); + } + + @EnableFeatures({ + ChromeFeatureList.ANDROID_KEYBOARD_A11Y, + ChromeFeatureList.TAB_STRIP_CONTEXT_MENU + }) + @Test + public void testOpenContextMenu_closeButton() { + initializeTest(false, false, 0); + // Set up a view for ListMenu to use (otherwise constructing the ListMenu will fail). + View tabView = new View(mActivity); + when(mModel.getTabAt(anyInt())).thenReturn(mTab); + when(mTab.getView()).thenReturn(tabView); + StripLayoutTab parentTab = mStripLayoutHelper.getStripLayoutTabsForTesting()[0]; + parentTab.getCloseButton().setKeyboardFocused(true); + assertTrue( + "Expected openKeyboardFocusedContextMenu to return true if tab context menu opened", + mStripLayoutHelper.openKeyboardFocusedContextMenu()); + assertTrue( + "Expected close button context menu to be showing", + mStripLayoutHelper.isCloseButtonMenuShowingForTesting()); + } + @Test @EnableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION}) public void testTabCreated_HorizontalAnimation() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java index 2633ef952..add678f9 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsUnitTest.java
@@ -420,6 +420,28 @@ } @Test + public void getInstanceCount_ExceedsLimit() { + when(mTabModelSelector.getModel(false)).thenReturn(mNormalTabModel); + when(mTabModelSelector.getModel(true)).thenReturn(mIncognitoTabModel); + int maxInstances = 3; + MultiWindowUtils.setMaxInstancesForTesting(maxInstances); + + // Simulate persistence of instance state for max instances = 3. + writeInstanceInfo( + INSTANCE_ID_0, URL_1, /* tabCount= */ 3, /* incognitoTabCount= */ 2, TASK_ID_5); + writeInstanceInfo( + INSTANCE_ID_1, URL_2, /* tabCount= */ 0, /* incognitoTabCount= */ 0, TASK_ID_6); + writeInstanceInfo( + INSTANCE_ID_2, URL_3, /* tabCount= */ 6, /* incognitoTabCount= */ 2, TASK_ID_7); + + // Simulate downgrade of instance limit. + MultiWindowUtils.setMaxInstancesForTesting(maxInstances - 1); + + // Verify instance count. + assertEquals(3, MultiWindowUtils.getInstanceCount()); + } + + @Test @Config(sdk = 31) public void testGetInstanceIdForViewIntent_LessThanMaxInstancesOpen() { MultiWindowTestUtils.enableMultiInstance();
diff --git a/chrome/browser/actor/tools/page_tool.cc b/chrome/browser/actor/tools/page_tool.cc index 6520934a..810a401 100644 --- a/chrome/browser/actor/tools/page_tool.cc +++ b/chrome/browser/actor/tools/page_tool.cc
@@ -4,12 +4,17 @@ #include "chrome/browser/actor/tools/page_tool.h" +#include "base/functional/bind.h" +#include "base/task/sequenced_task_runner.h" #include "chrome/browser/actor/actor_coordinator.h" #include "chrome/browser/actor/aggregated_journal.h" #include "chrome/common/actor/action_result.h" #include "chrome/common/chrome_render_frame.mojom.h" #include "components/optimization_guide/proto/features/actions_data.pb.h" +#include "content/public/browser/global_routing_id.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "third_party/abseil-cpp/absl/strings/str_format.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" @@ -17,7 +22,10 @@ namespace { +using ::content::GlobalRenderFrameHostId; using ::content::RenderFrameHost; +using ::content::WebContents; +using ::content::WebContentsObserver; using ::optimization_guide::proto::ActionInformation; using ::optimization_guide::proto::ActionTarget; using ::optimization_guide::proto::ClickAction_ClickCount; @@ -179,11 +187,36 @@ namespace actor { +// Observer to track if the a given RenderFrameHost is changed. +class RenderFrameChangeObserver : public WebContentsObserver { + public: + RenderFrameChangeObserver(RenderFrameHost& rfh, base::OnceClosure callback) + : WebContentsObserver(WebContents::FromRenderFrameHost(&rfh)), + rfh_id_(rfh.GetGlobalId()), + callback_(std::move(callback)) {} + + // WebContentsObserver + void RenderFrameHostChanged(RenderFrameHost* old_host, + RenderFrameHost* /*new_host*/) override { + if (!callback_) { + return; + } + + if (old_host && old_host->GetGlobalId() == rfh_id_) { + std::move(callback_).Run(); + } + } + + private: + GlobalRenderFrameHostId rfh_id_; + base::OnceClosure callback_; +}; + PageTool::PageTool(AggregatedJournal& journal, RenderFrameHost& frame, const ActionInformation& action_information) - : action_information_(action_information) { - frame.GetRemoteAssociatedInterfaces()->GetInterface(&chrome_render_frame_); + : render_frame_host_(frame.GetWeakDocumentPtr()), + action_information_(action_information) { journal.EnsureJournalBound(frame); } @@ -196,14 +229,20 @@ } void PageTool::Invoke(InvokeCallback callback) { + invoke_callback_ = std::move(callback); + RenderFrameHost* frame = render_frame_host_.AsRenderFrameHostIfValid(); + if (!frame) { + PostFinishInvoke(mojom::ActionResultCode::kFrameWentAway); + return; + } + auto request = actor::mojom::ToolInvocation::New(); switch (action_information_.action_info_case()) { case ActionInformation::ActionInfoCase::kClick: { auto click = mojom::ClickAction::New(); if (!SetClickToolArgs(click, action_information_)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kArgumentsInvalid)); + PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); return; } request->action = mojom::ToolAction::NewClick(std::move(click)); @@ -212,8 +251,7 @@ case ActionInformation::ActionInfoCase::kType: { auto type = mojom::TypeAction::New(); if (!SetTypeToolArgs(type, action_information_)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kArgumentsInvalid)); + PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); return; } request->action = mojom::ToolAction::NewType(std::move(type)); @@ -222,8 +260,7 @@ case ActionInformation::ActionInfoCase::kScroll: { auto scroll = mojom::ScrollAction::New(); if (!SetScrollToolArgs(scroll, action_information_)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kArgumentsInvalid)); + PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); return; } request->action = mojom::ToolAction::NewScroll(std::move(scroll)); @@ -256,7 +293,35 @@ NOTREACHED(); } - chrome_render_frame_->InvokeTool(std::move(request), std::move(callback)); + frame->GetRemoteAssociatedInterfaces()->GetInterface(&chrome_render_frame_); + + // Watch for the RenderFrameHost being swapped out by a navigation (e.g. after + // clicking on a link). In that case, finish the invocation successfully as + // the ToolController will wait on the new page to load if needed. We rely on + // this running before the RenderFrameHost is destroyed since otherwise the + // chrome_render_frame_ mojo pipe will call the disconnect error handler which + // finishes the invocation with an error. Finally, this also handles cases + // where the old frame is put into the BFCache since in that case we may not + // get a reply from the renderer at all. + // Note: If there's already an in progress navigation then + // frame_change_observer may call FinishInvoke as a result of that navigation + // rather than the tool use. In that case we'll return success as if the tool + // completed successfully (expecting that's fine, as a new observation will be + // taken). + // `this` Unretained because the observer is owned by this class and thus + // removed on destruction. + frame_change_observer_ = std::make_unique<RenderFrameChangeObserver>( + *frame, base::BindOnce(&PageTool::FinishInvoke, base::Unretained(this), + MakeOkResult())); + + // `this` Unretained because this class owns the mojo pipe that invokes the + // callbacks. + chrome_render_frame_.set_disconnect_handler( + base::BindOnce(&PageTool::FinishInvoke, base::Unretained(this), + MakeResult(mojom::ActionResultCode::kExecutorDestroyed))); + chrome_render_frame_->InvokeTool( + std::move(request), + base::BindOnce(&PageTool::FinishInvoke, base::Unretained(this))); } std::string PageTool::DebugString() const { @@ -293,4 +358,22 @@ } } +void PageTool::FinishInvoke(mojom::ActionResultPtr result) { + if (!invoke_callback_) { + return; + } + + std::move(invoke_callback_).Run(std::move(result)); + + frame_change_observer_.reset(); +} + +void PageTool::PostFinishInvoke(mojom::ActionResultCode result_code) { + CHECK(invoke_callback_); + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(&PageTool::FinishInvoke, weak_ptr_factory_.GetWeakPtr(), + MakeResult(result_code))); +} + } // namespace actor
diff --git a/chrome/browser/actor/tools/page_tool.h b/chrome/browser/actor/tools/page_tool.h index cbf86a6..194f4ac 100644 --- a/chrome/browser/actor/tools/page_tool.h +++ b/chrome/browser/actor/tools/page_tool.h
@@ -5,9 +5,14 @@ #ifndef CHROME_BROWSER_ACTOR_TOOLS_PAGE_TOOL_H_ #define CHROME_BROWSER_ACTOR_TOOLS_PAGE_TOOL_H_ +#include <memory> + +#include "base/memory/weak_ptr.h" #include "chrome/browser/actor/tools/tool.h" +#include "chrome/common/actor.mojom-forward.h" #include "chrome/common/chrome_render_frame.mojom.h" #include "components/optimization_guide/proto/features/actions_data.pb.h" +#include "content/public/browser/weak_document_ptr.h" #include "mojo/public/cpp/bindings/associated_remote.h" namespace content { @@ -17,6 +22,7 @@ namespace actor { class AggregatedJournal; +class RenderFrameChangeObserver; // A page tool is any tool implemented in the renderer by ToolExecutor. This // class is shared by multiple tools and serves to implement the mojo shuttling @@ -36,8 +42,17 @@ std::string JournalEvent() const override; private: + void FinishInvoke(mojom::ActionResultPtr result); + + void PostFinishInvoke(mojom::ActionResultCode result_code); + + InvokeCallback invoke_callback_; + content::WeakDocumentPtr render_frame_host_; + std::unique_ptr<RenderFrameChangeObserver> frame_change_observer_; optimization_guide::proto::ActionInformation action_information_; mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> chrome_render_frame_; + + base::WeakPtrFactory<PageTool> weak_ptr_factory_{this}; }; } // namespace actor
diff --git a/chrome/browser/actor/tools/tools_browsertest.cc b/chrome/browser/actor/tools/tools_browsertest.cc index 8501be897..33b7416 100644 --- a/chrome/browser/actor/tools/tools_browsertest.cc +++ b/chrome/browser/actor/tools/tools_browsertest.cc
@@ -2217,6 +2217,72 @@ ExpectErrorResult(result, mojom::ActionResultCode::kFrameWentAway); } +// Ensure a page tool (click, in this case) causing a cross-document navigation +// works successfully. +IN_PROC_BROWSER_TEST_F(ActorToolsTest, PageToolNavigates) { + const GURL url_start = + embedded_test_server()->GetURL("/actor/cross_document_nav.html"); + const GURL url_next = + embedded_test_server()->GetURL("/actor/simple_iframe.html"); + ASSERT_TRUE(content::NavigateToURL(web_contents(), url_start)); + + // Send a click to the link. + std::optional<int> link_id = GetDOMNodeId(*main_frame(), "#link"); + ASSERT_TRUE(link_id); + + // TODO(crbug.com/414662842): Add cases where the new document load is delayed + // as well as the PageTool doesn't outlive the outgoing RenderFrame + + BrowserAction action = MakeClick(*main_frame(), link_id.value()); + TestFuture<mojom::ActionResultPtr> result; + + // TODO(crbug.com/414662842): The TestNavigationManager can be removed once + // PageTools observe loading navigations. + TestNavigationManager main_manager(web_contents(), url_next); + actor_coordinator().Act(action, result.GetCallback()); + ASSERT_TRUE(main_manager.WaitForNavigationFinished()); + + ExpectOkResult(result); + + EXPECT_EQ(web_contents()->GetURL(), url_next); +} + +// Ensure a page tool (click, in this case) causing a cross-document navigation +// works successfully in cross-site cases (where a new RenderFrameHost is +// guaranteed). +IN_PROC_BROWSER_TEST_F(ActorToolsTest, PageToolNavigatesCrossSite) { + const GURL url_start = embedded_https_test_server().GetURL( + "foo.com", "/actor/cross_document_nav.html"); + const GURL url_next = embedded_https_test_server().GetURL( + "bar.com", "/actor/simple_iframe.html"); + ASSERT_TRUE(content::NavigateToURL(web_contents(), url_start)); + + // The link in the file is relative so replace it to include the mock + // hostname. + ASSERT_TRUE( + ExecJs(web_contents(), + JsReplace("document.getElementById('link').href = $1", url_next))); + + // Send a click to the link. + std::optional<int> link_id = GetDOMNodeId(*main_frame(), "#link"); + ASSERT_TRUE(link_id); + + // TODO(crbug.com/414662842): Add cases where the new document load is delayed + // as well as the PageTool doesn't outlive the outgoing RenderFrame + + BrowserAction action = MakeClick(*main_frame(), link_id.value()); + TestFuture<mojom::ActionResultPtr> result; + + // TODO(crbug.com/414662842): The TestNavigationManager can be removed once + // PageTools observe loading navigations. + TestNavigationManager main_manager(web_contents(), url_next); + actor_coordinator().Act(action, result.GetCallback()); + ASSERT_TRUE(main_manager.WaitForNavigationFinished()); + + ExpectOkResult(result); + + EXPECT_EQ(web_contents()->GetURL(), url_next); +} } // namespace } // namespace actor
diff --git a/chrome/browser/ai/ai_data_keyed_service.cc b/chrome/browser/ai/ai_data_keyed_service.cc index 03b4514..f7ad664 100644 --- a/chrome/browser/ai/ai_data_keyed_service.cc +++ b/chrome/browser/ai/ai_data_keyed_service.cc
@@ -28,7 +28,7 @@ #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/unguessable_token.h" #include "chrome/browser/content_extraction/inner_text.h" #include "chrome/browser/history_embeddings/history_embeddings_service_factory.h"
diff --git a/chrome/browser/ai/ai_language_model.cc b/chrome/browser/ai/ai_language_model.cc index d22c38b6..3d1915d14 100644 --- a/chrome/browser/ai/ai_language_model.cc +++ b/chrome/browser/ai/ai_language_model.cc
@@ -15,6 +15,7 @@ #include "base/notimplemented.h" #include "base/notreached.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/types/expected.h" #include "chrome/browser/ai/ai_context_bound_object.h" #include "chrome/browser/ai/ai_manager.h"
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index b7564fc..a472177 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -235,6 +235,9 @@ // Attempts restoring a previous session if there is one. Otherwise, opens // either the profile picker or a new browser, depending on user preferences. void AttemptSessionRestore(Profile* profile) { + if (!profile) { + return; + } DCHECK(!profile->IsGuestSession()); DCHECK(!IsProfileSignedOut(profile->GetPath())); SessionService* sessionService =
diff --git a/chrome/browser/ash/arc/tracing/arc_tracing_event_matcher.h b/chrome/browser/ash/arc/tracing/arc_tracing_event_matcher.h index d39c64a6..49f94e7 100644 --- a/chrome/browser/ash/arc/tracing/arc_tracing_event_matcher.h +++ b/chrome/browser/ash/arc/tracing/arc_tracing_event_matcher.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_ASH_ARC_TRACING_ARC_TRACING_EVENT_MATCHER_H_ #include <stddef.h> +#include <stdint.h> #include <map> #include <optional>
diff --git a/chrome/browser/ash/crostini/crostini_export_import_status_tracker.h b/chrome/browser/ash/crostini/crostini_export_import_status_tracker.h index 1907a20a..3f0dad7e 100644 --- a/chrome/browser/ash/crostini/crostini_export_import_status_tracker.h +++ b/chrome/browser/ash/crostini/crostini_export_import_status_tracker.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_ASH_CROSTINI_CROSTINI_EXPORT_IMPORT_STATUS_TRACKER_H_ #define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_EXPORT_IMPORT_STATUS_TRACKER_H_ +#include <stdint.h> + #include <memory> #include <string>
diff --git a/chrome/browser/ash/extensions/file_manager/private_api_strings.cc b/chrome/browser/ash/extensions/file_manager/private_api_strings.cc index ee82c33..9a6a49a 100644 --- a/chrome/browser/ash/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/ash/extensions/file_manager/private_api_strings.cc
@@ -7,8 +7,10 @@ #include <memory> #include <utility> +#include "base/check_deref.h" #include "base/values.h" #include "chrome/browser/ash/file_manager/file_manager_string_util.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "extensions/common/extension_l10n_util.h" @@ -21,11 +23,16 @@ default; ExtensionFunction::ResponseAction FileManagerPrivateGetStringsFunction::Run() { - base::Value::Dict dict = GetFileManagerStrings(); + // TODO(crbug.com/404131876): Remove g_browser_process usage. + const std::string& application_locale = + g_browser_process->GetApplicationLocale(); + base::Value::Dict dict = GetFileManagerStrings(application_locale); const std::string locale = extension_l10n_util::CurrentLocaleOrDefault(); AddFileManagerFeatureStrings( - locale, Profile::FromBrowserContext(browser_context()), &dict); + locale, application_locale, + CHECK_DEREF(g_browser_process->variations_service()), + Profile::FromBrowserContext(browser_context()), &dict); return RespondNow(WithArguments(std::move(dict))); }
diff --git a/chrome/browser/ash/file_manager/BUILD.gn b/chrome/browser/ash/file_manager/BUILD.gn index ab65183..4fe0b0b 100644 --- a/chrome/browser/ash/file_manager/BUILD.gn +++ b/chrome/browser/ash/file_manager/BUILD.gn
@@ -140,7 +140,6 @@ "//ash/webui/file_manager:constants", "//base:i18n", "//chrome/app:generated_resources", - "//chrome/browser:browser_process", "//chrome/browser/apps/app_service:constants", "//chrome/browser/ash/app_list", "//chrome/browser/ash/app_list/search", @@ -171,6 +170,7 @@ "//chromeos/ash/components/browser_context_helper", "//chromeos/ash/components/drivefs", "//chromeos/ash/components/file_manager:constants", + "//chromeos/ash/components/install_attributes", "//chromeos/ash/components/policy", "//chromeos/ash/experiences/arc:arc_base_utils", "//chromeos/ash/experiences/arc:arc_features", @@ -179,6 +179,7 @@ "//chromeos/components/disks:prefs", "//chromeos/constants", "//chromeos/dbus/power", + "//components/application_locale_storage", "//components/download/public/common:public", "//components/pref_registry", "//components/services/app_service/public/cpp:app_types", @@ -428,6 +429,7 @@ "//build/config/coverage:buildflags", "//chrome/browser", "//chrome/browser:browser_process", + "//chrome/browser:global_features", "//chrome/browser/apps/app_service", "//chrome/browser/apps/app_service:app_registry_cache_waiter", "//chrome/browser/apps/app_service:constants", @@ -502,6 +504,7 @@ "//chromeos/dbus/dlp", "//chromeos/dbus/dlp:dlp_proto", "//components/account_id", + "//components/application_locale_storage", "//components/download/public/common:public", "//components/drive", "//components/file_access:test_support",
diff --git a/chrome/browser/ash/file_manager/DEPS b/chrome/browser/ash/file_manager/DEPS index 41435e0..ce0227b0 100644 --- a/chrome/browser/ash/file_manager/DEPS +++ b/chrome/browser/ash/file_manager/DEPS
@@ -39,8 +39,6 @@ "+chrome/browser/ash/smb_client", "+chrome/browser/ash/system", "+chrome/browser/ash/system_web_apps", - "+chrome/browser/browser_process.h", - "+chrome/browser/browser_process_platform_part_ash.h", "+chrome/browser/chromeos/policy/dlp", "+chrome/browser/chromeos/upload_office_to_cloud", "+chrome/browser/download", @@ -89,6 +87,8 @@ specific_include_rules = { ".*test.*\..*": [ "+chrome/browser/ash/login/test", + "+chrome/browser/browser_process.h", + "+chrome/browser/global_features.h", "+chrome/browser/extensions/chrome_test_extension_loader.h", "+chrome/browser/extensions/extension_apitest.h", "+chrome/browser/extensions/mixin_based_extension_apitest.h",
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest.cc b/chrome/browser/ash/file_manager/file_manager_jstest.cc index 9617bd635..9d103f2 100644 --- a/chrome/browser/ash/file_manager/file_manager_jstest.cc +++ b/chrome/browser/ash/file_manager/file_manager_jstest.cc
@@ -431,6 +431,10 @@ RunTestURL("common/js/entry_utils_unittest.js"); } +IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DialogActionController) { + RunTestURL("foreground/js/dialog_action_controller_unittest.js"); +} + // Rerun some of the tests above, using CrosComponents. class FileManagerJsCrosComponentsTest : public FileManagerJsTest { public:
diff --git a/chrome/browser/ash/file_manager/file_manager_jstest_base.cc b/chrome/browser/ash/file_manager/file_manager_jstest_base.cc index dca335f..ce4607d8 100644 --- a/chrome/browser/ash/file_manager/file_manager_jstest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_jstest_base.cc
@@ -8,14 +8,18 @@ #include "ash/webui/file_manager/resource_loader.h" #include "ash/webui/file_manager/resources/grit/file_manager_swa_resources_map.h" #include "ash/webui/file_manager/url_constants.h" +#include "base/check_deref.h" #include "base/lazy_instance.h" #include "base/path_service.h" #include "chrome/browser/ash/file_manager/file_manager_string_util.h" #include "chrome/browser/ash/file_manager/file_manager_test_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/global_features.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/test_switches.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/application_locale_storage/application_locale_storage.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_controller.h" #include "content/public/browser/web_ui_data_source.h" @@ -57,8 +61,13 @@ ash::file_manager::AddFilesAppResources(files_swa_source, kFileManagerGenResources); - dict_ = GetFileManagerStrings(); - AddFileManagerFeatureStrings("en-US", Profile::FromWebUI(web_ui), &dict_); + const std::string& application_locale = + g_browser_process->GetFeatures()->application_locale_storage()->Get(); + dict_ = GetFileManagerStrings(application_locale); + AddFileManagerFeatureStrings( + "en-US", application_locale, + CHECK_DEREF(g_browser_process->variations_service()), + Profile::FromWebUI(web_ui), &dict_); files_swa_source->AddLocalizedStrings(dict_); files_swa_source->UseStringsJs();
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc index 6c1082e..9ae1575e 100644 --- a/chrome/browser/ash/file_manager/file_manager_string_util.cc +++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -27,8 +27,6 @@ #include "chrome/browser/ash/plugin_vm/plugin_vm_util.h" #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h" #include "chrome/browser/ash/profiles/profile_helper.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part_ash.h" #include "chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h" @@ -36,6 +34,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/ash/components/install_attributes/install_attributes.h" #include "chromeos/ash/experiences/arc/arc_features.h" #include "chromeos/ash/experiences/arc/arc_util.h" #include "chromeos/constants/chromeos_features.h" @@ -1185,12 +1184,12 @@ return ash::ProfileHelper::Get()->GetProfileByUser(user); } -bool IsEligibleAndEnabledGoogleOneOfferFilesBanner() { +bool IsEligibleAndEnabledGoogleOneOfferFilesBanner( + const std::string& application_locale, + const variations::VariationsService& variations_service) { // Google One offer is for a device, not for an account. Do not show a banner // if a device is enrolled. - if (g_browser_process->platform_part() - ->browser_policy_connector_ash() - ->IsDeviceEnterpriseManaged()) { + if (ash::InstallAttributes::Get()->IsEnterpriseManaged()) { return false; } @@ -1215,14 +1214,12 @@ return false; } - if (!kGoogleOneOfferBannerSupportedLocales.contains( - g_browser_process->GetApplicationLocale())) { + if (!kGoogleOneOfferBannerSupportedLocales.contains(application_locale)) { return false; } if (!kGoogleOneOfferBannerSupportedCountries.contains( - g_browser_process->variations_service() - ->GetStoredPermanentCountry())) { + variations_service.GetStoredPermanentCountry())) { return false; } @@ -1290,7 +1287,7 @@ } // namespace -base::Value::Dict GetFileManagerStrings() { +base::Value::Dict GetFileManagerStrings(const std::string& application_locale) { base::Value::Dict dict; AddStringsForDrive(&dict); @@ -1326,8 +1323,7 @@ base::StringPrintf(kHelpURLFormat, kNoActionForFileHelpNumber)); dict.Set("DLP_HELP_URL", policy::dlp::kDlpLearnMoreUrl); - webui::SetLoadTimeDataDefaults(g_browser_process->GetApplicationLocale(), - &dict); + webui::SetLoadTimeDataDefaults(application_locale, &dict); return dict; } @@ -1368,9 +1364,12 @@ return fmod(local_day_of_week - (day_of_week - 1) + 7, 7); } -void AddFileManagerFeatureStrings(const std::string& locale, - Profile* profile, - base::Value::Dict* dict) { +void AddFileManagerFeatureStrings( + const std::string& ui_locale, + const std::string& application_locale, + const variations::VariationsService& variations_service, + Profile* profile, + base::Value::Dict* dict) { DCHECK(profile); dict->Set("HIDE_SPACE_INFO", ash::DemoSession::IsDeviceInDemoMode()); @@ -1424,11 +1423,12 @@ dict->Set("VMS_FOR_SHARING", std::move(vms)); // Lastly, set UI_LOCALE and locale-dependent settings. - dict->Set("UI_LOCALE", locale); + dict->Set("UI_LOCALE", ui_locale); dict->Set("WEEK_START_FROM", GetLocaleBasedWeekStart()); // ELIGIBLE_AND_ENABLED_GOOGLE_ONE_OFFER_FILES_BANNER does additional checks // in addition to a feature flag check. dict->Set("ELIGIBLE_AND_ENABLED_GOOGLE_ONE_OFFER_FILES_BANNER", - IsEligibleAndEnabledGoogleOneOfferFilesBanner()); + IsEligibleAndEnabledGoogleOneOfferFilesBanner(application_locale, + variations_service)); }
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.h b/chrome/browser/ash/file_manager/file_manager_string_util.h index c01145e5..fcad23d1 100644 --- a/chrome/browser/ash/file_manager/file_manager_string_util.h +++ b/chrome/browser/ash/file_manager/file_manager_string_util.h
@@ -11,7 +11,13 @@ class Profile; -base::Value::Dict GetFileManagerStrings(); +namespace variations { +class VariationsService; +} // namespace variations + +// `application_locale` should be the locale associated with +// `g_browser_process`. +base::Value::Dict GetFileManagerStrings(const std::string& application_locale); base::Value::Dict GetFileManagerPluralStrings(); @@ -19,8 +25,13 @@ // to indicate which day is the start of week based on the current locale. int GetLocaleBasedWeekStart(); -void AddFileManagerFeatureStrings(const std::string& locale, - Profile* profile, - base::Value::Dict* dict); +// `application_locale` should be the locale associated with +// `g_browser_process`. +void AddFileManagerFeatureStrings( + const std::string& ui_locale, + const std::string& application_locale, + const variations::VariationsService& variations_service, + Profile* profile, + base::Value::Dict* dict); #endif // CHROME_BROWSER_ASH_FILE_MANAGER_FILE_MANAGER_STRING_UTIL_H_
diff --git a/chrome/browser/ash/floating_sso/cookie_sync_conversions.h b/chrome/browser/ash/floating_sso/cookie_sync_conversions.h index 5e015ac..23cd923 100644 --- a/chrome/browser/ash/floating_sso/cookie_sync_conversions.h +++ b/chrome/browser/ash/floating_sso/cookie_sync_conversions.h
@@ -9,6 +9,7 @@ #include <memory> #include <optional> +#include <string> namespace base { class Time;
diff --git a/chrome/browser/ash/login/oobe_quick_start/connectivity/fido_authentication_message_helper.h b/chrome/browser/ash/login/oobe_quick_start/connectivity/fido_authentication_message_helper.h index 9a3c09f..308abe9 100644 --- a/chrome/browser/ash/login/oobe_quick_start/connectivity/fido_authentication_message_helper.h +++ b/chrome/browser/ash/login/oobe_quick_start/connectivity/fido_authentication_message_helper.h
@@ -5,7 +5,10 @@ #ifndef CHROME_BROWSER_ASH_LOGIN_OOBE_QUICK_START_CONNECTIVITY_FIDO_AUTHENTICATION_MESSAGE_HELPER_H_ #define CHROME_BROWSER_ASH_LOGIN_OOBE_QUICK_START_CONNECTIVITY_FIDO_AUTHENTICATION_MESSAGE_HELPER_H_ +#include <stdint.h> + #include <vector> + namespace ash::quick_start::message_helper { inline constexpr char kCredentialIdKey[] = "id";
diff --git a/chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline.h b/chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline.h index efb03af..cbbfb1a 100644 --- a/chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline.h +++ b/chrome/browser/ash/power/auto_screen_brightness/monotone_cubic_spline.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_ASH_POWER_AUTO_SCREEN_BRIGHTNESS_MONOTONE_CUBIC_SPLINE_H_ #include <optional> +#include <string> #include <vector> namespace ash {
diff --git a/chrome/browser/ash/system_web_apps/apps/chrome_file_manager_ui_delegate.cc b/chrome/browser/ash/system_web_apps/apps/chrome_file_manager_ui_delegate.cc index 5dfefba6..4957c53 100644 --- a/chrome/browser/ash/system_web_apps/apps/chrome_file_manager_ui_delegate.cc +++ b/chrome/browser/ash/system_web_apps/apps/chrome_file_manager_ui_delegate.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ash/system_web_apps/apps/chrome_file_manager_ui_delegate.h" +#include "base/check_deref.h" #include "base/metrics/histogram_functions.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" @@ -31,10 +32,11 @@ ChromeFileManagerUIDelegate::~ChromeFileManagerUIDelegate() = default; base::Value::Dict ChromeFileManagerUIDelegate::GetLoadTimeData() const { - base::Value::Dict dict = GetFileManagerStrings(); - - const std::string locale = g_browser_process->GetApplicationLocale(); - AddFileManagerFeatureStrings(locale, Profile::FromWebUI(web_ui_), &dict); + const std::string& locale = g_browser_process->GetApplicationLocale(); + base::Value::Dict dict = GetFileManagerStrings(locale); + AddFileManagerFeatureStrings( + locale, locale, CHECK_DEREF(g_browser_process->variations_service()), + Profile::FromWebUI(web_ui_), &dict); return dict; }
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index 6c9b64cc..ff248ba 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc
@@ -46,7 +46,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected.h" #include "base/version.h" #include "base/win/elevation_util.h"
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h index b6397c1..e35d093 100644 --- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h +++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h
@@ -116,9 +116,8 @@ crosapi::mojom::TelemetryDiagnosticCameraSubtestResult input); template <class InputT, - class OutputT = decltype(Convert(std::declval<InputT>())), - class = std::enable_if_t<std::is_enum_v<InputT> || - std::is_integral_v<InputT>>> + class OutputT = decltype(Convert(std::declval<InputT>()))> + requires(std::is_enum_v<InputT> || std::is_integral_v<InputT>) std::vector<OutputT> ConvertVector(std::vector<InputT> input) { std::vector<OutputT> output; for (auto elem : input) { @@ -131,8 +130,8 @@ class... Types, class OutputT = decltype(unchecked::UncheckedConvertPtr( std::declval<InputT>(), - std::declval<Types>()...)), - class = std::enable_if_t<std::is_default_constructible_v<OutputT>>> + std::declval<Types>()...))> + requires(std::is_default_constructible_v<OutputT>) OutputT ConvertPtr(InputT input, Types... args) { return (input) ? unchecked::UncheckedConvertPtr(std::move(input), args...) : OutputT();
diff --git a/chrome/browser/device_identity/chromeos/token_encryptor.h b/chrome/browser/device_identity/chromeos/token_encryptor.h index 1e8a11c..4e11752 100644 --- a/chrome/browser/device_identity/chromeos/token_encryptor.h +++ b/chrome/browser/device_identity/chromeos/token_encryptor.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_DEVICE_IDENTITY_CHROMEOS_TOKEN_ENCRYPTOR_H_ #define CHROME_BROWSER_DEVICE_IDENTITY_CHROMEOS_TOKEN_ENCRYPTOR_H_ +#include <stdint.h> + #include <array> #include <memory> #include <string>
diff --git a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win_unittest.cc b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win_unittest.cc index 37db34e..f885dfc 100644 --- a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win_unittest.cc +++ b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win_unittest.cc
@@ -11,6 +11,7 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h"
diff --git a/chrome/browser/enterprise/signin/oidc_managed_profile_creation_delegate_unittest.cc b/chrome/browser/enterprise/signin/oidc_managed_profile_creation_delegate_unittest.cc index 8019f82..77567e1 100644 --- a/chrome/browser/enterprise/signin/oidc_managed_profile_creation_delegate_unittest.cc +++ b/chrome/browser/enterprise/signin/oidc_managed_profile_creation_delegate_unittest.cc
@@ -8,6 +8,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" #include "chrome/browser/enterprise/signin/enterprise_signin_prefs.h" #include "chrome/browser/profiles/profile_attributes_entry.h"
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc index e1dae7c..6e0060cde 100644 --- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc +++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -68,6 +68,12 @@ } protected: + std::vector<tabs::TabAlert> GetTabAlertStatesForContents( + content::WebContents* web_contents) { + return GetTabAlertStatesForTab( + tabs::TabInterface::GetFromContents(web_contents)); + } + void SimulateMouseClickInCurrentTab() { content::SimulateMouseClick( browser()->tab_strip_model()->GetActiveWebContents(), 0,
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc index 66b7a85..14444f5 100644 --- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc +++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -128,9 +128,13 @@ // ResourceBundle and g_browser_process are not always initialized in unit // tests. if (ui::ResourceBundle::HasSharedInstance() && g_browser_process) { + // TODO(crbug.com/404131876): Remove g_browser_process usage. + const std::string& application_locale = + g_browser_process->GetApplicationLocale(); + ui::TemplateReplacements file_manager_replacements; - ui::TemplateReplacementsFromDictionaryValue(GetFileManagerStrings(), - &file_manager_replacements); + ui::TemplateReplacementsFromDictionaryValue( + GetFileManagerStrings(application_locale), &file_manager_replacements); template_replacements_[extension_misc::kFilesManagerAppId] = std::move(file_manager_replacements); }
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 7eb8a16..a9c4424 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -350,27 +350,7 @@ LoadExtensionsFromCommandLineFlag(switches::kDisableExtensionsExcept); if (load_command_line_extensions) { - bool command_line_blocked = true; - if (base::FeatureList::IsEnabled( - extensions_features::kDisableLoadExtensionCommandLineSwitch)) { - LOG(WARNING) - << "--load-extension is not allowed in Google Chrome, ignoring."; - } else if (safe_browsing::IsEnhancedProtectionEnabled( - *profile_->GetPrefs())) { - VLOG(1) << "--load-extension is not allowed for users opted into " - << "Enhanced Safe Browsing, ignoring."; - } else if (ShouldBlockCommandLineExtension(*profile_)) { - // TODO(crbug.com/401529219): Deprecate this restriction once - // --load-extension switch is restricted on Chrome builds. - VLOG(1) - << "--load-extension is not allowed for users that have the policy " - << "ExtensionInstallTypeBlocklist::command_line, ignoring."; - } else { - LoadExtensionsFromCommandLineFlag(switches::kLoadExtension); - command_line_blocked = false; - } - base::UmaHistogramBoolean("Extensions.LoadingFromCommandLineBlocked", - command_line_blocked); + LoadExtensionsFromCommandLineFlag(switches::kLoadExtension); } EnabledReloadableExtensions(); delayed_install_manager_->FinishInstallationsDelayedByShutdown(); @@ -404,22 +384,58 @@ void ExtensionService::LoadExtensionsFromCommandLineFlag( const char* switch_name) { - if (command_line_->HasSwitch(switch_name)) { - base::CommandLine::StringType path_list = - command_line_->GetSwitchValueNative(switch_name); - base::StringTokenizerT<base::CommandLine::StringType, - base::CommandLine::StringType::const_iterator> - t(path_list, FILE_PATH_LITERAL(",")); - while (t.GetNext()) { - std::string extension_id; - UnpackedInstaller::Create(profile_)->LoadFromCommandLine( - base::FilePath(t.token_piece()), &extension_id, - false /*only-allow-apps*/); - if (switch_name == switches::kDisableExtensionsExcept) { - extension_registrar_->AddDisableFlagExemptedExtension(extension_id); - } + CHECK(switch_name == switches::kLoadExtension || + switch_name == switches::kDisableExtensionsExcept); + if (!command_line_->HasSwitch(switch_name)) { + return; + } + + // Check that --load-extension is allowed. + // TODO(crbug.com/419530940): Apply restrictions to + // --disable-extensions-except switch once the feature is approved and + // implemented. + if (switch_name == switches::kLoadExtension) { + if (base::FeatureList::IsEnabled( + extensions_features::kDisableLoadExtensionCommandLineSwitch)) { + LOG(WARNING) + << "--load-extension is not allowed in Google Chrome, ignoring."; + return; + } + if (safe_browsing::IsEnhancedProtectionEnabled(*profile_->GetPrefs())) { + VLOG(1) << "--load-extension is not allowed for users opted into " + << "Enhanced Safe Browsing, ignoring."; + return; + } + if (ShouldBlockCommandLineExtension(*profile_)) { + // TODO(crbug.com/401529219): Deprecate this restriction once + // --load-extension removal on Chrome builds is fully launched. + VLOG(1) + << "--load-extension is not allowed for users that have the policy " + << "ExtensionInstallTypeBlocklist::command_line, ignoring."; + return; } } + + base::CommandLine::StringType path_list = + command_line_->GetSwitchValueNative(switch_name); + base::StringTokenizerT<base::CommandLine::StringType, + base::CommandLine::StringType::const_iterator> + t(path_list, FILE_PATH_LITERAL(",")); + while (t.GetNext()) { + std::string extension_id; + UnpackedInstaller::Create(profile_)->LoadFromCommandLine( + base::FilePath(t.token_piece()), &extension_id, + /*only-allow-apps=*/false); + if (switch_name == switches::kDisableExtensionsExcept) { + extension_registrar_->AddDisableFlagExemptedExtension(extension_id); + } + } + + base::UmaHistogramEnumeration( + "Extensions.LoadingFromCommandLine", + switch_name == switches::kLoadExtension + ? ExtensionService::LoadExtensionFlag::kLoadExtension + : ExtensionService::LoadExtensionFlag::kDisableExtensionsExcept); } #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 4c22473d..29d9cedf 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -234,6 +234,21 @@ } #endif + // Load Extension Flags. + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + // + // LINT.IfChange(LoadExtensionFlag) + enum class LoadExtensionFlag { + // --load-extension flag. + kLoadExtension = 0, + // --disable-extensions-except flag. + kDisableExtensionsExcept = 1, + + kMaxValue = kDisableExtensionsExcept, + }; + // LINT.ThenChange(/tools/metrics/histograms/metadata/extensions/enums.xml:LoadExtensionFlag) + private: // Loads extensions specified via a command line flag/switch. void LoadExtensionsFromCommandLineFlag(const char* switch_name);
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 836a9ed1..89e08a1 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -5966,6 +5966,7 @@ // Tests that --load-extension is ignored for users opted in to Enhanced Safe // Browsing (ESB). TEST_F(ExtensionServiceTest, WillNotLoadFromCommandLineForESBUsers) { + base::HistogramTester histograms; InitializeEmptyExtensionServiceWithTestingPrefs(); // Enable ESB. profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true); @@ -5979,6 +5980,8 @@ task_environment()->RunUntilIdle(); ASSERT_EQ(0u, loaded_extensions().size()); ValidatePrefKeyCount(0); + + histograms.ExpectTotalCount("Extensions.LoadingFromCommandLine", 0); } // Tests --load-extension works for non-ESB users. @@ -5999,14 +6002,16 @@ ASSERT_EQ(1u, loaded_extensions().size()); ValidatePrefKeyCount(1); - histograms.ExpectUniqueSample("Extensions.LoadingFromCommandLineBlocked", - false, 1); + histograms.ExpectUniqueSample( + "Extensions.LoadingFromCommandLine", + ExtensionService::LoadExtensionFlag::kLoadExtension, 1); } // Tests that --load-extension is ignored for users with policy // ExtensionInstallTypeBlocklist containing command_line. TEST_F(ExtensionServiceTest, WillNotLoadFromCommandLineForUsersWithPolicyFalse) { + base::HistogramTester histograms; InitializeEmptyExtensionServiceWithTestingPrefs(); profile()->GetPrefs()->SetList(pref_names::kExtensionInstallTypeBlocklist, @@ -6021,11 +6026,15 @@ task_environment()->RunUntilIdle(); ASSERT_EQ(0u, loaded_extensions().size()); ValidatePrefKeyCount(0); + + histograms.ExpectTotalCount("Extensions.LoadingFromCommandLine", 0); } -// Tests --load-extension works for users with policy -// ExtensionInstallTypeBlocklist not containing "command_line" (default value) +// Tests --load-extension and --disable-extensions-except work for users with +// policy ExtensionInstallTypeBlocklist not containing "command_line" (default +// value) TEST_F(ExtensionServiceTest, LoadsFromCommandLineForUsersWithoutPolicy) { + base::HistogramTester histograms; InitializeEmptyExtensionServiceWithTestingPrefs(); // Not setting pref as false is default value. // Try to load an extension from command line. @@ -6033,11 +6042,20 @@ base::MakeAbsoluteFilePath(data_dir().AppendASCII("good_unpacked")); base::CommandLine::ForCurrentProcess()->AppendSwitchPath( switches::kLoadExtension, path); + base::CommandLine::ForCurrentProcess()->AppendSwitchPath( + switches::kDisableExtensionsExcept, path); service()->Init(); task_environment()->RunUntilIdle(); EXPECT_EQ(0u, GetErrors().size()); ASSERT_EQ(1u, loaded_extensions().size()); ValidatePrefKeyCount(1); + + histograms.ExpectBucketCount( + "Extensions.LoadingFromCommandLine", + ExtensionService::LoadExtensionFlag::kLoadExtension, 1); + histograms.ExpectBucketCount( + "Extensions.LoadingFromCommandLine", + ExtensionService::LoadExtensionFlag::kDisableExtensionsExcept, 1); } TEST_F(ExtensionServiceTest, DisableLoadExtensionCommandLineSwitch) { @@ -6063,8 +6081,7 @@ ASSERT_EQ(0u, loaded_extensions().size()); ValidatePrefKeyCount(0); - histograms.ExpectUniqueSample("Extensions.LoadingFromCommandLineBlocked", - true, 1); + histograms.ExpectTotalCount("Extensions.LoadingFromCommandLine", 0); } // Tests that we generate IDs when they are not specified in the manifest for
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc index 092801c..53cb772 100644 --- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc +++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -351,6 +351,12 @@ // InProcessBrowserTest override. void SetUp() override { InProcessBrowserTest::SetUp(); } + std::vector<tabs::TabAlert> GetTabAlertStatesForContents( + content::WebContents* web_contents) { + return GetTabAlertStatesForTab( + tabs::TabInterface::GetFromContents(web_contents)); + } + private: // mojom::SessionObserver mocks. MOCK_METHOD(void, OnError, (mojom::SessionError));
diff --git a/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc b/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc index 8e5683b..ca878fc 100644 --- a/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc +++ b/chrome/browser/metrics/family_link_user_metrics_provider_unittest.cc
@@ -6,6 +6,7 @@ #include <string> +#include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/signin/identity_manager_factory.h"
diff --git a/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler_unittest.cc b/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler_unittest.cc index 142ac61..11877d4 100644 --- a/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler_unittest.cc +++ b/chrome/browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler_unittest.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/hash/hash.h" #include "base/json/json_string_value_serializer.h" #include "base/memory/scoped_refptr.h" #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/on_device_translation/language_pack_util.cc b/chrome/browser/on_device_translation/language_pack_util.cc index acbed61..259fd5c 100644 --- a/chrome/browser/on_device_translation/language_pack_util.cc +++ b/chrome/browser/on_device_translation/language_pack_util.cc
@@ -102,6 +102,24 @@ } // namespace +bool IsPopularLanguage(SupportedLanguage supported_language) { + return supported_language == SupportedLanguage::kEn || + supported_language == SupportedLanguage::kZh || + supported_language == SupportedLanguage::kZhHant || + supported_language == SupportedLanguage::kJa || + supported_language == SupportedLanguage::kPt || + supported_language == SupportedLanguage::kRu || + supported_language == SupportedLanguage::kEs || + supported_language == SupportedLanguage::kTr || + supported_language == SupportedLanguage::kHi || + supported_language == SupportedLanguage::kVi || + supported_language == SupportedLanguage::kBn || + supported_language == SupportedLanguage::kKn || + supported_language == SupportedLanguage::kTa || + supported_language == SupportedLanguage::kTe || + supported_language == SupportedLanguage::kMr; +} + // Converts a SupportedLanguage to a language code. std::string_view ToLanguageCode(SupportedLanguage supported_language) { return kSupportedLanguageCodeMap.at(supported_language);
diff --git a/chrome/browser/on_device_translation/language_pack_util.h b/chrome/browser/on_device_translation/language_pack_util.h index 8eef7ef..e6c17768 100644 --- a/chrome/browser/on_device_translation/language_pack_util.h +++ b/chrome/browser/on_device_translation/language_pack_util.h
@@ -85,6 +85,10 @@ std::optional<SupportedLanguage> ToSupportedLanguage( std::string_view language_code); +// Returns whether the language is in the top 12 by number of native speakers. +// https://en.wikipedia.org/wiki/List_of_languages_by_number_of_native_speakers#Top_languages_by_population +bool IsPopularLanguage(SupportedLanguage supported_language); + // The key for language pack components. enum class LanguagePackKey { kEn_Es = 0,
diff --git a/chrome/browser/on_device_translation/language_pack_util_unittest.cc b/chrome/browser/on_device_translation/language_pack_util_unittest.cc index 43ab8c2..a1fc636d 100644 --- a/chrome/browser/on_device_translation/language_pack_util_unittest.cc +++ b/chrome/browser/on_device_translation/language_pack_util_unittest.cc
@@ -106,6 +106,49 @@ EXPECT_EQ(ToSupportedLanguage(""), std::nullopt); } +TEST(LanguagePackUtilTest, IsPopularLanguage) { + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kEn)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kEn)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kEs)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kJa)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kAr)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kBn)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kDe)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kFr)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kHi)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kIt)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kKo)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kNl)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kPl)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kPt)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kRu)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kTh)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kTr)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kVi)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kZh)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kZhHant)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kBg)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kCs)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kDa)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kEl)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kFi)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kHr)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kHu)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kId)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kIw)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kLt)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kNo)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kRo)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kSk)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kSl)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kSv)); + EXPECT_FALSE(IsPopularLanguage(SupportedLanguage::kUk)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kKn)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kTa)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kTe)); + EXPECT_TRUE(IsPopularLanguage(SupportedLanguage::kMr)); +} + TEST(LanguagePackUtilTest, GetLanguagePackComponentConfig) { // En to Es. EXPECT_EQ(GetLanguagePackComponentConfig(LanguagePackKey::kEn_Es).language1,
diff --git a/chrome/browser/on_device_translation/on_device_translation_browsertest.cc b/chrome/browser/on_device_translation/on_device_translation_browsertest.cc index 2a95d31..e07d1fe0 100644 --- a/chrome/browser/on_device_translation/on_device_translation_browsertest.cc +++ b/chrome/browser/on_device_translation/on_device_translation_browsertest.cc
@@ -186,6 +186,8 @@ case CanCreateTranslatorResult::kAfterDownloadTranslatorCreationRequired: return "downloadable"; case CanCreateTranslatorResult::kNoNotSupportedLanguage: + case CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed: + case CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation: case CanCreateTranslatorResult::kNoServiceCrashed: case CanCreateTranslatorResult::kNoDisallowedByPolicy: case CanCreateTranslatorResult::kNoExceedsServiceCountLimitation: @@ -360,36 +362,6 @@ EXPECT_FALSE(console_observer.messages().empty()); } - void ClearSiteContentSettings() { - content::BrowsingDataRemover* remover = - browser()->profile()->GetBrowsingDataRemover(); - content::BrowsingDataRemoverCompletionObserver observer(remover); - remover->RemoveAndReply( - base::Time(), base::Time::Max(), - chrome_browsing_data_remover::DATA_TYPE_CONTENT_SETTINGS, - chrome_browsing_data_remover::ALL_ORIGIN_TYPES, &observer); - observer.BlockUntilCompletion(); - } - - content::RenderFrameHost* CreateIframe(Browser* target_browser = nullptr) { - EXPECT_EQ(EvalJsCatchingError(R"( - window._iframe = document.createElement('iframe'); - document.body.appendChild(window._iframe); - return "OK"; - )", - target_browser), - "OK"); - - return ChildFrameAt((target_browser ? target_browser : browser()) - ->tab_strip_model() - ->GetActiveWebContents(), - 0); - } - - bool RemoveIframe(Browser* target_browser = nullptr) { - return ExecJs("document.body.removeChild(window._iframe);"); - } - private: base::ScopedTempDir tmp_dir_; base::test::ScopedFeatureList scoped_feature_list_; @@ -502,13 +474,10 @@ "en to ja: hello"); } -// TODO(crbug.com/421947718): Disabled because there's a race between triggering -// user activation and consuming it when calling `create` multiple times. -// // Tests the behavior of multiple create() calls with different // source/target languages. IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, - DISABLED_CreateTranslatorInstallMultipleLanguagePacks) { + CreateTranslatorInstallMultipleLanguagePacks) { MockComponentManager mock_component_manager(GetTempDir()); NavigateToEmptyPage(); @@ -533,45 +502,41 @@ run_loop_for_register_en_es_language_pack.Quit(); })); - // Helper function to get the state of a promise at the moment the helper - // function is called. - EXPECT_TRUE(ExecJs(R"( - self.getPromiseState = async promise => { - const symbol = Symbol(); - try { - const result = await Promise.race([promise, Promise.resolve(symbol)]); - return result == symbol ? "pending" : "fulfilled"; - } catch (e) { - return "rejected"; - } - } - )")); - // Create create() multiple times. // 1. En => Ja. // 2. En => Es. // 3. En => Ja. - EXPECT_TRUE(ExecJs(R"( - self.enJaPromise1 = Translator.create({ + EXPECT_EQ(EvalJsCatchingError(R"( + window._testEnJaPromise1 = Translator.create({ sourceLanguage: 'en', targetLanguage: 'ja', }); - )", - browser(), content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); - EXPECT_TRUE(ExecJs(R"( - self.enEsPromise = Translator.create({ + window._testEnJaPromise1Resolved = false; + window._testEnJaPromise1.then(() => { + window._testEnJaPromise1Resolved = true; + }); + + window._testEnEsPromise = Translator.create({ sourceLanguage: 'en', targetLanguage: 'es', }); - )", - browser(), content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); - EXPECT_TRUE(ExecJs(R"( - self.enJaPromise2 = Translator.create({ + window._testEnEsPromiseResolved = false; + window._testEnEsPromise.then(() => { + window._testEnEsPromiseResolved = true; + }); + + window._testEnJaPromise2 = Translator.create({ sourceLanguage: 'en', targetLanguage: 'ja', }); - )", - browser(), content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); + window._testEnJaPromise2Resolved = false; + window._testEnJaPromise2.then(() => { + window._testEnJaPromise2Resolved = true; + }); + + return 'OK'; + )"), + "OK"); // Wait until RegisterTranslateKitComponentImpl() is called. run_loop_for_register_translate_kit.Run(); @@ -584,40 +549,40 @@ mock_component_manager.InstallMockTranslateKitComponent(); // All promises should not be resolved yet. - EXPECT_EQ(EvalJs("getPromiseState(enJaPromise1)").ExtractString(), "pending"); - EXPECT_EQ(EvalJs("getPromiseState(enEsPromise)").ExtractString(), "pending"); - EXPECT_EQ(EvalJs("getPromiseState(enJaPromise2)").ExtractString(), "pending"); + EXPECT_FALSE(EvalJs("window._testEnJaPromise1Resolved").ExtractBool()); + EXPECT_FALSE(EvalJs("window._testEnJaPromise2Resolved").ExtractBool()); + EXPECT_FALSE(EvalJs("window._testEnEsPromiseResolved").ExtractBool()); // Install the mock `en_ja` language pack. mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Ja); // Translate to Japanese. Both `en_ja` promises should be resolved now. - EXPECT_EQ(EvalJsCatchingError( - "return await (await enJaPromise1).translate('hello');"), - "en to ja: hello"); EXPECT_EQ( - EvalJsCatchingError("return await (await enJaPromise2).translate('hi');"), + EvalJsCatchingError( + "return await (await window._testEnJaPromise1).translate('hello');"), + "en to ja: hello"); + EXPECT_EQ( + EvalJsCatchingError( + "return await (await window._testEnJaPromise2).translate('hi');"), "en to ja: hi"); // The promise of `en_es` should not be resolved yet. - EXPECT_EQ(EvalJs("getPromiseState(enEsPromise)").ExtractString(), "pending"); + EXPECT_FALSE(EvalJs("window._testEnEsPromiseResolved").ExtractBool()); // Install the mock `en_es` language pack. mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Es); // Translate to Spanish. The `en_es` promise should be resolved now. - EXPECT_EQ(EvalJsCatchingError( - "return await (await self.enEsPromise).translate('hello');"), - "en to es: hello"); + EXPECT_EQ( + EvalJsCatchingError( + "return await (await window._testEnEsPromise).translate('hello');"), + "en to es: hello"); } -// TODO(crbug.com/421947718): Disabled because there's a race between triggering -// user activation and consuming it when calling `create` multiple times. -// // Tests the behavior of create() when the number of pending tasks // exceeds the limit. IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, - DISABLED_ExceedMaxPendingTaskCount) { + ExceedMaxPendingTaskCount) { MockComponentManager mock_component_manager(GetTempDir()); NavigateToEmptyPage(); @@ -636,12 +601,6 @@ run_loop_for_register_language_pack.Quit(); })); - // TODO(crbug.com/421947718): Each `Translator.create` call should be in it's - // own `EvalJs` call like - // `CreateTranslator_Delay_ForTranslatorCreatedDuringInitialTranslatorCreationWithDelay`, - // but since we're blocked on the race issue from crbug.com/421947718, this - // hasn't been updated yet. - // // Call create() kMaxPendingTaskCount times. EXPECT_EQ(EvalJsCatchingError(base::StringPrintf(R"( window._testPromises = []; @@ -711,6 +670,49 @@ "OK"); } +// Tests the behavior of TranslationAPILimitLanguagePackCount +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, + ExceedLanguagePackCount) { + MockComponentManager mock_component_manager(GetTempDir()); + mock_component_manager.ExpectCallRegisterTranslateKitComponentAndInstall(); + const base::span<const LanguagePackKey> language_packs = + base::span(kLanguagePackKeys); + NavigateToEmptyPage(); + + // Get the amount of packages we can install and assert that we have enough + // language packs for this test. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount(0); + ASSERT_GE(language_packs.size(), installable_package_count + 1); + + // Add all the languages we're going to test to the selected languages so we + // don't fail PassAcceptLanguagesCheck. + SetSelectedLanguages(language_packs.first(installable_package_count + 1)); + + // Test that we can install all the language packs up to the language pack + // limitation. + mock_component_manager.ExpectCallRegisterLanguagePackComponentAndInstall( + language_packs.first(installable_package_count)); + for (const auto& language_pack_key : + language_packs.first(installable_package_count)) { + TestSimpleTranslationWorks(browser(), language_pack_key); + } + + // The language pack count is equal to the limitation. So no more language + // pack can be downloaded. + auto console_observer = CreateConsoleObserver( + "The Translator API language pack count exceeded the limitation. See " + "https://developer.chrome.com/docs/ai/" + "translator-api?#supported-languages for more details."); + + TestCreateTranslator(browser(), language_packs.at(installable_package_count), + "NotSupportedError: Unable to create translator for the " + "given source and target language."); + + // The console message should be logged. + WaitForConsoleObserver(*console_observer); +} + // Tests the behavior of the failure of translation. IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, TranslationFailure) { MockComponentManager mock_component_manager(GetTempDir()); @@ -1089,10 +1091,71 @@ ExpectUpdatesAre(expected_updates); } +// Tests V1 behavior. +class OnDeviceTranslationV1BrowserTest : public OnDeviceTranslationBrowserTest { + public: + OnDeviceTranslationV1BrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + blink::features::kTranslationAPIV1); + } + ~OnDeviceTranslationV1BrowserTest() override = default; + + protected: + void ClearSiteContentSettings() { + content::BrowsingDataRemover* remover = + browser()->profile()->GetBrowsingDataRemover(); + content::BrowsingDataRemoverCompletionObserver observer(remover); + remover->RemoveAndReply( + base::Time(), base::Time::Max(), + chrome_browsing_data_remover::DATA_TYPE_CONTENT_SETTINGS, + chrome_browsing_data_remover::ALL_ORIGIN_TYPES, &observer); + observer.BlockUntilCompletion(); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// The language model limit is not triggered when the V1 flag is enabled. +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationV1BrowserTest, + NoLanguageModelLimitation) { + MockComponentManager mock_component_manager(GetTempDir()); + mock_component_manager.ExpectCallRegisterTranslateKitComponentAndInstall(); + const base::span<const LanguagePackKey> language_packs = + base::span(kLanguagePackKeys); + NavigateToEmptyPage(); + + // Expect that the number of available language packs is less than the + // installable language pack size, given there is no limitation in place. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount(0); + ASSERT_LE(language_packs.size() + 1, installable_package_count); + + // Add all the languages we're going to test to the selected languages so we + // don't fail `PassAcceptLanguagesCheck`. + SetSelectedLanguages(language_packs); + + // Test that we can install all of the possible language packs for + // translation. + mock_component_manager.ExpectCallRegisterLanguagePackComponentAndInstall( + language_packs); + for (const auto& language_pack_key : language_packs) { + TestSimpleTranslationWorks(browser(), language_pack_key); + } + + // Get the last language pack key. + LanguagePackKey last_language_pack = *(language_packs.end() - 1); + + // Confirm that the last language pack install succeeded. + TestTranslationAvailable(browser(), GetSourceLanguageCode(last_language_pack), + GetTargetLanguageCode(last_language_pack), + "available"); +} + // Confirms that `Translator.availability()` is not masked for a translation // containing only English or the user's preferred languages. IN_PROC_BROWSER_TEST_F( - OnDeviceTranslationBrowserTest, + OnDeviceTranslationV1BrowserTest, TranslatorAvailabilityNotMasked_EnglishAndPreferredLanguages) { SetSelectedLanguages("fr"); MockComponentManager mock_component_manager(GetTempDir()); @@ -1110,7 +1173,7 @@ // Tests that `Translator.availability()` for a translation // containing a language outside of English + the user's preferred languages. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationV1BrowserTest, TranslatorAvailabilityMasked_ForNonPreferredLanguages) { SetSelectedLanguages("fr"); MockComponentManager mock_component_manager(GetTempDir()); @@ -1146,7 +1209,7 @@ // A delay is triggered for a "downloadable" translation containing a language // outside of English + preferred languages. IN_PROC_BROWSER_TEST_F( - OnDeviceTranslationBrowserTest, + OnDeviceTranslationV1BrowserTest, CreateTranslator_Delay_ForMaskedDownloadableTranslation) { // Setup Translate Kit Component and select Spanish as the preferred language. SetSelectedLanguages("en,es"); @@ -1171,15 +1234,12 @@ TestSimpleTranslationWorks(browser(), "en", "ja"); } -// TODO(crbug.com/421947718): Disabled because there's a race between triggering -// user activation and consuming it when calling `create` multiple times. -// // A delay is triggered when a second translator for a given translation is // created during the delay time window of an initial translator's creation // (which is also expected to trigger a delay). IN_PROC_BROWSER_TEST_F( - OnDeviceTranslationBrowserTest, - DISABLED_CreateTranslator_Delay_ForTranslatorCreatedDuringInitialTranslatorCreationWithDelay) { + OnDeviceTranslationV1BrowserTest, + CreateTranslator_Delay_ForTranslatorCreatedDuringInitialTranslatorCreationWithDelay) { SetSelectedLanguages("es"); MockComponentManager mock_component_manager(GetTempDir()); mock_component_manager.InstallMockTranslateKitComponent(); @@ -1218,7 +1278,7 @@ // `Translator.create` should still require user activation if the language pair // is readily available but the site hasn't created a Translator for the // language pair yet. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationV1BrowserTest, CreateRequiresUserActivationWhenDownloadedButMasked) { SetSelectedLanguages("es"); MockComponentManager mock_component_manager(GetTempDir()); @@ -1241,7 +1301,7 @@ // No delay is triggered for a "downloadable" translation between English + // preferred languages. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationV1BrowserTest, CreateTranslator_NoDelay_DownloadableTranslation) { SetSelectedLanguages("en,es"); MockComponentManager mock_component_manager(GetTempDir()); @@ -1262,7 +1322,7 @@ // No delay is triggered in attempt to create a translator for an unsupported // language. -IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationV1BrowserTest, CreateTranslator_NoDelay_UnsupportedLanguage) { SetSelectedLanguages("en,xx"); MockComponentManager mock_component_manager(GetTempDir()); @@ -1421,17 +1481,16 @@ NavigateToEmptyPage(); - content::RenderFrameHost* iframe = CreateIframe(); - // Create a translator in an iframe. - EXPECT_EQ(content::EvalJs(iframe, R"( - Translator.create({ + EXPECT_EQ(EvalJsCatchingError(R"( + window._testIframe = document.createElement('iframe'); + document.body.appendChild(window._testIframe); + window._testIframe.contentWindow.Translator.create({ sourceLanguage: 'en', targetLanguage: 'ja', }); - 'OK'; - )") - .ExtractString(), + return 'OK'; + )"), "OK"); // Wait until RegisterTranslateKitComponentImpl() is called. run_loop_for_register_translate_kit.Run(); @@ -1439,7 +1498,7 @@ run_loop_for_register_language_pack.Run(); // Deletes the iframe after the browser process receives the request. - EXPECT_TRUE(RemoveIframe()); + EXPECT_TRUE(ExecJs("document.body.removeChild(window._testIframe);")); // Install the mock TranslateKit component. mock_component_manager.InstallMockTranslateKitComponent(); @@ -1522,18 +1581,16 @@ // Set the idle timeout to be 100 microseconds. service_controller->SetServiceIdleTimeoutForTesting(base::Microseconds(100)); - content::RenderFrameHost* iframe = CreateIframe(); - // Test that Translator API on an iframe works. - EXPECT_EQ(content::EvalJs(iframe, R"( - (async () => { - const translator = - await Translator.create({ - sourceLanguage: 'en', - targetLanguage: 'ja', - }); - return await translator.translate('hello'); - })(); + EXPECT_EQ(EvalJsCatchingError(R"( + window._iframe = document.createElement('iframe'); + document.body.appendChild(window._iframe); + const translator = + await window._iframe.contentWindow.Translator.create({ + sourceLanguage: 'en', + targetLanguage: 'ja', + }); + return await translator.translate('hello'); )"), "en to ja: hello"); // Check that the service is still running. @@ -1567,15 +1624,7 @@ .Times(0); mock_component_manager.InstallMockTranslateKitComponent(); mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Ja); - - // Despite being ready, the availability will be masked since the site hasn't - // created a translator for this language pair yet. - // `kAfterDownloadTranslatorCreationRequired` is only ever returned in that - // situation, so receiving that value confirms that the package is readily - // available. - TestCanTranslateResult( - "en", "ja", - CanCreateTranslatorResult::kAfterDownloadTranslatorCreationRequired); + TestCanTranslateResult("en", "ja", CanCreateTranslatorResult::kReadily); } // Test the behavior of availability() when the language pack is not ready. @@ -1630,6 +1679,118 @@ CanCreateTranslatorResult::kNoNotSupportedLanguage); } +// Test the behavior of availability() when the language pack is not ready, and +// the language pack count will exceed the limitation. +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, + CanTranslateNoExceedsLanguagePackCountLimitation) { + // This test case uses English as the source language and French as the target + // language. To avoid the failure of PassAcceptLanguagesCheck(), we set the + // SelectedLanguages to be English and French. + SetSelectedLanguages("en,fr"); + MockComponentManager mock_component_manager(GetTempDir()); + EXPECT_CALL(mock_component_manager, RegisterTranslateKitComponentImpl()) + .Times(0); + mock_component_manager.InstallMockTranslateKitComponent(); + + // No language packs are installed yet. + size_t installed_package_count = 0; + + // Get the amount of packages we can install. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount( + installed_package_count); + ASSERT_NE(installable_package_count, std::numeric_limits<size_t>::max()); + + for (const auto& language_pack_key : kLanguagePackKeys) { + mock_component_manager.InstallMockLanguagePack(language_pack_key); + installed_package_count++; + + if (installed_package_count < installable_package_count) { + // The language pack count is less than the limitation. + TestCanTranslateResult( + "en", "fr", + CanCreateTranslatorResult::kAfterDownloadLanguagePackNotReady); + } else { + // The language pack count is equal to the limitation. So no more language + // pack can be downloaded. + TestCanTranslateResult( + "en", "fr", + CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation); + break; + } + } + + ASSERT_EQ(installed_package_count, installable_package_count); +} + +// Test the behavior of availability() when the language pack is not ready, and +// the language pack count exceed the limitation after downloading two language +// packs. +IN_PROC_BROWSER_TEST_F( + OnDeviceTranslationBrowserTest, + CanTranslateNoExceedsLanguagePackCountLimitationTwoPackagesRequired) { + // This test case use Hindi and French as the source and target languages. + // To translate from Hindi to French, two language packs are required one for + // hi->en and one for en->fr. + SetSelectedLanguages("hi,fr"); + MockComponentManager mock_component_manager(GetTempDir()); + EXPECT_CALL(mock_component_manager, RegisterTranslateKitComponentImpl()) + .Times(0); + mock_component_manager.InstallMockTranslateKitComponent(); + + // No language packs are installed yet. + size_t installed_package_count = 0; + + // Get the amount of packages we can install. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount( + installed_package_count); + ASSERT_NE(installable_package_count, std::numeric_limits<size_t>::max()); + + for (const auto& language_pack_key : kLanguagePackKeys) { + mock_component_manager.InstallMockLanguagePack(language_pack_key); + installed_package_count++; + + if (installed_package_count < installable_package_count - 1) { + // The language pack count is less than the limitation. + TestCanTranslateResult( + "hi", "fr", + CanCreateTranslatorResult::kAfterDownloadLanguagePackNotReady); + } else if (installed_package_count < installable_package_count) { + // The language pack count is less than the limitation. But if + // we download the required language packs, the language pack count will + // exceed the limitation. So availability() returns `no`. + TestCanTranslateResult( + "hi", "fr", + CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation); + } else { + // The language pack count is 3, which is equal to the limitation. So no + // more language pack can be downloaded. + TestCanTranslateResult( + "hi", "fr", + CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation); + break; + } + } + + ASSERT_EQ(installed_package_count, installable_package_count); +} + +// Test the behavior of availability() when PassAcceptLanguagesCheck() checks +// fails. +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, + CanTranslateNoAcceptLanguagesCheckFailed) { + MockComponentManager mock_component_manager(GetTempDir()); + EXPECT_CALL(mock_component_manager, RegisterTranslateKitComponentImpl()) + .Times(0); + mock_component_manager.InstallMockTranslateKitComponent(); + mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Ko); + // Korean is not treated as a popular language. So if `ko` is not in the + // accept languages, PassAcceptLanguagesCheck() will return false. + TestCanTranslateResult( + "en", "ko", CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed); +} + // Test the behavior of `availability()` when the execution context is not // valid. IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, @@ -1667,6 +1828,20 @@ TestTranslationAvailable(browser(), "en", "xx", "unavailable"); } +// Test the behavior of `availability()` when the `PassAcceptLanguagesCheck()` +// check fails. +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, + Availability_Unavailable_AcceptLanguagesCheckFailed) { + MockComponentManager mock_component_manager(GetTempDir()); + mock_component_manager.InstallMockTranslateKitComponent(); + mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Ko); + NavigateToEmptyPage(); + + // Korean is not treated as a popular language. So if `ko` is not in the + // accept languages, `PassAcceptLanguagesCheck()` will return false. + TestTranslationAvailable(browser(), "en", "ko", "unavailable"); +} + // Test the behavior of `availability()` where the source language and the // target language are the same language. IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, @@ -1679,6 +1854,92 @@ TestTranslationAvailable(browser(), "en", "en", "unavailable"); } +// Test the behavior of `availability()` when the language pack is not ready, +// and the language pack count will exceed the imitation. +IN_PROC_BROWSER_TEST_F(OnDeviceTranslationBrowserTest, + Availability_No_ExceedsLangPackCountLimitation) { + // This test case uses English as the source language and French as the target + // language. To avoid the failure of `PassAcceptLanguagesCheck()`, we set the + // preferred languages to English and French. + SetSelectedLanguages("en,fr"); + MockComponentManager mock_component_manager(GetTempDir()); + NavigateToEmptyPage(); + mock_component_manager.InstallMockTranslateKitComponent(); + + // No language packs are installed yet. + size_t installed_package_count = 0; + + // Get the amount of packages we can install. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount( + installed_package_count); + ASSERT_NE(installable_package_count, std::numeric_limits<size_t>::max()); + + for (const auto& language_pack_key : kLanguagePackKeys) { + mock_component_manager.InstallMockLanguagePack(language_pack_key); + installed_package_count++; + + if (installed_package_count < installable_package_count) { + // The language pack count is less than the limitation. + TestTranslationAvailable(browser(), "en", "fr", "downloadable"); + } else { + // The language pack count is equal to the limitation. So no more language + // pack can be downloaded. + TestTranslationAvailable(browser(), "en", "fr", "unavailable"); + break; + } + } + + ASSERT_EQ(installed_package_count, installable_package_count); +} + +// Test the behavior of `availability()` when the language pack is not ready, +// and the language pack count exceeds the limitation after downloading two +// more language packs. +IN_PROC_BROWSER_TEST_F( + OnDeviceTranslationBrowserTest, + Availability_Unavailable_ExceedsLangPackCountLimitationTwoPackagesRequired) { + // This test case uses Hindi and French as the source and target languages. + // To translate from Hindi to French, two language packs are required: one for + // the hi->en translation and one for the en->fr translation. + SetSelectedLanguages("hi,fr"); + MockComponentManager mock_component_manager(GetTempDir()); + NavigateToEmptyPage(); + mock_component_manager.InstallMockTranslateKitComponent(); + + // No language packs are installed yet. + size_t installed_package_count = 0; + + // Get the amount of packages we can install. + size_t installable_package_count = + on_device_translation::GetInstallablePackageCount( + installed_package_count); + ASSERT_NE(installable_package_count, std::numeric_limits<size_t>::max()); + + for (const auto& language_pack_key : kLanguagePackKeys) { + mock_component_manager.InstallMockLanguagePack(language_pack_key); + installed_package_count++; + + if (installed_package_count < installable_package_count - 1) { + // The language pack count is less than the limitation. + TestTranslationAvailable(browser(), "hi", "fr", "downloadable"); + } else if (installed_package_count < installable_package_count) { + // The language pack count is less than the limitation. + // If we download the required language packs, the language pack count + // will exceed the limitation. As a result, `availability()` is + // 'unavailable'. + TestTranslationAvailable(browser(), "hi", "fr", "unavailable"); + } else { + // The language pack count is 3, which is equal to the limitation. As a + // result, no more language packs can be downloaded. + TestTranslationAvailable(browser(), "hi", "fr", "unavailable"); + break; + } + } + + ASSERT_EQ(installed_package_count, installable_package_count); +} + // Test the behavior of `availability()` when both the library and the language // packs are not ready. IN_PROC_BROWSER_TEST_F( @@ -1824,14 +2085,7 @@ .Times(0); mock_component_manager.InstallMockTranslateKitComponent(); mock_component_manager.InstallMockLanguagePack(LanguagePackKey::kEn_Ko); - // Despite being ready, the availability will be masked since the site hasn't - // created a translator for this language pair yet. - // `kAfterDownloadTranslatorCreationRequired` is only ever returned in that - // situation, so receiving that value confirms that the package is readily - // available. - TestCanTranslateResult( - "en", "ko", - CanCreateTranslatorResult::kAfterDownloadTranslatorCreationRequired); + TestCanTranslateResult("en", "ko", CanCreateTranslatorResult::kReadily); } // Test the behavior of Translator API in a cross origin iframe. @@ -1873,19 +2127,14 @@ } // Adds an iframe to the test page and optionally sets its permission policy. - content::RenderFrameHost* AddIframe(size_t index, - Browser* target_browser, - bool permission_policy_enabled) { + void AddIframe(size_t index, + Browser* target_browser, + bool permission_policy_enabled) { EXPECT_EQ(EvalJsCatchingError(JsReplace("return addIframe($1, $2);", CreateCrossOriginIframeUrl(index), permission_policy_enabled), target_browser), "loaded"); - - return ChildFrameAt((target_browser ? target_browser : browser()) - ->tab_strip_model() - ->GetActiveWebContents(), - index); } // Removes the iframe and waits for the service deletion. @@ -1904,7 +2153,7 @@ // Creates a translator and translates in the iframe. Returns successful // translation or the error message. - std::string CheckTranslateInIframe(content::RenderFrameHost* iframe) { + std::string CheckTranslateInIframe(size_t index, Browser* target_browser) { const std::string_view translateTestScript = R"( (async () => { try { @@ -1920,11 +2169,14 @@ } })() )"; - return content::EvalJs(iframe, translateTestScript).ExtractString(); + return EvalJsCatchingError( + JsReplace("return evalInIframe($1, $2);", + CreateCrossOriginIframeUrl(index), translateTestScript), + target_browser); } // Checks the result of availability() in the iframe. - std::string TryCanTranslateInIframe(content::RenderFrameHost* iframe) { + std::string TryCanTranslateInIframe(size_t index, Browser* target_browser) { const std::string_view translateTestScript = R"( (async () => { try { @@ -1937,7 +2189,10 @@ } })() )"; - return content::EvalJs(iframe, translateTestScript).ExtractString(); + return EvalJsCatchingError( + JsReplace("return evalInIframe($1, $2);", + CreateCrossOriginIframeUrl(index), translateTestScript), + target_browser); } private: @@ -2013,12 +2268,11 @@ .Times(0); NavigateToTestPage(browser()); - content::RenderFrameHost* iframe = - AddIframe(0, browser(), /*enable_permission_policy=*/false); + AddIframe(0, browser(), /*enable_permission_policy=*/false); // Translation is not available in cross-origin iframes without permission // policy. - EXPECT_EQ(CheckTranslateInIframe(iframe), "NotAllowedError"); + EXPECT_EQ(CheckTranslateInIframe(0, browser()), "NotAllowedError"); } // Tests the behavior of the Translation API in a cross origin iframe when the @@ -2035,27 +2289,25 @@ // Until the service count exceeds the limit, the translator can be created, // and the translation is successful. for (; i < kTranslationAPIMaxServiceCount.Get(); i++) { - content::RenderFrameHost* iframe = - AddIframe(i, browser(), /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); - EXPECT_EQ(TryCanTranslateInIframe(iframe), "available"); + AddIframe(i, browser(), /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "en to ja: hello"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "available"); } // When the service count exceeds the limit, the translator cannot be created, // even when the permission policy is still enabled. - content::RenderFrameHost* iframe = - AddIframe(i, browser(), /*enable_permission_policy=*/true); + AddIframe(i, browser(), /*enable_permission_policy=*/true); auto console_observer = CreateConsoleObserver( "The translation service count exceeded the limitation."); - EXPECT_EQ(CheckTranslateInIframe(iframe), "NotSupportedError"); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "NotSupportedError"); WaitForConsoleObserver(*console_observer); - EXPECT_EQ(TryCanTranslateInIframe(iframe), "unavailable"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "unavailable"); // When the service count is back to under the limit, the translator can be // created again. RemoveIframeAndWaitForServiceDeletion(0, browser()); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); - EXPECT_EQ(TryCanTranslateInIframe(iframe), "available"); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "en to ja: hello"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "available"); } // Tests the behavior of the Translation API in a cross origin iframe using the @@ -2070,13 +2322,11 @@ Browser* incognito_browser = CreateIncognitoBrowser(); NavigateToTestPage(incognito_browser); - content::RenderFrameHost* iframe0 = - AddIframe(0, incognito_browser, /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(iframe0), "en to ja: hello"); + AddIframe(0, incognito_browser, /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(0, incognito_browser), "en to ja: hello"); - content::RenderFrameHost* iframe1 = - AddIframe(1, incognito_browser, /*enable_permission_policy=*/false); - EXPECT_EQ(CheckTranslateInIframe(iframe1), "NotAllowedError"); + AddIframe(1, incognito_browser, /*enable_permission_policy=*/false); + EXPECT_EQ(CheckTranslateInIframe(1, incognito_browser), "NotAllowedError"); } // Tests the behavior of the Translation API in a cross origin iframe using the @@ -2091,9 +2341,8 @@ Browser* guest_browser = CreateGuestBrowser(); NavigateToTestPage(guest_browser); - content::RenderFrameHost* iframe = - AddIframe(0, guest_browser, /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); + AddIframe(0, guest_browser, /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(0, guest_browser), "en to ja: hello"); } // Tests the behavior of the Translation API in a cross origin iframe using @@ -2128,39 +2377,32 @@ // translation is successful. for (size_t i = 0; i < kTranslationAPIMaxServiceCount.Get(); i++) { for (auto* target_browser : browsers) { - content::RenderFrameHost* iframe = - AddIframe(i, target_browser, /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); + AddIframe(i, target_browser, /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(i, target_browser), "en to ja: hello"); } } const size_t limit_count = kTranslationAPIMaxServiceCount.Get(); - std::vector<content::RenderFrameHost*> iframes; - // When the service count per profile exceeds the limit, the translator // cannot be created. for (auto* target_browser : browsers) { - content::RenderFrameHost* iframe = AddIframe( - limit_count, target_browser, /*enable_permission_policy=*/true); - iframes.push_back(iframe); + AddIframe(limit_count, target_browser, /*enable_permission_policy=*/true); auto console_observer = CreateConsoleObserver( "The translation service count exceeded the limitation.", target_browser); - EXPECT_EQ(CheckTranslateInIframe(iframe), "NotSupportedError"); + EXPECT_EQ(CheckTranslateInIframe(limit_count, target_browser), + "NotSupportedError"); // The console message should be logged. WaitForConsoleObserver(*console_observer); } - ASSERT_EQ(iframes.size(), browsers.size()); - // When the service count per profile is back to under the limit, the // translator can be created again. - for (size_t i = 0; i < browsers.size(); i++) { - Browser* target_browser = browsers[i]; - content::RenderFrameHost* iframe = iframes[i]; + for (auto* target_browser : browsers) { RemoveIframeAndWaitForServiceDeletion(0, target_browser); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); + EXPECT_EQ(CheckTranslateInIframe(limit_count, target_browser), + "en to ja: hello"); } } @@ -2195,23 +2437,21 @@ // Until the service count exceeds the limit, the translator can be created, // and the translation is successful. for (; i < kTranslationAPIMaxServiceCount.Get(); i++) { - content::RenderFrameHost* iframe = - AddIframe(i, browser(), /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(iframe), "en to ja: hello"); - EXPECT_EQ(TryCanTranslateInIframe(iframe), "available"); + AddIframe(i, browser(), /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "en to ja: hello"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "available"); } // When the service count exceeds the limit, the translator cannot be created. - content::RenderFrameHost* last_iframe = - AddIframe(i, browser(), /*enable_permission_policy=*/true); - EXPECT_EQ(CheckTranslateInIframe(last_iframe), "NotSupportedError"); - EXPECT_EQ(TryCanTranslateInIframe(last_iframe), "unavailable"); + AddIframe(i, browser(), /*enable_permission_policy=*/true); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "NotSupportedError"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "unavailable"); // When the service count is back to under the limit, the translator can be // created again. RemoveIframeAndWaitForServiceDeletion(0, browser()); - EXPECT_EQ(CheckTranslateInIframe(last_iframe), "en to ja: hello"); - EXPECT_EQ(TryCanTranslateInIframe(last_iframe), "available"); + EXPECT_EQ(CheckTranslateInIframe(i, browser()), "en to ja: hello"); + EXPECT_EQ(TryCanTranslateInIframe(i, browser()), "available"); } // Tests the behavior of the Origin Trial token for the Translation API. @@ -2447,15 +2687,7 @@ mock_component_manager.InstallMockTranslateKitComponent(); mock_component_manager.DoNotExpectCallRegisterLanguagePackComponent(); NavigateToEmptyPage(); - - // Despite being ready, the availability will be masked since the site hasn't - // created a translator for this language pair yet. - // `kAfterDownloadTranslatorCreationRequired` is only ever returned in that - // situation, so receiving that value confirms that the package is readily - // available. - TestCanTranslateResult( - "en", "ja", - CanCreateTranslatorResult::kAfterDownloadTranslatorCreationRequired); + TestCanTranslateResult("en", "ja", CanCreateTranslatorResult::kReadily); } // Tests the behavior of availability() when the required language package
diff --git a/chrome/browser/on_device_translation/service_controller.cc b/chrome/browser/on_device_translation/service_controller.cc index bc48543..5ffb9c0 100644 --- a/chrome/browser/on_device_translation/service_controller.cc +++ b/chrome/browser/on_device_translation/service_controller.cc
@@ -156,6 +156,19 @@ to_be_registered_packs); if (!to_be_registered_packs.empty()) { + if (!base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) && + (kTranslationAPILimitLanguagePackCount.Get() && + to_be_registered_packs.size() > + GetInstallablePackageCount( + ComponentManager::GetRegisteredLanguagePacks().size()))) { + RecordLanguagePairUma( + "Translate.OnDeviceTranslation.DownloadExceedLimit.LanguagePair", + source_lang, target_lang); + std::move(callback).Run(base::unexpected( + CreateTranslatorError::kExceedsLanguagePackCountLimitation)); + return; + } + for (const auto& language_pack : to_be_registered_packs) { RecordLanguagePairUma( "Translate.OnDeviceTranslation.Download.LanguagePair", @@ -307,6 +320,17 @@ return CanCreateTranslatorResult::kNoNotSupportedLanguage; } + if (!to_be_registered_packs.empty() && + !base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) && + kTranslationAPILimitLanguagePackCount.Get() && + to_be_registered_packs.size() > + GetInstallablePackageCount( + ComponentManager::GetRegisteredLanguagePacks().size())) { + // The number of installed language packs will exceed the limitation if the + // new required language packs are installed. + return CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation; + } + if (required_not_installed_packs.empty()) { // All required language packages are installed. if (ComponentManager::GetTranslateKitLibraryPath().empty()) {
diff --git a/chrome/browser/on_device_translation/translation_manager_impl.cc b/chrome/browser/on_device_translation/translation_manager_impl.cc index e847883..1c07542 100644 --- a/chrome/browser/on_device_translation/translation_manager_impl.cc +++ b/chrome/browser/on_device_translation/translation_manager_impl.cc
@@ -293,6 +293,15 @@ return; } + if (!PassAcceptLanguagesCheck(GetAcceptLanguages(browser_context()), + source_language, target_language)) { + mojo::Remote(std::move(client)) + ->OnResult(CreateTranslatorResult::NewError( + CreateTranslatorError::kAcceptLanguagesCheckFailed), + nullptr, nullptr); + return; + } + if (options->observer_remote) { base::flat_set<std::string> component_ids = { component_updater::TranslateKitComponentInstallerPolicy:: @@ -316,7 +325,8 @@ weak_ptr_factory_.GetWeakPtr(), std::move(client), source_language, target_language); - if (add_fake_download_delay) { + if (base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) && + add_fake_download_delay) { base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( FROM_HERE, std::move(create_translator), GetTranslatorDownloadDelay()); } else { @@ -364,6 +374,14 @@ const std::vector<std::string_view> accept_languages = GetAcceptLanguages(browser_context()); + // TODO(crbug.com/385173766): Remove once V1 is launched. + if (!PassAcceptLanguagesCheck(accept_languages, source_language, + target_language)) { + std::move(callback).Run( + CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed); + return; + } + bool are_source_and_target_accept_or_english = (IsInAcceptLanguage(accept_languages, source_language) || l10n_util::GetLanguage(source_language) == "en") && @@ -371,6 +389,7 @@ l10n_util::GetLanguage(target_language) == "en"); bool mask_readily_result = + base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) && !HasInitializedTranslator(source_language, target_language) && !are_source_and_target_accept_or_english;
diff --git a/chrome/browser/on_device_translation/translation_manager_util.cc b/chrome/browser/on_device_translation/translation_manager_util.cc index aa6018d..b5c6b6d 100644 --- a/chrome/browser/on_device_translation/translation_manager_util.cc +++ b/chrome/browser/on_device_translation/translation_manager_util.cc
@@ -18,6 +18,19 @@ namespace on_device_translation { +namespace { + +bool IsSupportedPopularLanguage(const std::string& lang) { + const std::optional<SupportedLanguage> supported_lang = + ToSupportedLanguage(lang); + if (!supported_lang) { + return false; + } + return IsPopularLanguage(*supported_lang); +} + +} // namespace + const std::vector<std::string_view> GetAcceptLanguages( content::BrowserContext* browser_context) { CHECK(browser_context); @@ -48,4 +61,34 @@ ->GetBoolean(prefs::kTranslatorAPIAllowed); } +bool PassAcceptLanguagesCheck( + const std::vector<std::string_view>& accept_languages, + const std::string& source_lang, + const std::string& target_lang) { + if (base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) || + !kTranslationAPIAcceptLanguagesCheck.Get()) { + return true; + } + + // TODO(crbug.com/371899260): Implement better language code handling. + + // One of the source or the destination language must be in the user's accept + // language. + const bool source_lang_is_in_accept_langs = + IsInAcceptLanguage(accept_languages, source_lang); + const bool target_lang_is_in_accept_langs = + IsInAcceptLanguage(accept_languages, target_lang); + + // The other language must be a popular language. + if (!source_lang_is_in_accept_langs && + !IsSupportedPopularLanguage(source_lang)) { + return false; + } + if (!target_lang_is_in_accept_langs && + !IsSupportedPopularLanguage(target_lang)) { + return false; + } + return true; +} + } // namespace on_device_translation
diff --git a/chrome/browser/on_device_translation/translation_manager_util.h b/chrome/browser/on_device_translation/translation_manager_util.h index 09910fb..67b24d2 100644 --- a/chrome/browser/on_device_translation/translation_manager_util.h +++ b/chrome/browser/on_device_translation/translation_manager_util.h
@@ -27,6 +27,14 @@ // Determines if the Translator API is enabled. bool IsTranslatorAllowed(content::BrowserContext* browser_context); +// When the `TranslationAPIAcceptLanguagesCheck` feature is enabled, the +// Translation API will fail if neither the source nor destination language is +// in Accept Languages. This is intended to mitigate privacy concerns. +bool PassAcceptLanguagesCheck( + const std::vector<std::string_view>& accept_languages, + const std::string& source_lang, + const std::string& target_lang); + // Implementation of LookupMatchingLocaleByBestFit // (https://tc39.es/ecma402/#sec-lookupmatchinglocalebybestfit) as // LookupMatchingLocaleByPrefix
diff --git a/chrome/browser/on_device_translation/translation_manager_util_unittest.cc b/chrome/browser/on_device_translation/translation_manager_util_unittest.cc index a5c767b..4033fc7 100644 --- a/chrome/browser/on_device_translation/translation_manager_util_unittest.cc +++ b/chrome/browser/on_device_translation/translation_manager_util_unittest.cc
@@ -19,6 +19,143 @@ ~TranslationManagerUtilTest() override = default; }; +TEST_F(TranslationManagerUtilTest, PassAcceptLanguagesCheck) { + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "es"}, "en", "es")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : false + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "fr"}, "en", "fr")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "es"}, "en", "zh")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "es"}, "en", "fr")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"de", "es"}, "de", "es")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : false + EXPECT_TRUE(PassAcceptLanguagesCheck({"de", "fr"}, "de", "fr")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"de", "es"}, "de", "zh")); + + // Source lang: + // - Is in accept-languages : true + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"de", "es"}, "de", "fr")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "es"}, "ja", "es")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : false + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "fr"}, "ja", "fr")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : true + EXPECT_TRUE(PassAcceptLanguagesCheck({"en", "es"}, "ja", "zh")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : true + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "es"}, "ja", "fr")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : true + // Source is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "es"}, "de", "es")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : true + // - Is popular lang : false + // Source is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "fr"}, "de", "fr")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : true + // Source is not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "es"}, "de", "zh")); + + // Source lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target lang: + // - Is in accept-languages : false + // - Is popular lang : false + // Target and source are not in accept-languages, and not popular. + EXPECT_FALSE(PassAcceptLanguagesCheck({"en", "es"}, "de", "fr")); +} + TEST_F(TranslationManagerUtilTest, LookupMatchingLocaleByBestFitFindsSupportedLanguageTag) { std::vector<std::string> en_variations{
diff --git a/chrome/browser/page_load_metrics/observers/gws_hp_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/gws_hp_page_load_metrics_observer.cc index 55a488e..5489039 100644 --- a/chrome/browser/page_load_metrics/observers/gws_hp_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/gws_hp_page_load_metrics_observer.cc
@@ -10,8 +10,8 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/named_trigger.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/page_load_metrics/observers/histogram_suffixes.h"
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc index a21f29a..6269227e 100644 --- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
@@ -8,7 +8,7 @@ #include "base/check_is_test.h" #include "base/notreached.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h" #include "chrome/browser/predictors/loading_predictor.h" #include "chrome/browser/predictors/loading_predictor_factory.h"
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc index 5c128365..517dd7c 100644 --- a/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc +++ b/chrome/browser/performance_manager/metrics/metrics_provider_desktop.cc
@@ -13,7 +13,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" #include "base/timer/timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h" #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/performance_manager/policies/keep_alive_dse_policy_unittest.cc b/chrome/browser/performance_manager/policies/keep_alive_dse_policy_unittest.cc index 6708c5f..37c359a 100644 --- a/chrome/browser/performance_manager/policies/keep_alive_dse_policy_unittest.cc +++ b/chrome/browser/performance_manager/policies/keep_alive_dse_policy_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/performance_manager/policies/keep_alive_dse_policy.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/performance_manager/public/performance_manager.h"
diff --git a/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc index 3958a4c..882dea4 100644 --- a/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc +++ b/chrome/browser/picture_in_picture/document_picture_in_picture_window_controller_browsertest.cc
@@ -605,18 +605,15 @@ LoadTabAndEnterPictureInPicture(browser(), maximum_window_size + gfx::Size(1000, 2000)); - // Confirm that the size of the outer window bounds are equal to or less than - // the maximum size. + // Confirm that the size of the outer window bounds are equal to the maximum + // window size. auto* pip_web_contents = window_controller()->GetChildWebContents(); ASSERT_NE(nullptr, pip_web_contents); WaitForPageLoad(pip_web_contents); auto* browser_view = static_cast<BrowserView*>( BrowserWindow::FindBrowserWindowWithWebContents(pip_web_contents)); - EXPECT_LE(browser_view->GetBounds().size().width(), - maximum_window_size.width()); - EXPECT_LE(browser_view->GetBounds().size().height(), - maximum_window_size.height()); + ASSERT_EQ(maximum_window_size, browser_view->GetBounds().size()); } // Context menu should not be shown when right clicking on a document picture in
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc index 395f622..ebdc395e 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
@@ -56,11 +56,6 @@ constexpr double kMaxWindowSizeRatio = 0.8; #if !BUILDFLAG(IS_ANDROID) -// The largest fraction of the screen that Document Picture-in-Picture windows -// can take up by request of the website. The user can still manually resize to -// `kMaxWindowSizeRatio`. -constexpr double kMaxSiteRequestedWindowSizeRatio = 0.25; - // Returns true if a document picture-in-picture window should be focused upon // opening it. bool ShouldFocusPictureInPictureWindow(const NavigateParams& params) { @@ -77,13 +72,6 @@ // AutoPictureInPictureTabHelper. return !auto_picture_in_picture_tab_helper->IsInAutoPictureInPicture(); } - -// Returns the maximum area in pixels that the site can request a -// picture-in-picture window to be. -base::CheckedNumeric<int> GetMaximumSiteRequestedWindowArea( - const display::Display& display) { - return display.size().GetCheckedArea() * kMaxSiteRequestedWindowSizeRatio; -} #endif // !BUILDFLAG(IS_ANDROID) } // namespace @@ -298,107 +286,6 @@ return instance->GetChildWebContents() == wc; } -// static -gfx::Size PictureInPictureWindowManager::AdjustRequestedSizeIfNecessary( - const gfx::Size& requested_size, - const display::Display& display) { -#if BUILDFLAG(IS_ANDROID) - return requested_size; -#else // BUILDFLAG(IS_ANDROID) - base::CheckedNumeric<int> requested_area = requested_size.GetCheckedArea(); - base::CheckedNumeric<int> max_requested_area = - GetMaximumSiteRequestedWindowArea(display); - - // If the website has requested an area too large to calculate, then their - // request isn't particularly useful and we will fall back to the minimum - // size. - if (!requested_area.IsValid()) { - return GetMinimumInnerWindowSize(); - } - - // If the screen size is too large to calculate, then fall back to allowing - // the requested size. Note that this should only occur with a ridiculous - // monitor size that would only happen in a test environment. - if (!max_requested_area.IsValid()) { - return requested_size; - } - - // If the website's requested size is not too large, then there's nothing that - // needs to change. - if (requested_area.ValueOrDie() <= max_requested_area.ValueOrDie()) { - return requested_size; - } - - // Otherwise, if the website's requested size is too large, then shrink it to - // the maximum allowed size while maintaining the given aspect ratio. - gfx::Size minimum_size(GetMinimumInnerWindowSize()); - gfx::Size maximum_size(GetMaximumWindowSize(display)); - maximum_size.SetToMax(minimum_size); - - double original_width = static_cast<double>(requested_size.width()); - double original_height = static_cast<double>(requested_size.height()); - - // Ideally, we could resize to perfectly maintain the aspect ratio while - // hitting the max requested area. - double ideal_scale_for_area = - std::sqrt(static_cast<double>(max_requested_area.ValueOrDie()) / - static_cast<double>(requested_area.ValueOrDie())); - - // However, we need to ensure that we remain large enough for the minimum size - // in both dimensions. - double scale_needed_for_min_width = - static_cast<double>(minimum_size.width()) / original_width; - double scale_needed_for_min_height = - static_cast<double>(minimum_size.height()) / original_height; - double minimum_scale = - std::max(scale_needed_for_min_width, scale_needed_for_min_height); - - // And also that we remain small enough to be within the maximum size in both - // dimensions. - double scale_needed_for_max_width = - static_cast<double>(maximum_size.width()) / original_width; - double scale_needed_for_max_height = - static_cast<double>(maximum_size.height()) / original_height; - double maximum_scale = - std::min(scale_needed_for_max_width, scale_needed_for_max_height); - - gfx::Size output_size; - - // If the smallest scale needed to reach the minimum size is larger than the - // largest scale that fits within the maximum bounds, then we can't perfectly - // maintain aspect ratio. - if (minimum_scale > maximum_scale) { - if (original_width > original_height) { - // If this is because the requested width is too large, then fall back to - // the minimum height with as much width as is allowed. - output_size.set_width( - static_cast<double>(max_requested_area.ValueOrDie()) / - minimum_size.height()); - output_size.set_height(minimum_size.height()); - } else { - // If this is because the requested height is too large, then fall back to - // the minimum width with as much height as is allowed. - output_size.set_width(minimum_size.width()); - output_size.set_height( - static_cast<double>(max_requested_area.ValueOrDie()) / - minimum_size.width()); - } - } else { - // Otherwise, either scale by the ideal factor or make it smaller than that - // to fit within the maximum size. - double effective_scale = std::min(ideal_scale_for_area, maximum_scale); - output_size.set_width(original_width * effective_scale); - output_size.set_height(original_height * effective_scale); - } - - // Ensure the standard size restrictions are still met. - output_size.SetToMax(minimum_size); - output_size.SetToMin(maximum_size); - - return output_size; -#endif // BUILDFLAG(IS_ANDROID) -} - std::optional<gfx::Rect> PictureInPictureWindowManager::GetPictureInPictureWindowBounds() const { return pip_window_controller_ ? pip_window_controller_->GetWindowBounds() @@ -441,27 +328,14 @@ } if (pip_options.width > 0 && pip_options.height > 0) { - // Use width and height if we have them both, and ensure that the size isn't - // too large. - gfx::Size requested_window_size( - base::saturated_cast<int>(pip_options.width), - base::saturated_cast<int>(pip_options.height)); - gfx::Size window_size = - AdjustRequestedSizeIfNecessary(requested_window_size, display); - -#if !BUILDFLAG(IS_ANDROID) - if (is_calculating_initial_document_pip_size_) { - base::UmaHistogramBoolean( - "Media.DocumentPictureInPicture.RequestedLargeInitialSize", - requested_window_size != window_size); - } -#endif // !BUILDFLAG(IS_ANDROID) - - // The pip options are the desired inner size, so we add any non-client size - // we need to convert to outer size by adding back the margin around the - // inner area. - window_size += excluded_margin; - + // Use width and height if we have them both, but ensure it's within the + // required bounds. Remember that the pip options are the desired inner + // size, so we add any non-client size we need to convert to outer size by + // adding back the margin around the inner area. + gfx::Size window_size( + base::saturated_cast<int>(pip_options.width + excluded_margin.width()), + base::saturated_cast<int>(pip_options.height + + excluded_margin.height())); window_size.SetToMin(GetMaximumWindowSize(display)); window_size.SetToMax(minimum_outer_window_size); window_bounds = gfx::Rect(window_size); @@ -508,8 +382,6 @@ const display::Display& display) { #if !BUILDFLAG(IS_ANDROID) RecordDocumentPictureInPictureRequestedSizeMetrics(pip_options, display); - base::AutoReset<bool> auto_reset(&is_calculating_initial_document_pip_size_, - true); #endif // !BUILDFLAG(IS_ANDROID) // Use an empty `excluded_margin`, which more or less guarantees that these
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h index b629247..8769fbb 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
@@ -129,18 +129,6 @@ // document PiP window. static bool IsChildWebContents(content::WebContents*); - // When a website requests size `requested_size` for a document - // picture-in-picture window (either when creating the window or when resizing - // the window via resizeTo()/resizeBy() APIs), we restrict the maximum size - // we'll make the pip window (this is a smaller maximum than the maximum size - // the user can manually resize to). If the given `requested_size` is small - // enough, this just returns the requested size. Otherwise, this shrinks the - // requested size to fit within the constraints, and attempts to keep the - // aspect ratio the same. - static gfx::Size AdjustRequestedSizeIfNecessary( - const gfx::Size& requested_size, - const display::Display& display); - // Returns the window bounds of the video picture-in-picture or the document // picture-in-picture if either of them is present. std::optional<gfx::Rect> GetPictureInPictureWindowBounds() const; @@ -327,12 +315,6 @@ // blocked. uint32_t number_of_existing_scoped_disallow_picture_in_pictures_ = 0; - // True if we're currently calculating document pip's initial size. Used to - // determine whether we should record the - // `Media.DocumentPictureInPicture.RequestedLargeInitialSize` metric and - // should be removed when that metric is removed. - bool is_calculating_initial_document_pip_size_ = false; - std::unique_ptr<PictureInPictureWindowManagerUmaHelper> uma_helper_; #endif //! BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc index ef8e05f..1695cce 100644 --- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc +++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager_unittest.cc
@@ -132,6 +132,32 @@ } // namespace +TEST_F(PictureInPictureWindowManagerTest, RespectsMinAndMaxSize) { + // The max window size should be 80% of the screen. + display::Display display(/*id=*/1, gfx::Rect(0, 0, 1000, 1000)); + EXPECT_EQ(gfx::Size(800, 800), + PictureInPictureWindowManager::GetMaximumWindowSize(display)); + + // The initial bounds of the PiP window should respect that. + blink::mojom::PictureInPictureWindowOptions pip_options; + pip_options.width = 900; + pip_options.height = 900; + EXPECT_EQ( + gfx::Size(800, 800), + PictureInPictureWindowManager::GetInstance() + ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) + .size()); + + // The minimum size should also be respected. + pip_options.width = 100; + pip_options.height = 500; + EXPECT_EQ( + gfx::Size(240, 500), + PictureInPictureWindowManager::GetInstance() + ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) + .size()); +} + TEST_F(PictureInPictureWindowManagerTest, ExitPictureInPictureReturnsFalseWhenThereIsNoWindow) { EXPECT_FALSE( @@ -158,74 +184,6 @@ } #if !BUILDFLAG(IS_ANDROID) -TEST_F(PictureInPictureWindowManagerTest, RespectsMinAndMaxSize) { - // The max window size should be 80% of the screen. - display::Display display(/*id=*/1, gfx::Rect(0, 0, 1000, 1000)); - EXPECT_EQ(gfx::Size(800, 800), - PictureInPictureWindowManager::GetMaximumWindowSize(display)); - - // The initial bounds of the PiP window should respect that. - blink::mojom::PictureInPictureWindowOptions pip_options; - pip_options.width = 900; - pip_options.height = 100; - EXPECT_EQ( - gfx::Size(800, 100), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); - - // Additionally, even if the given size is less than the absolute max, it - // should be forced to respect the maximum allowed area. - pip_options.width = 800; - pip_options.height = 800; - EXPECT_EQ( - gfx::Size(500, 500), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); - - // Additionally, even if the given size is less than the absolute max, it - // should be forced to respect the maximum allowed area. - pip_options.width = 800; - pip_options.height = 400; - EXPECT_EQ( - gfx::Size(707, 353), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); - - // If the requested width is so much larger than the height that maintaining - // the aspect ratio isn't possible within the min/max bounds, then it should - // keep the minimum height and expand the width to the maximum size. - pip_options.width = 10000; - pip_options.height = 400; - EXPECT_EQ( - gfx::Size(800, 52), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); - - // If the requested height is so much larger than the width that maintaining - // the aspect ratio isn't possible within the min/max bounds, then it should - // keep the minimum width and expand the height to the maximum size. - pip_options.width = 400; - pip_options.height = 10000; - EXPECT_EQ( - gfx::Size(240, 800), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); - - // The minimum size should also be respected. - pip_options.width = 100; - pip_options.height = 500; - EXPECT_EQ( - gfx::Size(240, 500), - PictureInPictureWindowManager::GetInstance() - ->CalculateInitialPictureInPictureWindowBounds(pip_options, display) - .size()); -} - TEST_F(PictureInPictureWindowManagerTest, OnEnterDocumentPictureInPicture) { PictureInPictureWindowManager* picture_in_picture_window_manager = PictureInPictureWindowManager::GetInstance();
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc index a4d4119..fe2501a1 100644 --- a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc +++ b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc
@@ -8,8 +8,7 @@ #include "base/metrics/histogram_functions.h" #include "base/notreached.h" #include "base/task/sequenced_task_runner.h" -#include "base/trace_event/base_tracing.h" -#include "base/trace_event/common/trace_event_common.h" +#include "base/trace_event/trace_event.h" #include "chrome/browser/after_startup_task_utils.h" #include "content/public/browser/browser_thread.h" #include "net/base/isolation_info.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 35b444c..82681d7c 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1131,6 +1131,10 @@ inline constexpr char kPrivacySandboxFakeNoticeFirstSignOutTime[] = "privacy_sandbox.fake_notice.first_sign_out_time"; +// Deprecated 06/2025. +inline constexpr char kStorageGarbageCollect[] = + "extensions.storage.garbagecollect"; + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -1612,6 +1616,9 @@ registry->RegisterTimeDeltaPref(kSyncPollInterval, base::TimeDelta()); registry->RegisterDictionaryPref(kSharingVapidKey); registry->RegisterBooleanPref(kHasSeenWelcomePage, false); + + // Deprecated 06/2025 + registry->RegisterBooleanPref(kStorageGarbageCollect, false); } } // namespace @@ -2934,6 +2941,9 @@ profile_prefs->ClearPref(kSharingVapidKey); profile_prefs->ClearPref(kHasSeenWelcomePage); + // Added 06/2025. + profile_prefs->ClearPref(kStorageGarbageCollect); + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/process_singleton_internal.cc b/chrome/browser/process_singleton_internal.cc index b52ead7..3da34780 100644 --- a/chrome/browser/process_singleton_internal.cc +++ b/chrome/browser/process_singleton_internal.cc
@@ -6,7 +6,7 @@ #include "base/metrics/histogram_macros.h" #include "base/notreached.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/tracing/protos/chrome_track_event.pbzero.h" #include "build/build_config.h"
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc index 68ca956b..1bc2d93 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc
@@ -22,7 +22,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/registry.h" #include "base/win/scoped_handle.h" #include "base/win/windows_version.h"
diff --git a/chrome/browser/profiles/profile_metrics_unittest.cc b/chrome/browser/profiles/profile_metrics_unittest.cc index a601498..826cf6d 100644 --- a/chrome/browser/profiles/profile_metrics_unittest.cc +++ b/chrome/browser/profiles/profile_metrics_unittest.cc
@@ -8,6 +8,7 @@ #include <vector> #include "base/files/file_path.h" +#include "base/strings/to_string.h" #include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" #include "chrome/browser/profiles/profile_attributes_entry.h"
diff --git a/chrome/browser/push_notification/server_client/push_notification_desktop_api_call_flow_impl_unittest.cc b/chrome/browser/push_notification/server_client/push_notification_desktop_api_call_flow_impl_unittest.cc index 7b75310..5e6d528 100644 --- a/chrome/browser/push_notification/server_client/push_notification_desktop_api_call_flow_impl_unittest.cc +++ b/chrome/browser/push_notification/server_client/push_notification_desktop_api_call_flow_impl_unittest.cc
@@ -11,6 +11,7 @@ #include <vector> #include "base/functional/bind.h" +#include "base/no_destructor.h" #include "base/test/task_environment.h" #include "net/base/net_errors.h" #include "net/base/url_util.h"
diff --git a/chrome/browser/renderer_host/javascript_optimizer_feature_browsertest.cc b/chrome/browser/renderer_host/javascript_optimizer_feature_browsertest.cc index 23b0aa05..c01d8fa 100644 --- a/chrome/browser/renderer_host/javascript_optimizer_feature_browsertest.cc +++ b/chrome/browser/renderer_host/javascript_optimizer_feature_browsertest.cc
@@ -15,6 +15,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_host_resolver.h" +#include "content/public/test/test_utils.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" @@ -390,13 +391,13 @@ content::ChildProcessSecurityPolicy::IsolatedOriginSource:: USER_TRIGGERED)); - if (content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites() && + if (content::AreStrictSiteInstancesEnabled() && !content::SiteIsolationPolicy:: AreOriginKeyedProcessesEnabledByDefault()) { - // if a.com is isolated already (as is the case with full - // site isolation but not the case under origin isolation), the navigation - // to sub.a.com will be made in a SiteInstance with a "a.com" site URL, - // which will match a.com BLOCK rule. + // if a.com is isolated already (as is the case with full site isolation) + // or if DefaultSiteInstanceGroups are enabled, and origin isolation is not + // used, the navigation to sub.a.com will be made in a SiteInstance with a + // "a.com" site URL, which will match a.com BLOCK rule. EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents()); } else { // If nothing is isolated by default (like on Android), we'll navigate in a
diff --git a/chrome/browser/resources/privacy_sandbox/BUILD.gn b/chrome/browser/resources/privacy_sandbox/BUILD.gn index c8012bd7..c2768783 100644 --- a/chrome/browser/resources/privacy_sandbox/BUILD.gn +++ b/chrome/browser/resources/privacy_sandbox/BUILD.gn
@@ -50,10 +50,13 @@ "three_ads_apis_notice.ts", "measurement_notice.html.ts", "measurement_notice.ts", + "base_dialog_learn_more.html.ts", + "base_dialog_learn_more.ts", ] css_files = [ "base_dialog_app.css", + "base_dialog_learn_more.css", "base_dialog_styles.css", "privacy_sandbox_privacy_policy_dialog.css", "shared_style.css",
diff --git a/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.css b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.css new file mode 100644 index 0000000..4ddcee75 --- /dev/null +++ b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.css
@@ -0,0 +1,26 @@ +/* Copyright 2025 The Chromium Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/* #css_wrapper_metadata_start + * #type=style-lit + * #scheme=relative + * #css_wrapper_metadata_end */ + +.learn-more { + border-bottom: 1px solid #D3E3FD; +} + +@media (prefers-color-scheme: dark) { + .learn-more { + border-bottom: 1px solid #5E5E5E; /* Dark mode border */ + } +} + +cr-expand-button { + --cr-section-vertical-padding: 16px; +} + +.cr-secondary-text{ + margin-left: 4px; +}
diff --git a/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.html.ts b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.html.ts new file mode 100644 index 0000000..ad4d529bf --- /dev/null +++ b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.html.ts
@@ -0,0 +1,21 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {html} from '//resources/lit/v3_0/lit.rollup.js'; + +import type {BaseDialogLearnMore} from './base_dialog_learn_more.js'; + +export function getHtml(this: BaseDialogLearnMore) { + return html`<!--_html_template_start_--> +<div class="learn-more"> + <cr-expand-button ?expanded="${this.expanded_}" + @expanded-changed="${this.onExpandedChanged_}"> + <div class="cr-secondary-text">${this.title}</div> + </cr-expand-button> + <cr-collapse id="collapse" ?opened="${this.expanded_}"> + <slot></slot> + </cr-collapse> +</div> +<!--_html_template_end_-->`; +}
diff --git a/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.ts b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.ts new file mode 100644 index 0000000..c4152c0 --- /dev/null +++ b/chrome/browser/resources/privacy_sandbox/base_dialog_learn_more.ts
@@ -0,0 +1,58 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '//resources/cr_elements/cr_collapse/cr_collapse.js'; +import '//resources/cr_elements/cr_expand_button/cr_expand_button.js'; + +import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; +import type {CrCollapseElement} from 'chrome://resources/cr_elements/cr_collapse/cr_collapse.js'; + +import {getCss} from './base_dialog_learn_more.css.js'; +import {getHtml} from './base_dialog_learn_more.html.js'; + +export interface BaseDialogLearnMore { + $: { + collapse: CrCollapseElement, + }; +} + +export class BaseDialogLearnMore extends CrLitElement { + static get is() { + return 'base-dialog-learn-more'; + } + + static override get styles() { + return getCss(); + } + + override render() { + return getHtml.bind(this)(); + } + + static override get properties() { + return { + expanded_: {type: Boolean, notify: true}, + title: {type: String}, + }; + } + + accessor expanded_: boolean = false; + + protected onExpandedChanged_(e: CustomEvent<{value: boolean}>) { + this.expanded_ = e.detail.value; + if (this.expanded_) { + requestAnimationFrame(() => { + this.$.collapse.scrollIntoView({block: 'start', behavior: 'smooth'}); + }); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + 'base-dialog-learn-more': BaseDialogLearnMore; + } +} + +customElements.define(BaseDialogLearnMore.is, BaseDialogLearnMore);
diff --git a/chrome/browser/safe_browsing/notification_content_detection/notification_content_detection_util_unittest.cc b/chrome/browser/safe_browsing/notification_content_detection/notification_content_detection_util_unittest.cc index b666f80..a756595d 100644 --- a/chrome/browser/safe_browsing/notification_content_detection/notification_content_detection_util_unittest.cc +++ b/chrome/browser/safe_browsing/notification_content_detection/notification_content_detection_util_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/safe_browsing/notification_content_detection/notification_content_detection_util.h" #include "base/json/json_string_value_serializer.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/test_future.h" #include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h" #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
diff --git a/chrome/browser/serial/serial_chooser_context.cc b/chrome/browser/serial/serial_chooser_context.cc index 63ebcb5..6199abe2 100644 --- a/chrome/browser/serial/serial_chooser_context.cc +++ b/chrome/browser/serial/serial_chooser_context.cc
@@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(crbug.com/40285824): Remove this and convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "chrome/browser/serial/serial_chooser_context.h" #include <string_view> @@ -15,6 +10,7 @@ #include "base/base64.h" #include "base/containers/contains.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/byte_conversions.h" #include "base/observer_list.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" @@ -74,9 +70,11 @@ return base::UnguessableToken(); } - const uint64_t* data = reinterpret_cast<const uint64_t*>(buffer.data()); + base::span<const uint8_t> byte_buffer = base::as_byte_span(buffer); + uint64_t high = base::U64FromLittleEndian(byte_buffer.first<8>()); + uint64_t low = base::U64FromLittleEndian(byte_buffer.subspan<8, 8>()); std::optional<base::UnguessableToken> token = - base::UnguessableToken::Deserialize(data[0], data[1]); + base::UnguessableToken::Deserialize(high, low); if (!token.has_value()) { return base::UnguessableToken(); }
diff --git a/chrome/browser/storage/shared_storage_browsertest.cc b/chrome/browser/storage/shared_storage_browsertest.cc index 31dfe6b3..51ce5de 100644 --- a/chrome/browser/storage/shared_storage_browsertest.cc +++ b/chrome/browser/storage/shared_storage_browsertest.cc
@@ -19,6 +19,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/to_string.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h"
diff --git a/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc b/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc index 3918c5d9..0a418fd 100644 --- a/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc +++ b/chrome/browser/support_tool/ash/chrome_user_logs_data_collector_unittest.cc
@@ -18,6 +18,7 @@ #include "base/test/task_environment.h" #include "base/test/test_file_util.h" #include "base/test/test_future.h" +#include "base/threading/thread_restrictions.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/support_tool/data_collector.h" #include "chrome/test/base/fake_profile_manager.h"
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn b/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn index 3b5c233..ba9436c 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn +++ b/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn
@@ -52,6 +52,7 @@ "java/res/layout/touch_to_fill_payment_method_footer_item.xml", "java/res/layout/touch_to_fill_payment_method_header_item.xml", "java/res/layout/touch_to_fill_terms_label_sheet_item.xml", + "java/res/layout/touch_to_fill_wallet_settings_button.xml", "java/res/values/dimens.xml", ] }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_wallet_settings_button.xml b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_wallet_settings_button.xml new file mode 100644 index 0000000..912a6be --- /dev/null +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_wallet_settings_button.xml
@@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2025 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<org.chromium.ui.widget.ButtonCompat + xmlns:android="http://schemas.android.com/apk/res/android" + android:descendantFocusability="blocksDescendants" + android:id="@+id/touch_to_fill_wallet_settings_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="0dp" + android:layout_marginHorizontal="8dp" + android:minHeight="48dp" + android:gravity="center" + android:ellipsize="end" + android:singleLine="true" + style="@style/TextButton"/>
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java index a9f1444..df9b773 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodControllerRobolectricTest.java
@@ -31,6 +31,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodMediator.TOUCH_TO_FILL_NUMBER_OF_IBANS_SHOWN; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodMediator.TOUCH_TO_FILL_NUMBER_OF_LOYALTY_CARDS_SHOWN; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ButtonProperties.ON_CLICK_ACTION; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ButtonProperties.TEXT_ID; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.APPLY_DEACTIVATED_STYLE; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.FIRST_LINE_LABEL; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.CreditCardSuggestionProperties.MAIN_TEXT; @@ -55,6 +56,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.IBAN; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.LOYALTY_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.TERMS_LABEL; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.WALLET_SETTINGS_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.LOYALTY_CARD_NUMBER; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.MERCHANT_NAME; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.ON_LOYALTY_CARD_CLICK_ACTION; @@ -913,10 +915,30 @@ assertThat(loyaltyCardModel.get(MERCHANT_NAME), is(LOYALTY_CARD_1.getMerchantName())); assertThat(getModelsOfType(itemList, FILL_BUTTON).size(), is(1)); + assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(1)); + PropertyModel walletSettingButtonModel = + getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).get(0); + assertThat( + walletSettingButtonModel.get(TEXT_ID), + is(R.string.autofill_loyalty_card_wallet_settings_button)); assertThat(getModelsOfType(itemList, FOOTER).size(), is(1)); } @Test + public void testWalletSettingsButtonRedirectsToSettings() { + mCoordinator.showLoyaltyCards( + List.of(LOYALTY_CARD_1), List.of(LOYALTY_CARD_1), /* firstTimeUsage= */ true); + + ModelList itemList = mTouchToFillPaymentMethodModel.get(SHEET_ITEMS); + assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(1)); + PropertyModel walletSettingButtonModel = + getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).get(0); + walletSettingButtonModel.get(ON_CLICK_ACTION).run(); + + verify(mDelegateMock).showGoogleWalletSettings(); + } + + @Test public void testShowOneLoyaltyCard() throws TimeoutException { HistogramWatcher histogramWatcher = HistogramWatcher.newSingleRecordWatcher( @@ -941,6 +963,7 @@ assertThat(loyaltyCardModel.get(MERCHANT_NAME), is(LOYALTY_CARD_1.getMerchantName())); assertThat(getModelsOfType(itemList, FILL_BUTTON).size(), is(1)); + assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(0)); assertThat(getModelsOfType(itemList, FOOTER).size(), is(1)); } @@ -977,6 +1000,7 @@ assertThat(loyaltyCardModel2.get(MERCHANT_NAME), is(LOYALTY_CARD_2.getMerchantName())); assertThat(getModelsOfType(itemList, FILL_BUTTON).size(), is(0)); + assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(0)); assertThat(getModelsOfType(itemList, FOOTER).size(), is(1)); }
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodCoordinator.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodCoordinator.java index 8972c11..9e3b91e 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodCoordinator.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodCoordinator.java
@@ -14,6 +14,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.IBAN; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.LOYALTY_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.TERMS_LABEL; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.WALLET_SETTINGS_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.SHEET_ITEMS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.VISIBLE; @@ -137,7 +138,11 @@ adapter.registerType( FILL_BUTTON, TouchToFillPaymentMethodViewBinder::createFillButtonView, - TouchToFillPaymentMethodViewBinder::bindFillButtonView); + TouchToFillPaymentMethodViewBinder::bindButtonView); + adapter.registerType( + WALLET_SETTINGS_BUTTON, + TouchToFillPaymentMethodViewBinder::createWalletSettingsButtonView, + TouchToFillPaymentMethodViewBinder::bindButtonView); adapter.registerType( FOOTER, TouchToFillPaymentMethodViewBinder::createFooterItemView,
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java index a57fbe07..0098e72 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodMediator.java
@@ -34,6 +34,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.IBAN; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.LOYALTY_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.TERMS_LABEL; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.WALLET_SETTINGS_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.LOYALTY_CARD_ICON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.LOYALTY_CARD_NUMBER; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.LoyaltyCardProperties.MERCHANT_NAME; @@ -319,6 +320,10 @@ () -> this.onSelectedLoyaltyCard(mLoyaltyCards.get(0))))); } + if (firstTimeUsage) { + sheetItems.add(new ListItem(WALLET_SETTINGS_BUTTON, createWalletSettingsButtonModel())); + } + sheetItems.add(0, buildHeaderForLoyaltyCards(firstTimeUsage)); sheetItems.add(buildFooterForLoyaltyCards()); @@ -484,6 +489,13 @@ .build(); } + private PropertyModel createWalletSettingsButtonModel() { + return new PropertyModel.Builder(ButtonProperties.ALL_KEYS) + .with(TEXT_ID, R.string.autofill_loyalty_card_wallet_settings_button) + .with(ON_CLICK_ACTION, mDelegate::showGoogleWalletSettings) + .build(); + } + private ListItem buildTermsLabel(boolean cardBenefitsTermsAvailable) { return new ListItem( TERMS_LABEL,
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java index 4d219ee2..6f3b900 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodProperties.java
@@ -47,11 +47,14 @@ // method available. int FILL_BUTTON = 4; + // A button that redirects the user to the Wallet settings in Chrome. + int WALLET_SETTINGS_BUTTON = 5; + // A footer section containing additional actions. - int FOOTER = 5; + int FOOTER = 6; // A section with a terms label is present when card benefits are available. - int TERMS_LABEL = 6; + int TERMS_LABEL = 7; } /** Metadata associated with a card's image. */
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodView.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodView.java index db49eb1..cc97044 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodView.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodView.java
@@ -44,6 +44,7 @@ case ItemType.HEADER: // Fallthrough. case ItemType.FOOTER: // Fallthrough. case ItemType.FILL_BUTTON: + case ItemType.WALLET_SETTINGS_BUTTON: case ItemType.TERMS_LABEL: return true; case ItemType.CREDIT_CARD:
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java index e5db0e6..0c7249b0 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBinder.java
@@ -39,6 +39,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -290,20 +291,51 @@ } } - static View createFillButtonView(ViewGroup parent) { - View buttonView = - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.touch_to_fill_fill_button, parent, false); + /** + * Factory used to create a new "Continue" or "Autofill" button that fills in data into the + * focused field. + * + * @param parent The parent {@link ViewGroup} of the new item. + */ + static Button createFillButtonView(ViewGroup parent) { + Button buttonView = + (Button) + LayoutInflater.from(parent.getContext()) + .inflate(R.layout.touch_to_fill_fill_button, parent, false); AutofillUiUtils.setFilterTouchForSecurity(buttonView); return buttonView; } - static void bindFillButtonView(PropertyModel model, View view, PropertyKey propertyKey) { + /** + * Factory used to create a new "Wallet settings" button that redirects the user to the + * corresponding Chrome settings page. + * + * @param parent The parent {@link ViewGroup} of the new item. + */ + static Button createWalletSettingsButtonView(ViewGroup parent) { + Button buttonView = + (Button) + LayoutInflater.from(parent.getContext()) + .inflate( + R.layout.touch_to_fill_wallet_settings_button, + parent, + false); + AutofillUiUtils.setFilterTouchForSecurity(buttonView); + return buttonView; + } + + /** + * Called whenever a property in the given model changes. It updates the given view accordingly. + * + * @param model The observed {@link PropertyModel}. Its data need to be reflected in the view. + * @param button The {@link Button} from the bottom sheet to update. + * @param key The {@link PropertyKey} which changed. + */ + static void bindButtonView(PropertyModel model, Button button, PropertyKey propertyKey) { if (propertyKey == TEXT_ID) { - TextView buttonTitleText = view.findViewById(R.id.touch_to_fill_button_title); - buttonTitleText.setText(model.get(TEXT_ID)); + button.setText(model.get(TEXT_ID)); } else if (propertyKey == ON_CLICK_ACTION) { - view.setOnClickListener(unusedView -> model.get(ON_CLICK_ACTION).run()); + button.setOnClickListener(unusedView -> model.get(ON_CLICK_ACTION).run()); } else { assert false : "Unhandled update to property:" + propertyKey; }
diff --git a/chrome/browser/touch_to_fill/autofill/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodComponent.java b/chrome/browser/touch_to_fill/autofill/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodComponent.java index cf569d8..3b9edad 100644 --- a/chrome/browser/touch_to_fill/autofill/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodComponent.java +++ b/chrome/browser/touch_to_fill/autofill/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodComponent.java
@@ -34,6 +34,12 @@ void showPaymentMethodSettings(); /** + * Causes navigation to the payment methods settings page and scrolls to the loyalty card + * settings preference. + */ + void showGoogleWalletSettings(); + + /** * Called when the user selects a card. * * @param uniqueId A backend id of the card.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e568c086..7543f2d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -948,6 +948,8 @@ sources += [ "android/extensions/extension_keybinding_registry_android.cc", "android/extensions/extension_keybinding_registry_android.h", + "android/toolbar/extension_action_popup_contents.cc", + "android/toolbar/extension_action_popup_contents.h", "android/toolbar/extension_actions_bridge.cc", "android/toolbar/extension_actions_bridge.h", "android/toolbar/extension_actions_bridge_factory.cc",
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn index c2b2384e2..703dce4 100644 --- a/chrome/browser/ui/android/toolbar/BUILD.gn +++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -239,12 +239,22 @@ "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonViewBinder.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java", + "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopup.java", + "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopupContents.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuButtonCoordinator.java", ] srcjar_deps += [ "//extensions/browser:extension_action_enums" ] + + deps += [ + "//base/version_info/android:version_constants_java", + "//components/embedder_support/android:content_view_java", + "//components/embedder_support/android:web_contents_delegate_java", + "//components/thin_webview:factory_java", + "//components/thin_webview:java", + ] } } @@ -260,6 +270,7 @@ if (enable_extensions_core) { sources += [ "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java", + "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopupContents.java", "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java", ] }
diff --git a/chrome/browser/ui/android/toolbar/DEPS b/chrome/browser/ui/android/toolbar/DEPS index d6daa04..ae543b21 100644 --- a/chrome/browser/ui/android/toolbar/DEPS +++ b/chrome/browser/ui/android/toolbar/DEPS
@@ -8,6 +8,7 @@ "+components/embedder_support/android", "+components/omnibox/browser/android", "+components/security_state/content/android", + "+components/thin_webview", "+content/public/android", "+extensions/android", ]
diff --git a/chrome/browser/ui/android/toolbar/extension_action_popup_contents.cc b/chrome/browser/ui/android/toolbar/extension_action_popup_contents.cc new file mode 100644 index 0000000..d2866545 --- /dev/null +++ b/chrome/browser/ui/android/toolbar/extension_action_popup_contents.cc
@@ -0,0 +1,117 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/android/toolbar/extension_action_popup_contents.h" + +#include "base/android/jni_string.h" +#include "base/notimplemented.h" +#include "chrome/browser/extensions/extension_view_host.h" +#include "chrome/browser/extensions/extension_view_host_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/extension_action.h" +#include "extensions/browser/extension_action_manager.h" +#include "extensions/browser/extension_registry.h" + +// Must come after all headers that specialize FromJniType() / ToJniType(). +#include "chrome/browser/ui/android/toolbar/jni_headers/ExtensionActionPopupContents_jni.h" + +using base::android::AttachCurrentThread; +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; +using content::RenderFrameHost; +using content::WebContents; +using extensions::Extension; +using extensions::ExtensionAction; +using extensions::ExtensionActionManager; +using extensions::ExtensionRegistry; +using extensions::ExtensionViewHost; +using extensions::ExtensionViewHostFactory; + +ExtensionActionPopupContents::ExtensionActionPopupContents( + std::unique_ptr<ExtensionViewHost> host) + : host_(std::move(host)) { + java_object_ = Java_ExtensionActionPopupContents_Constructor( + AttachCurrentThread(), reinterpret_cast<jlong>(this), + host_->host_contents()->GetJavaWebContents()); + host_->set_view(this); +} + +ExtensionActionPopupContents::~ExtensionActionPopupContents() = default; + +ScopedJavaLocalRef<jobject> ExtensionActionPopupContents::GetJavaObject() { + return java_object_.AsLocalRef(AttachCurrentThread()); +} + +void ExtensionActionPopupContents::ResizeDueToAutoResize( + content::WebContents* web_contents, + const gfx::Size& new_size) { + Java_ExtensionActionPopupContents_resizeDueToAutoResize( + AttachCurrentThread(), java_object_, new_size.width(), new_size.height()); +} + +void ExtensionActionPopupContents::RenderFrameCreated( + RenderFrameHost* render_frame_host) { + NOTIMPLEMENTED(); +} + +bool ExtensionActionPopupContents::HandleKeyboardEvent( + content::WebContents* source, + const input::NativeWebKeyboardEvent& event) { + NOTIMPLEMENTED(); + return false; +} + +void ExtensionActionPopupContents::OnLoaded() { + Java_ExtensionActionPopupContents_onLoaded(AttachCurrentThread(), + java_object_); +} + +void ExtensionActionPopupContents::Destroy(JNIEnv* env) { + delete this; +} + +void ExtensionActionPopupContents::LoadInitialPage(JNIEnv* env) { + host_->CreateRendererSoon(); +} + +// JNI method to create an ExtensionActionPopupContents instance. +// This is called from the Java side to initiate the display of an extension +// popup. +static ScopedJavaLocalRef<jobject> JNI_ExtensionActionPopupContents_Create( + JNIEnv* env, + Profile* profile, + std::string& action_id, + jint tab_id) { + ExtensionRegistry* registry = ExtensionRegistry::Get(profile); + DCHECK(registry); + + ExtensionActionManager* manager = ExtensionActionManager::Get(profile); + DCHECK(manager); + + const Extension* extension = + registry->enabled_extensions().GetByID(action_id); + DCHECK(extension); + + ExtensionAction* action = manager->GetExtensionAction(*extension); + DCHECK(action); + + GURL popup_url = action->GetPopupUrl(tab_id); + + std::unique_ptr<ExtensionViewHost> host = + ExtensionViewHostFactory::CreatePopupHost(popup_url, profile); + DCHECK(host); + + // The ExtensionActionPopupContents C++ object's lifetime is managed by its + // Java counterpart. The Java object holds a pointer to this C++ instance. + // When the Java side is finished with the popup, it will explicitly call + // a 'destroy()' method on its Java object, which in turn calls the native + // ExtensionActionPopupContents::Destroy() method, leading to the deletion + // of this C++ object. Therefore, 'new' is used here, and ownership is + // effectively passed to the Java-controlled lifecycle. + ExtensionActionPopupContents* popup = + new ExtensionActionPopupContents(std::move(host)); + return popup->GetJavaObject(); +}
diff --git a/chrome/browser/ui/android/toolbar/extension_action_popup_contents.h b/chrome/browser/ui/android/toolbar/extension_action_popup_contents.h new file mode 100644 index 0000000..9851877 --- /dev/null +++ b/chrome/browser/ui/android/toolbar/extension_action_popup_contents.h
@@ -0,0 +1,66 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ANDROID_TOOLBAR_EXTENSION_ACTION_POPUP_CONTENTS_H_ +#define CHROME_BROWSER_UI_ANDROID_TOOLBAR_EXTENSION_ACTION_POPUP_CONTENTS_H_ + +#include <memory> + +#include "base/android/jni_android.h" +#include "chrome/browser/extensions/extension_view.h" + +namespace content { +class RenderFrameHost; +} + +namespace extensions { +class ExtensionViewHost; +} + +// ExtensionActionPopupContents is the native C++ class responsible for managing +// the content of an extension's popup displayed on Android. An extension popup +// is typically a small HTML page an extension can show when its action icon +// is clicked. This class bridges the C++ extensions system with the Java UI. +// +// Lifetime Management: +// An instance of this C++ class is created when its Java counterpart +// (ExtensionActionPopupContents.java) requests it via a JNI call (specifically, +// JNI_ExtensionActionPopupContents_Create). The C++ object's lifetime is tied +// to its Java peer. The Java object holds a native pointer (jlong) to this C++ +// instance. When the Java object is no longer needed (e.g. the popup is +// closed), its `destroy()` method is called. This, in turn, calls the native +// `Destroy()` method on this C++ object, which then calls `delete this`. +class ExtensionActionPopupContents : public extensions::ExtensionView { + public: + explicit ExtensionActionPopupContents( + std::unique_ptr<extensions::ExtensionViewHost> popup_host); + ExtensionActionPopupContents(const ExtensionActionPopupContents&) = delete; + ExtensionActionPopupContents& operator=(const ExtensionActionPopupContents&) = + delete; + ~ExtensionActionPopupContents() override; + + // Returns a local JNI reference to the Java counterpart of this object. + base::android::ScopedJavaLocalRef<jobject> GetJavaObject(); + + // ExtensionView: + void ResizeDueToAutoResize(content::WebContents* web_contents, + const gfx::Size& new_size) override; + void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; + bool HandleKeyboardEvent(content::WebContents* source, + const input::NativeWebKeyboardEvent& event) override; + void OnLoaded() override; + + // Called from Java when the Java counterpart is being destroyed. + void Destroy(JNIEnv* env); + + // Called from Java to trigger the loading of the popup's initial URL in the + // hosted WebContents. + void LoadInitialPage(JNIEnv* env); + + private: + std::unique_ptr<extensions::ExtensionViewHost> host_; + base::android::ScopedJavaGlobalRef<jobject> java_object_; +}; + +#endif // CHROME_BROWSER_UI_ANDROID_TOOLBAR_EXTENSION_ACTION_POPUP_CONTENTS_H_
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java index 5ff0ad77..e1e83fc 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
@@ -17,6 +17,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.R; import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.listmenu.ListMenuButton; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.ViewGroupAdapter; @@ -34,10 +35,13 @@ public ExtensionActionListCoordinator( Context context, LinearLayout container, + WindowAndroid windowAndroid, ObservableSupplier<Profile> profileSupplier, ObservableSupplier<Tab> currentTabSupplier) { ModelList models = new ModelList(); - mMediator = new ExtensionActionListMediator(models, profileSupplier, currentTabSupplier); + mMediator = + new ExtensionActionListMediator( + context, windowAndroid, models, profileSupplier, currentTabSupplier); mAdapter = new ViewGroupAdapter.Builder(container, models) .registerType(
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java index 99be868..16cff81 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.toolbar.extensions; +import android.content.Context; import android.graphics.Bitmap; import android.view.View; @@ -19,6 +20,7 @@ import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType; import org.chromium.content_public.browser.WebContents; import org.chromium.extensions.ShowAction; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.ModelListAdapter; @@ -35,9 +37,12 @@ class ExtensionActionListMediator implements Destroyable { private static final String TAG = "EALMediator"; + private final Context mContext; + private final WindowAndroid mWindowAndroid; private final ModelList mModels; private final ObservableSupplier<Profile> mProfileSupplier; private final ObservableSupplier<Tab> mCurrentTabSupplier; + private final Callback<Profile> mProfileUpdatedCallback = this::onProfileUpdated; private final Callback<Tab> mTabChangedCallback = this::onTabChanged; private final ActionsObserver mActionsObserver = new ActionsObserver(); @@ -47,11 +52,16 @@ @Nullable private Profile mProfile; @Nullable private ExtensionActionsBridge mExtensionActionsBridge; @Nullable private Tab mCurrentTab; + @Nullable private ExtensionActionPopup mCurrentPopup; public ExtensionActionListMediator( + Context context, + WindowAndroid windowAndroid, ModelList models, ObservableSupplier<Profile> profileSupplier, ObservableSupplier<Tab> currentTabSupplier) { + mContext = context; + mWindowAndroid = windowAndroid; mModels = models; mProfileSupplier = profileSupplier; mCurrentTabSupplier = currentTabSupplier; @@ -68,6 +78,8 @@ mCurrentTabSupplier.removeObserver(mTabChangedCallback); mProfileSupplier.removeObserver(mProfileUpdatedCallback); + closePopup(); + assert mCurrentPopup == null; mCurrentTab = null; mExtensionActionsBridge = null; mProfile = null; @@ -80,6 +92,9 @@ return; } + closePopup(); + assert mCurrentPopup == null; + if (mExtensionActionsBridge != null) { mExtensionActionsBridge.removeObserver(mActionsObserver); } @@ -110,6 +125,9 @@ if (tab == mCurrentTab) { return; } + + closePopup(); + if (tab == null) { // The current tab can be null when a non-tab UI is shown (e.g. tab switcher). In this // case, we do not bother refreshing actions as they're hidden anyway. We do not set @@ -129,7 +147,7 @@ maybeUpdateAllActions(); } - private void onPrimaryClick(View unused_buttonView, String actionId) { + private void onPrimaryClick(View buttonView, String actionId) { if (mExtensionActionsBridge == null || mCurrentTab == null) { return; } @@ -145,7 +163,7 @@ case ShowAction.NONE: break; case ShowAction.SHOW_POPUP: - Log.e(TAG, "Extension popups are not implemented yet"); + openPopup(buttonView, actionId); break; case ShowAction.TOGGLE_SIDE_PANEL: Log.e(TAG, "Extension side panels are not implemented yet"); @@ -153,6 +171,37 @@ } } + private void openPopup(View buttonView, String actionId) { + // TODO(crbug.com/385987224): Do not open a popup again when the user clicks the action + // button while its popup is open. + closePopup(); + + if (mProfile == null || mCurrentTab == null) { + return; + } + int tabId = mCurrentTab.getId(); + + ExtensionActionPopupContents contents = + ExtensionActionPopupContents.create(mProfile, actionId, tabId); + assert mCurrentPopup == null; + mCurrentPopup = + new ExtensionActionPopup(mContext, mWindowAndroid, buttonView, actionId, contents); + mCurrentPopup.loadInitialPage(); + mCurrentPopup.addOnDismissListener(this::closePopup); + } + + private void closePopup() { + if (mCurrentPopup == null) { + return; + } + assert mExtensionActionsBridge != null; + + // Clear mCurrentPopup now to avoid calling closePopup recursively via OnDismissListener. + ExtensionActionPopup popup = mCurrentPopup; + mCurrentPopup = null; + popup.destroy(); + } + private void maybeUpdateAllActions() { if (mProfile == null || mExtensionActionsBridge == null || mCurrentTab == null) { mModels.clear();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java index 416e3d1e..a153098 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java
@@ -13,6 +13,7 @@ import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -35,6 +36,7 @@ import org.chromium.chrome.browser.tab.MockTab; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; @@ -54,8 +56,10 @@ private static final Bitmap ICON_WHITE = createSimpleIcon(Color.YELLOW); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock private Context mContext; @Mock private Profile mProfile; @Mock private ExtensionActionsBridge.Natives mActionsBridgeJniMock; + @Mock private WindowAndroid mWindowAndroid; private ExtensionActionsBridge mActionsBridge; private MockTab mTab1; @@ -106,7 +110,9 @@ mProfileSupplier = new ObservableSupplierImpl<>(); mCurrentTabSupplier = new ObservableSupplierImpl<>(); mModels = new ModelList(); - mMediator = new ExtensionActionListMediator(mModels, mProfileSupplier, mCurrentTabSupplier); + mMediator = + new ExtensionActionListMediator( + mContext, mWindowAndroid, mModels, mProfileSupplier, mCurrentTabSupplier); // Wait for the main thread to settle. shadowOf(Looper.getMainLooper()).idle();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopup.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopup.java new file mode 100644 index 0000000..0c99ffc --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopup.java
@@ -0,0 +1,152 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.toolbar.extensions; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.PopupWindow.OnDismissListener; + +import org.chromium.base.lifetime.Destroyable; +import org.chromium.base.version_info.VersionInfo; +import org.chromium.build.NullUtil; +import org.chromium.build.annotations.NullMarked; +import org.chromium.components.embedder_support.view.ContentView; +import org.chromium.components.thinwebview.ThinWebView; +import org.chromium.components.thinwebview.ThinWebViewConstraints; +import org.chromium.components.thinwebview.ThinWebViewFactory; +import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.ViewAndroidDelegate; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.widget.AnchoredPopupWindow; +import org.chromium.ui.widget.ViewRectProvider; + +/** + * Manages the display of an extension action's popup UI. + * + * <p>This class is responsible for creating and managing an {@link AnchoredPopupWindow} that hosts + * a {@link ThinWebView} rendering the extension's popup HTML. It owns {@link + * ExtensionActionPopupContents} which handles the native interactions and WebContents for the + * popup. + * + * <p>The popup's size is determined by the popup content, constrained by hard-coded limits, and + * managed by the nested {@link ContentsFrame}. + */ +@NullMarked +class ExtensionActionPopup implements Destroyable { + /** The ID of the extension action this popup is associated with. */ + private final String mActionId; + + /** The content manager for the popup, bridging to native. */ + private final ExtensionActionPopupContents mContents; + + /** The ThinWebView component that renders the extension's HTML content. */ + private final ThinWebView mThinWebView; + + /** The View containing the popup contents. Content sizing can be applied to this view. */ + private final View mMainView; + + /** The PopupWindow that is displayed on the screen, anchored to a view. */ + private final AnchoredPopupWindow mPopupWindow; + + /** + * Constructs an ExtensionActionPopup. + * + * @param context The {@link Context} to use for creating views. + * @param windowAndroid The {@link WindowAndroid} for the current activity. + * @param anchorView The {@link View} to which the popup will be anchored. + * @param actionId The ID of the extension action. + * @param contents The {@link ExtensionActionPopupContents} instance that manages the + * WebContents and native communication for this popup. The new {@link ExtensionActionPopup} + * instance takes ownership of the provided {@code contents} and will be responsible for + * calling its {@code destroy()} method. + */ + public ExtensionActionPopup( + Context context, + WindowAndroid windowAndroid, + View anchorView, + String actionId, + ExtensionActionPopupContents contents) { + mActionId = actionId; + mContents = contents; + + WebContents webContents = contents.getWebContents(); + + ContentView contentView = ContentView.createContentView(context, webContents); + + webContents.setDelegates( + VersionInfo.getProductVersion(), + ViewAndroidDelegate.createBasicDelegate(contentView), + contentView, + windowAndroid, + WebContents.createDefaultInternalsHolder()); + + mThinWebView = + ThinWebViewFactory.create( + context, + new ThinWebViewConstraints(), + NullUtil.assumeNonNull(windowAndroid.getIntentRequestTracker())); + mThinWebView.attachWebContents(webContents, contentView, null); + + mMainView = mThinWebView.getView(); + // TODO(crbug.com/385987224): Resize according to the content size. + mMainView.setLayoutParams(new FrameLayout.LayoutParams(480, 480)); + + // This intermediate frame is needed in order for LayoutParams to take effect. + FrameLayout frame = new FrameLayout(context); + frame.addView(mMainView); + + View decorView = ((Activity) anchorView.getContext()).getWindow().getDecorView(); + mPopupWindow = + new AnchoredPopupWindow( + context, + decorView, + new ColorDrawable(Color.TRANSPARENT), + frame, + new ViewRectProvider(anchorView)); + mPopupWindow.setHorizontalOverlapAnchor(true); + mPopupWindow.setOutsideTouchable(true); + + contents.setDelegate(new ContentsDelegate()); + } + + /** Cleans up resources used by this popup. */ + @Override + public void destroy() { + mPopupWindow.dismiss(); + mThinWebView.destroy(); + mContents.destroy(); + } + + /** Returns the ID of the extension action this popup represents. */ + public String getActionId() { + return mActionId; + } + + /** Triggers the loading of the initial page for the extension popup. */ + public void loadInitialPage() { + mContents.loadInitialPage(); + } + + /** Adds a listener that will be notified when the popup window is dismissed. */ + public void addOnDismissListener(OnDismissListener listener) { + mPopupWindow.addOnDismissListener(listener); + } + + private class ContentsDelegate implements ExtensionActionPopupContents.Delegate { + @Override + public void resizeDueToAutoResize(int width, int height) { + // TODO(crbug.com/385987224): Resize according to the content size. + } + + @Override + public void onLoaded() { + mPopupWindow.show(); + } + } +}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopupContents.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopupContents.java new file mode 100644 index 0000000..6f188ed --- /dev/null +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionPopupContents.java
@@ -0,0 +1,148 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.toolbar.extensions; + +import org.jni_zero.CalledByNative; +import org.jni_zero.JniType; +import org.jni_zero.NativeMethods; + +import org.chromium.base.lifetime.Destroyable; +import org.chromium.build.annotations.NullMarked; +import org.chromium.build.annotations.Nullable; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.content_public.browser.WebContents; + +/** + * Manages the Java-side representation of an extension action's popup. + * + * <p>An extension action popup is typically a small HTML page displayed when an extension's action + * button in the toolbar is clicked. This class owns the {@link WebContents} that hosts the popup's + * content and bridges communication with its native C++ counterpart. + * + * <p>This class implements {@link Destroyable} to ensure proper cleanup of its associated native + * resources. The native counterpart's lifetime is tied to this Java object; when {@link #destroy()} + * is called, the native object is also destroyed. + */ +@NullMarked +public class ExtensionActionPopupContents implements Destroyable { + /** + * Pointer to the native C++ ExtensionActionPopupContents object. This is 0 if the native object + * has been destroyed. + */ + private long mNativeExtensionActionPopupContents; + + /** The WebContents hosting the extension popup's UI. */ + private final WebContents mWebContents; + + /** Delegate to handle UI events related to the popup, such as resizing. */ + @Nullable private Delegate mDelegate; + + @CalledByNative + private ExtensionActionPopupContents( + long nativeExtensionActionPopupContents, WebContents webContents) { + mNativeExtensionActionPopupContents = nativeExtensionActionPopupContents; + mWebContents = webContents; + } + + /** Creates an {@link ExtensionActionPopupContents} instance. */ + public static ExtensionActionPopupContents create(Profile profile, String actionId, int tabId) { + return ExtensionActionPopupContentsJni.get().create(profile, actionId, tabId); + } + + /** + * Cleans up the resources associated with this popup. + * + * <p>This method must be called when the popup is no longer needed to prevent resource leaks. + * Safe to call multiple times; subsequent calls after the first are no-ops. + */ + @Override + public void destroy() { + if (mNativeExtensionActionPopupContents == 0) { + return; + } + ExtensionActionPopupContentsJni.get().destroy(mNativeExtensionActionPopupContents); + mNativeExtensionActionPopupContents = 0; + } + + /** Returns the {@link WebContents} that hosts the extension popup's UI. */ + public WebContents getWebContents() { + return mWebContents; + } + + /** + * Instructs to load the initial page for the extension popup into its {@link WebContents}. + * + * <p>This should be called after the popup is created and its view is ready to display content. + */ + public void loadInitialPage() { + assert mNativeExtensionActionPopupContents != 0; + ExtensionActionPopupContentsJni.get().loadInitialPage(mNativeExtensionActionPopupContents); + } + + /** + * Sets the delegate to receive UI-related callbacks for this popup. + * + * @param delegate The {@link Delegate} to handle events, or {@code null} to remove the current + * delegate. + */ + public void setDelegate(@Nullable Delegate delegate) { + mDelegate = delegate; + } + + @CalledByNative + private void resizeDueToAutoResize(int width, int height) { + if (mDelegate != null) { + mDelegate.resizeDueToAutoResize(width, height); + } + } + + @CalledByNative + private void onLoaded() { + if (mDelegate != null) { + mDelegate.onLoaded(); + } + } + + /** + * Interface for receiving UI-related callbacks from an {@link ExtensionActionPopupContents}. + * + * <p>This allows embedders or UI coordinators to react to events like content resizing. + */ + public interface Delegate { + void resizeDueToAutoResize(int width, int height); + + void onLoaded(); + } + + @NativeMethods + public interface Natives { + /** + * Creates the native ExtensionActionPopupContents object and returns its Java peer. + * + * @param profile The {@link Profile} associated with the extension. + * @param actionId The ID of the extension action. + * @param tabId The ID of the tab context. + * @return The Java {@link ExtensionActionPopupContents} object, or {@code null} on failure. + */ + ExtensionActionPopupContents create( + @JniType("Profile*") Profile profile, + @JniType("std::string") String actionId, + int tabId); + + /** + * Destroys the native ExtensionActionPopupContents object. + * + * @param nativeExtensionActionPopupContents The pointer to the native object. + */ + void destroy(long nativeExtensionActionPopupContents); + + /** + * Triggers the loading of the initial URL in the native ExtensionActionPopupContents. + * + * @param nativeExtensionActionPopupContents The pointer to the native object. + */ + void loadInitialPage(long nativeExtensionActionPopupContents); + } +}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java index 060c913..48d05a42 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java
@@ -15,6 +15,7 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.theme.ThemeColorProvider; +import org.chromium.ui.base.WindowAndroid; /** Provides extension-related buttons for {@link ToolbarManager}. */ @NullMarked @@ -23,6 +24,7 @@ public void initialize( Context context, ViewStub extensionToolbarStub, + WindowAndroid windowAndroid, ObservableSupplier<Profile> profileSupplier, ObservableSupplier<Tab> currentTabSupplier, ThemeColorProvider themeColorProvider); @@ -32,6 +34,7 @@ public static ExtensionToolbarManager maybeCreate( Context context, ViewStub extensionToolbarStub, + WindowAndroid windowAndroid, ObservableSupplier<Profile> profileSupplier, ObservableSupplier<Tab> currentTabSupplier, ThemeColorProvider themeColorProvider) { @@ -43,6 +46,7 @@ manager.initialize( context, extensionToolbarStub, + windowAndroid, profileSupplier, currentTabSupplier, themeColorProvider);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java index e73c004..7c9f5ca 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.theme.ThemeColorProvider; import org.chromium.chrome.browser.toolbar.R; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.listmenu.ListMenuButton; /** @@ -40,6 +41,7 @@ public void initialize( Context context, ViewStub extensionToolbarStub, + WindowAndroid windowAndroid, ObservableSupplier<Profile> profileSupplier, ObservableSupplier<Tab> currentTabSupplier, ThemeColorProvider themeColorProvider) { @@ -48,7 +50,11 @@ LinearLayout actionListContainer = container.findViewById(R.id.extension_action_list); mExtensionActionListCoordinator = new ExtensionActionListCoordinator( - context, actionListContainer, profileSupplier, currentTabSupplier); + context, + actionListContainer, + windowAndroid, + profileSupplier, + currentTabSupplier); mExtensionsMenuButton = container.findViewById(R.id.extensions_menu_button); mExtensionsMenuButtonCoordinator =
diff --git a/chrome/browser/ui/ash/clipboard/clipboard_history_browsertest.cc b/chrome/browser/ui/ash/clipboard/clipboard_history_browsertest.cc index b2ef8a49..dccd399 100644 --- a/chrome/browser/ui/ash/clipboard/clipboard_history_browsertest.cc +++ b/chrome/browser/ui/ash/clipboard/clipboard_history_browsertest.cc
@@ -520,15 +520,8 @@ } // Verifies item deletion through the mouse click at the delete button. -#if BUILDFLAG(IS_CHROMEOS) -// TODO(https://crbug.com/394710875): Fix ui_test_utils::Navigation timeout. -#define MAYBE_DeleteItemByClickAtDeleteButton \ - DISABLED_DeleteItemByClickAtDeleteButton -#else -#define MAYBE_DeleteItemByClickAtDeleteButton DeleteItemByClickAtDeleteButton -#endif IN_PROC_BROWSER_TEST_F(ClipboardHistoryBrowserTest, - MAYBE_DeleteItemByClickAtDeleteButton) { + DeleteItemByClickAtDeleteButton) { base::HistogramTester histogram_tester; // Write some things to the clipboard.
diff --git a/chrome/browser/ui/ash/input_method/candidate_window_view_pixeltest.cc b/chrome/browser/ui/ash/input_method/candidate_window_view_pixeltest.cc index 1ce6a39..8e55db1c 100644 --- a/chrome/browser/ui/ash/input_method/candidate_window_view_pixeltest.cc +++ b/chrome/browser/ui/ash/input_method/candidate_window_view_pixeltest.cc
@@ -5,6 +5,7 @@ #include <optional> #include "base/i18n/base_i18n_switches.h" +#include "base/strings/string_number_conversions.h" #include "chrome/browser/ui/ash/input_method/candidate_view.h" #include "chrome/browser/ui/ash/input_method/candidate_window_view.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc index 78d6df7..ab0e471 100644 --- a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc +++ b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
@@ -21,6 +21,7 @@ #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/vector_icons/vector_icons.h"
diff --git a/chrome/browser/ui/ash/shelf/crostini_app_display.h b/chrome/browser/ui/ash/shelf/crostini_app_display.h index b7792d3..44f027b19 100644 --- a/chrome/browser/ui/ash/shelf/crostini_app_display.h +++ b/chrome/browser/ui/ash/shelf/crostini_app_display.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_ASH_SHELF_CROSTINI_APP_DISPLAY_H_ #define CHROME_BROWSER_UI_ASH_SHELF_CROSTINI_APP_DISPLAY_H_ +#include <stdint.h> + #include <deque> #include <map> #include <string>
diff --git a/chrome/browser/ui/bookmarks/bookmark_ui_operations_helper_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_ui_operations_helper_unittest.cc index 4e58a6c..7268333 100644 --- a/chrome/browser/ui/bookmarks/bookmark_ui_operations_helper_unittest.cc +++ b/chrome/browser/ui/bookmarks/bookmark_ui_operations_helper_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/raw_ptr.h" #include "base/notreached.h" #include "base/scoped_observation.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/bookmarks/bookmark_merged_surface_service.h" #include "chrome/browser/bookmarks/bookmark_merged_surface_service_factory.h"
diff --git a/chrome/browser/ui/download/download_bubble_security_view_info_unittest.cc b/chrome/browser/ui/download/download_bubble_security_view_info_unittest.cc index bc956e2..545274c 100644 --- a/chrome/browser/ui/download/download_bubble_security_view_info_unittest.cc +++ b/chrome/browser/ui/download/download_bubble_security_view_info_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/download/download_bubble_security_view_info.h" #include "base/strings/pattern.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/download/bubble/download_bubble_prefs.h" #include "chrome/browser/download/download_item_model.h"
diff --git a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc index fd735d4..3dfacea 100644 --- a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc +++ b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc
@@ -8,6 +8,7 @@ #include "base/functional/callback_helpers.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h"
diff --git a/chrome/browser/ui/tabs/tab_renderer_data.cc b/chrome/browser/ui/tabs/tab_renderer_data.cc index 5a1673c..b181e1b0 100644 --- a/chrome/browser/ui/tabs/tab_renderer_data.cc +++ b/chrome/browser/ui/tabs/tab_renderer_data.cc
@@ -126,7 +126,7 @@ data.pinned || model->delegate()->ShouldDisplayFavicon(contents); data.blocked = model->IsTabBlocked(index); data.should_hide_throbber = tab_ui_helper->ShouldHideThrobber(); - data.alert_state = GetTabAlertStatesForContents(contents); + data.alert_state = GetTabAlertStatesForTab(tab); content::NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
diff --git a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc index 2d70e6f..134d812b 100644 --- a/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc +++ b/chrome/browser/ui/tabs/tab_strip_api/converters/tab_converters.cc
@@ -22,8 +22,7 @@ result->url = data.visible_url; result->network_state = data.network_state; if (handle.Get() != nullptr) { - for (const auto alert_state : - GetTabAlertStatesForContents(handle.Get()->GetContents())) { + for (const auto alert_state : GetTabAlertStatesForTab(handle.Get())) { result->alert_states.push_back(alert_state); } }
diff --git a/chrome/browser/ui/tabs/tab_utils.cc b/chrome/browser/ui/tabs/tab_utils.cc index 16d9767..6097701 100644 --- a/chrome/browser/ui/tabs/tab_utils.cc +++ b/chrome/browser/ui/tabs/tab_utils.cc
@@ -30,9 +30,13 @@ #include "chrome/browser/glic/resources/grit/glic_browser_resources.h" #endif -std::vector<tabs::TabAlert> GetTabAlertStatesForContents( - content::WebContents* contents) { +std::vector<tabs::TabAlert> GetTabAlertStatesForTab( + const tabs::TabInterface* tab) { std::vector<tabs::TabAlert> states; + if (!tab) { + return states; + } + content::WebContents* contents = tab->GetContents(); if (!contents) { return states; }
diff --git a/chrome/browser/ui/tabs/tab_utils.h b/chrome/browser/ui/tabs/tab_utils.h index c5aa63f..4984daa 100644 --- a/chrome/browser/ui/tabs/tab_utils.h +++ b/chrome/browser/ui/tabs/tab_utils.h
@@ -21,6 +21,7 @@ namespace tabs { enum class TabAlert; +class TabInterface; } // namespace tabs struct LastMuteMetadata @@ -39,8 +40,8 @@ // privacy, i.e. if only one is to be shown, it should be the first. // TabAlertState::NONE will never be present in the list; an empty list // is returned instead. -std::vector<tabs::TabAlert> GetTabAlertStatesForContents( - content::WebContents* contents); +std::vector<tabs::TabAlert> GetTabAlertStatesForTab( + const tabs::TabInterface* tab); // Returns a localized string describing the |alert_state|. std::u16string GetTabAlertStateText(const tabs::TabAlert alert_state);
diff --git a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc index 1317b16..60a9f03 100644 --- a/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc +++ b/chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/autofill/payments/save_iban_bubble_view.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/autofill/payments/save_iban_ui.h" #include "chrome/browser/ui/views/accessibility/theme_tracking_non_accessible_image_view.h"
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc index 7879b94..6351999 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -12,6 +12,7 @@ #include "base/memory/raw_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index dd3a0b0..19b7b3b8 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -435,22 +435,6 @@ #endif // DCHECK_IS_ON() -void MaybeResetStoredFocusForWebContents(content::WebContents* web_contents) { - // In the case that the last focused view of the WebContents is a - // ContentsWebView, but not the ContentsWebView hosting the WebContents - // itself, we must reset the stored focus to prevent incorrect split-tab - // activation behavior when the split-view is swapped in during a tab switch. - ChromeWebContentsViewFocusHelper* focus_helper = - ChromeWebContentsViewFocusHelper::FromWebContents(web_contents); - if (focus_helper) { - ContentsWebView* focused_view = - views::AsViewClass<ContentsWebView>(focus_helper->GetStoredFocus()); - if (focused_view && focused_view->web_contents() != web_contents) { - focus_helper->ResetStoredFocus(); - } - } -} - bool GetGestureCommand(ui::GestureEvent* event, int* command) { DCHECK(command); *command = 0; @@ -1667,6 +1651,25 @@ } } +void BrowserView::MaybeUpdateStoredFocusForWebContents( + content::WebContents* web_contents) { + ChromeWebContentsViewFocusHelper* focus_helper = + ChromeWebContentsViewFocusHelper::FromWebContents(web_contents); + if (!focus_helper) { + return; + } + + // In the case that the last focused view of the WebContents is a + // ContentsWebView, but not the ContentsWebView hosting the WebContents + // itself, we must reset the stored focus to prevent incorrect tab + // activation behavior when the split view is swapped in during a tab switch. + ContentsWebView* focused_view = + views::AsViewClass<ContentsWebView>(focus_helper->GetStoredFocus()); + if (focused_view && focused_view->web_contents() != web_contents) { + focus_helper->SetStoredFocusView(GetContentsView()); + } +} + /////////////////////////////////////////////////////////////////////////////// // BrowserView, BrowserWindow implementation: @@ -2196,7 +2199,6 @@ multi_contents_view_->GetActiveContentsView()->SetWebContents( new_contents); } - MaybeResetStoredFocusForWebContents(new_contents); } else { active_contents_view->SetWebContents(new_contents); } @@ -2213,10 +2215,17 @@ UpdateActiveTabInSplitView(); } + MaybeUpdateStoredFocusForWebContents(new_contents); + if (will_restore_focus) { // We only restore focus if our window is visible, to avoid invoking blur // handlers when we are eventually shown. new_contents->RestoreFocus(); + } else if (!GetWidget()->IsActive()) { + // When the window is inactive during tab switch, restore focus for the + // active web content on activation. + GetFocusManager()->SetStoredFocusView(nullptr); + restore_focus_on_activation_ = true; } // Update all the UI bits.
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 339a9737..26c90a4 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -516,6 +516,9 @@ // Activate the tab containing the given WebContents (if any). void ActivateWebContents(content::WebContents* web_contents); + // Updates stored focus for web contents that is being activated. + void MaybeUpdateStoredFocusForWebContents(content::WebContents*); + // BrowserWindow: void Show() override; void ShowInactive() override;
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc index b6adbee..8f7d65f 100644 --- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -207,9 +207,15 @@ #endif // Verifies that page and devtools WebViews are being correctly laid out -// when DevTools is opened/closed/updated/undocked. -// TODO(crbug.com/40834238): Re-enable; currently failing on multiple platforms. -IN_PROC_BROWSER_TEST_F(BrowserViewTest, DISABLED_DevToolsUpdatesBrowserWindow) { +// when DevTools is opened/closed/updated while docked. +IN_PROC_BROWSER_TEST_F(BrowserViewTest, DevToolsDockedUpdatesBrowserWindow) { +#if BUILDFLAG(IS_OZONE) + // Ozone/wayland doesn't support getting/setting window position in global + // screen coordinates. So this test is not applicable. + if (ui::OzonePlatform::GetPlatformNameForTest() == "wayland") { + GTEST_SKIP(); + } +#endif gfx::Rect full_bounds = browser_view()->GetContentsContainerForTest()->GetLocalBounds(); gfx::Rect small_bounds(10, 20, 30, 40); @@ -243,8 +249,22 @@ EXPECT_FALSE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds()); EXPECT_EQ(full_bounds, contents_web_view()->bounds()); +} - // Undocked. +// Verifies that page and devtools WebViews are being correctly laid out +// when DevTools is opened/closed/updated while undocked. +IN_PROC_BROWSER_TEST_F(BrowserViewTest, DevToolsUndockedUpdatesBrowserWindow) { +#if BUILDFLAG(IS_OZONE) + // Ozone/wayland doesn't support getting/setting window position in global + // screen coordinates. So this test is not applicable. + if (ui::OzonePlatform::GetPlatformNameForTest() == "wayland") { + GTEST_SKIP(); + } +#endif + gfx::Rect full_bounds = + browser_view()->GetContentsContainerForTest()->GetLocalBounds(); + gfx::Rect small_bounds(10, 20, 30, 40); + OpenDevToolsWindow(false); EXPECT_TRUE(devtools_web_view()->web_contents()); EXPECT_EQ(full_bounds, devtools_web_view()->bounds());
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc index 1b9a634..94a6116 100644 --- a/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/frame/multi_contents_view_interactive_uitest.cc
@@ -185,7 +185,7 @@ // Tests switching tabs with split views. This also adds coverage to ensuring // that there isn't any unnecessary re-layout during tab switching. -IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, TabSwitchWithSplitViews) { +IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, TabSwitchWithSplitView) { DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(MultiContentsViewBoundsChangedObserver, kMultiContentsViewBoundsChangedObserver); RunTestSequence( @@ -237,6 +237,70 @@ EnterSplitView(2, 0), CheckTabIsActive(2), CheckActiveContentsHasFocus()); } +// Split view active tab change while browser window doesn't have focus. This +// is used to simulate tab switching scenarios using Tab Search +IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, + TabChangeInSplitViewWithInactiveBrowserWindow) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFirstTab); + + RunTestSequence( + InstrumentTab(kFirstTab, 0), + NavigateWebContents(kFirstTab, GURL(chrome::kChromeUISettingsURL)), + FocusWebContents(kFirstTab), + AddInstrumentedTab(kNewTab, GURL(chrome::kChromeUISettingsURL), 1), + FocusWebContents(kNewTab), + AddInstrumentedTab(kSecondTab, GURL(chrome::kChromeUISettingsURL), 2), + FocusWebContents(kSecondTab), + CheckResult([this]() { return tab_strip_model()->count(); }, 3u), + EnterSplitView(2, 0), CheckTabIsActive(2), + PressButton(kTabSearchButtonElementId), + WaitForShow(kTabSearchBubbleElementId), + Do([this]() { browser()->tab_strip_model()->ActivateTabAt(1); }), + WaitForHide(kTabSearchBubbleElementId), CheckTabIsActive(1), + CheckActiveContentsHasFocus()); +} + +// Switch to the not last used tab inside a split view from a not split tab +// while the browser is inactive. This is used to simulate tab switching +// scenarios using Tab Search +IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, + SwitchToSplitViewWithInactiveBrowserWindow) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFirstTab); + + RunTestSequence( + InstrumentTab(kFirstTab, 0), + NavigateWebContents(kFirstTab, GURL(chrome::kChromeUISettingsURL)), + FocusWebContents(kFirstTab), + AddInstrumentedTab(kNewTab, GURL(chrome::kChromeUISettingsURL), 1), + FocusWebContents(kNewTab), + AddInstrumentedTab(kSecondTab, GURL(chrome::kChromeUISettingsURL), 2), + FocusWebContents(kSecondTab), + CheckResult([this]() { return tab_strip_model()->count(); }, 3u), + EnterSplitView(2, 0), CheckTabIsActive(2), + // Switch from the split view to a regular tab + SelectTab(kTabStripElementId, 0, InputType::kMouse), CheckTabIsActive(0), + FocusWebContents(kNewTab), + // Launch the tab search bubble using the tab search button + PressButton(kTabSearchButtonElementId), + WaitForShow(kTabSearchBubbleElementId), + // Switch from a regular tab directly to an inactive tab, which is on + // the left side of a split with the TabSearch bubble dialog opened. + Do([this]() { browser()->tab_strip_model()->ActivateTabAt(1); }), + WaitForHide(kTabSearchBubbleElementId), CheckTabIsActive(1), + CheckActiveContentsHasFocus(), + // Switch out of the split view back to the regular tab + SelectTab(kTabStripElementId, 0, InputType::kMouse), CheckTabIsActive(0), + FocusWebContents(kNewTab), + // Launch the tab search bubble using the tab search button + PressButton(kTabSearchButtonElementId), + WaitForShow(kTabSearchBubbleElementId), + // Switch from a regular tab directly to an inactive tab, which is on + // the right side of a split with the TabSearch bubble dialog opened. + Do([this]() { browser()->tab_strip_model()->ActivateTabAt(2); }), + WaitForHide(kTabSearchBubbleElementId), CheckTabIsActive(2), + CheckActiveContentsHasFocus()); +} + IN_PROC_BROWSER_TEST_F(MultiContentsViewUiTest, ResizesToMinWidth) { RunTestSequence( CreateTabsAndEnterSplitView(), ResizeWindow(1000),
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc index 7f5daf3..11731b8f 100644 --- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
@@ -891,42 +891,14 @@ } void PictureInPictureBrowserFrameView::SetFrameBounds(const gfx::Rect& bounds) { - gfx::Rect adjusted_bounds(bounds); - gfx::Rect current_bounds = GetWidget()->GetWindowBoundsInScreen(); - bool did_adjust_size = false; - - // If the website is requesting that the window increases in size, then ensure - // that it's not increasing beyond the site-requested maximum. - if (bounds.size().width() > current_bounds.size().width() || - bounds.size().height() > current_bounds.size().height()) { - auto display = display::Screen::GetScreen()->GetDisplayNearestWindow( - GetWidget()->GetNativeWindow()); - gfx::Size adjusted_new_size = - PictureInPictureWindowManager::AdjustRequestedSizeIfNecessary( - bounds.size(), display); - - // If so, then use the adjusted size centered on the current location rather - // than centered on the new location (as we only ever expect size to change, - // and a large requested size could incidentally move the window). - if (adjusted_new_size != bounds.size()) { - adjusted_bounds = current_bounds; - adjusted_bounds.ClampToCenteredSize(adjusted_new_size); - did_adjust_size = true; - } - } - - base::UmaHistogramBoolean( - "Media.DocumentPictureInPicture.RequestedLargeResize", did_adjust_size); - if (!base::FeatureList::IsEnabled( media::kDocumentPictureInPictureAnimateResize) || !gfx::Animation::ShouldRenderRichAnimation()) { - BrowserNonClientFrameView::SetFrameBounds(adjusted_bounds); + BrowserNonClientFrameView::SetFrameBounds(bounds); return; } bounds_change_animation_ = - std::make_unique<BrowserFrameBoundsChangeAnimation>(*frame(), - adjusted_bounds); + std::make_unique<BrowserFrameBoundsChangeAnimation>(*frame(), bounds); bounds_change_animation_->Start(); }
diff --git a/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc b/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc index a7c72c8..afed2899 100644 --- a/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc +++ b/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc
@@ -171,6 +171,12 @@ lens::LensOverlayInvocationSource::kHomeworkActionChip); UserEducationService::MaybeNotifyNewBadgeFeatureUsed( GetWebContents()->GetBrowserContext(), lens::features::kLensOverlay); + + // TODO(crbug.com/422844464): Fix Update() so that it correctly handles the + // chip disappearing at this point, so that the following lines are no longer + // needed. + SetVisible(false); + ResetSlideAnimation(true); } views::BubbleDialogDelegate* LensOverlayHomeworkPageActionIconView::GetBubble()
diff --git a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc index bc4cdfd0..7727980 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/omnibox/omnibox_row_view.h" +#include "base/strings/string_number_conversions.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/omnibox/omnibox_theme.h" #include "chrome/browser/ui/views/omnibox/omnibox_header_view.h"
diff --git a/chrome/browser/ui/views/page_info/page_info_permission_content_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_permission_content_view_unittest.cc index 9eda14b..45c208c 100644 --- a/chrome/browser/ui/views/page_info/page_info_permission_content_view_unittest.cc +++ b/chrome/browser/ui/views/page_info/page_info_permission_content_view_unittest.cc
@@ -7,6 +7,7 @@ #if !BUILDFLAG(IS_CHROMEOS) #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h"
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc index 9fe07b8..a4282bd 100644 --- a/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc +++ b/chrome/browser/ui/views/passwords/manage_passwords_details_view.cc
@@ -8,6 +8,7 @@ #include "base/functional/bind.h" #include "base/functional/callback_forward.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/ui/layout_constants.h"
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc index f9f00b2..479f76a 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view_unittest.cc
@@ -8,6 +8,7 @@ #include "base/containers/to_vector.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc index 24fa45b..0883205 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h"
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc index f075b14..f70fa9ff 100644 --- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc +++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.cc
@@ -80,6 +80,10 @@ return nullptr; } +void ChromeWebContentsViewFocusHelper::SetStoredFocusView(views::View* view) { + last_focused_view_tracker_.SetView(view); +} + gfx::NativeView ChromeWebContentsViewFocusHelper::GetActiveNativeView() { return GetWebContents().GetNativeView(); }
diff --git a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h index 30853310..41e643b 100644 --- a/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h +++ b/chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h
@@ -35,6 +35,7 @@ bool TakeFocus(bool reverse); // Returns the View that will be focused if RestoreFocus() is called. views::View* GetStoredFocus(); + void SetStoredFocusView(views::View* view); private: explicit ChromeWebContentsViewFocusHelper(content::WebContents* web_contents);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc index a683707..fe3b62941 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc
@@ -10,6 +10,7 @@ #include <variant> #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/toolbar/overflow_button.h"
diff --git a/chrome/browser/ui/web_applications/app_browser_document_picture_in_picture_browsertest.cc b/chrome/browser/ui/web_applications/app_browser_document_picture_in_picture_browsertest.cc index 2f5bd97a..cd8b854 100644 --- a/chrome/browser/ui/web_applications/app_browser_document_picture_in_picture_browsertest.cc +++ b/chrome/browser/ui/web_applications/app_browser_document_picture_in_picture_browsertest.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/functional/bind.h" -#include "base/functional/callback.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/picture_in_picture/document_picture_in_picture_mixin_test_base.h" #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h" @@ -23,15 +21,11 @@ namespace { // Helper class to wait for widget bound changes. Stops waiting once widget size -// passes the given `size_ready_callback` check. +// matches the `expected_size_`. class WidgetResizeWaiter : public views::WidgetObserver { public: - // Should return true if the given size should end waiting. - using SizeReadyCallback = base::RepeatingCallback<bool(const gfx::Size&)>; - - WidgetResizeWaiter(views::Widget* widget, - SizeReadyCallback size_ready_callback) - : size_ready_callback_(std::move(size_ready_callback)) { + explicit WidgetResizeWaiter(views::Widget* widget, gfx::Size expected_size) + : expected_size_(expected_size) { observation_.Observe(widget); } @@ -39,7 +33,7 @@ void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& bounds) override { - if (size_ready_callback_.Run(bounds.size())) { + if (bounds.size() == expected_size_) { run_loop_.Quit(); } } @@ -47,7 +41,7 @@ private: base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{ this}; - SizeReadyCallback size_ready_callback_; + gfx::Size expected_size_; base::RunLoop run_loop_; }; @@ -219,20 +213,12 @@ { WidgetResizeWaiter waiter( pip_browser_view->GetWidget(), - base::BindRepeating( - [](gfx::Size maximum_window_size, const gfx::Size& size) { - return size.width() <= maximum_window_size.width() && - size.height() <= maximum_window_size.height(); - }, - maximum_window_size)); + PictureInPictureWindowManager::GetMaximumWindowSize(display)); EXPECT_TRUE(ExecJs(pip_web_contents, script)); waiter.Wait(); } - EXPECT_LE(pip_browser_view->GetBounds().size().width(), - maximum_window_size.width()); - EXPECT_LE(pip_browser_view->GetBounds().size().height(), - maximum_window_size.height()); + EXPECT_EQ(pip_browser_view->GetBounds().size(), maximum_window_size); } } // namespace
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc index 5512da5..6961c90 100644 --- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc +++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/password_manager/password_manager_ui.h" #include "base/i18n/message_formatter.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc index 9b7bad2..deef4f9 100644 --- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc +++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -1447,8 +1447,7 @@ ? custom_last_active_text : GetLastActiveElapsedText(last_active_time_ticks); - std::vector<tabs::TabAlert> alert_states = - GetTabAlertStatesForContents(contents); + std::vector<tabs::TabAlert> alert_states = GetTabAlertStatesForTab(tab); // Currently, we only report media alert states. std::ranges::copy_if(alert_states.begin(), alert_states.end(), std::back_inserter(tab_data->alert_states),
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc index 7fb12363..ac6b209 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
@@ -307,7 +307,8 @@ switch (change.type()) { case TabStripModelChange::kInserted: { for (const auto& contents : change.GetInsert()->contents) { - page_->TabCreated(GetTabData(contents.contents, contents.index)); + page_->TabCreated( + GetTabData(contents.contents, contents.tab, contents.index)); } break; } @@ -350,18 +351,23 @@ int index, TabChangeType change_type) { TRACE_EVENT0("browser", "TabStripPageHandler:TabChangedAt"); - page_->TabUpdated(GetTabData(contents, index)); + TabStripModel* tab_strip_model = browser_->tab_strip_model(); + page_->TabUpdated( + GetTabData(contents, tab_strip_model->GetTabAtIndex(index), index)); } void TabStripPageHandler::TabPinnedStateChanged(TabStripModel* tab_strip_model, content::WebContents* contents, int index) { - page_->TabUpdated(GetTabData(contents, index)); + page_->TabUpdated( + GetTabData(contents, tab_strip_model->GetTabAtIndex(index), index)); } void TabStripPageHandler::TabBlockedStateChanged(content::WebContents* contents, int index) { - page_->TabUpdated(GetTabData(contents, index)); + TabStripModel* tab_strip_model = browser_->tab_strip_model(); + page_->TabUpdated( + GetTabData(contents, tab_strip_model->GetTabAtIndex(index), index)); } bool TabStripPageHandler::PreHandleGestureEvent( @@ -490,6 +496,7 @@ tab_strip::mojom::TabPtr TabStripPageHandler::GetTabData( content::WebContents* contents, + const tabs::TabInterface* tab, int index) { DCHECK(index >= 0); auto tab_data = tab_strip::mojom::Tab::New(); @@ -544,7 +551,7 @@ tab_data->crashed = tab_renderer_data.IsCrashed(); // TODO(johntlee): Add the rest of TabRendererData - for (const auto alert_state : GetTabAlertStatesForContents(contents)) { + for (const auto alert_state : GetTabAlertStatesForTab(tab)) { tab_data->alert_states.push_back(alert_state); } @@ -576,7 +583,8 @@ std::vector<tab_strip::mojom::TabPtr> tabs; TabStripModel* tab_strip_model = browser_->tab_strip_model(); for (int i = 0; i < tab_strip_model->count(); ++i) { - tabs.push_back(GetTabData(tab_strip_model->GetWebContentsAt(i), i)); + tabs.push_back(GetTabData(tab_strip_model->GetWebContentsAt(i), + tab_strip_model->GetTabAtIndex(i), i)); } std::move(callback).Run(std::move(tabs)); }
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h index 99be7c9..c4836cd 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h
@@ -27,6 +27,10 @@ class Browser; class TabStripUIEmbedder; +namespace tabs { +class TabInterface; +} // namespace tabs + class TabStripPageHandler : public tab_strip::mojom::PageHandler, public TabStripModelObserver, public content::WebContentsDelegate, @@ -97,6 +101,7 @@ void OnLongPressTimer(); tab_strip::mojom::TabPtr GetTabData(content::WebContents* contents, + const tabs::TabInterface* tab, int index); tab_strip::mojom::TabGroupVisualDataPtr GetTabGroupData(TabGroup* group); void HandleThumbnailUpdate(content::WebContents* tab,
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc index ef96894..d06a6138 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <optional> +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/values.h"
diff --git a/chrome/browser/ui/webui/tabs/OWNERS b/chrome/browser/ui/webui/tabs/OWNERS index 6701594..16fe190 100644 --- a/chrome/browser/ui/webui/tabs/OWNERS +++ b/chrome/browser/ui/webui/tabs/OWNERS
@@ -1,7 +1,7 @@ -elainechien@chromium.org romanarora@chromium.org +yuhengh@chromium.org per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS per-file *_mojom_traits*.*=set noparent -per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS \ No newline at end of file +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/web_applications/extensions/extensions_manager.cc b/chrome/browser/web_applications/extensions/extensions_manager.cc index 5746718..b71545f 100644 --- a/chrome/browser/web_applications/extensions/extensions_manager.cc +++ b/chrome/browser/web_applications/extensions/extensions_manager.cc
@@ -74,27 +74,6 @@ return allowlist; } -bool ExtensionsManager::ShouldGarbageCollectStoragePartitions() { - // `ExtensionPrefs` can be created lazily, so we don't need to wait on - // extension service. - extensions::ExtensionPrefs* extension_prefs = - extensions::ExtensionPrefs::Get(profile_); - return extension_prefs && extension_prefs->NeedsStorageGarbageCollection(); -} - -void ExtensionsManager::ResetStorageGarbageCollectPref( - base::OnceClosure callback) { - // `ExtensionPrefs` can be created lazily, so we don't need to wait on - // extension service. - extensions::ExtensionPrefs* extension_prefs = - extensions::ExtensionPrefs::Get(profile_); - if (extension_prefs) { - extension_prefs->pref_service()->SetBoolean( - extensions::pref_names::kStorageGarbageCollect, false); - extension_prefs->pref_service()->CommitPendingWrite(std::move(callback)); - } -} - std::unique_ptr<ExtensionInstallGate> ExtensionsManager::RegisterGarbageCollectionInstallGate() { return std::make_unique<web_app::ExtensionInstallGateImpl>(profile_);
diff --git a/chrome/browser/web_applications/extensions_manager.h b/chrome/browser/web_applications/extensions_manager.h index d1f305b..58c42ff 100644 --- a/chrome/browser/web_applications/extensions_manager.h +++ b/chrome/browser/web_applications/extensions_manager.h
@@ -38,14 +38,6 @@ virtual std::unordered_set<base::FilePath> GetIsolatedStoragePaths(); - // Returns ExtensionsPref::kStorageGarbageCollect which indicates possibly - // deleted Storage Partitions on disk requiring garbage collection. - // TODO(crbug.com/40922689): Delete ExtensionsPref::kStorageGarbageCollect. - virtual bool ShouldGarbageCollectStoragePartitions(); - - // Sets ExtensionsPref::kStorageGarbageCollect to false. - virtual void ResetStorageGarbageCollectPref(base::OnceClosure callback); - // Creates an ExtensionInstallerGate which registers itself on // ExtensionService to delay Extension installs. virtual std::unique_ptr<ExtensionInstallGate>
diff --git a/chrome/browser/web_applications/isolated_web_apps/commands/garbage_collect_storage_partitions_command.cc b/chrome/browser/web_applications/isolated_web_apps/commands/garbage_collect_storage_partitions_command.cc index 8111deb..47cc0b10 100644 --- a/chrome/browser/web_applications/isolated_web_apps/commands/garbage_collect_storage_partitions_command.cc +++ b/chrome/browser/web_applications/isolated_web_apps/commands/garbage_collect_storage_partitions_command.cc
@@ -54,10 +54,6 @@ // resetting to false early. profile_->GetPrefs()->SetBoolean( prefs::kShouldGarbageCollectStoragePartitions, false); - // Waits for both prefs to be written to disk before proceeding to prevent - // repeating crashes. - lock_->extensions_manager().ResetStorageGarbageCollectPref( - concurrent.CreateClosure()); profile_->GetPrefs()->CommitPendingWrite(concurrent.CreateClosure()); std::move(concurrent) .Done(base::BindOnce(&GarbageCollectStoragePartitionsCommand::OnPrefReset,
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_installation_manager.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_installation_manager.cc index c34ac13..0cbf1fc1 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_installation_manager.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_installation_manager.cc
@@ -466,13 +466,8 @@ } void IsolatedWebAppInstallationManager::MaybeScheduleGarbageCollection() { - // We are migrating from `ExtensionsPref::kStorageGarbageCollect` to - // `prefs::kShouldGarbageCollectStoragePartitions`. During the migration, - // either one of the prefs can trigger garbage collection. - // TODO(crbug.com/40922689): Delete `ExtensionsPref::kStorageGarbageCollect`. if (profile_->GetPrefs()->GetBoolean( - prefs::kShouldGarbageCollectStoragePartitions) || - provider_->extensions_manager().ShouldGarbageCollectStoragePartitions()) { + prefs::kShouldGarbageCollectStoragePartitions)) { provider_->command_manager().ScheduleCommand( std::make_unique<web_app::GarbageCollectStoragePartitionsCommand>( &profile_.get(),
diff --git a/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc index e704a22..13ae8d7 100644 --- a/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc
@@ -19,6 +19,7 @@ #include "base/test/scoped_path_override.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" +#include "base/threading/thread_restrictions.h" #include "base/version.h" #include "chrome/browser/component_updater/iwa_key_distribution_component_installer.h" #include "chrome/browser/web_applications/isolated_web_apps/iwa_identity_validator.h"
diff --git a/chrome/browser/web_applications/locks/web_app_lock_manager.cc b/chrome/browser/web_applications/locks/web_app_lock_manager.cc index 1869f86..44e3878 100644 --- a/chrome/browser/web_applications/locks/web_app_lock_manager.cc +++ b/chrome/browser/web_applications/locks/web_app_lock_manager.cc
@@ -15,6 +15,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "base/strings/to_string.h" #include "base/task/sequenced_task_runner.h" #include "base/task/task_runner.h" #include "base/types/pass_key.h"
diff --git a/chrome/browser/win/chrome_process_finder.cc b/chrome/browser/win/chrome_process_finder.cc index 019ac7e..6e6ba54 100644 --- a/chrome/browser/win/chrome_process_finder.cc +++ b/chrome/browser/win/chrome_process_finder.cc
@@ -20,7 +20,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/win/message_window.h" #include "base/win/scoped_handle.h" #include "base/win/win_util.h"
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index 37790ff..b543a9e 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1749153838-ceba28aa4231d55de2d5c3044b579bea55cc2f2f-d0051c9105d286b12ca0e06027eee86eef8d23e3.profdata +chrome-android64-main-1749167123-a0ad2132230a4e0439f87fdd8a87e34cfe88172d-b795f62e31ff577fa4b982385931634663b70e63.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 2b7c26d..defcc35 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1749146264-08be9ef2c8d32a7e2f0b5e539442a8e1ebf9c428-46225ed4889da320c0d607a3a8e9ce0400bd3e88.profdata +chrome-linux-main-1749167123-293fd6638f0497c300313ab3e8e310974cf00832-b795f62e31ff577fa4b982385931634663b70e63.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 512be71..a9fcbe4 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1749160339-e3b5e65b915732db0524b523a1e19a5c14855359-426353f6aa9c4aa0ba2aa86037878fd70cc31978.profdata +chrome-mac-arm-main-1749189211-e4c66fdb1539547ad8f307f14b5e1dd450462cc0-e074fdf9bf476ecb65885b2fc4b04be6d99b5ab3.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 6929db59..e35c56b 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1749146264-c2239ee6ba19dcec39e96903fefd2269cb9e695c-46225ed4889da320c0d607a3a8e9ce0400bd3e88.profdata +chrome-mac-main-1749167123-8c1216a847ba10d1ec64777522a5913741e795d2-b795f62e31ff577fa4b982385931634663b70e63.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 859bb5a..b359a154 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1749135429-5b56efea6604cfbe7785014fa474c2d4fe7d82a7-2ef25ae91c6fed5f715c962d43ca9cceb5da14e4.profdata +chrome-win32-main-1749167123-67bbb7f7d4be123087527492e3014c469885ca3a-b795f62e31ff577fa4b982385931634663b70e63.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 470fb43a..6783e67 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1749135429-5f146d27ad510f64753a2aa20c28c5f2a6492dee-2ef25ae91c6fed5f715c962d43ca9cceb5da14e4.profdata +chrome-win64-main-1749157182-a9e9c1a2e1d9e6a37d825cf4c3791d906170cc35-d641dd235e14d971eec18239f5e90d33f985800b.profdata
diff --git a/chrome/common/actor.mojom b/chrome/common/actor.mojom index 7088375..8aca4ea8 100644 --- a/chrome/common/actor.mojom +++ b/chrome/common/actor.mojom
@@ -179,6 +179,10 @@ // The task for the action was paused. kTaskPaused = 23, + // The tool executor in the renderer was destroyed before the tool finished + // executing. + kExecutorDestroyed = 24, + /////////////////////////////////////////////////////////////////////// // Codes 100-199: Errors for navigation. (Not part of the ToolAction union // as it's a browser-side tool.)
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc index e9d3d68..49a7a79 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc +++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/path_service.h" +#include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/types/cxx23_to_underlying.h"
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_test_utils.cc b/chrome/renderer/accessibility/read_anything/read_anything_test_utils.cc index baf2a46..68fc49d 100644 --- a/chrome/renderer/accessibility/read_anything/read_anything_test_utils.cc +++ b/chrome/renderer/accessibility/read_anything/read_anything_test_utils.cc
@@ -4,6 +4,8 @@ #include "chrome/renderer/accessibility/read_anything/read_anything_test_utils.h" +#include "base/strings/string_number_conversions.h" + namespace test { void SetUpdateTreeID(ui::AXTreeUpdate* update, ui::AXTreeID tree_id) {
diff --git a/chrome/renderer/actor/click_tool.cc b/chrome/renderer/actor/click_tool.cc index b6cacd2..0ab59877 100644 --- a/chrome/renderer/actor/click_tool.cc +++ b/chrome/renderer/actor/click_tool.cc
@@ -45,11 +45,10 @@ ClickTool::~ClickTool() = default; -void ClickTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr ClickTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } gfx::PointF click_point = validated_result.value(); @@ -77,9 +76,8 @@ } } - mojom::ActionResultPtr result = CreateAndDispatchClick( - button, click_count, click_point, frame_->GetWebFrame()->FrameWidget()); - std::move(callback).Run(std::move(result)); + return CreateAndDispatchClick(button, click_count, click_point, + frame_->GetWebFrame()->FrameWidget()); } std::string ClickTool::DebugString() const {
diff --git a/chrome/renderer/actor/click_tool.h b/chrome/renderer/actor/click_tool.h index a098dd93..171b981 100644 --- a/chrome/renderer/actor/click_tool.h +++ b/chrome/renderer/actor/click_tool.h
@@ -12,10 +12,6 @@ #include "chrome/common/actor.mojom.h" #include "chrome/renderer/actor/tool_base.h" -namespace blink { -class WebMouseEvent; -} // namespace blink - namespace content { class RenderFrame; } // namespace content @@ -36,16 +32,13 @@ ~ClickTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private: using ValidatedResult = base::expected<gfx::PointF, mojom::ActionResultPtr>; ValidatedResult Validate() const; - void SendMouseUp(blink::WebMouseEvent mouse_event, - ToolFinishedCallback callback); - mojom::ClickActionPtr action_; };
diff --git a/chrome/renderer/actor/drag_and_release_tool.cc b/chrome/renderer/actor/drag_and_release_tool.cc index 1b452f12..8430615 100644 --- a/chrome/renderer/actor/drag_and_release_tool.cc +++ b/chrome/renderer/actor/drag_and_release_tool.cc
@@ -37,11 +37,10 @@ DragAndReleaseTool::~DragAndReleaseTool() = default; -void DragAndReleaseTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr DragAndReleaseTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } gfx::PointF from_point = validated_result->from; @@ -52,34 +51,27 @@ // Move and press down the mouse on the from_point. if (!InjectMouseEvent(EventType::kMouseMove, from_point, WebMouseEvent::Button::kNoButton)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kDragAndReleaseFromMoveSuppressed)); - return; + return MakeResult( + mojom::ActionResultCode::kDragAndReleaseFromMoveSuppressed); } if (!InjectMouseEvent(EventType::kMouseDown, from_point, WebMouseEvent::Button::kLeft)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kDragAndReleaseDownSuppressed)); - return; + return MakeResult(mojom::ActionResultCode::kDragAndReleaseDownSuppressed); } // Move and release the mouse on the to_point. if (!InjectMouseEvent(EventType::kMouseMove, to_point, WebMouseEvent::Button::kLeft)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kDragAndReleaseToMoveSuppressed)); - return; + return MakeResult(mojom::ActionResultCode::kDragAndReleaseToMoveSuppressed); } if (!InjectMouseEvent(EventType::kMouseUp, to_point, WebMouseEvent::Button::kLeft)) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kDragAndReleaseUpSuppressed)); - return; + return MakeResult(mojom::ActionResultCode::kDragAndReleaseUpSuppressed); } - std::move(callback).Run(MakeOkResult()); + return MakeOkResult(); } std::string DragAndReleaseTool::DebugString() const {
diff --git a/chrome/renderer/actor/drag_and_release_tool.h b/chrome/renderer/actor/drag_and_release_tool.h index c65c660..353412e2 100644 --- a/chrome/renderer/actor/drag_and_release_tool.h +++ b/chrome/renderer/actor/drag_and_release_tool.h
@@ -35,7 +35,7 @@ ~DragAndReleaseTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private:
diff --git a/chrome/renderer/actor/mouse_move_tool.cc b/chrome/renderer/actor/mouse_move_tool.cc index 815b384b..49a50c38 100644 --- a/chrome/renderer/actor/mouse_move_tool.cc +++ b/chrome/renderer/actor/mouse_move_tool.cc
@@ -46,11 +46,10 @@ MouseMoveTool::~MouseMoveTool() = default; -void MouseMoveTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr MouseMoveTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } gfx::PointF move_point = validated_result.value(); @@ -66,11 +65,10 @@ // Note: KNotHandled probably shouldn't result in an error. if (move_result == blink::WebInputEventResult::kNotHandled || move_result == blink::WebInputEventResult::kHandledSuppressed) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kMouseMoveEventSuppressed)); - return; + return MakeResult(mojom::ActionResultCode::kMouseMoveEventSuppressed); } - std::move(callback).Run(MakeOkResult()); + + return MakeOkResult(); } std::string MouseMoveTool::DebugString() const {
diff --git a/chrome/renderer/actor/mouse_move_tool.h b/chrome/renderer/actor/mouse_move_tool.h index fa8fe139..8baf11dc 100644 --- a/chrome/renderer/actor/mouse_move_tool.h +++ b/chrome/renderer/actor/mouse_move_tool.h
@@ -30,7 +30,7 @@ ~MouseMoveTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private:
diff --git a/chrome/renderer/actor/scroll_tool.cc b/chrome/renderer/actor/scroll_tool.cc index a351bd72..6ee0f4f 100644 --- a/chrome/renderer/actor/scroll_tool.cc +++ b/chrome/renderer/actor/scroll_tool.cc
@@ -36,11 +36,10 @@ ScrollTool::~ScrollTool() = default; -void ScrollTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr ScrollTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } WebElement scrolling_element = validated_result->scroller; @@ -54,10 +53,9 @@ scrolling_element.SetScrollOffset(start_offset_css + offset_css); bool did_scroll = scrolling_element.GetScrollOffset() != start_offset_css; - std::move(callback).Run( - did_scroll - ? MakeOkResult() - : MakeResult(mojom::ActionResultCode::kScrollOffsetDidNotChange)); + return did_scroll + ? MakeOkResult() + : MakeResult(mojom::ActionResultCode::kScrollOffsetDidNotChange); } std::string ScrollTool::DebugString() const {
diff --git a/chrome/renderer/actor/scroll_tool.h b/chrome/renderer/actor/scroll_tool.h index 73dd59d3..3bb671402 100644 --- a/chrome/renderer/actor/scroll_tool.h +++ b/chrome/renderer/actor/scroll_tool.h
@@ -31,7 +31,7 @@ ~ScrollTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private:
diff --git a/chrome/renderer/actor/select_tool.cc b/chrome/renderer/actor/select_tool.cc index 09a8bb73..e8733a8 100644 --- a/chrome/renderer/actor/select_tool.cc +++ b/chrome/renderer/actor/select_tool.cc
@@ -36,11 +36,10 @@ SelectTool::~SelectTool() = default; -void SelectTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr SelectTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } WebSelectElement select = validated_result.value().select; @@ -49,13 +48,12 @@ // Check if the set value is now the current value in the <select> if (select.Value() != value) { - std::move(callback).Run( - MakeResult(mojom::ActionResultCode::kSelectUnexpectedValue, - absl::StrFormat("ValueAfter [%s]", select.Value().Utf8()))); - return; + return MakeResult( + mojom::ActionResultCode::kSelectUnexpectedValue, + absl::StrFormat("ValueAfter [%s]", select.Value().Utf8())); } - std::move(callback).Run(MakeOkResult()); + return MakeOkResult(); } std::string SelectTool::DebugString() const {
diff --git a/chrome/renderer/actor/select_tool.h b/chrome/renderer/actor/select_tool.h index b030ec3a..a3b4073c 100644 --- a/chrome/renderer/actor/select_tool.h +++ b/chrome/renderer/actor/select_tool.h
@@ -28,7 +28,7 @@ ~SelectTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private:
diff --git a/chrome/renderer/actor/tool_base.h b/chrome/renderer/actor/tool_base.h index e6dd2ce..f82d185 100644 --- a/chrome/renderer/actor/tool_base.h +++ b/chrome/renderer/actor/tool_base.h
@@ -21,15 +21,14 @@ class ToolBase { public: - using ToolFinishedCallback = base::OnceCallback<void(mojom::ActionResultPtr)>; ToolBase(content::RenderFrame& frame, Journal::TaskId task_id, Journal& journal) : frame_(frame), task_id_(task_id), journal_(journal) {} virtual ~ToolBase() = default; - // Executes the tool. `callback` is invoked with the tool result. - virtual void Execute(ToolFinishedCallback callback) = 0; + // Executes the tool and returns the result code. + virtual mojom::ActionResultPtr Execute() = 0; // Returns a human readable string representing this tool and its parameters. // Used primarily for logging and debugging.
diff --git a/chrome/renderer/actor/tool_executor.cc b/chrome/renderer/actor/tool_executor.cc index 71ba047..24bc857 100644 --- a/chrome/renderer/actor/tool_executor.cc +++ b/chrome/renderer/actor/tool_executor.cc
@@ -10,7 +10,9 @@ #include "base/functional/callback.h" #include "base/memory/ptr_util.h" #include "base/notreached.h" +#include "base/task/sequenced_task_runner.h" #include "chrome/common/actor.mojom.h" +#include "chrome/common/actor/action_result.h" #include "chrome/renderer/actor/click_tool.h" #include "chrome/renderer/actor/drag_and_release_tool.h" #include "chrome/renderer/actor/journal.h" @@ -33,47 +35,47 @@ void ToolExecutor::InvokeTool(mojom::ToolInvocationPtr request, ToolExecutorCallback callback) { - CHECK(!tool_); + std::unique_ptr<ToolBase> tool; switch (request->action->which()) { case actor::mojom::ToolAction::Tag::kClick: { // Check the mojom we received is in good shape. CHECK(request->action->get_click()); - tool_ = std::make_unique<ClickTool>( + tool = std::make_unique<ClickTool>( frame_.get(), request->task_id, journal_.get(), std::move(request->action->get_click())); break; } case actor::mojom::ToolAction::Tag::kMouseMove: { CHECK(request->action->get_mouse_move()); - tool_ = std::make_unique<MouseMoveTool>( + tool = std::make_unique<MouseMoveTool>( frame_.get(), request->task_id, journal_.get(), std::move(request->action->get_mouse_move())); break; } case actor::mojom::ToolAction::Tag::kType: { CHECK(request->action->get_type()); - tool_ = std::make_unique<TypeTool>( - frame_.get(), request->task_id, journal_.get(), - std::move(request->action->get_type())); + tool = std::make_unique<TypeTool>(frame_.get(), request->task_id, + journal_.get(), + std::move(request->action->get_type())); break; } case actor::mojom::ToolAction::Tag::kScroll: { CHECK(request->action->get_scroll()); - tool_ = std::make_unique<ScrollTool>( + tool = std::make_unique<ScrollTool>( frame_.get(), request->task_id, journal_.get(), std::move(request->action->get_scroll())); break; } case actor::mojom::ToolAction::Tag::kSelect: { CHECK(request->action->get_select()); - tool_ = std::make_unique<SelectTool>( + tool = std::make_unique<SelectTool>( frame_.get(), request->task_id, journal_.get(), std::move(request->action->get_select())); break; } case actor::mojom::ToolAction::Tag::kDragAndRelease: { CHECK(request->action->get_drag_and_release()); - tool_ = std::make_unique<DragAndReleaseTool>( + tool = std::make_unique<DragAndReleaseTool>( frame_.get(), request->task_id, journal_.get(), std::move(request->action->get_drag_and_release())); break; @@ -82,19 +84,9 @@ NOTREACHED(); } - journal_->Log(request->task_id, "Renderer InvokeTool", tool_->DebugString()); + journal_->Log(request->task_id, "Renderer InvokeTool", tool->DebugString()); - // It's safe to use base::Unretained as tool_ is owned by this object and - // tool_ has its own weak factory to manage the callback. - tool_->Execute(base::BindOnce(&ToolExecutor::ToolFinished, - base::Unretained(this), std::move(callback))); -} - -void ToolExecutor::ToolFinished(ToolExecutorCallback callback, - mojom::ActionResultPtr result) { - CHECK(tool_); - // Release current tool so we can accept a new tool invocation. - tool_.reset(); + mojom::ActionResultPtr result = tool->Execute(); std::move(callback).Run(std::move(result)); }
diff --git a/chrome/renderer/actor/tool_executor.h b/chrome/renderer/actor/tool_executor.h index 702ad197..a248db1 100644 --- a/chrome/renderer/actor/tool_executor.h +++ b/chrome/renderer/actor/tool_executor.h
@@ -7,7 +7,6 @@ #include "base/functional/callback_forward.h" #include "base/memory/raw_ref.h" -#include "base/memory/stack_allocated.h" #include "chrome/common/actor.mojom-forward.h" #include "chrome/common/chrome_render_frame.mojom.h" #include "chrome/renderer/actor/tool_base.h" @@ -25,13 +24,7 @@ // // This class is responsible for receiving tool request messages and invoking // the requested tool in the renderer. -// -// WARNING: This class is stack allocated but is written in a way that implies -// that tools can be asynchronously executed. In practice the tools are -// synchronous, and there's a lot of re-entrancy. class ToolExecutor { - STACK_ALLOCATED(); - public: using ToolExecutorCallback = base::OnceCallback<void(mojom::ActionResultPtr)>; explicit ToolExecutor(content::RenderFrame* frame, Journal& journal); @@ -44,13 +37,9 @@ ToolExecutorCallback callback); private: - void ToolFinished(ToolExecutorCallback callback, - mojom::ActionResultPtr result); - - // Raw ref since the executor is currently only stack allocated by the - // render frame so it must be outlived. + // Raw ref since the executor is owned by the RenderFrameObserver which has + // the same lifetime as RenderFrame. base::raw_ref<content::RenderFrame> frame_; - std::unique_ptr<ToolBase> tool_; base::raw_ref<Journal> journal_; };
diff --git a/chrome/renderer/actor/type_tool.cc b/chrome/renderer/actor/type_tool.cc index 7e78b63..83a6eaf3 100644 --- a/chrome/renderer/actor/type_tool.cc +++ b/chrome/renderer/actor/type_tool.cc
@@ -262,11 +262,10 @@ return MakeOkResult(); } -void TypeTool::Execute(ToolFinishedCallback callback) { +mojom::ActionResultPtr TypeTool::Execute() { ValidatedResult validated_result = Validate(); if (!validated_result.has_value()) { - std::move(callback).Run(std::move(validated_result.error())); - return; + return std::move(validated_result.error()); } if (std::holds_alternative<gfx::PointF>(validated_result->target)) { @@ -278,8 +277,7 @@ // Cancel rest of typing if initial click failed. if (!IsOk(*result)) { - std::move(callback).Run(std::move(result)); - return; + return result; } } else { WebElement element = std::get<blink::WebElement>(validated_result->target); @@ -310,12 +308,11 @@ for (const auto& param : validated_result->key_sequence) { mojom::ActionResultPtr result = SimulateKeyPress(param); if (!IsOk(*result)) { - std::move(callback).Run(std::move(result)); - return; + return result; } } - std::move(callback).Run(MakeOkResult()); + return MakeOkResult(); } std::string TypeTool::DebugString() const {
diff --git a/chrome/renderer/actor/type_tool.h b/chrome/renderer/actor/type_tool.h index 4c98751..930aa601 100644 --- a/chrome/renderer/actor/type_tool.h +++ b/chrome/renderer/actor/type_tool.h
@@ -35,7 +35,7 @@ ~TypeTool() override; // actor::ToolBase - void Execute(ToolFinishedCallback callback) override; + mojom::ActionResultPtr Execute() override; std::string DebugString() const override; private:
diff --git a/chrome/renderer/benchmarking_extension.cc b/chrome/renderer/benchmarking_extension.cc index 9b12fbaf7..d28a018e 100644 --- a/chrome/renderer/benchmarking_extension.cc +++ b/chrome/renderer/benchmarking_extension.cc
@@ -12,7 +12,7 @@ #include "base/profiler/module_cache.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "content/public/common/content_switches.h" #include "content/public/renderer/render_thread.h" #include "v8-local-handle.h"
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc index b6f3621..a92ad797 100644 --- a/chrome/renderer/chrome_render_frame_observer.cc +++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -622,8 +622,12 @@ void ChromeRenderFrameObserver::InvokeTool( actor::mojom::ToolInvocationPtr request, InvokeToolCallback callback) { - actor::ToolExecutor executor(render_frame(), *actor_journal_); - executor.InvokeTool(std::move(request), std::move(callback)); + if (!tool_executor_) { + tool_executor_ = + std::make_unique<actor::ToolExecutor>(render_frame(), *actor_journal_); + } + + tool_executor_->InvokeTool(std::move(request), std::move(callback)); } void ChromeRenderFrameObserver::StartActorJournal(
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h index d785ab23..feecfd5 100644 --- a/chrome/renderer/chrome_render_frame_observer.h +++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -5,6 +5,7 @@ #ifndef CHROME_RENDERER_CHROME_RENDER_FRAME_OBSERVER_H_ #define CHROME_RENDERER_CHROME_RENDER_FRAME_OBSERVER_H_ +#include <memory> #include <string> #include <vector> @@ -21,6 +22,7 @@ #if !BUILDFLAG(IS_ANDROID) #include "chrome/common/actor.mojom.h" +#include "chrome/renderer/actor/tool_executor.h" #endif class SkBitmap; @@ -192,6 +194,10 @@ std::vector<std::u16string> webui_javascript_; #endif +#if !BUILDFLAG(IS_ANDROID) + std::unique_ptr<actor::ToolExecutor> tool_executor_; +#endif + mojo::AssociatedReceiverSet<chrome::mojom::ChromeRenderFrame> receivers_; service_manager::BinderRegistry registry_;
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc index 91994c0..6c3c24e67 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_medium_unittest.cc
@@ -10,6 +10,7 @@ #include "base/task/thread_pool.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" +#include "base/threading/thread_restrictions.h" #include "chrome/services/sharing/nearby/platform/wifi_direct_server_socket.h" #include "chromeos/ash/services/nearby/public/cpp/fake_firewall_hole_factory.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket_unittest.cc index b19992c..8a573b5 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_server_socket_unittest.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_server_socket_unittest.cc
@@ -8,6 +8,7 @@ #include "base/task/thread_pool.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" +#include "base/threading/thread_restrictions.h" #include "chromeos/ash/services/nearby/public/cpp/fake_firewall_hole.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/net_errors.h"
diff --git a/chrome/services/sharing/nearby/platform/wifi_direct_socket_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_direct_socket_unittest.cc index 2346a2d..2e44bd0 100644 --- a/chrome/services/sharing/nearby/platform/wifi_direct_socket_unittest.cc +++ b/chrome/services/sharing/nearby/platform/wifi_direct_socket_unittest.cc
@@ -14,6 +14,7 @@ #include "base/task/thread_pool.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" +#include "base/threading/thread_restrictions.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/socket/stream_socket.h"
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 578fb52..08ddc94 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -182,12 +182,6 @@ # Unable to run chrome-headless-shell with logging enabled on Mac. See # crbug.com/1011000. 'ChromeLogPathCapabilityTest.testChromeLogPath', - # https://crbug.com/chromedriver/4631 - # chrome-headless-shell does not set the window rect as requested. - 'ChromeDriverTest.testWindowMinimize', - 'ChromeDriverTest.testWindowPosition', - 'ChromeDriverTest.testWindowRect', - 'ChromeDriverTest.testWindowSize', # https://crbug.com/chromedriver/4632 # chrome-headless-shell ignores the selected range while inserting the text 'ChromeDriverW3cTest.testSendKeysToElementDoesNotAppend',
diff --git a/chrome/test/data/actor/cross_document_nav.html b/chrome/test/data/actor/cross_document_nav.html new file mode 100644 index 0000000..50f58d7 --- /dev/null +++ b/chrome/test/data/actor/cross_document_nav.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> + <head> + <meta name="viewport" content="width=device-width, minimum-scale=1.0"> + <title>Cross Document Navigation</title> + </head> + <body> + <a id="link" href="simple_iframe.html">Go To Next Page</a> + </body> +</html>
diff --git a/chrome/test/data/webui/privacy_sandbox/base_dialog_browsertest.cc b/chrome/test/data/webui/privacy_sandbox/base_dialog_browsertest.cc index 92cfa6b..c5ff182 100644 --- a/chrome/test/data/webui/privacy_sandbox/base_dialog_browsertest.cc +++ b/chrome/test/data/webui/privacy_sandbox/base_dialog_browsertest.cc
@@ -67,4 +67,8 @@ IN_PROC_BROWSER_TEST_P(PrivacySandboxBaseDialogMochaTest, EEAConsentAndNotice) { RunTestSuite("EEAConsentAndNotice"); } + +IN_PROC_BROWSER_TEST_P(PrivacySandboxBaseDialogMochaTest, BaseDialogLearnMore) { + RunTestSuite("BaseDialogLearnMore"); +} } // namespace
diff --git a/chrome/test/data/webui/privacy_sandbox/base_dialog_test.ts b/chrome/test/data/webui/privacy_sandbox/base_dialog_test.ts index 067eb10..7336c84c 100644 --- a/chrome/test/data/webui/privacy_sandbox/base_dialog_test.ts +++ b/chrome/test/data/webui/privacy_sandbox/base_dialog_test.ts
@@ -6,13 +6,16 @@ import 'chrome://privacy-sandbox-base-dialog/topics_consent_notice.js'; import 'chrome://privacy-sandbox-base-dialog/protected_audience_measurement_notice.js'; import 'chrome://privacy-sandbox-base-dialog/three_ads_apis_notice.js'; +import 'chrome://privacy-sandbox-base-dialog/base_dialog_learn_more.js'; import type {BaseDialogPageRemote} from 'chrome://privacy-sandbox-base-dialog/base_dialog.mojom-webui.js'; import type {BaseDialogApp} from 'chrome://privacy-sandbox-base-dialog/base_dialog_app.js'; import {BaseDialogBrowserProxy} from 'chrome://privacy-sandbox-base-dialog/base_dialog_browser_proxy.js'; +import type {BaseDialogLearnMore} from 'chrome://privacy-sandbox-base-dialog/base_dialog_learn_more.js'; import {PrivacySandboxNotice, PrivacySandboxNoticeEvent} from 'chrome://privacy-sandbox-base-dialog/notice.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {microtasksFinished} from 'chrome://webui-test/test_util.js'; import type {TestBaseDialogPageHandler} from './test_base_dialog_browser_proxy.js'; import {TestBaseDialogBrowserProxy} from './test_base_dialog_browser_proxy.js'; @@ -257,3 +260,31 @@ PrivacySandboxNoticeEvent.kAck, testHandler); }); }); + +suite('BaseDialogLearnMore', function() { + let learnMoreElement: BaseDialogLearnMore; + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + learnMoreElement = document.createElement('base-dialog-learn-more'); + document.body.appendChild(learnMoreElement); + }); + + test('ExpandAndCollapse', async function() { + const expandButton = + learnMoreElement.shadowRoot.querySelector('cr-expand-button'); + assertTrue(!!expandButton); + // Ensure it's initially collapsed + const collapse = learnMoreElement.shadowRoot.querySelector('cr-collapse'); + assertTrue(!!collapse); + assertFalse(collapse.opened); + // Expand and ensure it's open + expandButton.click(); + await microtasksFinished(); + assertTrue(collapse.opened); + // // Collapse and ensure it's closed + expandButton.click(); + await microtasksFinished(); + assertFalse(collapse.opened); + }); +});
diff --git a/chrome/updater/app/server/win/com_classes_legacy_unittest.cc b/chrome/updater/app/server/win/com_classes_legacy_unittest.cc index 480fd37..dd4ee73 100644 --- a/chrome/updater/app/server/win/com_classes_legacy_unittest.cc +++ b/chrome/updater/app/server/win/com_classes_legacy_unittest.cc
@@ -17,6 +17,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/path_service.h" #include "base/strings/strcat.h" +#include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/test/bind.h" #include "base/test/task_environment.h"
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index bd7c647..fb9b5d7c 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -237,6 +237,7 @@ "//chromecast/media/cdm:cdm_origin_provider", "//chromecast/media/common:media_pipeline_backend_manager", "//chromecast/media/service", + "//chromecast/media/service:video_geometry_setter_service", "//chromecast/media/service/mojom", "//chromecast/net", "//chromecast/net:connectivity_checker",
diff --git a/chromecast/media/service/BUILD.gn b/chromecast/media/service/BUILD.gn index 6b5fd743..022afb67 100644 --- a/chromecast/media/service/BUILD.gn +++ b/chromecast/media/service/BUILD.gn
@@ -10,8 +10,6 @@ "cast_mojo_media_client.h", "cast_renderer.cc", "cast_renderer.h", - "video_geometry_setter_service.cc", - "video_geometry_setter_service.h", ] public_deps = [ @@ -20,6 +18,7 @@ ] deps = [ + ":video_geometry_setter_service", "//base", "//chromecast/base", "//chromecast/common/mojom", @@ -30,3 +29,15 @@ "//ui/gfx/geometry", ] } + +cast_source_set("video_geometry_setter_service") { + sources = [ + "video_geometry_setter_service.cc", + "video_geometry_setter_service.h", + ] + deps = [ + "//base", + "//chromecast/media/service/mojom", + "//mojo/public/cpp/bindings", + ] +}
diff --git a/chromecast/starboard/DEPS b/chromecast/starboard/DEPS index 51e3da6..18d9b76 100644 --- a/chromecast/starboard/DEPS +++ b/chromecast/starboard/DEPS
@@ -2,7 +2,11 @@ "+chromecast/media", "+google_apis", "+media/base", + "+mojo/core/embedder", + "+mojo/public/cpp/bindings", "+ui/base", + "+ui/display", "+ui/events", + "+ui/gfx", "+ui/platform_window", ]
diff --git a/chromecast/starboard/media/BUILD.gn b/chromecast/starboard/media/BUILD.gn index 08250a3..abe5bc3 100644 --- a/chromecast/starboard/media/BUILD.gn +++ b/chromecast/starboard/media/BUILD.gn
@@ -15,5 +15,8 @@ "//chromecast/starboard/media/media:starboard_resampler_test", "//chromecast/starboard/media/media:starboard_video_decoder_test", "//chromecast/starboard/media/media:starboard_video_plane_test", + "//chromecast/starboard/media/renderer:chromium_starboard_conversions_test", + "//chromecast/starboard/media/renderer:client_stats_tracker_test", + "//chromecast/starboard/media/renderer:demuxer_stream_reader_test", ] }
diff --git a/chromecast/starboard/media/media/BUILD.gn b/chromecast/starboard/media/media/BUILD.gn index 1f9fab3..1d8944b 100644 --- a/chromecast/starboard/media/media/BUILD.gn +++ b/chromecast/starboard/media/media/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//chromecast/build/tests/cast_test.gni") import("//chromecast/chromecast.gni") import("//chromecast/starboard/starboard.gni") import("//testing/test.gni") @@ -11,19 +12,23 @@ "//chromecast/starboard/third_party/starboard/sabi/base_configuration.gni") } +# This is necessary until code under //chromecast/starboard/media/renderer is +# hooked up to production code. This way, gn can find those test targets. +cast_test_group("starboard_renderer_tests") { + tests = [ + "//chromecast/starboard/media/renderer:chromium_starboard_conversions_test", + ] +} + source_set("starboard") { sources = [ "cast_media_starboard.cc", - "drm_util.cc", - "drm_util.h", "media_pipeline_backend_starboard.cc", "media_pipeline_backend_starboard.h", "starboard_audio_decoder.cc", "starboard_audio_decoder.h", "starboard_decoder.cc", "starboard_decoder.h", - "starboard_resampler.cc", - "starboard_resampler.h", "starboard_video_decoder.cc", "starboard_video_decoder.h", "starboard_video_plane.cc", @@ -31,8 +36,10 @@ "starboard_volume_control.cc", ] deps = [ + ":drm_util", ":mime_utils", ":starboard_api_wrapper", + ":starboard_resampler", "//base", "//chromecast/base", "//chromecast/public", @@ -46,6 +53,31 @@ ] } +source_set("starboard_resampler") { + sources = [ + "starboard_resampler.cc", + "starboard_resampler.h", + ] + deps = [ + "//base", + "//chromecast/public/media", + "//chromecast/starboard/chromecast/starboard_cast_api:cast_starboard_api_types", + "//media", + ] +} + +source_set("drm_util") { + sources = [ + "drm_util.cc", + "drm_util.h", + ] + deps = [ + ":starboard_api_wrapper", + "//chromecast/public/media", + "//media", + ] +} + source_set("mock_starboard_api_wrapper") { testonly = true sources = [ @@ -96,9 +128,23 @@ "mime_utils.cc", "mime_utils.h", ] + public_deps = [ + "//chromecast/public/media", + "//media", + ] deps = [ "//base", - "//chromecast/public/media", + "//chromecast/media/base:media_codec_support", + ] +} + +source_set("test_matchers") { + testonly = true + public = [ "test_matchers.h" ] + sources = [ "test_matchers.cc" ] + public_deps = [ + ":starboard_api_wrapper", + "//testing/gmock", ] } @@ -160,6 +206,7 @@ ":mock_starboard_api_wrapper", ":starboard", ":starboard_api_wrapper", + ":starboard_resampler", "//base/test:run_all_unittests", "//base/test:test_support", "//chromecast/media/base", @@ -188,8 +235,23 @@ deps = [ ":mime_utils", "//base/test:run_all_unittests", + "//chromecast/media/base:media_codec_support", "//chromecast/public/media", "//testing/gmock", "//testing/gtest", ] } + +test("drm_util_test") { + sources = [ "drm_util_test.cc" ] + deps = [ + ":drm_util", + ":test_matchers", + "//base", + "//base/test:run_all_unittests", + "//chromecast/media/cma/base", + "//media", + "//testing/gmock", + "//testing/gtest", + ] +}
diff --git a/chromecast/starboard/media/media/drm_util.cc b/chromecast/starboard/media/media/drm_util.cc index 532b435..549fb42 100644 --- a/chromecast/starboard/media/media/drm_util.cc +++ b/chromecast/starboard/media/media/drm_util.cc
@@ -15,9 +15,9 @@ // Rather than hard-coding values here, we simply read the length of the // relevant arrays in StarboardDrmSampleInfo. -constexpr int kMaxIvLength = +constexpr size_t kMaxIvLength = std::size(StarboardDrmSampleInfo{}.initialization_vector); -constexpr int kMaxIdLength = std::size(StarboardDrmSampleInfo{}.identifier); +constexpr size_t kMaxIdLength = std::size(StarboardDrmSampleInfo{}.identifier); DrmInfoWrapper::DrmInfoWrapper() = default; @@ -114,5 +114,95 @@ return DrmInfoWrapper(std::move(drm_info), std::move(subsample_mappings)); } +DrmInfoWrapper DrmInfoWrapper::Create(const ::media::DecoderBuffer& buffer) { + if (buffer.decrypt_config() == nullptr) { + return DrmInfoWrapper(); + } + + // Populate drm_sample_info. + auto drm_info = std::make_unique<StarboardDrmSampleInfo>(); + + const ::media::DecryptConfig& decrypt_config = *buffer.decrypt_config(); + switch (decrypt_config.encryption_scheme()) { + case ::media::EncryptionScheme::kUnencrypted: + return DrmInfoWrapper(); + case ::media::EncryptionScheme::kCenc: + drm_info->encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCtr; + break; + case ::media::EncryptionScheme::kCbcs: + drm_info->encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCbc; + break; + default: + LOG(ERROR) << "Unsupported DRM encryption scheme: " + << decrypt_config.encryption_scheme(); + return DrmInfoWrapper(); + } + + // Populate drm_sample_info. + if (decrypt_config.HasPattern()) { + drm_info->encryption_pattern.crypt_byte_block = + decrypt_config.encryption_pattern()->crypt_byte_block(); + drm_info->encryption_pattern.skip_byte_block = + decrypt_config.encryption_pattern()->skip_byte_block(); + } + + size_t iv_size = decrypt_config.iv().size(); + if (iv_size > kMaxIvLength) { + LOG(ERROR) + << "Encrypted buffer contained too many initialization vector values " + "(max supported by Starboard is " + << kMaxIvLength << "): " << iv_size; + iv_size = kMaxIvLength; + } + + // Populate drm_info->initialization_vector. + base::span<uint8_t>(drm_info->initialization_vector) + .first(iv_size) + .copy_from_nonoverlapping( + base::as_byte_span(decrypt_config.iv()).first(iv_size)); + drm_info->initialization_vector_size = iv_size; + + size_t id_size = decrypt_config.key_id().size(); + if (id_size > kMaxIdLength) { + LOG(ERROR) << "Encrypted buffer contained too many key ID vector values " + "(max supported by Starboard is " + << kMaxIdLength << "): " << id_size; + id_size = kMaxIdLength; + } + + // Populate drm_info->identifier. + base::span<uint8_t>(drm_info->identifier) + .first(id_size) + .copy_from_nonoverlapping( + base::as_byte_span(decrypt_config.key_id()).first(id_size)); + drm_info->identifier_size = id_size; + + // Populate subsample_mappings. + auto subsample_mappings = + std::make_unique<std::vector<StarboardDrmSubSampleMapping>>(); + subsample_mappings->reserve(decrypt_config.subsamples().size()); + for (const ::media::SubsampleEntry& subsample : decrypt_config.subsamples()) { + StarboardDrmSubSampleMapping mapping; + mapping.clear_byte_count = subsample.clear_bytes; + mapping.encrypted_byte_count = subsample.cypher_bytes; + subsample_mappings->push_back(std::move(mapping)); + } + + if (subsample_mappings->empty()) { + // DecryptConfig may contain 0 subsamples if all content is encrypted. Map + // this case to a single fully-encrypted "subsample", since Starboard + // requires at least one subsample. + subsample_mappings->push_back( + {.clear_byte_count = 0, + .encrypted_byte_count = static_cast<int32_t>(buffer.size())}); + } + drm_info->subsample_mapping = + base::span<const StarboardDrmSubSampleMapping>(*subsample_mappings); + + return DrmInfoWrapper(std::move(drm_info), std::move(subsample_mappings)); +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/starboard/media/media/drm_util.h b/chromecast/starboard/media/media/drm_util.h index 3cc55c020..8bdf486 100644 --- a/chromecast/starboard/media/media/drm_util.h +++ b/chromecast/starboard/media/media/drm_util.h
@@ -11,6 +11,7 @@ #include "chromecast/public/media/cast_decoder_buffer.h" #include "chromecast/public/media/cast_decrypt_config.h" #include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/decoder_buffer.h" namespace chromecast { namespace media { @@ -26,11 +27,16 @@ // Instances of this class should be created via DrmInfoWrapper::Create(). class DrmInfoWrapper { public: + // TODO(antoniori): deprecate this version after moving to StarboardRenderer. + // // Extracts and returns DRM info from `buffer`. If the buffer is not - // encrypted, the StarboardDrmSampleInfo returned by GetDrmSampleInfo will be - // null. + // encrypted, GetDrmSampleInfo() will return null. static DrmInfoWrapper Create(const CastDecoderBuffer& buffer); + // Extracts and returns DRM info from `buffer`. If the buffer is not + // encrypted, GetDrmSampleInfo() will return null. + static DrmInfoWrapper Create(const ::media::DecoderBuffer& buffer); + // DrmInfoWrapper is movable but not copyable. DrmInfoWrapper(DrmInfoWrapper&& other); DrmInfoWrapper& operator=(DrmInfoWrapper&& other);
diff --git a/chromecast/starboard/media/media/drm_util_test.cc b/chromecast/starboard/media/media/drm_util_test.cc new file mode 100644 index 0000000..2c9747b02 --- /dev/null +++ b/chromecast/starboard/media/media/drm_util_test.cc
@@ -0,0 +1,211 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/media/drm_util.h" + +#include <array> +#include <memory> +#include <optional> +#include <string> +#include <string_view> + +#include "base/containers/span.h" +#include "base/memory/scoped_refptr.h" +#include "chromecast/media/cma/base/decoder_buffer_adapter.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "chromecast/starboard/media/media/test_matchers.h" +#include "media/base/decoder_buffer.h" +#include "media/base/decrypt_config.h" +#include "media/base/encryption_pattern.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromecast { +namespace media { +namespace { + +using ::testing::IsNull; +using ::testing::Pointee; + +constexpr auto kDefaultBufferData = + std::to_array<uint8_t>({1, 2, 3, 4, 5, 6, 7}); + +// Creates a chromium buffer from the given decrypt config and data. +scoped_refptr<::media::DecoderBuffer> CreateChromiumBuffer( + std::unique_ptr<::media::DecryptConfig> decrypt_config, + base::span<const uint8_t> data = kDefaultBufferData) { + scoped_refptr<::media::DecoderBuffer> buffer = + ::media::DecoderBuffer::CopyFrom(data); + CHECK(buffer); + buffer->set_decrypt_config(std::move(decrypt_config)); + return buffer; +} + +TEST(DrmUtilTest, UnencryptedBufferHasNullDrmSampleInfo) { + scoped_refptr<::media::DecoderBuffer> chromium_buffer = + CreateChromiumBuffer(/*decrypt_config=*/nullptr); + CHECK(chromium_buffer); + + EXPECT_THAT(DrmInfoWrapper::Create(*chromium_buffer).GetDrmSampleInfo(), + IsNull()); + + // Check the version that uses CastDecoderBuffer. + auto cast_buffer = + base::MakeRefCounted<DecoderBufferAdapter>(chromium_buffer); + CHECK(cast_buffer); + EXPECT_THAT(DrmInfoWrapper::Create(*cast_buffer).GetDrmSampleInfo(), + IsNull()); +} + +TEST(DrmUtilTest, CreatesCencDrmInfo) { + constexpr std::string_view kId = "drm_id"; + constexpr std::string_view kIv = "0123456789abcdef"; + CHECK_EQ(kIv.size(), + static_cast<size_t>(::media::DecryptConfig::kDecryptionKeySize)); + const ::media::SubsampleEntry subsample(2, 5); + StarboardDrmSubSampleMapping sb_subsample; + sb_subsample.clear_byte_count = subsample.clear_bytes; + sb_subsample.encrypted_byte_count = subsample.cypher_bytes; + + std::unique_ptr<::media::DecryptConfig> decrypt_config = + ::media::DecryptConfig::CreateCencConfig(std::string(kId), + std::string(kIv), {subsample}); + CHECK(decrypt_config); + + scoped_refptr<::media::DecoderBuffer> chromium_buffer = + CreateChromiumBuffer(std::move(decrypt_config)); + CHECK(chromium_buffer); + + DrmInfoWrapper wrapper = DrmInfoWrapper::Create(*chromium_buffer); + + StarboardDrmSampleInfo expected_drm_info; + expected_drm_info.encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCtr; + expected_drm_info.encryption_pattern.crypt_byte_block = 0; + expected_drm_info.encryption_pattern.skip_byte_block = 0; + base::span<uint8_t>(expected_drm_info.initialization_vector) + .copy_from_nonoverlapping(base::as_byte_span(kIv)); + expected_drm_info.initialization_vector_size = kIv.size(); + base::span<uint8_t>(expected_drm_info.identifier) + .first<kId.size()>() + .copy_from_nonoverlapping(base::as_byte_span(kId)); + expected_drm_info.identifier_size = kId.size(); + expected_drm_info.subsample_mapping = base::span_from_ref(sb_subsample); + + EXPECT_THAT(DrmInfoWrapper::Create(*chromium_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); + + // Check the version that uses CastDecoderBuffer. + auto cast_buffer = + base::MakeRefCounted<DecoderBufferAdapter>(chromium_buffer); + CHECK(cast_buffer); + EXPECT_THAT(DrmInfoWrapper::Create(*cast_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); +} + +TEST(DrmUtilTest, CreatesCbcsDrmInfo) { + constexpr std::string_view kId = "drm_id_2"; + constexpr std::string_view kIv = "abcdefghijklmnop"; + CHECK_EQ(kIv.size(), + static_cast<size_t>(::media::DecryptConfig::kDecryptionKeySize)); + const ::media::EncryptionPattern encryption_pattern(10, 20); + const ::media::SubsampleEntry subsample(1, 6); + StarboardDrmSubSampleMapping sb_subsample; + sb_subsample.clear_byte_count = subsample.clear_bytes; + sb_subsample.encrypted_byte_count = subsample.cypher_bytes; + + std::unique_ptr<::media::DecryptConfig> decrypt_config = + ::media::DecryptConfig::CreateCbcsConfig( + std::string(kId), std::string(kIv), {subsample}, encryption_pattern); + CHECK(decrypt_config); + + scoped_refptr<::media::DecoderBuffer> chromium_buffer = + CreateChromiumBuffer(std::move(decrypt_config)); + CHECK(chromium_buffer); + + DrmInfoWrapper wrapper = DrmInfoWrapper::Create(*chromium_buffer); + + StarboardDrmSampleInfo expected_drm_info; + expected_drm_info.encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCbc; + expected_drm_info.encryption_pattern.crypt_byte_block = + encryption_pattern.crypt_byte_block(); + expected_drm_info.encryption_pattern.skip_byte_block = + encryption_pattern.skip_byte_block(); + base::span<uint8_t>(expected_drm_info.initialization_vector) + .copy_from_nonoverlapping(base::as_byte_span(kIv)); + expected_drm_info.initialization_vector_size = kIv.size(); + base::span<uint8_t>(expected_drm_info.identifier) + .first<kId.size()>() + .copy_from_nonoverlapping(base::as_byte_span(kId)); + expected_drm_info.identifier_size = kId.size(); + expected_drm_info.subsample_mapping = base::span_from_ref(sb_subsample); + + EXPECT_THAT(DrmInfoWrapper::Create(*chromium_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); + + // Check the version that uses CastDecoderBuffer. + auto cast_buffer = + base::MakeRefCounted<DecoderBufferAdapter>(chromium_buffer); + CHECK(cast_buffer); + EXPECT_THAT(DrmInfoWrapper::Create(*cast_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); +} + +TEST(DrmUtilTest, HandlesEmptySubsampleMappings) { + // Chromium buffers might not specify a subsample mapping. We should assume + // that the entire buffer is encrypted, in that case. + constexpr auto kBufferData = std::to_array<uint8_t>({7, 8, 9}); + constexpr std::string_view kId = "drm_id"; + constexpr std::string_view kIv = "0123456789abcdef"; + CHECK_EQ(kIv.size(), + static_cast<size_t>(::media::DecryptConfig::kDecryptionKeySize)); + + std::unique_ptr<::media::DecryptConfig> decrypt_config = + ::media::DecryptConfig::CreateCencConfig( + std::string(kId), std::string(kIv), /*subsamples=*/{}); + CHECK(decrypt_config); + + scoped_refptr<::media::DecoderBuffer> chromium_buffer = + CreateChromiumBuffer(std::move(decrypt_config), /*data=*/kBufferData); + CHECK(chromium_buffer); + + DrmInfoWrapper wrapper = DrmInfoWrapper::Create(*chromium_buffer); + + StarboardDrmSampleInfo expected_drm_info; + expected_drm_info.encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCtr; + expected_drm_info.encryption_pattern.crypt_byte_block = 0; + expected_drm_info.encryption_pattern.skip_byte_block = 0; + base::span<uint8_t>(expected_drm_info.initialization_vector) + .copy_from_nonoverlapping(base::as_byte_span(kIv)); + expected_drm_info.initialization_vector_size = kIv.size(); + base::span<uint8_t>(expected_drm_info.identifier) + .first<kId.size()>() + .copy_from_nonoverlapping(base::as_byte_span(kId)); + expected_drm_info.identifier_size = kId.size(); + + // There should be a single subsample mapping specifying that the entire + // buffer is encrypted. + StarboardDrmSubSampleMapping sb_subsample; + sb_subsample.clear_byte_count = 0; + sb_subsample.encrypted_byte_count = kBufferData.size(); + expected_drm_info.subsample_mapping = base::span_from_ref(sb_subsample); + + EXPECT_THAT(DrmInfoWrapper::Create(*chromium_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); + + // Check the version that uses CastDecoderBuffer. The cast code that converts + // from chromium structs -> cast structs should have performed the same logic + // of creating a single subsample mapping. + auto cast_buffer = + base::MakeRefCounted<DecoderBufferAdapter>(chromium_buffer); + CHECK(cast_buffer); + EXPECT_THAT(DrmInfoWrapper::Create(*cast_buffer).GetDrmSampleInfo(), + Pointee(MatchesDrmInfo(expected_drm_info))); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/media/mime_utils.cc b/chromecast/starboard/media/media/mime_utils.cc index f134982..b20afe78 100644 --- a/chromecast/starboard/media/media/mime_utils.cc +++ b/chromecast/starboard/media/media/mime_utils.cc
@@ -4,12 +4,14 @@ #include "chromecast/starboard/media/media/mime_utils.h" +#include <limits> #include <string> #include <string_view> #include "base/containers/fixed_flat_map.h" #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "chromecast/media/base/media_codec_support.h" namespace chromecast { namespace media { @@ -190,6 +192,18 @@ } } +std::string GetMimeType(::media::VideoCodec codec, + ::media::VideoCodecProfile profile, + uint32_t level) { + // Ensure that `level` can be converted to int32_t safely. + if (int64_t{level} > int64_t{std::numeric_limits<int32_t>::max()}) { + LOG(ERROR) << "Invalid codec level: " << level; + return ""; + } + return GetMimeType(ToCastVideoCodec(codec, profile), + ToCastVideoProfile(profile), static_cast<int32_t>(level)); +} + std::string GetMimeType(AudioCodec codec) { if (auto it = kAudioCodecToMime.find(codec); it != kAudioCodecToMime.end()) { return std::string(it->second); @@ -197,5 +211,9 @@ return ""; } +std::string GetMimeType(::media::AudioCodec codec) { + return GetMimeType(ToCastAudioCodec(codec)); +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/starboard/media/media/mime_utils.h b/chromecast/starboard/media/media/mime_utils.h index f60baec..fe0e36fc 100644 --- a/chromecast/starboard/media/media/mime_utils.h +++ b/chromecast/starboard/media/media/mime_utils.h
@@ -9,6 +9,8 @@ #include <string> #include "chromecast/public/media/decoder_config.h" +#include "media/base/audio_codecs.h" +#include "media/base/video_codecs.h" namespace chromecast { namespace media { @@ -21,6 +23,11 @@ // If a MIME type cannot be determined, an empty string is returned. std::string GetMimeType(VideoCodec codec, VideoProfile profile, int32_t level); +// Same as above, but uses chromium enums. +std::string GetMimeType(::media::VideoCodec codec, + ::media::VideoCodecProfile profile, + uint32_t level); + // Returns the MIME string for the given audio codec. Container is guessed in a // way that should be compatible with Starboard's checks (e.g. for opus we guess // webm). Ideally Starboard should not care about the container, since they do @@ -29,6 +36,9 @@ // If a MIME type cannot be determined, an empty string is returned. std::string GetMimeType(AudioCodec codec); +// Same as above, but uses the chromium version of the codec enum. +std::string GetMimeType(::media::AudioCodec codec); + } // namespace media } // namespace chromecast
diff --git a/chromecast/starboard/media/media/mime_utils_test.cc b/chromecast/starboard/media/media/mime_utils_test.cc index 2b46ee7..40877e2 100644 --- a/chromecast/starboard/media/media/mime_utils_test.cc +++ b/chromecast/starboard/media/media/mime_utils_test.cc
@@ -7,7 +7,9 @@ #include <string> #include <vector> +#include "chromecast/media/base/media_codec_support.h" #include "chromecast/public/media/decoder_config.h" +#include "media/base/video_codecs.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,13 +21,13 @@ // Holds video codec info and the corresponding MIME type. struct VideoCodecInfoAndMime { - CodecProfileLevel codec_profile_level; + ::media::CodecProfileLevel codec_profile_level; std::string mime; }; // Holds audio codec info and the corresponding MIME type. struct AudioCodecInfoAndMime { - AudioCodec codec; + ::media::AudioCodec codec; std::string mime; }; @@ -36,154 +38,212 @@ std::vector<VideoCodecInfoAndMime> out; // h.264 baseline profile. - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264Baseline, - .level = 30}, - .mime = R"-(video/mp4; codecs="avc1.42E01E")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264Baseline, - .level = 31}, - .mime = R"-(video/mp4; codecs="avc1.42E01F")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kH264, + .profile = ::media::VideoCodecProfile::H264PROFILE_BASELINE, + .level = 30}, + .mime = R"-(video/mp4; codecs="avc1.42E01E")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kH264, + .profile = ::media::VideoCodecProfile::H264PROFILE_BASELINE, + .level = 31}, + .mime = R"-(video/mp4; codecs="avc1.42E01F")-"}); // h.264 main profile. - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264Main, - .level = 31}, - .mime = R"-(video/mp4; codecs="avc1.4D401F")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264Main, - .level = 40}, - .mime = R"-(video/mp4; codecs="avc1.4D4028")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kH264, + .profile = + ::media::VideoCodecProfile::H264PROFILE_MAIN, + .level = 31}, + .mime = R"-(video/mp4; codecs="avc1.4D401F")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kH264, + .profile = + ::media::VideoCodecProfile::H264PROFILE_MAIN, + .level = 40}, + .mime = R"-(video/mp4; codecs="avc1.4D4028")-"}); // h.264 high profile. - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264High, - .level = 40}, - .mime = R"-(video/mp4; codecs="avc1.640028")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264High, - .level = 41}, - .mime = R"-(video/mp4; codecs="avc1.640029")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecH264, - .profile = kH264High, - .level = 42}, - .mime = R"-(video/mp4; codecs="avc1.64002A")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kH264, + .profile = + ::media::VideoCodecProfile::H264PROFILE_HIGH, + .level = 40}, + .mime = R"-(video/mp4; codecs="avc1.640028")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kH264, + .profile = + ::media::VideoCodecProfile::H264PROFILE_HIGH, + .level = 41}, + .mime = R"-(video/mp4; codecs="avc1.640029")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kH264, + .profile = + ::media::VideoCodecProfile::H264PROFILE_HIGH, + .level = 42}, + .mime = R"-(video/mp4; codecs="avc1.64002A")-"}); // HEVC main profile. - out.push_back({.codec_profile_level = {.codec = kCodecHEVC, - .profile = kHEVCMain, - .level = 150}, - .mime = R"-(video/mp4; codecs="hev1.1.6.L150.B0")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecHEVC, - .profile = kHEVCMain, - .level = 153}, - .mime = R"-(video/mp4; codecs="hev1.1.6.L153.B0")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kHEVC, + .profile = + ::media::VideoCodecProfile::HEVCPROFILE_MAIN, + .level = 150}, + .mime = R"-(video/mp4; codecs="hev1.1.6.L150.B0")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kHEVC, + .profile = + ::media::VideoCodecProfile::HEVCPROFILE_MAIN, + .level = 153}, + .mime = R"-(video/mp4; codecs="hev1.1.6.L153.B0")-"}); // HEVC main10 profile. - out.push_back({.codec_profile_level = {.codec = kCodecHEVC, - .profile = kHEVCMain10, - .level = 150}, + out.push_back({.codec_profile_level = + {.codec = ::media::VideoCodec::kHEVC, + .profile = ::media::VideoCodecProfile::HEVCPROFILE_MAIN10, + .level = 150}, .mime = R"-(video/mp4; codecs="hev1.2.6.L150.B0")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecHEVC, - .profile = kHEVCMain10, - .level = 153}, + out.push_back({.codec_profile_level = + {.codec = ::media::VideoCodec::kHEVC, + .profile = ::media::VideoCodecProfile::HEVCPROFILE_MAIN10, + .level = 153}, .mime = R"-(video/mp4; codecs="hev1.2.6.L153.B0")-"}); // VP8. - out.push_back({.codec_profile_level = {.codec = kCodecVP8, - .profile = kVP8ProfileAny, - .level = 0}, - .mime = R"-(video/webm; codecs="vp8")-"}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kVP8, + .profile = + ::media::VideoCodecProfile::VP8PROFILE_ANY, + .level = 0}, + .mime = R"-(video/webm; codecs="vp8")-"}); // VP9. Note that these assume bit depth 10, since the chromium code does not // include bit depth when checking decoder support for the codec. - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile0, - .level = 10}, - .mime = R"-(video/webm; codecs="vp09.00.10.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile1, - .level = 10}, - .mime = R"-(video/webm; codecs="vp09.01.10.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile2, - .level = 10}, - .mime = R"-(video/webm; codecs="vp09.02.10.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile3, - .level = 10}, - .mime = R"-(video/webm; codecs="vp09.03.10.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE0, + .level = 10}, + .mime = R"-(video/webm; codecs="vp09.00.10.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE1, + .level = 10}, + .mime = R"-(video/webm; codecs="vp09.01.10.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE2, + .level = 10}, + .mime = R"-(video/webm; codecs="vp09.02.10.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE3, + .level = 10}, + .mime = R"-(video/webm; codecs="vp09.03.10.10")-"}); // Check VP9 with a different level. There are many supported levels, so we do // not include all possible values. - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile0, - .level = 62}, - .mime = R"-(video/webm; codecs="vp09.00.62.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile1, - .level = 62}, - .mime = R"-(video/webm; codecs="vp09.01.62.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile2, - .level = 62}, - .mime = R"-(video/webm; codecs="vp09.02.62.10")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kVP9Profile3, - .level = 62}, - .mime = R"-(video/webm; codecs="vp09.03.62.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE0, + .level = 62}, + .mime = R"-(video/webm; codecs="vp09.00.62.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE1, + .level = 62}, + .mime = R"-(video/webm; codecs="vp09.01.62.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE2, + .level = 62}, + .mime = R"-(video/webm; codecs="vp09.02.62.10")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kVP9, + .profile = ::media::VideoCodecProfile::VP9PROFILE_PROFILE3, + .level = 62}, + .mime = R"-(video/webm; codecs="vp09.03.62.10")-"}); // Dolby Vision profile 5. - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile5, - .level = 6}, - .mime = R"-(video/mp4; codecs="dvhe.05.06")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile5, - .level = 7}, - .mime = R"-(video/mp4; codecs="dvhe.05.07")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile5, - .level = 9}, - .mime = R"-(video/mp4; codecs="dvhe.05.09")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE5, + .level = 6}, + .mime = R"-(video/mp4; codecs="dvhe.05.06")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE5, + .level = 7}, + .mime = R"-(video/mp4; codecs="dvhe.05.07")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE5, + .level = 9}, + .mime = R"-(video/mp4; codecs="dvhe.05.09")-"}); // Dolby Vision profile 8. - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile8, - .level = 6}, - .mime = R"-(video/mp4; codecs="dvhe.08.06")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile8, - .level = 7}, - .mime = R"-(video/mp4; codecs="dvhe.08.07")-"}); - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile8, - .level = 9}, - .mime = R"-(video/mp4; codecs="dvhe.08.09")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE8, + .level = 6}, + .mime = R"-(video/mp4; codecs="dvhe.08.06")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE8, + .level = 7}, + .mime = R"-(video/mp4; codecs="dvhe.08.07")-"}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE8, + .level = 9}, + .mime = R"-(video/mp4; codecs="dvhe.08.09")-"}); // Unsupported cases should return an empty string for the MIME type. - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile5, - .level = 11}, - .mime = ""}); - out.push_back({.codec_profile_level = {.codec = kCodecDolbyVisionHEVC, - .profile = kDolbyVisionProfile8, - .level = 11}, - .mime = ""}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE5, + .level = 11}, + .mime = ""}); + out.push_back( + {.codec_profile_level = + {.codec = ::media::VideoCodec::kDolbyVision, + .profile = ::media::VideoCodecProfile::DOLBYVISION_PROFILE8, + .level = 11}, + .mime = ""}); // Invalid codec/profile/level combinations should return an empty string. // Mixed h.264 profile with HEVC codec. - out.push_back({.codec_profile_level = {.codec = kCodecHEVC, - .profile = kH264Main, - .level = 150}, - .mime = ""}); + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kHEVC, + .profile = + ::media::VideoCodecProfile::H264PROFILE_MAIN, + .level = 150}, + .mime = ""}); - // Mixed VP9 with HEVC profile. - out.push_back({.codec_profile_level = {.codec = kCodecVP9, - .profile = kH264Main, - .level = 62}, - .mime = ""}); + // Mixed VP9 with h.264 profile. + out.push_back( + {.codec_profile_level = {.codec = ::media::VideoCodec::kVP9, + .profile = + ::media::VideoCodecProfile::H264PROFILE_MAIN, + .level = 62}, + .mime = ""}); return out; } @@ -195,40 +255,44 @@ std::vector<AudioCodecInfoAndMime> out; // AAC. - out.push_back( - {.codec = kCodecAAC, .mime = R"-(audio/mp4; codecs="mp4a.40.5")-"}); + out.push_back({.codec = ::media::AudioCodec::kAAC, + .mime = R"-(audio/mp4; codecs="mp4a.40.5")-"}); // MP3 - out.push_back( - {.codec = kCodecMP3, .mime = R"-(audio/mp4; codecs="mp4a.69")-"}); + out.push_back({.codec = ::media::AudioCodec::kMP3, + .mime = R"-(audio/mp4; codecs="mp4a.69")-"}); // PCM. - out.push_back({.codec = kCodecPCM, .mime = R"-(audio/wav; codecs="1")-"}); - out.push_back( - {.codec = kCodecPCM_S16BE, .mime = R"-(audio/wav; codecs="1")-"}); + out.push_back({.codec = ::media::AudioCodec::kPCM, + .mime = R"-(audio/wav; codecs="1")-"}); + out.push_back({.codec = ::media::AudioCodec::kPCM_S16BE, + .mime = R"-(audio/wav; codecs="1")-"}); // Vorbis. - out.push_back( - {.codec = kCodecVorbis, .mime = R"-(audio/webm; codecs="vorbis")-"}); + out.push_back({.codec = ::media::AudioCodec::kVorbis, + .mime = R"-(audio/webm; codecs="vorbis")-"}); // Opus. - out.push_back( - {.codec = kCodecOpus, .mime = R"-(audio/webm; codecs="opus")-"}); + out.push_back({.codec = ::media::AudioCodec::kOpus, + .mime = R"-(audio/webm; codecs="opus")-"}); // E-AC-3. - out.push_back({.codec = kCodecEAC3, .mime = R"-(audio/mp4; codecs="ec-3")-"}); + out.push_back({.codec = ::media::AudioCodec::kEAC3, + .mime = R"-(audio/mp4; codecs="ec-3")-"}); // AC-3. - out.push_back({.codec = kCodecAC3, .mime = R"-(audio/mp4; codecs="ac-3")-"}); + out.push_back({.codec = ::media::AudioCodec::kAC3, + .mime = R"-(audio/mp4; codecs="ac-3")-"}); // FLAC. - out.push_back({.codec = kCodecFLAC, .mime = R"-(audio/ogg; codecs="flac")-"}); + out.push_back({.codec = ::media::AudioCodec::kFLAC, + .mime = R"-(audio/ogg; codecs="flac")-"}); // Unsupported codecs should return an empty string. - out.push_back({.codec = kCodecDTS, .mime = ""}); - out.push_back({.codec = kCodecMpegHAudio, .mime = ""}); - out.push_back({.codec = kCodecDTSXP2, .mime = ""}); - out.push_back({.codec = kCodecDTSE, .mime = ""}); + out.push_back({.codec = ::media::AudioCodec::kDTS, .mime = ""}); + out.push_back({.codec = ::media::AudioCodec::kMpegHAudio, .mime = ""}); + out.push_back({.codec = ::media::AudioCodec::kDTSXP2, .mime = ""}); + out.push_back({.codec = ::media::AudioCodec::kDTSE, .mime = ""}); return out; } @@ -237,13 +301,22 @@ using MimeUtilsVideoCodecTest = ::testing::TestWithParam<VideoCodecInfoAndMime>; TEST_P(MimeUtilsVideoCodecTest, ConvertsToMimeType) { - const CodecProfileLevel codec_profile_level = GetParam().codec_profile_level; + const ::media::CodecProfileLevel codec_profile_level = + GetParam().codec_profile_level; const std::string expected_mime = GetParam().mime; + // Check the function that takes chromium enums. EXPECT_THAT( GetMimeType(codec_profile_level.codec, codec_profile_level.profile, codec_profile_level.level), StrEq(expected_mime)); + + // Check the function that takes cast enums. + EXPECT_THAT(GetMimeType(ToCastVideoCodec(codec_profile_level.codec, + codec_profile_level.profile), + ToCastVideoProfile(codec_profile_level.profile), + static_cast<int32_t>(codec_profile_level.level)), + StrEq(expected_mime)); } INSTANTIATE_TEST_SUITE_P(VideoMimeTypes, @@ -254,7 +327,12 @@ using MimeUtilsAudioCodecTest = ::testing::TestWithParam<AudioCodecInfoAndMime>; TEST_P(MimeUtilsAudioCodecTest, ConvertsToMimeType) { + // Check the function that takes ::media::AudioCodec. EXPECT_THAT(GetMimeType(GetParam().codec), StrEq(GetParam().mime)); + + // Check the function that takes ::chromecast::media::AudioCodec. + EXPECT_THAT(GetMimeType(ToCastAudioCodec(GetParam().codec)), + StrEq(GetParam().mime)); } INSTANTIATE_TEST_SUITE_P(AudioMimeTypes,
diff --git a/chromecast/starboard/media/media/starboard_resampler.cc b/chromecast/starboard/media/media/starboard_resampler.cc index 42474d7..e0b364cb 100644 --- a/chromecast/starboard/media/media/starboard_resampler.cc +++ b/chromecast/starboard/media/media/starboard_resampler.cc
@@ -133,6 +133,8 @@ case kStarboardPcmSampleFormatS32: case kStarboardPcmSampleFormatF32: return 4; + default: + LOG(FATAL) << "Unsupported StarboardPcmSampleFormat: " << format; } } @@ -267,6 +269,71 @@ format_to_decode_from == kSampleFormatF32); return !same_format; } + +// Converts from chromium SampleFormat to cast SampleFormat. +// +// TODO(crbug.com/323610278): remove this after deprecating CMA. +SampleFormat ToCastSampleFormat(::media::SampleFormat format) { + switch (format) { + case ::media::kSampleFormatU8: + return kSampleFormatU8; + case ::media::kSampleFormatS16: + return kSampleFormatS16; + case ::media::kSampleFormatS24: + return kSampleFormatS24; + case ::media::kSampleFormatS32: + return kSampleFormatS32; + case ::media::kSampleFormatF32: + return kSampleFormatF32; + case ::media::kSampleFormatPlanarU8: + return kSampleFormatPlanarU8; + case ::media::kSampleFormatPlanarS16: + return kSampleFormatPlanarS16; + case ::media::kSampleFormatPlanarF32: + return kSampleFormatPlanarF32; + case ::media::kSampleFormatPlanarS32: + return kSampleFormatPlanarS32; + default: + LOG(FATAL) << "Unsupported ::media::SampleFormat: " << format; + } +} + +// Converts from chromium AudioCodec to cast AudioCodec. +// +// TODO(crbug.com/323610278): remove this after deprecating CMA. +AudioCodec ToCastAudioCodec(::media::AudioCodec codec) { + switch (codec) { + case ::media::AudioCodec::kAAC: + return kCodecAAC; + case ::media::AudioCodec::kMP3: + return kCodecMP3; + case ::media::AudioCodec::kPCM: + return kCodecPCM; + case ::media::AudioCodec::kPCM_S16BE: + return kCodecPCM_S16BE; + case ::media::AudioCodec::kVorbis: + return kCodecVorbis; + case ::media::AudioCodec::kOpus: + return kCodecOpus; + case ::media::AudioCodec::kFLAC: + return kCodecFLAC; + case ::media::AudioCodec::kEAC3: + return kCodecEAC3; + case ::media::AudioCodec::kAC3: + return kCodecAC3; + case ::media::AudioCodec::kMpegHAudio: + return kCodecMpegHAudio; + case ::media::AudioCodec::kDTS: + return kCodecDTS; + case ::media::AudioCodec::kDTSXP2: + return kCodecDTSXP2; + case ::media::AudioCodec::kDTSE: + return kCodecDTSE; + default: + LOG(FATAL) << "Unsupported audio codec: " << codec; + } +} + } // namespace base::HeapArray<uint8_t> ResamplePCMAudioDataForStarboard( @@ -290,5 +357,16 @@ format_to_decode_to, audio_codec); } +base::HeapArray<uint8_t> ResamplePCMAudioDataForStarboard( + StarboardPcmSampleFormat format_to_decode_to, + ::media::SampleFormat format_to_decode_from, + ::media::AudioCodec audio_codec, + int audio_channels, + base::span<const uint8_t> in_data) { + return ResamplePCMAudioDataForStarboard( + format_to_decode_to, ToCastSampleFormat(format_to_decode_from), + ToCastAudioCodec(audio_codec), audio_channels, in_data); +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_resampler.h b/chromecast/starboard/media/media/starboard_resampler.h index 50f2c09..80a9c1b 100644 --- a/chromecast/starboard/media/media/starboard_resampler.h +++ b/chromecast/starboard/media/media/starboard_resampler.h
@@ -12,6 +12,8 @@ #include "chromecast/public/media/cast_decoder_buffer.h" #include "chromecast/public/media/decoder_config.h" #include "chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api_types.h" +#include "media/base/audio_codecs.h" +#include "media/base/sample_format.h" namespace chromecast { namespace media { @@ -22,8 +24,7 @@ // kCodecPCM_S16BE. `audio_channels` is the number of channels in the input // data, and must be greater than 0. `in_data` contains the input PCM data. // -// TODO(b/334991778): see if we can reuse existing chromium infra to do the -// conversion. +// TODO: crbug.com/323610278 - remove this when cast no longer uses CMA. base::HeapArray<uint8_t> ResamplePCMAudioDataForStarboard( StarboardPcmSampleFormat format_to_decode_to, SampleFormat format_to_decode_from, @@ -31,6 +32,14 @@ int audio_channels, base::span<const uint8_t> in_data); +// Same as above, but uses chromium enums instead of cast ones. +base::HeapArray<uint8_t> ResamplePCMAudioDataForStarboard( + StarboardPcmSampleFormat format_to_decode_to, + ::media::SampleFormat format_to_decode_from, + ::media::AudioCodec audio_codec, + int audio_channels, + base::span<const uint8_t> in_data); + } // namespace media } // namespace chromecast
diff --git a/chromecast/starboard/media/media/starboard_resampler_test.cc b/chromecast/starboard/media/media/starboard_resampler_test.cc index 624f7324..446a6bd 100644 --- a/chromecast/starboard/media/media/starboard_resampler_test.cc +++ b/chromecast/starboard/media/media/starboard_resampler_test.cc
@@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO: crbug.com/323610278 - Remove the "Cast enum version" calls in each test +// once linux cast builds no longer use CMA. + #include "chromecast/starboard/media/media/starboard_resampler.h" #include <cstdint> @@ -49,11 +52,20 @@ const std::vector<int16_t> expected_data = {static_cast<int16_t>(0x8000), 0, 0x7FFF}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS16, kSampleFormatU8, kCodecPCM, 2, buffer_data) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatU8, + ::media::AudioCodec::kPCM, 2, buffer_data) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCM8ToS32) { @@ -61,11 +73,20 @@ const std::vector<int32_t> expected_data = {static_cast<int32_t>(0x80000000), 0, 0x7FFFFFFF}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS32, kSampleFormatU8, kCodecPCM, 2, buffer_data) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS32, ::media::SampleFormat::kSampleFormatU8, + ::media::AudioCodec::kPCM, 2, buffer_data) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMU8ToFloat) { @@ -73,10 +94,18 @@ const std::vector<float> expected_f32_data = {-0.9921875, -0.984375, -0.9765625, -0.96875}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatF32, kSampleFormatU8, kCodecPCM, 2, buffer_data), MatchesFloatSpan(expected_f32_data)); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatF32, ::media::SampleFormat::kSampleFormatU8, + ::media::AudioCodec::kPCM, 2, buffer_data), + MatchesFloatSpan(expected_f32_data)); } ////// END OF U8 TO OTHER FORMATS @@ -86,11 +115,20 @@ const std::vector<int16_t> buffer_data = {-32768, 0, 32767}; const std::vector<int16_t> expected_data = {-32768, 0, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS16, kSampleFormatS16, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatS16, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS16ToS32) { @@ -99,11 +137,20 @@ const std::vector<int32_t> expected_data = {static_cast<int32_t>(0x80000000), 0, 0x7FFFFFFF}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS32, kSampleFormatS16, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS32, ::media::SampleFormat::kSampleFormatS16, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS16ToFloat) { @@ -113,10 +160,18 @@ const std::vector<float> expected_f32_data = {-1.0f, -0.5f, 0.0f, 0.499984741f, 1.0f}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatF32, kSampleFormatS16, kCodecPCM, 2, base::as_byte_span(buffer_data)), MatchesFloatSpan(expected_f32_data)); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatF32, ::media::SampleFormat::kSampleFormatS16, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)), + MatchesFloatSpan(expected_f32_data)); } // End of Signed 16 Conversions @@ -127,11 +182,20 @@ 0, 0xFF, 0xFF, 0x7F}; const std::vector<int16_t> expected_data = {-17493, 0, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS16, kSampleFormatS24, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatS24, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS24ToS32) { @@ -142,11 +206,20 @@ const std::vector<int32_t> expected_data = {static_cast<int32_t>(0x80000000), 0, 0x7FFFFFFF}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS32, kSampleFormatS24, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS32, ::media::SampleFormat::kSampleFormatS24, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS24ToFloat) { @@ -154,10 +227,18 @@ 0, 0xFF, 0xFF, 0x7F}; const std::vector<float> expected_f32_data = {-1.0f, 0.0f, 1.0f}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatF32, kSampleFormatS24, kCodecPCM, 2, base::as_byte_span(buffer_data)), MatchesFloatSpan(expected_f32_data)); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatF32, ::media::SampleFormat::kSampleFormatS24, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)), + MatchesFloatSpan(expected_f32_data)); } // End of Signed 24 Conversions @@ -167,22 +248,40 @@ const std::vector<int32_t> buffer_data = {-2147483648, 0, 70000, 2147483647}; const std::vector<int16_t> expected_data = {-32768, 0, 1, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS16, kSampleFormatS32, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatS32, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS32ToS32) { const std::vector<int32_t> buffer_data = {-2147483647, 0, 2147483647}; const std::vector<int32_t> expected_data = {-2147483647, 0, 2147483647}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatS32, kSampleFormatS32, kCodecPCM, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS32, ::media::SampleFormat::kSampleFormatS32, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMS32ToFloat) { @@ -190,10 +289,18 @@ 0x7FFFFFFF}; const std::vector<float> expected_f32_data = {-1.0f, 0.0f, 1.0f}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard(kStarboardPcmSampleFormatF32, kSampleFormatS32, kCodecPCM, 2, base::as_byte_span(buffer_data)), MatchesFloatSpan(expected_f32_data)); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatF32, ::media::SampleFormat::kSampleFormatS32, + ::media::AudioCodec::kPCM, 2, base::as_byte_span(buffer_data)), + MatchesFloatSpan(expected_f32_data)); } // End of Signed 32 Conversions @@ -203,32 +310,61 @@ const std::vector<float> buffer_data = {-1.0f, 0.0f, 1.0f}; const std::vector<int16_t> expected_data = {-32768, 0, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatF32, kCodecPCM, 2, base::as_byte_span(base::allow_nonunique_obj, buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatF32, + ::media::AudioCodec::kPCM, 2, + base::as_byte_span(base::allow_nonunique_obj, buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMFloatToS32) { const std::vector<float> buffer_data = {-1.0f, 0.0f, 1.0f}; const std::vector<int32_t> expected_data = {-2147483648, 0, 2147483647}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS32, kSampleFormatF32, kCodecPCM, 2, base::as_byte_span(base::allow_nonunique_obj, buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS32, ::media::SampleFormat::kSampleFormatF32, + ::media::AudioCodec::kPCM, 2, + base::as_byte_span(base::allow_nonunique_obj, buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PCMFloatToFloat) { const std::vector<float> buffer_data = {-1, 0.0234375, 0, 1}; const std::vector<float> expected_f32_data = {-1, 0.0234375, 0, 1}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatF32, kSampleFormatF32, kCodecPCM, 2, base::as_byte_span(base::allow_nonunique_obj, buffer_data)), MatchesFloatSpan(expected_f32_data)); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatF32, ::media::SampleFormat::kSampleFormatF32, + ::media::AudioCodec::kPCM, 2, + base::as_byte_span(base::allow_nonunique_obj, buffer_data)), + MatchesFloatSpan(expected_f32_data)); } // End of Float Conversions @@ -240,11 +376,20 @@ const std::vector<int16_t> expected_data = {-32768, 16384, 32767, -32768, 16384, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatPlanarS16, kCodecPCM, 3, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT(ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, + ::media::SampleFormat::kSampleFormatPlanarS16, + ::media::AudioCodec::kPCM, 3, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PushesBufferToStarboardPlanarPCM32) { @@ -254,11 +399,20 @@ const std::vector<int16_t> expected_data = {-32768, 15, 31, 32767, -32768, 15, 31, 32767}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatPlanarS32, kCodecPCM, 4, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT(ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, + ::media::SampleFormat::kSampleFormatPlanarS32, + ::media::AudioCodec::kPCM, 4, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PushesBufferToStarboardPlanarPCMF32) { @@ -267,12 +421,22 @@ const std::vector<int16_t> expected_data = {-32768, 15, 32767, -32768, 15, 32767}; + // Cast enum version. EXPECT_THAT( ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatPlanarF32, kCodecPCM, 3, base::as_byte_span(base::allow_nonunique_obj, buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT(ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, + ::media::SampleFormat::kSampleFormatPlanarF32, + ::media::AudioCodec::kPCM, 3, + base::as_byte_span(base::allow_nonunique_obj, buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PushesBufferToStarboardPlanarPCM32Mono) { @@ -300,11 +464,20 @@ 0x900, 0x7FFF}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatPlanarS32, kCodecPCM, 1, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT(ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, + ::media::SampleFormat::kSampleFormatPlanarS32, + ::media::AudioCodec::kPCM, 1, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, PushesBufferToStarboardPlanarPCM32MaxChannels) { @@ -316,11 +489,20 @@ 0x0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatPlanarS32, kCodecPCM, 8, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT(ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, + ::media::SampleFormat::kSampleFormatPlanarS32, + ::media::AudioCodec::kPCM, 8, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } TEST(StarboardResamplerTest, @@ -328,11 +510,20 @@ const std::vector<int16_t> buffer_data = {32640, 1040, 4100, 255}; const std::vector<int16_t> expected_data = {-32641, 4100, 1040, -256}; + // Cast enum version. EXPECT_THAT(ResamplePCMAudioDataForStarboard( kStarboardPcmSampleFormatS16, kSampleFormatS16, kCodecPCM_S16BE, 2, base::as_byte_span(buffer_data)) .as_span(), ElementsAreArray(base::as_byte_span(expected_data))); + + // Chromium enum version. + EXPECT_THAT( + ResamplePCMAudioDataForStarboard( + kStarboardPcmSampleFormatS16, ::media::SampleFormat::kSampleFormatS16, + ::media::AudioCodec::kPCM_S16BE, 2, base::as_byte_span(buffer_data)) + .as_span(), + ElementsAreArray(base::as_byte_span(expected_data))); } // End of Signed 16 Conversions
diff --git a/chromecast/starboard/media/media/test_matchers.cc b/chromecast/starboard/media/media/test_matchers.cc new file mode 100644 index 0000000..f5a0eb2 --- /dev/null +++ b/chromecast/starboard/media/media/test_matchers.cc
@@ -0,0 +1,282 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/media/test_matchers.h" + +#include <cstdint> +#include <tuple> + +namespace chromecast { +namespace media { + +namespace { + +using ::testing::AllOf; +using ::testing::ElementsAreArray; +using ::testing::Eq; +using ::testing::ExplainMatchResult; +using ::testing::Field; +using ::testing::FloatEq; +using ::testing::IsNull; +using ::testing::Matcher; +using ::testing::Pointee; +using ::testing::Pointwise; +using ::testing::StrEq; + +// Takes an arg that can be converted to a span, and matches the first +// expected.size() values to expected. +MATCHER_P(SpanMatches, expected_span, "") { + base::span<const uint8_t> actual_span = arg; + if (actual_span.size() < expected_span.size()) { + *result_listener << "too few elements (expected at least " + << expected_span.size() << ", got " << actual_span.size() + << ")"; + return false; + } + return ExplainMatchResult(ElementsAreArray(expected_span), + actual_span.first(expected_span.size()), + result_listener); +} + +auto MatchesSubsampleMapping(const StarboardDrmSubSampleMapping& expected) { + return AllOf( + Field("clear_byte_count", &StarboardDrmSubSampleMapping::clear_byte_count, + Eq(expected.clear_byte_count)), + Field("encrypted_byte_count", + &StarboardDrmSubSampleMapping::encrypted_byte_count, + Eq(expected.encrypted_byte_count))); +} + +// Used as an argument to Pointwise. Takes a tuple of +// StarboardDrmSubSampleMapping values and returns whether they are equal +// according to MatchesSubsampleMapping. +MATCHER(MatchesSubsampleMappingTuple, "") { + const StarboardDrmSubSampleMapping left = std::get<0>(arg); + const StarboardDrmSubSampleMapping right = std::get<1>(arg); + return ExplainMatchResult(MatchesSubsampleMapping(right), left, + result_listener); +} + +auto MatchesSideData(const StarboardSampleSideData& expected) { + return AllOf(Field("type", &StarboardSampleSideData::type, Eq(expected.type)), + Field("data", &StarboardSampleSideData::data, + ElementsAreArray(expected.data))); +} + +// Used as an argument to Pointwise. Takes a tuple of StarboardSampleSideData +// values and returns whether they are equal according to MatchesSideData. +MATCHER(MatchesSideDataTuple, "") { + const StarboardSampleSideData left = std::get<0>(arg); + const StarboardSampleSideData right = std::get<1>(arg); + return left.type == right.type && + ExplainMatchResult(MatchesSideData(right), left, result_listener); +} + +auto MatchesMasteringMetadata(const StarboardMediaMasteringMetadata& expected) { + return AllOf( + Field("primary_r_chromaticity_x", + &StarboardMediaMasteringMetadata::primary_r_chromaticity_x, + FloatEq(expected.primary_r_chromaticity_x)), + Field("primary_r_chromaticity_y", + &StarboardMediaMasteringMetadata::primary_r_chromaticity_y, + FloatEq(expected.primary_r_chromaticity_y)), + Field("primary_g_chromaticity_x", + &StarboardMediaMasteringMetadata::primary_g_chromaticity_x, + FloatEq(expected.primary_g_chromaticity_x)), + Field("primary_g_chromaticity_y", + &StarboardMediaMasteringMetadata::primary_g_chromaticity_y, + FloatEq(expected.primary_g_chromaticity_y)), + Field("primary_b_chromaticity_x", + &StarboardMediaMasteringMetadata::primary_b_chromaticity_x, + FloatEq(expected.primary_b_chromaticity_x)), + Field("primary_b_chromaticity_y", + &StarboardMediaMasteringMetadata::primary_b_chromaticity_y, + FloatEq(expected.primary_b_chromaticity_y)), + Field("white_point_chromaticity_x", + &StarboardMediaMasteringMetadata::white_point_chromaticity_x, + FloatEq(expected.white_point_chromaticity_x)), + Field("white_point_chromaticity_y", + &StarboardMediaMasteringMetadata::white_point_chromaticity_y, + FloatEq(expected.white_point_chromaticity_y)), + Field("luminance_max", &StarboardMediaMasteringMetadata::luminance_max, + FloatEq(expected.luminance_max)), + Field("luminance_min", &StarboardMediaMasteringMetadata::luminance_min, + FloatEq(expected.luminance_min))); +} + +auto MatchesColorMetadata(const StarboardColorMetadata& expected) { + return AllOf( + Field("bits_per_channel", &StarboardColorMetadata::bits_per_channel, + Eq(expected.bits_per_channel)), + Field("chroma_subsampling_horizontal", + &StarboardColorMetadata::chroma_subsampling_horizontal, + Eq(expected.chroma_subsampling_horizontal)), + Field("chroma_subsampling_vertical", + &StarboardColorMetadata::chroma_subsampling_vertical, + Eq(expected.chroma_subsampling_vertical)), + Field("cb_subsampling_horizontal", + &StarboardColorMetadata::cb_subsampling_horizontal, + Eq(expected.cb_subsampling_horizontal)), + Field("cb_subsampling_vertical", + &StarboardColorMetadata::cb_subsampling_vertical, + Eq(expected.cb_subsampling_vertical)), + Field("chroma_siting_horizontal", + &StarboardColorMetadata::chroma_siting_horizontal, + Eq(expected.chroma_siting_horizontal)), + Field("chroma_siting_vertical", + &StarboardColorMetadata::chroma_siting_vertical, + Eq(expected.chroma_siting_vertical)), + Field("mastering_metadata", &StarboardColorMetadata::mastering_metadata, + MatchesMasteringMetadata(expected.mastering_metadata)), + Field("max_cll", &StarboardColorMetadata::max_cll, Eq(expected.max_cll)), + Field("max_fall", &StarboardColorMetadata::max_fall, + Eq(expected.max_fall)), + Field("primaries", &StarboardColorMetadata::primaries, + Eq(expected.primaries)), + Field("transfer", &StarboardColorMetadata::transfer, + Eq(expected.transfer)), + Field("matrix", &StarboardColorMetadata::matrix, Eq(expected.matrix)), + Field("range", &StarboardColorMetadata::range, Eq(expected.range)), + Field("custom_primary_matrix", + &StarboardColorMetadata::custom_primary_matrix, + Pointwise(FloatEq(), expected.custom_primary_matrix))); +} + +} // namespace + +Matcher<StarboardSampleInfo> MatchesStarboardSampleInfo( + const StarboardSampleInfo& expected) { + auto common_checks = + AllOf(Field("type", &StarboardSampleInfo::type, Eq(expected.type)), + Field("buffer", &StarboardSampleInfo::buffer, Eq(expected.buffer)), + Field("buffer_size", &StarboardSampleInfo::buffer_size, + Eq(expected.buffer_size)), + Field("timestamp", &StarboardSampleInfo::timestamp, + Eq(expected.timestamp)), + Field("side_data", &StarboardSampleInfo::side_data, + Pointwise(MatchesSideDataTuple(), expected.side_data)), + expected.drm_info == nullptr + ? Field("drm_info", &StarboardSampleInfo::drm_info, IsNull()) + : Field("drm_info", &StarboardSampleInfo::drm_info, + Pointee(MatchesDrmInfo(*expected.drm_info)))); + + // Note that AllOf short circuits, so if there is a mismatch on `type` we + // avoid reading the audio_sample_info/video_sample_info union of the object + // being matched. + if (expected.type == 0) { + // Audio sample. + return AllOf( + common_checks, + Field("audio_sample_info", &StarboardSampleInfo::audio_sample_info, + MatchesAudioSampleInfo(expected.audio_sample_info))); + } else { + // Video sample. + return AllOf( + common_checks, + Field("video_sample_info", &StarboardSampleInfo::video_sample_info, + MatchesVideoSampleInfo(expected.video_sample_info))); + } +} + +Matcher<StarboardAudioSampleInfo> MatchesAudioSampleInfo( + const StarboardAudioSampleInfo& expected) { + return AllOf( + Field("codec", &StarboardAudioSampleInfo::codec, Eq(expected.codec)), + expected.mime == nullptr + ? Field("mime", &StarboardAudioSampleInfo::mime, IsNull()) + : Field("mime", &StarboardAudioSampleInfo::mime, + StrEq(expected.mime)), + Field("format_tag", &StarboardAudioSampleInfo::format_tag, + Eq(expected.format_tag)), + Field("number_of_channels", &StarboardAudioSampleInfo::number_of_channels, + Eq(expected.number_of_channels)), + Field("samples_per_second", &StarboardAudioSampleInfo::samples_per_second, + Eq(expected.samples_per_second)), + Field("average_bytes_per_second", + &StarboardAudioSampleInfo::average_bytes_per_second, + Eq(expected.average_bytes_per_second)), + Field("block_alignment", &StarboardAudioSampleInfo::block_alignment, + Eq(expected.block_alignment)), + Field("bits_per_sample", &StarboardAudioSampleInfo::bits_per_sample, + Eq(expected.bits_per_sample)), + Field("audio_specific_config", + &StarboardAudioSampleInfo::audio_specific_config, + Eq(expected.audio_specific_config)), + Field("audio_specific_config", + &StarboardAudioSampleInfo::audio_specific_config, + Eq(expected.audio_specific_config))); +} + +Matcher<StarboardVideoSampleInfo> MatchesVideoSampleInfo( + const StarboardVideoSampleInfo& expected) { + return AllOf( + Field("codec", &StarboardVideoSampleInfo::codec, Eq(expected.codec)), + expected.mime == nullptr + ? Field("mime", &StarboardVideoSampleInfo::mime, IsNull()) + : Field("mime", &StarboardVideoSampleInfo::mime, + StrEq(expected.mime)), + expected.max_video_capabilities == nullptr + ? Field("max_video_capabilities", + &StarboardVideoSampleInfo::max_video_capabilities, IsNull()) + : Field("max_video_capabilities", + &StarboardVideoSampleInfo::max_video_capabilities, + StrEq(expected.max_video_capabilities)), + Field("is_key_frame", &StarboardVideoSampleInfo::is_key_frame, + Eq(expected.is_key_frame)), + Field("frame_width", &StarboardVideoSampleInfo::frame_width, + Eq(expected.frame_width)), + Field("frame_height", &StarboardVideoSampleInfo::frame_height, + Eq(expected.frame_height)), + Field("color_metadata", &StarboardVideoSampleInfo::color_metadata, + MatchesColorMetadata(expected.color_metadata))); +} + +Matcher<StarboardDrmSampleInfo> MatchesDrmInfo( + const StarboardDrmSampleInfo& expected) { + return AllOf( + Field("encryption_scheme", &StarboardDrmSampleInfo::encryption_scheme, + Eq(expected.encryption_scheme)), + Field("encryption_pattern", &StarboardDrmSampleInfo::encryption_pattern, + AllOf(Field("crypt_byte_block", + &StarboardDrmEncryptionPattern::crypt_byte_block, + Eq(expected.encryption_pattern.crypt_byte_block)), + Field("skip_byte_block", + &StarboardDrmEncryptionPattern::skip_byte_block, + Eq(expected.encryption_pattern.skip_byte_block)))), + Field( + "initialization_vector", + &StarboardDrmSampleInfo::initialization_vector, + SpanMatches(base::span<const uint8_t>(expected.initialization_vector) + .first(static_cast<size_t>( + expected.initialization_vector_size)))), + Field("initialization_vector_size", + &StarboardDrmSampleInfo::initialization_vector_size, + Eq(expected.initialization_vector_size)), + Field("identifier", &StarboardDrmSampleInfo::identifier, + SpanMatches( + base::span<const uint8_t>(expected.identifier) + .first(static_cast<size_t>(expected.identifier_size)))), + Field("identifier_size", &StarboardDrmSampleInfo::identifier_size, + Eq(expected.identifier_size)), + Field("subsample_mapping", &StarboardDrmSampleInfo::subsample_mapping, + Pointwise(MatchesSubsampleMappingTuple(), + expected.subsample_mapping))); +} + +Matcher<StarboardPlayerCreationParam> MatchesPlayerCreationParam( + const StarboardPlayerCreationParam& expected) { + return AllOf(Field("drm_system", &StarboardPlayerCreationParam::drm_system, + Eq(expected.drm_system)), + Field("audio_sample_info", + &StarboardPlayerCreationParam::audio_sample_info, + MatchesAudioSampleInfo(expected.audio_sample_info)), + Field("video_sample_info", + &StarboardPlayerCreationParam::video_sample_info, + MatchesVideoSampleInfo(expected.video_sample_info)), + Field("output_mode", &StarboardPlayerCreationParam::output_mode, + Eq(expected.output_mode))); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/media/test_matchers.h b/chromecast/starboard/media/media/test_matchers.h new file mode 100644 index 0000000..c2554f451 --- /dev/null +++ b/chromecast/starboard/media/media/test_matchers.h
@@ -0,0 +1,49 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Contains matchers for starboard-related structs that can be used in tests. +// +// If more fine-grained matchers are needed in multiple tests, they can be moved +// from the .cc file to this header. + +#ifndef CHROMECAST_STARBOARD_MEDIA_MEDIA_TEST_MATCHERS_H_ +#define CHROMECAST_STARBOARD_MEDIA_MEDIA_TEST_MATCHERS_H_ + +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromecast { +namespace media { + +// Returns a matcher that compares against a given StarboardSampleInfo. Note +// that the "buffer" field (a void*) is checked for equality by address. The +// individual elements are not compared. This was done because the lifetime of +// the buffer is important, so the actual address is usually relevant. +// +// Also note that when resampling occurs for PCM data, the address in "buffer" +// may not match the one provided by a mock (since a new buffer is created +// internally). +::testing::Matcher<StarboardSampleInfo> MatchesStarboardSampleInfo( + const StarboardSampleInfo& expected); + +// Returns a matcher that compares against a given StarboardAudioSampleInfo. +::testing::Matcher<StarboardAudioSampleInfo> MatchesAudioSampleInfo( + const StarboardAudioSampleInfo& expected); + +// Returns a matcher that compares against a given StarboardVideoSampleInfo. +::testing::Matcher<StarboardVideoSampleInfo> MatchesVideoSampleInfo( + const StarboardVideoSampleInfo& expected); + +// Returns a matcher that compares against a given StarboardDrmSampleInfo. +::testing::Matcher<StarboardDrmSampleInfo> MatchesDrmInfo( + const StarboardDrmSampleInfo& expected); + +// Returns a matcher that compares against a given StarboardPlayerCreationParam. +::testing::Matcher<StarboardPlayerCreationParam> MatchesPlayerCreationParam( + const StarboardPlayerCreationParam& expected); + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_MEDIA_TEST_MATCHERS_H_
diff --git a/chromecast/starboard/media/renderer/BUILD.gn b/chromecast/starboard/media/renderer/BUILD.gn new file mode 100644 index 0000000..83c980a --- /dev/null +++ b/chromecast/starboard/media/renderer/BUILD.gn
@@ -0,0 +1,157 @@ +# Copyright 2025 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("//testing/test.gni") + +source_set("geometry_change_handler") { + public = [ "geometry_change_handler.h" ] + sources = [ "geometry_change_handler.cc" ] + public_deps = [ + "//base", + "//chromecast/media/service/mojom", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//ui/gfx:memory_buffer", + "//ui/gfx/geometry", + ] + deps = [ + "//chromecast/media/service:video_geometry_setter_service", + "//mojo/public/cpp/bindings", + "//ui/display", + ] +} + +source_set("starboard_player_manager") { + public = [ "starboard_player_manager.h" ] + sources = [ "starboard_player_manager.cc" ] + public_deps = [ + ":client_stats_tracker", + ":demuxer_stream_reader", + "//base", + "//chromecast/starboard/media/cdm:starboard_drm_wrapper", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//media", + ] + deps = [ ":chromium_starboard_conversions" ] +} + +source_set("demuxer_stream_reader") { + public = [ "demuxer_stream_reader.h" ] + sources = [ "demuxer_stream_reader.cc" ] + public_deps = [ + "//base", + "//chromecast/starboard/media/media:drm_util", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//media", + ] + deps = [ + ":chromium_starboard_conversions", + "//chromecast/starboard/chromecast/starboard_cast_api:cast_starboard_api_types", + "//chromecast/starboard/media/cdm:starboard_drm_key_tracker", + "//chromecast/starboard/media/media:starboard_resampler", + ] +} + +source_set("chromium_starboard_conversions") { + public = [ "chromium_starboard_conversions.h" ] + sources = [ "chromium_starboard_conversions.cc" ] + public_deps = [ + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//media", + ] + deps = [ + "//base", + "//chromecast/starboard/media/media:mime_utils", + "//third_party/abseil-cpp:absl", + "//ui/gfx:color_space", + "//ui/gfx/geometry", + ] +} + +source_set("client_stats_tracker") { + sources = [ + "client_stats_tracker.cc", + "client_stats_tracker.h", + ] + deps = [ + "//base", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//media", + ] +} + +test("client_stats_tracker_test") { + sources = [ "client_stats_tracker_test.cc" ] + deps = [ + ":client_stats_tracker", + "//base", + "//base/test:run_all_unittests", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//media:test_support", + "//testing/gmock", + "//testing/gtest", + ] +} + +test("demuxer_stream_reader_test") { + sources = [ "demuxer_stream_reader_test.cc" ] + deps = [ + ":demuxer_stream_reader", + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//chromecast/starboard/media/cdm:starboard_drm_key_tracker", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//chromecast/starboard/media/media:test_matchers", + "//media", + "//media:test_support", + "//testing/gmock", + "//testing/gtest", + ] +} + +test("chromium_starboard_conversions_test") { + sources = [ "chromium_starboard_conversions_test.cc" ] + deps = [ + ":chromium_starboard_conversions", + "//base/test:run_all_unittests", + "//chromecast/starboard/media/media:test_matchers", + "//media", + "//testing/gmock", + "//testing/gtest", + "//ui/gfx/geometry", + ] +} + +test("geometry_change_handler_test") { + sources = [ "geometry_change_handler_test.cc" ] + deps = [ + ":geometry_change_handler", + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//chromecast/media/service:video_geometry_setter_service", + "//chromecast/starboard/media/media:mock_starboard_api_wrapper", + "//mojo/core/embedder", + "//ui/display:test_support", + "//ui/gfx:memory_buffer", + "//ui/gfx/geometry", + ] +} + +test("starboard_player_manager_test") { + sources = [ "starboard_player_manager_test.cc" ] + deps = [ + ":starboard_player_manager", + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//chromecast/starboard/media/cdm:starboard_drm_wrapper", + "//chromecast/starboard/media/media:mock_starboard_api_wrapper", + "//chromecast/starboard/media/media:starboard_api_wrapper", + "//chromecast/starboard/media/media:test_matchers", + "//media", + "//media:test_support", + "//ui/gfx/geometry", + ] +}
diff --git a/chromecast/starboard/media/renderer/chromium_starboard_conversions.cc b/chromecast/starboard/media/renderer/chromium_starboard_conversions.cc new file mode 100644 index 0000000..a845ce9 --- /dev/null +++ b/chromecast/starboard/media/renderer/chromium_starboard_conversions.cc
@@ -0,0 +1,343 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/chromium_starboard_conversions.h" + +#include "base/logging.h" +#include "base/no_destructor.h" +#include "base/synchronization/lock.h" +#include "base/thread_annotations.h" +#include "chromecast/starboard/media/media/mime_utils.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/audio_codecs.h" +#include "media/base/channel_layout.h" +#include "media/base/video_codecs.h" +#include "media/base/video_color_space.h" +#include "third_party/abseil-cpp/absl/container/node_hash_set.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/hdr_metadata.h" + +namespace chromecast { +namespace media { + +namespace { + +using ::media::VideoColorSpace; + +// Registers the given MIME type, if it has not already been registered. Returns +// a c string of the MIME type, which is guaranteed to point to valid data for +// the duration of the program. +const char* RegisterMimeType(std::string mime) { + if (mime.empty()) { + return ""; + } + + static base::Lock lock; + // A node_hash_set is used here because we require key ptr stability (so that + // c strings remain valid). + static base::NoDestructor<absl::node_hash_set<std::string>> registry + GUARDED_BY(lock); + + base::AutoLock autlock(lock); + auto it_and_inserted = registry->insert(std::move(mime)); + return it_and_inserted.first->c_str(); +} + +// Converts a chromium codec to a starboard codec, returning nullopt if the +// codec does not exist in starboard. +// +// `profile` is necessary for differentiating Dolby Vision codecs. +std::optional<StarboardVideoCodec> ToSbVideoCodec( + ::media::VideoCodec codec, + ::media::VideoCodecProfile profile) { + switch (codec) { + case ::media::VideoCodec::kH264: + return StarboardVideoCodec::kStarboardVideoCodecH264; + case ::media::VideoCodec::kMPEG2: + return StarboardVideoCodec::kStarboardVideoCodecMpeg2; + case ::media::VideoCodec::kTheora: + return StarboardVideoCodec::kStarboardVideoCodecTheora; + case ::media::VideoCodec::kVP8: + return StarboardVideoCodec::kStarboardVideoCodecVp8; + case ::media::VideoCodec::kVP9: + return StarboardVideoCodec::kStarboardVideoCodecVp9; + case ::media::VideoCodec::kHEVC: + return StarboardVideoCodec::kStarboardVideoCodecH265; + case ::media::VideoCodec::kAV1: + return StarboardVideoCodec::kStarboardVideoCodecAv1; + case ::media::VideoCodec::kVC1: + return StarboardVideoCodec::kStarboardVideoCodecVc1; + case ::media::VideoCodec::kDolbyVision: + switch (profile) { + // This logic was copied from + // https://source.chromium.org/chromium/chromium/src/+/main:chromecast/media/base/media_codec_support.cc;l=63;drc=586d9e059d27bfbe85c8df737882821e7b68929d + case ::media::VideoCodecProfile::DOLBYVISION_PROFILE5: + case ::media::VideoCodecProfile::DOLBYVISION_PROFILE7: + case ::media::VideoCodecProfile::DOLBYVISION_PROFILE8: + return StarboardVideoCodec::kStarboardVideoCodecH265; + default: + // We only support Dolby Vision for HEVC currently. The H264 profiles + // (DOLBYVISION_PROFILE0 and DOLBYVISION_PROFILE9) are considered + // unsupported. + LOG(INFO) << "Unsupported Dolby Vision profile=" << profile; + return std::nullopt; + } + default: + LOG(ERROR) << "Unsupported video codec: " << codec; + return std::nullopt; + } +} + +// Populates HDR fields of `out_color_metadata` based on `hdr_metadata`. +void PopulateHdrMetadata(const gfx::HDRMetadata& hdr_metadata, + StarboardColorMetadata& out_color_metadata) { + if (hdr_metadata.cta_861_3) { + out_color_metadata.max_cll = + hdr_metadata.cta_861_3->max_content_light_level; + out_color_metadata.max_fall = + hdr_metadata.cta_861_3->max_frame_average_light_level; + } else { + LOG(INFO) << "HDR metadata is missing cta_861_3 info."; + } + + if (hdr_metadata.smpte_st_2086) { + const auto& color_volume_metadata = hdr_metadata.smpte_st_2086->primaries; + + StarboardMediaMasteringMetadata& mastering_metadata = + out_color_metadata.mastering_metadata; + mastering_metadata.primary_r_chromaticity_x = color_volume_metadata.fRX; + mastering_metadata.primary_r_chromaticity_y = color_volume_metadata.fRY; + mastering_metadata.primary_g_chromaticity_x = color_volume_metadata.fGX; + mastering_metadata.primary_g_chromaticity_y = color_volume_metadata.fGY; + mastering_metadata.primary_b_chromaticity_x = color_volume_metadata.fBX; + mastering_metadata.primary_b_chromaticity_y = color_volume_metadata.fBY; + mastering_metadata.white_point_chromaticity_x = color_volume_metadata.fWX; + mastering_metadata.white_point_chromaticity_y = color_volume_metadata.fWY; + mastering_metadata.luminance_max = + hdr_metadata.smpte_st_2086->luminance_max; + mastering_metadata.luminance_min = + hdr_metadata.smpte_st_2086->luminance_min; + } else { + LOG(INFO) << "HDR metadata is missing smpte_st_2086 info."; + } +} + +// Converts chromium color metadata to starboard color metadata, returning +// nullopt if the chromium color metadata cannot be converted. +std::optional<StarboardColorMetadata> ToSbColorMetadata( + const std::optional<gfx::HDRMetadata>& hdr_metadata, + const ::media::VideoColorSpace& color_space) { + StarboardColorMetadata color_metadata = {}; + // bits_per_channel and the chroma_*/cb_* fields below need to be derived from + // the MIME string. See crbug.com/230915942 for more info. + // Unfortunately, it doesn't look like MIME type is exposed to cast. Note that + // in Cobalt, these fields are all currently hard-coded to zero (in + // third_party/chromium/media/base/starboard_utils.cc). I don't think they're + // necessary for cast either, since cast doesn't seem to populate this info + // anywhere. + + // 0 translates to "unknown". + color_metadata.bits_per_channel = 0; + color_metadata.chroma_subsampling_horizontal = 0; + color_metadata.chroma_subsampling_vertical = 0; + color_metadata.cb_subsampling_horizontal = 0; + color_metadata.cb_subsampling_vertical = 0; + color_metadata.chroma_siting_horizontal = 0; + color_metadata.chroma_siting_vertical = 0; + + if (hdr_metadata) { + LOG(INFO) << "Video config has HDR metadata."; + PopulateHdrMetadata(*hdr_metadata, color_metadata); + } else { + LOG(INFO) << "Video config has no HDR metadata."; + color_metadata.max_cll = 0; + color_metadata.max_fall = 0; + } + + switch (color_space.primaries) { + case VideoColorSpace::PrimaryID::INVALID: + case VideoColorSpace::PrimaryID::BT709: + case VideoColorSpace::PrimaryID::UNSPECIFIED: + case VideoColorSpace::PrimaryID::BT470M: + case VideoColorSpace::PrimaryID::BT470BG: + case VideoColorSpace::PrimaryID::SMPTE170M: + case VideoColorSpace::PrimaryID::SMPTE240M: + case VideoColorSpace::PrimaryID::FILM: + case VideoColorSpace::PrimaryID::BT2020: + case VideoColorSpace::PrimaryID::SMPTEST428_1: + case VideoColorSpace::PrimaryID::SMPTEST431_2: + case VideoColorSpace::PrimaryID::SMPTEST432_1: + color_metadata.primaries = static_cast<int>(color_space.primaries); + break; + default: + LOG(ERROR) << "Unsupported color space primaries: " + << static_cast<int>(color_space.primaries); + return std::nullopt; + } + + switch (color_space.transfer) { + case VideoColorSpace::TransferID::INVALID: + case VideoColorSpace::TransferID::BT709: + case VideoColorSpace::TransferID::UNSPECIFIED: + case VideoColorSpace::TransferID::GAMMA22: + case VideoColorSpace::TransferID::GAMMA28: + case VideoColorSpace::TransferID::SMPTE170M: + case VideoColorSpace::TransferID::SMPTE240M: + case VideoColorSpace::TransferID::LINEAR: + case VideoColorSpace::TransferID::LOG: + case VideoColorSpace::TransferID::LOG_SQRT: + case VideoColorSpace::TransferID::IEC61966_2_4: + case VideoColorSpace::TransferID::BT1361_ECG: + case VideoColorSpace::TransferID::IEC61966_2_1: + case VideoColorSpace::TransferID::BT2020_10: + case VideoColorSpace::TransferID::BT2020_12: + case VideoColorSpace::TransferID::SMPTEST2084: + case VideoColorSpace::TransferID::SMPTEST428_1: + color_metadata.transfer = static_cast<int>(color_space.transfer); + break; + default: + LOG(ERROR) << "Unsupported color space transfer: " + << static_cast<int>(color_space.transfer); + return std::nullopt; + } + + switch (color_space.matrix) { + case VideoColorSpace::MatrixID::RGB: + case VideoColorSpace::MatrixID::BT709: + case VideoColorSpace::MatrixID::UNSPECIFIED: + case VideoColorSpace::MatrixID::FCC: + case VideoColorSpace::MatrixID::BT470BG: + case VideoColorSpace::MatrixID::SMPTE170M: + case VideoColorSpace::MatrixID::SMPTE240M: + case VideoColorSpace::MatrixID::YCOCG: + case VideoColorSpace::MatrixID::BT2020_NCL: + case VideoColorSpace::MatrixID::BT2020_CL: + case VideoColorSpace::MatrixID::YDZDX: + case VideoColorSpace::MatrixID::INVALID: + color_metadata.matrix = static_cast<int>(color_space.matrix); + break; + default: + LOG(ERROR) << "Unsupported color space matrix: " + << static_cast<int>(color_space.matrix); + return std::nullopt; + } + + switch (color_space.range) { + case gfx::ColorSpace::RangeID::INVALID: + case gfx::ColorSpace::RangeID::LIMITED: + case gfx::ColorSpace::RangeID::FULL: + case gfx::ColorSpace::RangeID::DERIVED: + color_metadata.range = static_cast<int>(color_space.range); + break; + default: + LOG(ERROR) << "Unsupported color space range: " + << static_cast<int>(color_space.range); + return std::nullopt; + } + + // color_space.primaries (::media::VideoColorSpace::PrimaryID) + // does not support any value equivalent to Starboard's + // kSbMediaPrimaryIdCustom. Thus, we don't need to populate + // custom_primary_matrix. Just zero it, in case something reads from it. + return color_metadata; +} + +} // namespace + +std::optional<StarboardAudioSampleInfo> ToStarboardAudioSampleInfo( + const ::media::AudioDecoderConfig& in_config) { + StarboardAudioSampleInfo out_config = {}; + + switch (in_config.codec()) { + case ::media::AudioCodec::kAAC: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecAac; + break; + case ::media::AudioCodec::kMP3: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecMp3; + break; + case ::media::AudioCodec::kVorbis: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecVorbis; + break; + case ::media::AudioCodec::kFLAC: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecFlac; + break; + case ::media::AudioCodec::kPCM: + case ::media::AudioCodec::kPCM_S16BE: + case ::media::AudioCodec::kPCM_S24BE: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecPcm; + break; + case ::media::AudioCodec::kOpus: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecOpus; + break; + case ::media::AudioCodec::kEAC3: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecEac3; + break; + case ::media::AudioCodec::kAC3: + out_config.codec = StarboardAudioCodec::kStarboardAudioCodecAc3; + break; + default: + LOG(ERROR) << "Unsupported audio codec: " << in_config.codec(); + return std::nullopt; + } + + out_config.mime = RegisterMimeType(GetMimeType(in_config.codec())); + out_config.format_tag = 0; + out_config.number_of_channels = in_config.channels(); + out_config.samples_per_second = in_config.samples_per_second(); + + // Based on starboard_utils.cc (MediaAudioConfigToSbMediaAudioSampleInfo) in + // the cobalt codebase, bits_per_sample does not take into account the number + // of channels. + if (out_config.codec == StarboardAudioCodec::kStarboardAudioCodecPcm) { + // TODO(antoniori): handle resampling to other formats. Currently we only + // support S16. + out_config.bits_per_sample = 16; + } else { + // For starboard, "bits per sample" does not factor in channel count. + out_config.bits_per_sample = in_config.bytes_per_channel() * 8; + } + out_config.average_bytes_per_second = out_config.number_of_channels * + out_config.samples_per_second * + out_config.bits_per_sample / 8; + out_config.block_alignment = 4; + out_config.audio_specific_config_size = in_config.extra_data().size(); + out_config.audio_specific_config = in_config.extra_data().data(); + + return out_config; +} + +std::optional<StarboardVideoSampleInfo> ToStarboardVideoSampleInfo( + const ::media::VideoDecoderConfig& in_config) { + StarboardVideoSampleInfo out_config = {}; + + std::optional<StarboardVideoCodec> sb_codec = + ToSbVideoCodec(in_config.codec(), in_config.profile()); + if (!sb_codec.has_value()) { + return std::nullopt; + } + + out_config.codec = *sb_codec; + out_config.mime = RegisterMimeType( + GetMimeType(in_config.codec(), in_config.profile(), in_config.level())); + // Specify that the max capabilities are not known. + out_config.max_video_capabilities = ""; + // This needs to be set on a per-sample basis later. + out_config.is_key_frame = false; + + const gfx::Size aspect_ratio = in_config.coded_size(); + out_config.frame_width = aspect_ratio.width(); + out_config.frame_height = aspect_ratio.height(); + + std::optional<StarboardColorMetadata> sb_color_metadata = + ToSbColorMetadata(in_config.hdr_metadata(), in_config.color_space_info()); + if (!sb_color_metadata.has_value()) { + return std::nullopt; + } + out_config.color_metadata = *std::move(sb_color_metadata); + + return out_config; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/chromium_starboard_conversions.h b/chromecast/starboard/media/renderer/chromium_starboard_conversions.h new file mode 100644 index 0000000..d42e966 --- /dev/null +++ b/chromecast/starboard/media/renderer/chromium_starboard_conversions.h
@@ -0,0 +1,33 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Contains functions for converting chromium structs to equivalent starboard +// structs. + +#ifndef CHROMECAST_STARBOARD_MEDIA_RENDERER_CHROMIUM_STARBOARD_CONVERSIONS_H_ +#define CHROMECAST_STARBOARD_MEDIA_RENDERER_CHROMIUM_STARBOARD_CONVERSIONS_H_ + +#include <optional> + +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/video_decoder_config.h" + +namespace chromecast { +namespace media { + +// Converts an AudioDecoderConfig to StarboardAudioSampleInfo, returning nullopt +// if the config is not supported or is invalid. +std::optional<StarboardAudioSampleInfo> ToStarboardAudioSampleInfo( + const ::media::AudioDecoderConfig& in_config); + +// Converts a VideoDecoderConfig to StarboardVideoSampleInfo, returning nullopt +// if the config is not supported or is invalid. +std::optional<StarboardVideoSampleInfo> ToStarboardVideoSampleInfo( + const ::media::VideoDecoderConfig& in_config); + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_RENDERER_CHROMIUM_STARBOARD_CONVERSIONS_H_
diff --git a/chromecast/starboard/media/renderer/chromium_starboard_conversions_test.cc b/chromecast/starboard/media/renderer/chromium_starboard_conversions_test.cc new file mode 100644 index 0000000..253e023 --- /dev/null +++ b/chromecast/starboard/media/renderer/chromium_starboard_conversions_test.cc
@@ -0,0 +1,191 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/chromium_starboard_conversions.h" + +#include <cstring> +#include <optional> +#include <vector> + +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "chromecast/starboard/media/media/test_matchers.h" +#include "media/base/audio_codecs.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/channel_layout.h" +#include "media/base/encryption_scheme.h" +#include "media/base/sample_format.h" +#include "media/base/video_codecs.h" +#include "media/base/video_color_space.h" +#include "media/base/video_decoder_config.h" +#include "media/base/video_transformation.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +namespace chromecast { +namespace media { +namespace { + +using ::media::AudioCodec; +using ::media::AudioDecoderConfig; +using ::media::ChannelLayout; +using ::media::EncryptionScheme; +using ::media::SampleFormat; +using ::media::VideoCodec; +using ::media::VideoCodecProfile; +using ::media::VideoColorSpace; +using ::media::VideoDecoderConfig; +using ::media::VideoTransformation; +using ::testing::Optional; + +TEST(StarboardConversionsTest, ConvertsValidAudioConfigToStarboardConfig) { + EXPECT_THAT( + ToStarboardAudioSampleInfo(AudioDecoderConfig( + AudioCodec::kAAC, SampleFormat::kSampleFormatS32, + ChannelLayout::CHANNEL_LAYOUT_5_1, /*samples_per_second=*/48000, + /*extra_data=*/{}, EncryptionScheme::kCenc)), + Optional(MatchesAudioSampleInfo({ + .codec = StarboardAudioCodec::kStarboardAudioCodecAac, + .mime = R"-(audio/mp4; codecs="mp4a.40.5")-", + .format_tag = 0, + .number_of_channels = 6, + .samples_per_second = 48000, + .average_bytes_per_second = 48000 * 4 * 6, + .block_alignment = 4, + .bits_per_sample = 32, + .audio_specific_config_size = 0, + .audio_specific_config = nullptr, + }))); +} + +TEST(StarboardConversionsTest, ReturnsNulloptForInvalidAudioConfig) { + // DTS is not supported in starboard. + EXPECT_EQ(ToStarboardAudioSampleInfo(AudioDecoderConfig( + AudioCodec::kDTS, SampleFormat::kSampleFormatS32, + ChannelLayout::CHANNEL_LAYOUT_5_1, /*samples_per_second=*/48000, + /*extra_data=*/{}, EncryptionScheme::kCenc)), + std::nullopt); +} + +TEST(StarboardConversionsTest, ConvertsValidVideoConfigToStarboardConfig) { + EXPECT_THAT( + ToStarboardVideoSampleInfo(VideoDecoderConfig( + VideoCodec::kHEVC, VideoCodecProfile::HEVCPROFILE_MAIN10, + VideoDecoderConfig::AlphaMode::kIsOpaque, + VideoColorSpace(1, 1, 1, gfx::ColorSpace::RangeID::LIMITED), + VideoTransformation(), gfx::Size(1920, 1080), gfx::Rect(1920, 1080), + gfx::Size(1920, 1080), /*extra_data=*/{}, EncryptionScheme::kCenc)), + Optional(MatchesVideoSampleInfo({ + .codec = StarboardVideoCodec::kStarboardVideoCodecH265, + .mime = R"-(video/mp4; codecs="hev1.2.6.L0.B0")-", + .max_video_capabilities = "", + .is_key_frame = false, + .frame_width = 1920, + .frame_height = 1080, + .color_metadata = + StarboardColorMetadata{ + .bits_per_channel = 0, // unknown + .chroma_subsampling_horizontal = 0, // unknown + .chroma_subsampling_vertical = 0, // unknown + .cb_subsampling_horizontal = 0, // unknown + .cb_subsampling_vertical = 0, // unknown + .chroma_siting_horizontal = 0, // unknown + .chroma_siting_vertical = 0, // unknown + .mastering_metadata = {}, + .max_cll = 0, + .max_fall = 0, + .primaries = 1, + .transfer = 1, + .matrix = 1, + .range = 1, + }, + }))); +} + +TEST(StarboardConversionsTest, + ConvertsValidVideoConfigWithHdrMetadataToStarboardConfig) { + VideoDecoderConfig chromium_config( + VideoCodec::kHEVC, VideoCodecProfile::HEVCPROFILE_MAIN10, + VideoDecoderConfig::AlphaMode::kIsOpaque, + VideoColorSpace(9, 16, 9, gfx::ColorSpace::RangeID::LIMITED), + VideoTransformation(), gfx::Size(3840, 2160), gfx::Rect(3840, 2160), + gfx::Size(3840, 2160), /*extra_data=*/{}, EncryptionScheme::kUnencrypted); + gfx::HDRMetadata hdr_metadata; + gfx::HdrMetadataSmpteSt2086 smpte; + smpte.luminance_max = 0.9; + smpte.primaries.fRX = 0.1; + smpte.primaries.fRY = 0.2; + smpte.primaries.fGX = 0.3; + smpte.primaries.fGY = 0.4; + smpte.primaries.fBX = 0.5; + smpte.primaries.fBY = 0.6; + smpte.primaries.fWX = 0.7; + smpte.primaries.fWY = 0.8; + smpte.luminance_max = 1.1; + smpte.luminance_min = 0.01; + + gfx::HdrMetadataCta861_3 cta; + cta.max_content_light_level = 100; + cta.max_frame_average_light_level = 1000; + + hdr_metadata.smpte_st_2086 = smpte; + hdr_metadata.cta_861_3 = cta; + chromium_config.set_hdr_metadata(hdr_metadata); + + EXPECT_THAT(ToStarboardVideoSampleInfo(chromium_config), + Optional(MatchesVideoSampleInfo({ + .codec = StarboardVideoCodec::kStarboardVideoCodecH265, + .mime = R"-(video/mp4; codecs="hev1.2.6.L0.B0")-", + .max_video_capabilities = "", + .is_key_frame = false, + .frame_width = 3840, + .frame_height = 2160, + .color_metadata = + { + .bits_per_channel = 0, // unknown + .chroma_subsampling_horizontal = 0, // unknown + .chroma_subsampling_vertical = 0, // unknown + .cb_subsampling_horizontal = 0, // unknown + .cb_subsampling_vertical = 0, // unknown + .chroma_siting_horizontal = 0, // unknown + .chroma_siting_vertical = 0, // unknown + .mastering_metadata = + { + .primary_r_chromaticity_x = 0.1, + .primary_r_chromaticity_y = 0.2, + .primary_g_chromaticity_x = 0.3, + .primary_g_chromaticity_y = 0.4, + .primary_b_chromaticity_x = 0.5, + .primary_b_chromaticity_y = 0.6, + .white_point_chromaticity_x = 0.7, + .white_point_chromaticity_y = 0.8, + .luminance_max = 1.1, + .luminance_min = 0.01, + }, + .max_cll = 100, + .max_fall = 1000, + .primaries = 9, + .transfer = 16, + .matrix = 9, + .range = 1, + }, + }))); +} + +TEST(StarboardConversionsTest, ReturnsNulloptForInvalidVideoConfig) { + // Dolby Vision is paired with a bad profile. + EXPECT_EQ( + ToStarboardVideoSampleInfo(VideoDecoderConfig( + VideoCodec::kDolbyVision, VideoCodecProfile::VVCPROFILE_MAIN10, + VideoDecoderConfig::AlphaMode::kIsOpaque, + VideoColorSpace(1, 1, 1, gfx::ColorSpace::RangeID::LIMITED), + VideoTransformation(), gfx::Size(1920, 1080), gfx::Rect(1920, 1080), + gfx::Size(1920, 1080), /*extra_data=*/{}, EncryptionScheme::kCenc)), + std::nullopt); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/client_stats_tracker.cc b/chromecast/starboard/media/renderer/client_stats_tracker.cc new file mode 100644 index 0000000..ac28542 --- /dev/null +++ b/chromecast/starboard/media/renderer/client_stats_tracker.cc
@@ -0,0 +1,68 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/client_stats_tracker.h" + +#include "base/check.h" +#include "base/logging.h" + +namespace chromecast { +namespace media { + +ClientStatsTracker::ClientStatsTracker(::media::RendererClient* client) + : client_(client) { + CHECK(client_); +} + +ClientStatsTracker::~ClientStatsTracker() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void ClientStatsTracker::UpdateStats(const StarboardPlayerInfo& player_info, + const StarboardSampleInfo& sample_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (sample_info.type == StarboardMediaType::kStarboardMediaTypeAudio) { + UpdateAudioStats(sample_info); + } else if (sample_info.type == StarboardMediaType::kStarboardMediaTypeVideo) { + UpdateVideoStats(player_info, sample_info); + } else { + LOG(ERROR) << "Unsupported starboard media type: " << sample_info.type; + } +} + +void ClientStatsTracker::UpdateAudioStats( + const StarboardSampleInfo& sample_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Per the documentation of RendererClient, *_decoded is a delta when passed + // to OnStatisticsUpdate. + ::media::PipelineStatistics stats; + stats.audio_bytes_decoded = sample_info.buffer_size; + + client_->OnStatisticsUpdate(stats); +} + +void ClientStatsTracker::UpdateVideoStats( + const StarboardPlayerInfo& player_info, + const StarboardSampleInfo& sample_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Per the documentation of RendererClient, *_decoded and *_dropped are + // deltas when passed to OnStatisticsUpdate. + ::media::PipelineStatistics stats; + stats.video_bytes_decoded = sample_info.buffer_size; + stats.video_frames_decoded = + player_info.total_video_frames - total_video_frames_decoded_; + stats.video_frames_dropped = + player_info.dropped_video_frames - total_video_frames_dropped_; + + total_video_frames_decoded_ = player_info.total_video_frames; + total_video_frames_dropped_ = player_info.dropped_video_frames; + + client_->OnStatisticsUpdate(stats); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/client_stats_tracker.h b/chromecast/starboard/media/renderer/client_stats_tracker.h new file mode 100644 index 0000000..c0c3396 --- /dev/null +++ b/chromecast/starboard/media/renderer/client_stats_tracker.h
@@ -0,0 +1,48 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_STARBOARD_MEDIA_RENDERER_CLIENT_STATS_TRACKER_H_ +#define CHROMECAST_STARBOARD_MEDIA_RENDERER_CLIENT_STATS_TRACKER_H_ + +#include <cstdint> + +#include "base/sequence_checker.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/renderer_client.h" + +namespace chromecast { +namespace media { + +// Tracks media stats and reports them to a RendererClient. +// +// This class is not threadsafe, and must only be used on a single sequence. +class ClientStatsTracker { + public: + // `client` must not be null. + explicit ClientStatsTracker(::media::RendererClient* client); + ~ClientStatsTracker(); + + // Updates stats based on a buffer pushed to starboard. + void UpdateStats(const StarboardPlayerInfo& player_info, + const StarboardSampleInfo& sample_info); + + private: + // Updates stats for an audio buffer. + void UpdateAudioStats(const StarboardSampleInfo& sample_info); + + // Updates stats for a video buffer. + void UpdateVideoStats(const StarboardPlayerInfo& player_info, + const StarboardSampleInfo& sample_info); + + SEQUENCE_CHECKER(sequence_checker_); + + ::media::RendererClient* client_ = nullptr; + uint32_t total_video_frames_decoded_ = 0; + uint32_t total_video_frames_dropped_ = 0; +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_RENDERER_CLIENT_STATS_TRACKER_H_
diff --git a/chromecast/starboard/media/renderer/client_stats_tracker_test.cc b/chromecast/starboard/media/renderer/client_stats_tracker_test.cc new file mode 100644 index 0000000..0f36350 --- /dev/null +++ b/chromecast/starboard/media/renderer/client_stats_tracker_test.cc
@@ -0,0 +1,123 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/client_stats_tracker.h" + +#include <array> +#include <cstdint> + +#include "base/containers/span.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/mock_filters.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromecast { +namespace media { +namespace { + +using ::media::PipelineStatistics; +using ::testing::AllOf; +using ::testing::Eq; +using ::testing::Field; + +auto MatchesStats(const PipelineStatistics& stats) { + return AllOf(Field(&PipelineStatistics::audio_bytes_decoded, + Eq(stats.audio_bytes_decoded)), + Field(&PipelineStatistics::video_bytes_decoded, + Eq(stats.video_bytes_decoded)), + Field(&PipelineStatistics::video_frames_decoded, + Eq(stats.video_frames_decoded)), + Field(&PipelineStatistics::video_frames_dropped, + Eq(stats.video_frames_dropped))); +} + +// Creates an audio sample containing the given data. +StarboardSampleInfo CreateAudioSample(base::span<const uint8_t> data) { + StarboardSampleInfo sample_info; + sample_info.type = kStarboardMediaTypeAudio; + sample_info.buffer = data.data(); + sample_info.buffer_size = data.size(); + sample_info.timestamp = 0; + sample_info.side_data = base::span<const StarboardSampleSideData>(); + sample_info.audio_sample_info = {}; + sample_info.drm_info = nullptr; + + return sample_info; +} + +// Creates a video sample containing the given data. +StarboardSampleInfo CreateVideoSample(base::span<const uint8_t> data) { + StarboardSampleInfo sample_info; + sample_info.type = kStarboardMediaTypeVideo; + sample_info.buffer = data.data(); + sample_info.buffer_size = data.size(); + sample_info.timestamp = 0; + sample_info.side_data = base::span<const StarboardSampleSideData>(); + sample_info.video_sample_info = {}; + sample_info.drm_info = nullptr; + + return sample_info; +} + +TEST(ClientStatsTrackerTest, UpdatesStatsForAudioBuffer) { + constexpr auto kAudioData = std::to_array<uint8_t>({1, 2, 3}); + StarboardPlayerInfo player_info = {}; + StarboardSampleInfo sample_info = CreateAudioSample(kAudioData); + PipelineStatistics expected_stats; + expected_stats.audio_bytes_decoded = kAudioData.size(); + expected_stats.video_bytes_decoded = 0; + expected_stats.video_frames_decoded = 0; + expected_stats.video_frames_dropped = 0; + + ::media::MockRendererClient client; + EXPECT_CALL(client, OnStatisticsUpdate(MatchesStats(expected_stats))) + .Times(1); + + ClientStatsTracker stats_tracker(&client); + + stats_tracker.UpdateStats(player_info, sample_info); +} + +TEST(ClientStatsTrackerTest, UpdatesStatsForVideoBuffer) { + constexpr auto kVideoData1 = std::to_array<uint8_t>({1, 2, 3, 4, 5}); + constexpr auto kVideoData2 = std::to_array<uint8_t>({6, 7, 8}); + + StarboardPlayerInfo player_info_1 = {}; + player_info_1.total_video_frames = 2; + player_info_1.dropped_video_frames = 0; + + StarboardSampleInfo sample_info_1 = CreateVideoSample(kVideoData1); + PipelineStatistics expected_stats_1; + expected_stats_1.audio_bytes_decoded = 0; + expected_stats_1.video_bytes_decoded = kVideoData1.size(); + expected_stats_1.video_frames_decoded = 2; + expected_stats_1.video_frames_dropped = 0; + + StarboardPlayerInfo player_info_2 = {}; + player_info_2.total_video_frames = 3; + player_info_2.dropped_video_frames = 0; + + StarboardSampleInfo sample_info_2 = CreateVideoSample(kVideoData2); + PipelineStatistics expected_stats_2; + expected_stats_2.audio_bytes_decoded = 0; + expected_stats_2.video_bytes_decoded = kVideoData2.size(); + expected_stats_2.video_frames_decoded = 1; + expected_stats_2.video_frames_dropped = 0; + + ::media::MockRendererClient client; + EXPECT_CALL(client, OnStatisticsUpdate(MatchesStats(expected_stats_1))) + .Times(1); + EXPECT_CALL(client, OnStatisticsUpdate(MatchesStats(expected_stats_2))) + .Times(1); + + ClientStatsTracker stats_tracker(&client); + + stats_tracker.UpdateStats(player_info_1, sample_info_1); + stats_tracker.UpdateStats(player_info_2, sample_info_2); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/demuxer_stream_reader.cc b/chromecast/starboard/media/renderer/demuxer_stream_reader.cc new file mode 100644 index 0000000..50f641dc --- /dev/null +++ b/chromecast/starboard/media/renderer/demuxer_stream_reader.cc
@@ -0,0 +1,327 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/demuxer_stream_reader.h" + +#include "base/check.h" +#include "base/containers/span.h" +#include "base/functional/bind.h" +#include "base/hash/hash.h" +#include "base/logging.h" +#include "base/task/bind_post_task.h" +#include "base/task/sequenced_task_runner.h" +#include "chromecast/starboard/chromecast/starboard_cast_api/cast_starboard_api_types.h" +#include "chromecast/starboard/media/cdm/starboard_drm_key_tracker.h" +#include "chromecast/starboard/media/media/starboard_resampler.h" +#include "chromecast/starboard/media/renderer/chromium_starboard_conversions.h" +#include "media/base/video_decoder_config.h" + +namespace chromecast { +namespace media { + +namespace { + +using ::media::DecoderBuffer; + +scoped_refptr<DecoderBuffer> ConvertPcmAudioBufferToS16( + ::media::AudioCodec codec, + ::media::SampleFormat sample_format, + int channel_count, + scoped_refptr<DecoderBuffer> buffer) { + return DecoderBuffer::FromArray( + chromecast::media::ResamplePCMAudioDataForStarboard( + StarboardPcmSampleFormat::kStarboardPcmSampleFormatS16, sample_format, + codec, channel_count, *buffer)); +} + +// Function used to "convert" buffers that do not need to be converted. +scoped_refptr<DecoderBuffer> DoNotConvertBuffer( + scoped_refptr<DecoderBuffer> buffer) { + return buffer; +} + +// Returns whether it is necessary to resample audio specified by `audio_config` +// to S16. +bool IsResamplingNecessary(const ::media::AudioDecoderConfig& audio_config) { + return (audio_config.codec() == ::media::AudioCodec::kPCM && + audio_config.sample_format() != + ::media::SampleFormat::kSampleFormatS16) || + audio_config.codec() == ::media::AudioCodec::kPCM_S16BE || + audio_config.codec() == ::media::AudioCodec::kPCM_S24BE; +} + +} // namespace + +DemuxerStreamReader::DemuxerStreamReader( + ::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + std::optional<StarboardAudioSampleInfo> audio_sample_info, + std::optional<StarboardVideoSampleInfo> video_sample_info, + HandleBufferCb handle_buffer_cb, + HandleEosCb handle_eos_cb, + ::media::RendererClient* client) + : handle_buffer_cb_(std::move(handle_buffer_cb)), + handle_eos_cb_(std::move(handle_eos_cb)), + client_(client), + audio_stream_(audio_stream), + video_stream_(video_stream), + audio_sample_info_(std::move(audio_sample_info)), + video_sample_info_(std::move(video_sample_info)) { + if (audio_stream_) { + ::media::AudioDecoderConfig audio_config = + audio_stream_->audio_decoder_config(); + + if (IsResamplingNecessary(audio_config)) { + convert_audio_fn_ = base::BindRepeating( + &ConvertPcmAudioBufferToS16, audio_config.codec(), + audio_config.sample_format(), audio_config.channels()); + } else { + convert_audio_fn_ = base::BindRepeating(&DoNotConvertBuffer); + } + } +} + +DemuxerStreamReader::~DemuxerStreamReader() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + for (const auto& [token, unused] : token_to_drm_key_cb_) { + StarboardDrmKeyTracker::GetInstance().UnregisterCallback(token); + } +} + +void DemuxerStreamReader::ReadBuffer(int seek_ticket, StarboardMediaType type) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + ::media::DemuxerStream* stream = + type == StarboardMediaType::kStarboardMediaTypeAudio ? audio_stream_ + : video_stream_; + CHECK(stream); + stream->Read(1, + base::BindOnce(&DemuxerStreamReader::OnReadBuffer, + weak_factory_.GetWeakPtr(), type, seek_ticket)); +} + +void DemuxerStreamReader::HandleNonOkDemuxerStatus( + ::media::DemuxerStream::Status status, + StarboardMediaType type, + int seek_ticket) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + switch (status) { + case ::media::DemuxerStream::Status::kAborted: { + LOG(ERROR) << "DemuxerStream was aborted."; + // This can happen if a flush occurs while we were trying to read from a + // DemuxerStream. In that case, upstream code will call StartPlayingFrom + // again, so we should not do another read here. + return; + } + case ::media::DemuxerStream::Status::kConfigChanged: { + if (type == StarboardMediaType::kStarboardMediaTypeAudio) { + UpdateAudioConfig(); + + // Keep reading more data. + audio_stream_->Read( + 1, base::BindOnce(&DemuxerStreamReader::OnReadBuffer, + weak_factory_.GetWeakPtr(), type, seek_ticket)); + } else { + CHECK_EQ(type, StarboardMediaType::kStarboardMediaTypeVideo); + UpdateVideoConfig(); + + // Keep reading more data. + video_stream_->Read( + 1, base::BindOnce(&DemuxerStreamReader::OnReadBuffer, + weak_factory_.GetWeakPtr(), type, seek_ticket)); + } + return; + } + case ::media::DemuxerStream::Status::kError: + LOG(ERROR) << "DemuxerStream error occurred"; + client_->OnError(::media::PIPELINE_ERROR_READ); + return; + case ::media::DemuxerStream::Status::kOk: + LOG(FATAL) << "OK status must be handled separately"; + default: + LOG(WARNING) << "Received unknown DemuxerStream status: " << status + << ", with name " + << ::media::DemuxerStream::GetStatusName(status); + return; + } +} + +void DemuxerStreamReader::OnReadBuffer( + StarboardMediaType type, + int seek_ticket, + ::media::DemuxerStream::Status status, + std::vector<scoped_refptr<DecoderBuffer>> buffers) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (status != ::media::DemuxerStream::Status::kOk) { + DCHECK(buffers.empty()); + HandleNonOkDemuxerStatus(status, type, seek_ticket); + return; + } + + CHECK_EQ(buffers.size(), 1UL); + scoped_refptr<DecoderBuffer> buffer = std::move(buffers[0]); + CHECK(buffer); + + if (buffer->end_of_stream()) { + handle_eos_cb_.Run(seek_ticket, type); + return; + } + + if (type == StarboardMediaType::kStarboardMediaTypeAudio) { + buffer = convert_audio_fn_.Run(std::move(buffer)); + } + + StarboardSampleInfo sample_info = {}; + sample_info.type = type; + sample_info.buffer = buffer->data(); + sample_info.buffer_size = buffer->size(); + sample_info.timestamp = buffer->timestamp().InMicroseconds(); + sample_info.side_data = base::span<const StarboardSampleSideData>(); + + if (type == StarboardMediaType::kStarboardMediaTypeAudio) { + DCHECK(audio_sample_info_); + sample_info.audio_sample_info = *audio_sample_info_; + } else { + DCHECK(video_sample_info_); + sample_info.video_sample_info = *video_sample_info_; + // is_key_frame needs to be set per sample. + sample_info.video_sample_info.is_key_frame = buffer->is_key_frame(); + + if (first_video_frame_) { + first_video_frame_ = false; + client_->OnVideoNaturalSizeChange( + gfx::Size(sample_info.video_sample_info.frame_width, + sample_info.video_sample_info.frame_height)); + } + } + + // drm_info must not be deleted until after sample_info is passed to + // starboard. + DrmInfoWrapper drm_info = DrmInfoWrapper::Create(*buffer); + sample_info.drm_info = drm_info.GetDrmSampleInfo(); + + // For encrypted buffers, we should not push data to starboard util the + // buffer's DRM key is available to the CDM. To accomplish this, we check with + // the StarboardDrmKeyTracker singleton -- which is updated by the CDM, + // StarboardDecryptorCast -- to see whether the key is available. If the key + // is not available yet, we register a callback that will be run once the key + // becomes available. + if (sample_info.drm_info) { + const std::string drm_key( + reinterpret_cast<const char*>(sample_info.drm_info->identifier), + sample_info.drm_info->identifier_size); + if (!StarboardDrmKeyTracker::GetInstance().HasKey(drm_key)) { + WaitForKey(std::move(drm_info), std::move(sample_info), std::move(buffer), + seek_ticket); + return; + } + + // The key is already available; continue the logic of pushing the buffer to + // starboard. + } + + handle_buffer_cb_.Run(seek_ticket, std::move(sample_info), std::move(buffer)); +} + +void DemuxerStreamReader::WaitForKey(DrmInfoWrapper drm_info, + StarboardSampleInfo sample_info, + scoped_refptr<DecoderBuffer> buffer, + int seek_ticket) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + StarboardDrmSampleInfo* const drm_sample_info = drm_info.GetDrmSampleInfo(); + const std::string drm_key( + reinterpret_cast<const char*>(drm_sample_info->identifier), + drm_sample_info->identifier_size); + + const size_t key_hash = base::FastHash( + base::span(drm_sample_info->identifier) + .first(static_cast<size_t>(drm_sample_info->identifier_size))); + LOG(INFO) << "Waiting for DRM key with hash: " << key_hash; + CHECK(base::SequencedTaskRunner::HasCurrentDefault()); + const int64_t token = StarboardDrmKeyTracker::GetInstance().WaitForKey( + drm_key, + base::BindPostTask( + base::SequencedTaskRunner::GetCurrentDefault(), + base::BindOnce(&DemuxerStreamReader::RunPendingDrmKeyCallback, + weak_factory_.GetWeakPtr()))); + + CHECK(!token_to_drm_key_cb_.contains(token)) + << "Got duplicate DRM key token: " << token; + + // Bind the buffer to a closure that will be run when the DRM key is + // available. + base::OnceClosure handle_buffer_closure = + base::BindOnce(handle_buffer_cb_, seek_ticket, std::move(sample_info), + std::move(buffer)); + + // Bind the DrmInfoWrapper as well, so that it outlives handle_buffer_closure. + token_to_drm_key_cb_[token] = base::BindOnce( + [](base::OnceClosure cb, DrmInfoWrapper drm_info) { + // drm_info must outlive this call. Otherwise, the pointers in the + // sample_info could point to bad memory. + std::move(cb).Run(); + }, + std::move(handle_buffer_closure), std::move(drm_info)); + + client_->OnWaiting(::media::WaitingReason::kNoDecryptionKey); +} + +void DemuxerStreamReader::RunPendingDrmKeyCallback(int64_t token) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (auto it = token_to_drm_key_cb_.find(token); + it != token_to_drm_key_cb_.end()) { + std::move(it->second).Run(); + token_to_drm_key_cb_.erase(it); + } +} + +void DemuxerStreamReader::UpdateAudioConfig() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + CHECK(audio_stream_); + chromium_audio_config_ = audio_stream_->audio_decoder_config(); + LOG(INFO) << "Audio config changed to " + << chromium_audio_config_.AsHumanReadableString(); + audio_sample_info_ = ToStarboardAudioSampleInfo(chromium_audio_config_); + if (IsResamplingNecessary(chromium_audio_config_)) { + convert_audio_fn_ = base::BindRepeating( + &ConvertPcmAudioBufferToS16, chromium_audio_config_.codec(), + chromium_audio_config_.sample_format(), + chromium_audio_config_.channels()); + } else { + convert_audio_fn_ = base::BindRepeating(&DoNotConvertBuffer); + } + client_->OnAudioConfigChange(chromium_audio_config_); +} + +void DemuxerStreamReader::UpdateVideoConfig() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + DCHECK(video_stream_); + const ::media::VideoDecoderConfig video_config = + video_stream_->video_decoder_config(); + LOG(INFO) << "Video config changed to " + << video_config.AsHumanReadableString(); + std::optional<StarboardVideoSampleInfo> new_sample_info = + ToStarboardVideoSampleInfo(video_config); + + // TODO(antoniori): maybe fail gracefully here, rather than crashing. + DCHECK(new_sample_info); + if (!video_sample_info_ || + video_sample_info_->frame_width != new_sample_info->frame_width || + video_sample_info_->frame_height != new_sample_info->frame_height) { + client_->OnVideoNaturalSizeChange(gfx::Size( + video_sample_info_->frame_width, video_sample_info_->frame_height)); + } + video_sample_info_ = std::move(new_sample_info); + client_->OnVideoConfigChange(video_config); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/demuxer_stream_reader.h b/chromecast/starboard/media/renderer/demuxer_stream_reader.h new file mode 100644 index 0000000..5d27f30 --- /dev/null +++ b/chromecast/starboard/media/renderer/demuxer_stream_reader.h
@@ -0,0 +1,126 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_STARBOARD_MEDIA_RENDERER_DEMUXER_STREAM_READER_H_ +#define CHROMECAST_STARBOARD_MEDIA_RENDERER_DEMUXER_STREAM_READER_H_ + +#include <optional> + +#include "base/containers/flat_map.h" +#include "base/functional/callback.h" +#include "base/functional/callback_forward.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "chromecast/starboard/media/media/drm_util.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/decoder_buffer.h" +#include "media/base/demuxer_stream.h" +#include "media/base/renderer_client.h" + +namespace chromecast { +namespace media { + +// Receives buffers from one or more DemuxerStreams, calling handle_buffer_cb +// when a buffer is ready to be processed. Audio buffers are processed via +// `convert_audio_fn` before being passed to starboard, e.g. to convert PCM +// data to S16. +// +// This class ensures that encrypted buffers are not handled until the +// relevant DRM key is available to the CDM. +// +// This class must only be used on one sequence. +class DemuxerStreamReader { + public: + // Note that this contains both a StarboardSampleInfo and a + // scoped_refptr<DecoderBuffer>. This is so that the lifetime of the + // underlying buffer data (stored in the scoped_refptr) can be managed + // properly. + // + // sample_info may contain pointers (to DRM-related info) that become + // invalid after the callback returns. + using HandleBufferCb = base::RepeatingCallback<void( + int seek_ticket, + StarboardSampleInfo sample_info, + scoped_refptr<::media::DecoderBuffer> buffer)>; + + using HandleEosCb = + base::RepeatingCallback<void(int seek_ticket, StarboardMediaType type)>; + + DemuxerStreamReader(::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + std::optional<StarboardAudioSampleInfo> audio_sample_info, + std::optional<StarboardVideoSampleInfo> video_sample_info, + HandleBufferCb handle_buffer_cb, + HandleEosCb handle_eos_cb, + ::media::RendererClient* client); + + ~DemuxerStreamReader(); + + // Requests that a buffer of type `type` be read from the relevant + // DemuxerStream. `seek_ticket` and `type` will be passed to the + // HandleBufferCb along with the buffer. + void ReadBuffer(int seek_ticket, StarboardMediaType type); + + private: + using ConvertAudioFn = + base::RepeatingCallback<scoped_refptr<::media::DecoderBuffer>( + scoped_refptr<::media::DecoderBuffer>)>; + + // Callback called by a DemuxerStream. + void OnReadBuffer(StarboardMediaType type, + int seek_ticket, + ::media::DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers); + + // Handles a non-OK status from a DemuxerStream of type `type`. `status` must + // NOT be OK. + void HandleNonOkDemuxerStatus(::media::DemuxerStream::Status status, + StarboardMediaType type, + int seek_ticket); + + // Waits for a DRM key to be available to the CDM. Once the key is available, + // the buffer will be pushed to starboard via handle_buffer_cb_. + void WaitForKey(DrmInfoWrapper drm_info, + StarboardSampleInfo sample_info, + scoped_refptr<::media::DecoderBuffer> buffer, + int seek_ticket); + + // Runs a pending callback now that a DRM key is available. + void RunPendingDrmKeyCallback(int64_t token); + + // Updates the audio config to match the current config from audio_stream_. + void UpdateAudioConfig(); + + // Updates the video config to match the current config from video_stream_. + void UpdateVideoConfig(); + + SEQUENCE_CHECKER(sequence_checker_); + ConvertAudioFn convert_audio_fn_; + HandleBufferCb handle_buffer_cb_; + HandleEosCb handle_eos_cb_; + ::media::RendererClient* client_; + ::media::DemuxerStream* audio_stream_ = nullptr; + ::media::DemuxerStream* video_stream_ = nullptr; + + // StarboardAudioSampleInfo contains a const void* audio_specific_config. That + // field can point to the extra data of this config, so we should ensure that + // the ptr remains valid until the next buffer is read. + ::media::AudioDecoderConfig chromium_audio_config_; + std::optional<StarboardAudioSampleInfo> audio_sample_info_; + std::optional<StarboardVideoSampleInfo> video_sample_info_; + bool first_video_frame_ = true; + // Maps from opaque token to a callback that should be run when the DRM key + // represented by that token is available. + base::flat_map<int64_t, base::OnceClosure> token_to_drm_key_cb_; + + // This should be destructed first, to invalidate any weak ptrs. + base::WeakPtrFactory<DemuxerStreamReader> weak_factory_{this}; +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_RENDERER_DEMUXER_STREAM_READER_H_
diff --git a/chromecast/starboard/media/renderer/demuxer_stream_reader_test.cc b/chromecast/starboard/media/renderer/demuxer_stream_reader_test.cc new file mode 100644 index 0000000..9f8b901 --- /dev/null +++ b/chromecast/starboard/media/renderer/demuxer_stream_reader_test.cc
@@ -0,0 +1,435 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/demuxer_stream_reader.h" + +#include <array> +#include <cstdint> +#include <functional> +#include <string> +#include <string_view> +#include <tuple> + +#include "base/run_loop.h" +#include "base/task/sequenced_task_runner.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "chromecast/starboard/media/cdm/starboard_drm_key_tracker.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "chromecast/starboard/media/media/test_matchers.h" +#include "media/base/audio_codecs.h" +#include "media/base/audio_decoder_config.h" +#include "media/base/channel_layout.h" +#include "media/base/decoder_buffer.h" +#include "media/base/decrypt_config.h" +#include "media/base/encryption_scheme.h" +#include "media/base/mock_filters.h" +#include "media/base/sample_format.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromecast { +namespace media { +namespace { + +using ::base::test::SingleThreadTaskEnvironment; +using ::media::AudioDecoderConfig; +using ::media::DecoderBuffer; +using ::media::DecryptConfig; +using ::media::DemuxerStream; +using ::media::MockDemuxerStream; +using ::media::MockRendererClient; +using ::testing::_; +using ::testing::DoAll; +using ::testing::MockFunction; +using ::testing::NotNull; +using ::testing::Pointee; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::SaveArgByMove; + +// Some default data. The values themselves are not relevant to the logic of the +// DemuxerStreamReader. +constexpr auto kBufferData = std::to_array<uint8_t>({1, 2, 3, 4, 5}); +constexpr std::string_view kIv = "0123456789ABCDEF"; +static_assert(kIv.size() == DecryptConfig::kDecryptionKeySize); +constexpr std::string_view kIdentifier = "drm_key_1"; +constexpr StarboardDrmSubSampleMapping kSubsampleMapping = { + .clear_byte_count = 0, + .encrypted_byte_count = kBufferData.size(), +}; + +// Matches a DecoderBuffer. +MATCHER_P(DecoderBufferMatches, expected_buffer, "") { + const DecoderBuffer& decoder_buffer = arg; + return decoder_buffer.MatchesForTesting(expected_buffer); +} + +// Creates an audio sample containing the given data and (optional) DRM info. +StarboardSampleInfo CreateAudioSample( + base::span<const uint8_t> data, + StarboardDrmSampleInfo* drm_info = nullptr) { + StarboardSampleInfo sample_info; + sample_info.type = 0; // Audio + sample_info.buffer = data.data(); + sample_info.buffer_size = data.size(); + sample_info.timestamp = 0; + sample_info.side_data = base::span<const StarboardSampleSideData>(); + sample_info.audio_sample_info = {}; + sample_info.audio_sample_info.codec = + StarboardAudioCodec::kStarboardAudioCodecAac; + sample_info.audio_sample_info.mime = ""; + sample_info.drm_info = drm_info; + + return sample_info; +} + +// Creates a video sample containing the given data and (optional) DRM info. +StarboardSampleInfo CreateVideoSample( + base::span<const uint8_t> data, + StarboardDrmSampleInfo* drm_info = nullptr) { + StarboardSampleInfo sample_info; + sample_info.type = 1; // Video + sample_info.buffer = data.data(); + sample_info.buffer_size = data.size(); + sample_info.timestamp = 0; + sample_info.side_data = base::span<const StarboardSampleSideData>(); + sample_info.video_sample_info.codec = + StarboardVideoCodec::kStarboardVideoCodecH265; + sample_info.video_sample_info.mime = ""; + sample_info.video_sample_info.max_video_capabilities = ""; + sample_info.video_sample_info.is_key_frame = false; + sample_info.video_sample_info.frame_width = 1920; + sample_info.video_sample_info.frame_height = 1080; + sample_info.video_sample_info.color_metadata = {}; + sample_info.drm_info = drm_info; + + return sample_info; +} + +// A test fixture is used to avoid a bit of boilerplate in each test (creating +// the task environment, mocks, etc). +class DemuxerStreamReaderTest : public ::testing::Test { + protected: + DemuxerStreamReaderTest() + : audio_stream_(DemuxerStream::Type::AUDIO), + video_stream_(DemuxerStream::Type::VIDEO) { + // Ensure that tests begin with a clean slate regarding DRM keys. + StarboardDrmKeyTracker::GetInstance().ClearStateForTesting(); + } + + ~DemuxerStreamReaderTest() override = default; + + // This should be destructed last. + SingleThreadTaskEnvironment task_environment_; + MockDemuxerStream audio_stream_; + MockDemuxerStream video_stream_; + MockRendererClient renderer_client_; + MockFunction<void(int seek_ticket, + StarboardSampleInfo sample_info, + scoped_refptr<::media::DecoderBuffer> buffer)> + handle_buffer_cb_; + MockFunction<void(int seek_ticket, StarboardMediaType type)> handle_eos_cb_; +}; + +TEST_F(DemuxerStreamReaderTest, ReadsVideoBufferAndCallsBufferCb) { + constexpr int kSeekTicket = 7; + scoped_refptr<DecoderBuffer> buffer = + DecoderBuffer::CopyFrom({1, 2, 3, 4, 5}); + StarboardSampleInfo expected_info = CreateVideoSample(*buffer); + + EXPECT_CALL(handle_eos_cb_, Call).Times(0); + EXPECT_CALL(handle_buffer_cb_, + Call(kSeekTicket, MatchesStarboardSampleInfo(expected_info), + Pointee(DecoderBufferMatches(std::cref(*buffer))))) + .Times(1); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(video_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + /*audio_stream=*/nullptr, &video_stream_, + /*audio_sample_info=*/std::nullopt, expected_info.video_sample_info, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeVideo); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, {buffer}); +} + +TEST_F(DemuxerStreamReaderTest, ReadsVideoBufferAndCallsEosCb) { + constexpr int kSeekTicket = 7; + StarboardVideoSampleInfo video_sample_info = {}; + + EXPECT_CALL(handle_eos_cb_, + Call(kSeekTicket, StarboardMediaType::kStarboardMediaTypeVideo)) + .Times(1); + EXPECT_CALL(handle_buffer_cb_, Call).Times(0); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(video_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + /*audio_stream=*/nullptr, &video_stream_, + /*audio_sample_info=*/std::nullopt, video_sample_info, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeVideo); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, + {DecoderBuffer::CreateEOSBuffer()}); +} + +TEST_F(DemuxerStreamReaderTest, ReadsAudioBufferAndCallsBufferCb) { + constexpr int kSeekTicket = 7; + scoped_refptr<DecoderBuffer> buffer = + DecoderBuffer::CopyFrom({1, 2, 3, 4, 5, 6, 7, 8}); + StarboardSampleInfo expected_info = CreateAudioSample(*buffer); + + EXPECT_CALL(handle_eos_cb_, Call).Times(0); + EXPECT_CALL(handle_buffer_cb_, + Call(kSeekTicket, MatchesStarboardSampleInfo(expected_info), + Pointee(DecoderBufferMatches(std::cref(*buffer))))) + .Times(1); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(audio_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + &audio_stream_, /*video_stream=*/nullptr, expected_info.audio_sample_info, + /*video_sample_info=*/std::nullopt, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeAudio); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, {buffer}); +} + +TEST_F(DemuxerStreamReaderTest, ReadsAudioBufferAndCallsEosCb) { + constexpr int kSeekTicket = 7; + StarboardAudioSampleInfo audio_sample_info = {}; + + EXPECT_CALL(handle_eos_cb_, + Call(kSeekTicket, StarboardMediaType::kStarboardMediaTypeAudio)) + .Times(1); + EXPECT_CALL(handle_buffer_cb_, Call).Times(0); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(audio_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + &audio_stream_, /*video_stream=*/nullptr, audio_sample_info, + /*video_sample_info=*/std::nullopt, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeAudio); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, + {DecoderBuffer::CreateEOSBuffer()}); +} + +TEST_F(DemuxerStreamReaderTest, ReadsAudioBufferAndConvertsPcmToS16) { + constexpr int kSeekTicket = 7; + // These values represent the min value, the max value, and 0. These can + // easily be converted to S16 for comparison (see kS16Data below). + constexpr auto kS32Data = + std::to_array<uint32_t>({0x80000000, 0x7FFFFFFF, 0}); + // The equivalent to kS32Data, but represented as 16-bit samples. + constexpr auto kS16Data = std::to_array<uint16_t>({0x8000, 0x7FFF, 0}); + scoped_refptr<DecoderBuffer> buffer = + DecoderBuffer::CopyFrom(base::as_byte_span(kS32Data)); + scoped_refptr<DecoderBuffer> s16_buffer = + DecoderBuffer::CopyFrom(base::as_byte_span(kS16Data)); + StarboardSampleInfo expected_info = CreateAudioSample(*buffer); + expected_info.audio_sample_info.codec = + StarboardAudioCodec::kStarboardAudioCodecPcm; + + // The relevant bits of information here are: + // * codec = PCM (so that the DemuxerStreamReader converts it to S16) + // * sample format = S32 + // * channel layout = mono (since there are only 3 samples in kS32Data) + // * encryption scheme = unencrypted + audio_stream_.set_audio_decoder_config(AudioDecoderConfig( + ::media::AudioCodec::kPCM, ::media::SampleFormat::kSampleFormatS32, + ::media::ChannelLayout::CHANNEL_LAYOUT_MONO, 44100, {}, + ::media::EncryptionScheme::kUnencrypted)); + + EXPECT_CALL(handle_eos_cb_, Call).Times(0); + scoped_refptr<DecoderBuffer> captured_buffer; + StarboardSampleInfo captured_sample_info; + EXPECT_CALL(handle_buffer_cb_, + Call(kSeekTicket, _, + Pointee(DecoderBufferMatches(std::cref(*s16_buffer))))) + .WillOnce(DoAll(SaveArg<1>(&captured_sample_info), + SaveArg<2>(&captured_buffer))); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(audio_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + &audio_stream_, /*video_stream=*/nullptr, expected_info.audio_sample_info, + /*video_sample_info=*/std::nullopt, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeAudio); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, {buffer}); + + ASSERT_THAT(captured_buffer, NotNull()); + + // Update the expectations to match the buffer that was returned from the + // DemuxerStreamReader. That info needs to be match the info in the starboard + // structs, so that the data passed to starboard has its lifetime managed + // properly. + expected_info.buffer = captured_buffer->data(); + expected_info.buffer_size = captured_buffer->size(); + EXPECT_THAT(captured_sample_info, MatchesStarboardSampleInfo(expected_info)); +} + +TEST_F(DemuxerStreamReaderTest, + ReadsVideoBufferButDoesNotCallCbIfDrmKeyUnavailable) { + constexpr int kSeekTicket = 7; + scoped_refptr<DecoderBuffer> buffer = DecoderBuffer::CopyFrom(kBufferData); + buffer->set_decrypt_config(DecryptConfig::CreateCencConfig( + std::string(kIdentifier), std::string(kIv), + /*subsamples=*/{})); + + StarboardDrmSampleInfo drm_info; + drm_info.encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCtr; + // CENC encryption scheme does not use an encryption pattern. + drm_info.encryption_pattern.crypt_byte_block = 0; + drm_info.encryption_pattern.skip_byte_block = 0; + base::span<uint8_t>(drm_info.initialization_vector) + .first<kIv.size()>() + .copy_from(base::as_byte_span(kIv)); + drm_info.initialization_vector_size = kIv.size(); + base::span<uint8_t>(drm_info.identifier) + .first<kIdentifier.size()>() + .copy_from(base::as_byte_span(kIdentifier)); + drm_info.identifier_size = kIdentifier.size(); + drm_info.subsample_mapping = base::span_from_ref(kSubsampleMapping); + + StarboardSampleInfo expected_info = CreateVideoSample(*buffer, &drm_info); + + EXPECT_CALL(handle_eos_cb_, Call).Times(0); + // This should not be called, since the DRM key is not available. + EXPECT_CALL(handle_buffer_cb_, Call).Times(0); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(video_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + /*audio_stream=*/nullptr, &video_stream_, + /*audio_sample_info=*/std::nullopt, expected_info.video_sample_info, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeVideo); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, {buffer}); +} + +TEST_F(DemuxerStreamReaderTest, + ReadsVideoBufferAndCallsCbWhenDrmKeyIsAvailable) { + constexpr int kSeekTicket = 7; + scoped_refptr<DecoderBuffer> buffer = DecoderBuffer::CopyFrom(kBufferData); + buffer->set_decrypt_config(DecryptConfig::CreateCencConfig( + std::string(kIdentifier), std::string(kIv), + /*subsamples=*/{})); + + StarboardDrmSampleInfo drm_info; + drm_info.encryption_scheme = + StarboardDrmEncryptionScheme::kStarboardDrmEncryptionSchemeAesCtr; + // CENC encryption scheme does not use an encryption pattern. + drm_info.encryption_pattern.crypt_byte_block = 0; + drm_info.encryption_pattern.skip_byte_block = 0; + base::span<uint8_t>(drm_info.initialization_vector) + .first<kIv.size()>() + .copy_from(base::as_byte_span(kIv)); + drm_info.initialization_vector_size = kIv.size(); + base::span<uint8_t>(drm_info.identifier) + .first<kIdentifier.size()>() + .copy_from(base::as_byte_span(kIdentifier)); + drm_info.identifier_size = kIdentifier.size(); + drm_info.subsample_mapping = base::span_from_ref(kSubsampleMapping); + + StarboardSampleInfo expected_info = CreateVideoSample(*buffer, &drm_info); + + EXPECT_CALL(handle_eos_cb_, Call).Times(0); + // This should be called once the DRM key is available. + EXPECT_CALL(handle_buffer_cb_, + Call(kSeekTicket, MatchesStarboardSampleInfo(expected_info), + Pointee(DecoderBufferMatches(std::cref(*buffer))))) + .Times(1); + base::OnceCallback<void( + DemuxerStream::Status status, + std::vector<scoped_refptr<::media::DecoderBuffer>> buffers)> + read_cb; + EXPECT_CALL(video_stream_, OnRead).WillOnce(SaveArgByMove<0>(&read_cb)); + + DemuxerStreamReader stream_reader( + /*audio_stream=*/nullptr, &video_stream_, + /*audio_sample_info=*/std::nullopt, expected_info.video_sample_info, + base::BindLambdaForTesting(handle_buffer_cb_.AsStdFunction()), + base::BindLambdaForTesting(handle_eos_cb_.AsStdFunction()), + &renderer_client_); + stream_reader.ReadBuffer(kSeekTicket, + StarboardMediaType::kStarboardMediaTypeVideo); + + // Simulate the DemuxerStream providing a buffer. + ASSERT_FALSE(read_cb.is_null()); + std::move(read_cb).Run(DemuxerStream::Status::kOk, {buffer}); + + // Simulate the DRM key being available. This should trigger the call to + // handle_buffer_cb_. + StarboardDrmKeyTracker::GetInstance().AddKey(std::string(kIdentifier), + "some_session"); + + // Use a run loop here, since the DRM key callback may be posted to a separate + // task. + base::RunLoop run_loop; + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/geometry_change_handler.cc b/chromecast/starboard/media/renderer/geometry_change_handler.cc new file mode 100644 index 0000000..e683aab --- /dev/null +++ b/chromecast/starboard/media/renderer/geometry_change_handler.cc
@@ -0,0 +1,89 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/geometry_change_handler.h" + +#include "base/check.h" +#include "base/logging.h" +#include "chromecast/media/service/video_geometry_setter_service.h" +#include "ui/display/screen.h" + +namespace chromecast { +namespace media { + +namespace { + +// Sets the SbPlayer's bounds as specified. `starboard` and `sb_player` must not +// be null. +void SetPlayerBounds(const gfx::RectF& bounds, + StarboardApiWrapper* starboard, + void* sb_player) { + CHECK(starboard); + CHECK(sb_player); + + LOG(INFO) << "Setting SbPlayer's bounds to z=0, x=" << bounds.x() + << ", y=" << bounds.y() << ", width=" << bounds.width() + << ", height=" << bounds.height(); + starboard->SetPlayerBounds( + sb_player, /*z_index=*/0, static_cast<int>(bounds.x()), + static_cast<int>(bounds.y()), static_cast<int>(bounds.width()), + static_cast<int>(bounds.height())); +} + +} // namespace + +GeometryChangeHandler::GeometryChangeHandler( + VideoGeometrySetterService* geometry_setter_service, + StarboardApiWrapper* starboard, + const base::UnguessableToken& overlay_plane_id) + : starboard_(starboard) { + CHECK(starboard_); + CHECK(geometry_setter_service); + geometry_setter_service->GetVideoGeometryChangeSubscriber( + geometry_change_subscriber_remote_.BindNewPipeAndPassReceiver()); + geometry_change_subscriber_remote_->SubscribeToVideoGeometryChange( + overlay_plane_id, + geometry_change_client_receiver_.BindNewPipeAndPassRemote(), + base::DoNothing()); +} + +GeometryChangeHandler::~GeometryChangeHandler() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +void GeometryChangeHandler::SetSbPlayer(void* sb_player) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + CHECK(sb_player); + sb_player_ = sb_player; + + // Update the player's bounds. + if (current_geometry_.has_value()) { + // Use the bounds specified by a mojo call. + SetPlayerBounds(*current_geometry_, starboard_, sb_player_); + } else { + // Default to fullscreen. + const gfx::Size display_size = + display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel(); + SetPlayerBounds( + gfx::RectF(0, 0, display_size.width(), display_size.height()), + starboard_, sb_player_); + } +} + +void GeometryChangeHandler::OnVideoGeometryChange( + const gfx::RectF& rect_f, + gfx::OverlayTransform transform) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (current_geometry_.has_value() && rect_f == *current_geometry_) { + return; + } + + current_geometry_ = rect_f; + if (sb_player_) { + SetPlayerBounds(*current_geometry_, starboard_, sb_player_); + } +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/geometry_change_handler.h b/chromecast/starboard/media/renderer/geometry_change_handler.h new file mode 100644 index 0000000..729ed79 --- /dev/null +++ b/chromecast/starboard/media/renderer/geometry_change_handler.h
@@ -0,0 +1,75 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_STARBOARD_MEDIA_RENDERER_GEOMETRY_CHANGE_HANDLER_H_ +#define CHROMECAST_STARBOARD_MEDIA_RENDERER_GEOMETRY_CHANGE_HANDLER_H_ + +#include <optional> + +#include "base/sequence_checker.h" +#include "chromecast/media/service/mojom/video_geometry_setter.mojom.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/overlay_transform.h" + +namespace chromecast { +namespace media { + +class VideoGeometrySetterService; + +// Receives notifications of geometry changes and sets an SbPlayer's bounds +// accordingly. If no SbPlayer is available when a geometry change occurs, the +// player's bounds will be set once an SbPlayer is assigned via SetSbPlayer. +// +// If no bounds have been set by the VideoGeometrySetterService, this class will +// use the display resolution to set the bounds to fullscreen by default. +// +// A GeometryChangeHandler must be used on a single sequence. +class GeometryChangeHandler : public mojom::VideoGeometryChangeClient { + public: + // `geometry_setter_service` and `starboard` must outlive this object, and + // cannot be null. + GeometryChangeHandler(VideoGeometrySetterService* geometry_setter_service, + StarboardApiWrapper* starboard, + const base::UnguessableToken& overlay_plane_id); + + // Disallow copy and assign. + GeometryChangeHandler(const GeometryChangeHandler&) = delete; + GeometryChangeHandler& operator=(const GeometryChangeHandler&) = delete; + + ~GeometryChangeHandler() override; + + // Sets the SbPlayer that GeometryChangeHandler will notify of bounds changes. + // SbPlayerSetBounds will be called immediately. If a bounds change was + // pending, that geometry will be used. Otherwise, the bounds will be set to + // fullscreen. + // + // `sb_player` must not be null. + void SetSbPlayer(void* sb_player); + + // mojom::VideoGeometryChangeClient implementation. + void OnVideoGeometryChange(const gfx::RectF& rect_f, + gfx::OverlayTransform transform) override; + + private: + SEQUENCE_CHECKER(sequence_checker_); + + mojo::Remote<mojom::VideoGeometryChangeSubscriber> + geometry_change_subscriber_remote_; + mojo::Receiver<mojom::VideoGeometryChangeClient> + geometry_change_client_receiver_{this}; + + StarboardApiWrapper* starboard_ = nullptr; + // This is nullopt if a geometry has not yet been set. + std::optional<gfx::RectF> current_geometry_; + + void* sb_player_ = nullptr; +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_RENDERER_GEOMETRY_CHANGE_HANDLER_H_
diff --git a/chromecast/starboard/media/renderer/geometry_change_handler_test.cc b/chromecast/starboard/media/renderer/geometry_change_handler_test.cc new file mode 100644 index 0000000..f9ae35a --- /dev/null +++ b/chromecast/starboard/media/renderer/geometry_change_handler_test.cc
@@ -0,0 +1,152 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/geometry_change_handler.h" + +#include "base/run_loop.h" +#include "base/task/sequenced_task_runner.h" +#include "base/test/task_environment.h" +#include "base/unguessable_token.h" +#include "chromecast/media/service/video_geometry_setter_service.h" +#include "chromecast/starboard/media/media/mock_starboard_api_wrapper.h" +#include "mojo/core/embedder/embedder.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/display/test/test_screen.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/overlay_transform.h" + +namespace chromecast { +namespace media { +namespace { + +using ::testing::InSequence; + +// Runs any pending tasks that have been posted to the current sequence. +void RunPendingTasks() { + base::RunLoop run_loop; + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); +} + +TEST(GeometryChangeHandlerTest, ReadsBoundsFromVideoGeometrySetterService) { + base::test::TaskEnvironment task_environment; + mojo::core::Init(); + display::test::TestScreen test_screen(/*create_display=*/true, + /*register_screen=*/true); + + VideoGeometrySetterService geometry_setter_service; + MockStarboardApiWrapper starboard; + + const auto plane_id = base::UnguessableToken::Create(); + + const gfx::RectF geometry(0, 0, 1920, 1080); + const gfx::OverlayTransform transform = + gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE; + // This will be used as an opaque ptr; its value does not matter. + int sb_player = 7; + + EXPECT_CALL(starboard, + SetPlayerBounds(&sb_player, 0, static_cast<int>(geometry.x()), + static_cast<int>(geometry.y()), + static_cast<int>(geometry.width()), + static_cast<int>(geometry.height()))) + .Times(1); + + GeometryChangeHandler handler(&geometry_setter_service, &starboard, plane_id); + RunPendingTasks(); + + static_cast<mojom::VideoGeometrySetter*>(&geometry_setter_service) + ->SetVideoGeometry(geometry, transform, plane_id); + RunPendingTasks(); + handler.SetSbPlayer(&sb_player); +} + +TEST(GeometryChangeHandlerTest, + ForwardsUpdatesFromVideoGeometrySetterServiceToStarboard) { + base::test::TaskEnvironment task_environment; + mojo::core::Init(); + display::test::TestScreen test_screen(/*create_display=*/true, + /*register_screen=*/true); + + VideoGeometrySetterService geometry_setter_service; + MockStarboardApiWrapper starboard; + + const auto plane_id = base::UnguessableToken::Create(); + + const gfx::RectF geometry_1(0, 0, 1920, 1080); + const gfx::RectF geometry_2(0, 0, 720, 1280); + const gfx::OverlayTransform transform = + gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE; + // This will be used as an opaque ptr; its value does not matter. + int sb_player = 7; + + { + InSequence s; + EXPECT_CALL(starboard, + SetPlayerBounds(&sb_player, 0, static_cast<int>(geometry_1.x()), + static_cast<int>(geometry_1.y()), + static_cast<int>(geometry_1.width()), + static_cast<int>(geometry_1.height()))) + .Times(1); + + EXPECT_CALL(starboard, + SetPlayerBounds(&sb_player, 0, static_cast<int>(geometry_2.x()), + static_cast<int>(geometry_2.y()), + static_cast<int>(geometry_2.width()), + static_cast<int>(geometry_2.height()))) + .Times(1); + } + + GeometryChangeHandler handler(&geometry_setter_service, &starboard, plane_id); + RunPendingTasks(); + + static_cast<mojom::VideoGeometrySetter*>(&geometry_setter_service) + ->SetVideoGeometry(geometry_1, transform, plane_id); + RunPendingTasks(); + handler.SetSbPlayer(&sb_player); + + static_cast<mojom::VideoGeometrySetter*>(&geometry_setter_service) + ->SetVideoGeometry(geometry_2, transform, plane_id); + RunPendingTasks(); +} + +TEST(GeometryChangeHandlerTest, ReadsBoundsFromScreenResolution) { + base::test::TaskEnvironment task_environment; + mojo::core::Init(); + display::test::TestScreen test_screen(/*create_display=*/true, + /*register_screen=*/true); + + VideoGeometrySetterService geometry_setter_service; + MockStarboardApiWrapper starboard; + + const auto plane_id = base::UnguessableToken::Create(); + + // This will be used as an opaque ptr; its value does not matter. + int sb_player = 7; + + // Since a resolution has not been set, the bounds should be set to + // fullscreen. + EXPECT_CALL( + starboard, + SetPlayerBounds( + &sb_player, 0, + static_cast<int>(display::test::TestScreen::kDefaultScreenBounds.x()), + static_cast<int>(display::test::TestScreen::kDefaultScreenBounds.y()), + static_cast<int>( + display::test::TestScreen::kDefaultScreenBounds.width()), + static_cast<int>( + display::test::TestScreen::kDefaultScreenBounds.height()))) + .Times(1); + + GeometryChangeHandler handler(&geometry_setter_service, &starboard, plane_id); + RunPendingTasks(); + handler.SetSbPlayer(&sb_player); + RunPendingTasks(); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/starboard_player_manager.cc b/chromecast/starboard/media/renderer/starboard_player_manager.cc new file mode 100644 index 0000000..7ac1564 --- /dev/null +++ b/chromecast/starboard/media/renderer/starboard_player_manager.cc
@@ -0,0 +1,353 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/starboard_player_manager.h" + +#include "base/check.h" +#include "base/containers/span.h" +#include "base/functional/bind.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h" +#include "chromecast/starboard/media/media/drm_util.h" +#include "chromecast/starboard/media/renderer/chromium_starboard_conversions.h" + +namespace chromecast { +namespace media { + +std::unique_ptr<StarboardPlayerManager> StarboardPlayerManager::Create( + StarboardApiWrapper* starboard, + ::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + ::media::RendererClient* client, + scoped_refptr<base::SequencedTaskRunner> media_task_runner, + bool enable_buffering) { + if ((!audio_stream && !video_stream) || !starboard || !client || + !media_task_runner) { + return nullptr; + } + + // These objects need to outlive the call to CreatePlayer, since + // creation_param might reference pointers derived from vectors stored in + // these objects (for extra_data). + ::media::AudioDecoderConfig audio_config; + ::media::VideoDecoderConfig video_config; + + std::optional<StarboardAudioSampleInfo> audio_sample_info; + std::optional<StarboardVideoSampleInfo> video_sample_info; + + chromecast::media::StarboardPlayerCreationParam creation_param = {}; + creation_param.drm_system = StarboardDrmWrapper::GetInstance().GetDrmSystem(); + creation_param.output_mode = + StarboardPlayerOutputMode::kStarboardPlayerOutputModePunchOut; + + if (audio_stream) { + audio_stream->EnableBitstreamConverter(); + audio_config = audio_stream->audio_decoder_config(); + audio_sample_info = ToStarboardAudioSampleInfo(audio_config); + if (!audio_sample_info) { + LOG(ERROR) << "Invalid or unsupported audio config: " + << audio_config.AsHumanReadableString(); + return nullptr; + } + + LOG(INFO) << "Initial audio config: " + << audio_config.AsHumanReadableString(); + creation_param.audio_sample_info = *audio_sample_info; + } + + if (video_stream) { + // Convert to H264 and HEVC content to annex-b form, since that's the form + // that Starboard requires. + video_stream->EnableBitstreamConverter(); + video_config = video_stream->video_decoder_config(); + video_sample_info = ToStarboardVideoSampleInfo(video_config); + if (!video_sample_info) { + LOG(ERROR) << "Invalid or unsupported video config: " + << video_config.AsHumanReadableString(); + return nullptr; + } + + LOG(INFO) << "Initial video config: " + << video_config.AsHumanReadableString(); + creation_param.video_sample_info = *video_sample_info; + + if (!enable_buffering) { + // Note: this is not part of the official starboard API. We are using this + // arbitrary string value to inform the starboard impl that they should + // prioritize minimizing latency (render the frames as soon as possible). + creation_param.video_sample_info.max_video_capabilities = "streaming=1"; + } + } + + // base::WrapUnique is necessary because we're calling a private ctor. + auto starboard_player_manager = base::WrapUnique(new StarboardPlayerManager( + starboard, audio_stream, video_stream, std::move(audio_sample_info), + std::move(video_sample_info), client, std::move(media_task_runner))); + + starboard->EnsureInitialized(); + void* sb_player = starboard->CreatePlayer( + &creation_param, &starboard_player_manager->callback_handler_); + + if (!sb_player) { + LOG(ERROR) << "Could not create SbPlayer"; + return nullptr; + } + starboard_player_manager->player_ = sb_player; + return starboard_player_manager; +} + +StarboardPlayerManager::StarboardPlayerManager( + StarboardApiWrapper* starboard, + ::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + std::optional<StarboardAudioSampleInfo> audio_sample_info, + std::optional<StarboardVideoSampleInfo> video_sample_info, + ::media::RendererClient* client, + scoped_refptr<base::SequencedTaskRunner> media_task_runner) + : // base::Unretained(this) is safe here because demuxer_stream_reader_ + // will be destroyed before `this`. + starboard_(starboard), + client_(client), + stats_tracker_(client), + task_runner_(std::move(media_task_runner)), + demuxer_stream_reader_( + audio_stream, + video_stream, + std::move(audio_sample_info), + std::move(video_sample_info), + /*handle_buffer_cb=*/ + base::BindRepeating(&StarboardPlayerManager::PushBuffer, + base::Unretained(this)), + base::BindRepeating(&StarboardPlayerManager::PushEos, + base::Unretained(this)), + client_) { + CHECK(starboard_); + CHECK(client_); + CHECK(task_runner_); + // player_ is set later in the factory function to create + // StarboardPlayerManager. +} + +StarboardPlayerManager::~StarboardPlayerManager() { + CHECK(task_runner_->RunsTasksInCurrentSequence()); + + if (player_) { + starboard_->DestroyPlayer(player_); + } +} + +void StarboardPlayerManager::PushBuffer( + int seek_ticket, + StarboardSampleInfo sample_info, + scoped_refptr<::media::DecoderBuffer> buffer) { + CHECK(player_); + if (seek_ticket != seek_ticket_) { + LOG(INFO) << "Ignoring buffer for old seek ticket (expected " + << seek_ticket_ << ", got " << seek_ticket << ")"; + return; + } + + starboard_->WriteSample(player_, + static_cast<StarboardMediaType>(sample_info.type), + base::span_from_ref(sample_info)); + CHECK(addr_to_buffer_.insert({sample_info.buffer, std::move(buffer)}).second) + << "Attempted to insert a buffer that already exists, at address: " + << sample_info.buffer; + + UpdateStats(sample_info); +} + +void StarboardPlayerManager::UpdateStats( + const StarboardSampleInfo& sample_info) { + StarboardPlayerInfo player_info = {}; + starboard_->GetPlayerInfo(player_, &player_info); + + stats_tracker_.UpdateStats(player_info, sample_info); +} + +void StarboardPlayerManager::PushEos(int seek_ticket, StarboardMediaType type) { + CHECK(player_); + if (seek_ticket != seek_ticket_) { + LOG(INFO) << "Ignoring end of stream for old seek ticket (expected " + << seek_ticket_ << ", got " << seek_ticket << ")"; + return; + } + starboard_->WriteEndOfStream(player_, type); +} + +void StarboardPlayerManager::StartPlayingFrom(base::TimeDelta time) { + CHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(player_); + LOG(INFO) << "StartPlayingFrom: " << time; + flushing_ = false; + LOG(INFO) << "Setting playback rate to " << playback_rate_; + // In case this is the first call to StartPlayingFrom, or if this is called + // after a flush, ensure that we have the correct rate set before seeking. + starboard_->SetPlaybackRate(player_, playback_rate_); + starboard_->SeekTo(player_, time.InMicroseconds(), ++seek_ticket_); +} + +void StarboardPlayerManager::Flush() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(player_); + LOG(INFO) << "StarboardPlayerManager::Flush"; + flushing_ = true; + // Setting the playback rate to 0 pauses playback. + starboard_->SetPlaybackRate(player_, 0.0); + + StarboardPlayerInfo player_info = {}; + starboard_->GetPlayerInfo(player_, &player_info); + + // Seeking causes starboard to flush its pipeline. + starboard_->SeekTo(player_, player_info.current_media_timestamp_micros, + ++seek_ticket_); +} + +void StarboardPlayerManager::SetPlaybackRate(double playback_rate) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(player_); + LOG(INFO) << "SetPlaybackRate: " << playback_rate; + playback_rate_ = playback_rate; + starboard_->SetPlaybackRate(player_, playback_rate); +} + +void StarboardPlayerManager::SetVolume(float volume) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(player_); + LOG(INFO) << "StarboardPlayerManager::SetVolume: " << volume; + starboard_->SetVolume(player_, volume); +} + +base::TimeDelta StarboardPlayerManager::GetMediaTime() { + CHECK(task_runner_->RunsTasksInCurrentSequence()); + CHECK(player_); + StarboardPlayerInfo player_info = {}; + starboard_->GetPlayerInfo(player_, &player_info); + return base::Microseconds(player_info.current_media_timestamp_micros); +} + +void* StarboardPlayerManager::GetSbPlayer() { + return player_; +} + +void StarboardPlayerManager::OnDecoderStatus( + void* player, + StarboardMediaType type, + StarboardDecoderState decoder_state, + int ticket) { + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&StarboardPlayerManager::OnDecoderStatus, + weak_factory_.GetWeakPtr(), player, type, + decoder_state, ticket)); + return; + } + + if (flushing_) { + LOG(INFO) << "Ignoring call for data from Starboard, because the pipeline " + "is flushing."; + return; + } + if (ticket != seek_ticket_) { + LOG(INFO) << "Ignoring call for data from Starboard, because the seek " + "ticket does not match (" + << ticket << " vs expected " << seek_ticket_ << ")"; + return; + } + + demuxer_stream_reader_.ReadBuffer(seek_ticket_, type); +} + +void StarboardPlayerManager::DeallocateSample(void* player, + const void* sample_buffer) { + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&StarboardPlayerManager::DeallocateSample, + weak_factory_.GetWeakPtr(), player, sample_buffer)); + return; + } + + addr_to_buffer_.erase(sample_buffer); +} + +void StarboardPlayerManager::OnPlayerStatus( + void* player, + chromecast::media::StarboardPlayerState state, + int ticket) { + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&StarboardPlayerManager::OnPlayerStatus, + weak_factory_.GetWeakPtr(), player, state, ticket)); + return; + } + + DCHECK_EQ(player, player_); + LOG(INFO) << "Received SbPlayer state: " << state; + if (state == StarboardPlayerState::kStarboardPlayerStateEndOfStream) { + client_->OnEnded(); + } else if (state == StarboardPlayerState::kStarboardPlayerStatePresenting) { + client_->OnBufferingStateChange( + ::media::BufferingState::BUFFERING_HAVE_ENOUGH, + ::media::BufferingStateChangeReason::BUFFERING_CHANGE_REASON_UNKNOWN); + } +} + +void StarboardPlayerManager::OnPlayerError( + void* player, + chromecast::media::StarboardPlayerError error, + std::string message) { + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&StarboardPlayerManager::OnPlayerError, + weak_factory_.GetWeakPtr(), player, error, message)); + return; + } + + DCHECK_EQ(player, player_); + LOG(ERROR) << "Received SbPlayer error " << error + << ", with message: " << message; + client_->OnError(::media::PIPELINE_ERROR_COULD_NOT_RENDER); +} + +void StarboardPlayerManager::CallOnDecoderStatus( + void* player, + void* context, + chromecast::media::StarboardMediaType type, + chromecast::media::StarboardDecoderState decoder_state, + int ticket) { + reinterpret_cast<StarboardPlayerManager*>(context)->OnDecoderStatus( + player, type, decoder_state, ticket); +} + +void StarboardPlayerManager::CallDeallocateSample(void* player, + void* context, + const void* sample_buffer) { + reinterpret_cast<StarboardPlayerManager*>(context)->DeallocateSample( + player, sample_buffer); +} + +void StarboardPlayerManager::CallOnPlayerStatus( + void* player, + void* context, + chromecast::media::StarboardPlayerState state, + int ticket) { + reinterpret_cast<StarboardPlayerManager*>(context)->OnPlayerStatus( + player, state, ticket); +} + +void StarboardPlayerManager::CallOnPlayerError( + void* player, + void* context, + chromecast::media::StarboardPlayerError error, + std::string message) { + reinterpret_cast<StarboardPlayerManager*>(context)->OnPlayerError( + player, error, message); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/starboard/media/renderer/starboard_player_manager.h b/chromecast/starboard/media/renderer/starboard_player_manager.h new file mode 100644 index 0000000..e87be57 --- /dev/null +++ b/chromecast/starboard/media/renderer/starboard_player_manager.h
@@ -0,0 +1,173 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_STARBOARD_MEDIA_RENDERER_STARBOARD_PLAYER_MANAGER_H_ +#define CHROMECAST_STARBOARD_MEDIA_RENDERER_STARBOARD_PLAYER_MANAGER_H_ + +#include <memory> +#include <vector> + +#include "base/functional/callback.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/task/sequenced_task_runner.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "chromecast/starboard/media/renderer/client_stats_tracker.h" +#include "chromecast/starboard/media/renderer/demuxer_stream_reader.h" +#include "media/base/decoder_buffer.h" +#include "media/base/demuxer_stream.h" +#include "media/base/renderer_client.h" + +namespace chromecast { +namespace media { + +// Manages interactions with an SbPlayer. In particular, this class has several +// responsibilities: +// +// * Reading buffers from DemuxerStreams (this logic is encapsulated in a +// separate class, DemuxerStreamReader, which is used by this one) +// * Providing those buffers to Starboard as they are requested +// * Deallocating those buffers once they are no longer needed +// * Notifying RendererClient when certain events occur +// * Updating RendererClient stats (this logic is encapsulated in a separate +// class, ClientStatsTracker, which is used by this one) +// +// Instances of StarboardPlayerManager should be created via Create(). +// +// Public functions must be called on the media sequence matching the runner +// which is provided to Create. +class StarboardPlayerManager { + public: + // Factory function for creating a StarboardPlayerManager. One of + // `audio_stream` or `video_stream` may be null (but not both). All other args + // must not be null. + // + // If an SbPlayer cannot be created, or if any of the conditions above are not + // met, null will be returned. + static std::unique_ptr<StarboardPlayerManager> Create( + StarboardApiWrapper* starboard, + ::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + ::media::RendererClient* client, + scoped_refptr<base::SequencedTaskRunner> media_task_runner, + bool enable_buffering); + + // Disallow copy and assign. + StarboardPlayerManager(const StarboardPlayerManager&) = delete; + StarboardPlayerManager& operator=(const StarboardPlayerManager&) = delete; + + ~StarboardPlayerManager(); + + // Begins playback from `time`. This triggers a seek in starboard, which will + // cause starboard to start requesting buffers. A request for buffers from + // starboard in turn triggers a call to DemuxerStream::Read via + // DemuxerStreamReader. + void StartPlayingFrom(base::TimeDelta time); + + // Discards any pending buffers and pauses playback. + void Flush(); + + // Sets the playback rate. 0 means that playback is paused. + void SetPlaybackRate(double playback_rate); + + // Sets the media volume. This is different from the system volume; it is + // essentially a multiplier, e.g. for fade in/out effects. Most cast apps do + // not use this. + void SetVolume(float volume); + + // Returns the current media time. + base::TimeDelta GetMediaTime(); + + // Returns the SbPlayer owned by this object. + void* GetSbPlayer(); + + private: + explicit StarboardPlayerManager( + StarboardApiWrapper* starboard, + ::media::DemuxerStream* audio_stream, + ::media::DemuxerStream* video_stream, + std::optional<StarboardAudioSampleInfo> audio_sample_info, + std::optional<StarboardVideoSampleInfo> video_sample_info, + ::media::RendererClient* client, + scoped_refptr<base::SequencedTaskRunner> media_task_runner); + + // Pushes `buffer` to starboard. + void PushBuffer(int seek_ticket, + StarboardSampleInfo sample_info, + scoped_refptr<::media::DecoderBuffer> buffer); + + // Signals to starboard that the end of a stream has been reached (for type + // `type`). + void PushEos(int seek_ticket, StarboardMediaType type); + + // Updates the client's stats based on an audio/video buffer being pushed. + void UpdateStats(const StarboardSampleInfo& sample_info); + + // Called by Starboard when a decoder's status changes. + void OnDecoderStatus(void* player, + StarboardMediaType type, + StarboardDecoderState decoder_state, + int ticket); + + // Called by Starboard when a buffer can safely be deallocated. + void DeallocateSample(void* player, const void* sample_buffer); + + // Called by Starboard when the player's state changes. + void OnPlayerStatus(void* player, StarboardPlayerState state, int ticket); + + // Called by Starboard when a player-related error has occurred. + void OnPlayerError(void* player, + StarboardPlayerError error, + std::string message); + + // Callbacks called by Starboard. These simply call the private methods + // declared above. + static void CallOnDecoderStatus(void* player, + void* context, + StarboardMediaType type, + StarboardDecoderState decoder_state, + int ticket); + static void CallDeallocateSample(void* player, + void* context, + const void* sample_buffer); + static void CallOnPlayerStatus(void* player, + void* context, + StarboardPlayerState state, + int ticket); + static void CallOnPlayerError(void* player, + void* context, + StarboardPlayerError error, + std::string message); + + StarboardPlayerCallbackHandler callback_handler_{ + this, + &StarboardPlayerManager::CallOnDecoderStatus, + &StarboardPlayerManager::CallDeallocateSample, + &StarboardPlayerManager::CallOnPlayerStatus, + &StarboardPlayerManager::CallOnPlayerError, + }; + StarboardApiWrapper* starboard_ = nullptr; + // This class owns the SbPlayer. + void* player_ = nullptr; + ::media::RendererClient* client_ = nullptr; + ClientStatsTracker stats_tracker_; + bool flushing_ = false; + double playback_rate_ = 0.0; + // Buffers from an old seek ticket can be safely ignored. + int seek_ticket_ = 0; + scoped_refptr<base::SequencedTaskRunner> task_runner_; + DemuxerStreamReader demuxer_stream_reader_; + // Maps from a buffer address to the scoped_refptr managing the buffer's + // lifetime. + base::flat_map<const void*, scoped_refptr<::media::DecoderBuffer>> + addr_to_buffer_; + + // This should be destructed first, to invalidate any weak ptrs. + base::WeakPtrFactory<StarboardPlayerManager> weak_factory_{this}; +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_STARBOARD_MEDIA_RENDERER_STARBOARD_PLAYER_MANAGER_H_
diff --git a/chromecast/starboard/media/renderer/starboard_player_manager_test.cc b/chromecast/starboard/media/renderer/starboard_player_manager_test.cc new file mode 100644 index 0000000..9f287360 --- /dev/null +++ b/chromecast/starboard/media/renderer/starboard_player_manager_test.cc
@@ -0,0 +1,731 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/starboard/media/renderer/starboard_player_manager.h" + +#include <array> +#include <vector> + +#include "base/task/sequenced_task_runner.h" +#include "base/test/gmock_callback_support.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "chromecast/starboard/media/cdm/starboard_drm_wrapper.h" +#include "chromecast/starboard/media/media/mock_starboard_api_wrapper.h" +#include "chromecast/starboard/media/media/starboard_api_wrapper.h" +#include "chromecast/starboard/media/media/test_matchers.h" +#include "media/base/demuxer_stream.h" +#include "media/base/encryption_scheme.h" +#include "media/base/mock_filters.h" +#include "media/base/video_color_space.h" +#include "media/base/video_transformation.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +namespace chromecast { +namespace media { +namespace { + +using ::base::test::RunOnceCallback; +using ::media::DemuxerStream; +using ::media::MockDemuxerStream; +using ::media::MockRendererClient; +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::AtLeast; +using ::testing::DoAll; +using ::testing::DoubleEq; +using ::testing::InSequence; +using ::testing::IsNull; +using ::testing::NiceMock; +using ::testing::NotNull; +using ::testing::Pointee; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::WithArg; + +// Returns a valid audio config with values arbitrarily set. The values will +// match the values of GetStarboardAudioConfig. +::media::AudioDecoderConfig GetChromiumAudioConfig() { + return ::media::AudioDecoderConfig( + ::media::AudioCodec::kAC3, ::media::SampleFormat::kSampleFormatS32, + ::media::ChannelLayout::CHANNEL_LAYOUT_5_1, 44100, /*extra_data=*/{}, + ::media::EncryptionScheme::kUnencrypted); +} + +// Returns a valid video config with values arbitrarily set. The values will +// match the values of GetStarboardVideoConfig. +::media::VideoDecoderConfig GetChromiumVideoConfig() { + ::media::VideoDecoderConfig video_config( + ::media::VideoCodec::kHEVC, ::media::VideoCodecProfile::HEVCPROFILE_MAIN, + ::media::VideoDecoderConfig::AlphaMode::kIsOpaque, + ::media::VideoColorSpace(1, 1, 1, gfx::ColorSpace::RangeID::LIMITED), + ::media::VideoTransformation(), gfx::Size(1920, 1080), + gfx::Rect(0, 0, 1919, 1079), gfx::Size(1280, 720), /*extra_data=*/{}, + ::media::EncryptionScheme::kUnencrypted); + video_config.set_level(5); + return video_config; +} + +// Returns a valid starboard audio config with values arbitrarily set. The +// values will match the values of GetChromiumAudioConfig. +StarboardAudioSampleInfo GetStarboardAudioConfig() { + return StarboardAudioSampleInfo{ + .codec = kStarboardAudioCodecAc3, + .mime = R"-(audio/mp4; codecs="ac-3")-", + .format_tag = 0, + .number_of_channels = 6, + .samples_per_second = 44100, + .average_bytes_per_second = (32 / 8) * 44100 * 6, + .block_alignment = 4, + .bits_per_sample = 32, + .audio_specific_config_size = 0, + .audio_specific_config = nullptr, + }; +} + +// Returns a valid starboard video config with values arbitrarily set. The +// values will match the values of GetChromiumVideoConfig. +StarboardVideoSampleInfo GetStarboardVideoConfig() { + return StarboardVideoSampleInfo{ + .codec = kStarboardVideoCodecH265, + .mime = R"-(video/mp4; codecs="hev1.1.6.L5.B0")-", + .max_video_capabilities = "", + .is_key_frame = false, + .frame_width = 1920, + .frame_height = 1080, + .color_metadata = + StarboardColorMetadata{ + // These 0 fields signify "unknown" to starboard. + .bits_per_channel = 0, + .chroma_subsampling_horizontal = 0, + .chroma_subsampling_vertical = 0, + .cb_subsampling_horizontal = 0, + .cb_subsampling_vertical = 0, + .chroma_siting_horizontal = 0, + .chroma_siting_vertical = 0, + // No HDR metadata, so everything is 0. + .mastering_metadata = StarboardMediaMasteringMetadata{}, + .max_cll = 0, + .max_fall = 0, + .primaries = 1, // BT.709 + .transfer = 1, // BT.709 + .matrix = 1, // BT.709 + .range = 1, // broadcast range + .custom_primary_matrix = {0}, + }, + }; +} + +// A test fixture is used to avoid boilerplate in each test (managing the +// lifetime of the TaskEnvironment, creating mocks, etc). +class StarboardPlayerManagerTest : public ::testing::Test { + protected: + StarboardPlayerManagerTest() + : audio_stream_(DemuxerStream::Type::AUDIO), + video_stream_(DemuxerStream::Type::VIDEO) { + ON_CALL(starboard_for_drm_, CreateDrmSystem) + .WillByDefault(Return(&drm_system_)); + StarboardDrmWrapper::SetSingletonForTesting(&starboard_for_drm_); + } + + ~StarboardPlayerManagerTest() override = default; + + // This should be destructed last. + base::test::TaskEnvironment task_environment_; + NiceMock<MockStarboardApiWrapper> starboard_; + + // It is undefined behavior to set expectations on a mock after its mock + // functions have been called. Thus, to be safe we use a separate mock + // starboard for the StarboardDrmWrapper. All expectations are set before it + // is passed to the StarboardDrmWrapper (in this fixture's ctor). + NiceMock<MockStarboardApiWrapper> starboard_for_drm_; + MockDemuxerStream audio_stream_; + MockDemuxerStream video_stream_; + MockRendererClient renderer_client_; + + // Since SbPlayer is used as an opaque void* by cast, we can use any type + // here. All that matters is the address. + int sb_player_ = 1; + // Same for SbDrmSystem. + int drm_system_ = 2; +}; + +TEST_F(StarboardPlayerManagerTest, + EnablesBitstreamConvertersForDemuxerStreams) { + // Starboard requires bitstream formats, so it is important that this be + // configured properly. + EXPECT_CALL(audio_stream_, EnableBitstreamConverter); + EXPECT_CALL(video_stream_, EnableBitstreamConverter); + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + EXPECT_THAT( + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true), + NotNull()); +} + +TEST_F(StarboardPlayerManagerTest, PlaybackStartCausesSeekInStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kSeekTime.InMicroseconds(), _)) + .Times(1); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); +} + +TEST_F(StarboardPlayerManagerTest, FlushCausesSeekToCurrentTimeInStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr auto kMediaTime = base::Seconds(12); + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + EXPECT_CALL(starboard_, GetPlayerInfo(&sb_player_, NotNull())) + .WillOnce(WithArg<1>([kMediaTime](StarboardPlayerInfo* player_info) { + // player_info cannot be null due to the NotNull matcher, so no need to + // check for null here. + *player_info = {}; + player_info->current_media_timestamp_micros = + kMediaTime.InMicroseconds(); + })); + + { + InSequence s; + // There should be two seeks: one when we start playback, and one when we + // flush (set to the current media time). + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kSeekTime.InMicroseconds(), _)) + .Times(1); + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kMediaTime.InMicroseconds(), _)) + .Times(1); + } + + // Additionally, the playback rate should be set to 0 on flush. + EXPECT_CALL(starboard_, SetPlaybackRate(&sb_player_, DoubleEq(0))) + .Times(AtLeast(1)); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + player_manager->Flush(); +} + +TEST_F(StarboardPlayerManagerTest, ForwardsPlaybackRateChangesToStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr double kPlaybackRate = 2.0; + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + EXPECT_CALL(starboard_, SetPlaybackRate(&sb_player_, DoubleEq(0.0))) + .Times(AnyNumber()); + EXPECT_CALL(starboard_, SetPlaybackRate(&sb_player_, DoubleEq(kPlaybackRate))) + .Times(1); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + player_manager->SetPlaybackRate(kPlaybackRate); +} + +TEST_F(StarboardPlayerManagerTest, ForwardsStreamVolumeChangesToStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr float kVolume = 0.3; + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + EXPECT_CALL(starboard_, SetVolume(&sb_player_, DoubleEq(kVolume))).Times(1); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + player_manager->SetVolume(kVolume); +} + +TEST_F(StarboardPlayerManagerTest, GetsCurrentMediaTimeFromStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr auto kMediaTime = base::Seconds(11); + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + EXPECT_CALL(starboard_, GetPlayerInfo(&sb_player_, NotNull())) + .WillOnce(WithArg<1>([kMediaTime](StarboardPlayerInfo* player_info) { + // player_info cannot be null due to the NotNull matcher, so no need to + // check for null here. + *player_info = {}; + player_info->current_media_timestamp_micros = + kMediaTime.InMicroseconds(); + })); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + EXPECT_EQ(player_manager->GetMediaTime(), kMediaTime); +} + +TEST_F(StarboardPlayerManagerTest, GetSbPlayerReturnsTheSbPlayer) { + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = GetStarboardVideoConfig(), + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + EXPECT_EQ(player_manager->GetSbPlayer(), &sb_player_); +} + +TEST_F(StarboardPlayerManagerTest, + BufferingDisabledSetsStreamingInMaxVideoCapabilities) { + // streaming=1 is not part of an official starboard API, but cast sets this + // field to signal to partners that their SbPlayer should prioritize + // minimizing latency (e.g. for when the user is mirroring to the cast + // device). + StarboardVideoSampleInfo sb_video_config = GetStarboardVideoConfig(); + sb_video_config.max_video_capabilities = "streaming=1"; + + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = GetStarboardAudioConfig(), + .video_sample_info = sb_video_config, + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(Return(&sb_player_)); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + EXPECT_THAT( + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/false), + NotNull()); +} + +TEST_F(StarboardPlayerManagerTest, + ReadsFromDemuxerStreamsAndWritesBuffersToStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr auto kVideoBufferTs = base::Milliseconds(10001); + constexpr auto kVideoData = std::to_array<uint8_t>({1, 2, 3, 4, 5}); + constexpr auto kAudioBufferTs = base::Milliseconds(10002); + constexpr auto kAudioData = std::to_array<uint8_t>({9, 8, 7}); + + const StarboardAudioSampleInfo sb_audio_config = GetStarboardAudioConfig(); + const StarboardVideoSampleInfo sb_video_config = GetStarboardVideoConfig(); + + // This will be updated whenever the player manager seeks in starboard. + int seek_ticket = -1; + ON_CALL(starboard_, SeekTo(&sb_player_, _, _)) + .WillByDefault(SaveArg<2>(&seek_ticket)); + + // This will be set to the callbacks received by the mock Starboard. + const StarboardPlayerCallbackHandler* callbacks = nullptr; + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = sb_audio_config, + .video_sample_info = sb_video_config, + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(DoAll(SaveArg<1>(&callbacks), Return(&sb_player_))); + + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kSeekTime.InMicroseconds(), _)) + .Times(1); + + // Set expectations for the video buffer. + scoped_refptr<::media::DecoderBuffer> video_buffer = + ::media::DecoderBuffer::CopyFrom(kVideoData); + video_buffer->set_timestamp(kVideoBufferTs); + const StarboardSampleInfo expected_video_info = { + .type = 1, + .buffer = video_buffer->data(), + .buffer_size = static_cast<int>(video_buffer->size()), + .timestamp = kVideoBufferTs.InMicroseconds(), + .side_data = base::span<const StarboardSampleSideData>(), + .video_sample_info = sb_video_config, + .drm_info = nullptr, + }; + EXPECT_CALL(video_stream_, OnRead) + .WillOnce(RunOnceCallback<0>( + DemuxerStream::Status::kOk, + std::vector<scoped_refptr<::media::DecoderBuffer>>({video_buffer}))); + EXPECT_CALL( + starboard_, + WriteSample(&sb_player_, StarboardMediaType::kStarboardMediaTypeVideo, + ElementsAre(MatchesStarboardSampleInfo(expected_video_info)))) + .Times(1); + + // Set expectations for the audio buffer. + scoped_refptr<::media::DecoderBuffer> audio_buffer = + ::media::DecoderBuffer::CopyFrom(kAudioData); + audio_buffer->set_timestamp(kAudioBufferTs); + const StarboardSampleInfo expected_audio_info = { + .type = 0, + .buffer = audio_buffer->data(), + .buffer_size = static_cast<int>(audio_buffer->size()), + .timestamp = kAudioBufferTs.InMicroseconds(), + .side_data = base::span<const StarboardSampleSideData>(), + .audio_sample_info = sb_audio_config, + .drm_info = nullptr, + }; + EXPECT_CALL(audio_stream_, OnRead) + .WillOnce(RunOnceCallback<0>( + DemuxerStream::Status::kOk, + std::vector<scoped_refptr<::media::DecoderBuffer>>({audio_buffer}))); + EXPECT_CALL( + starboard_, + WriteSample(&sb_player_, StarboardMediaType::kStarboardMediaTypeAudio, + ElementsAre(MatchesStarboardSampleInfo(expected_audio_info)))) + .Times(1); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, &renderer_client_, + base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + + // Simulate Starboard requesting a video buffer, then an audio buffer. The + // player manager should read from the video stream and provide that buffer to + // starboard, then read from the audio stream and provide that buffer to + // starboard. + ASSERT_THAT(callbacks, NotNull()); + ASSERT_THAT(callbacks->decoder_status_fn, NotNull()); + ASSERT_THAT(callbacks->context, NotNull()); + callbacks->decoder_status_fn( + &sb_player_, callbacks->context, + StarboardMediaType::kStarboardMediaTypeVideo, + StarboardDecoderState::kStarboardDecoderStateNeedsData, seek_ticket); + + callbacks->decoder_status_fn( + &sb_player_, callbacks->context, + StarboardMediaType::kStarboardMediaTypeAudio, + StarboardDecoderState::kStarboardDecoderStateNeedsData, seek_ticket); +} + +TEST_F(StarboardPlayerManagerTest, + VideoOnlyReadsFromDemuxerStreamAndWritesBufferToStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr auto kVideoBufferTs = base::Milliseconds(10001); + constexpr auto kVideoData = std::to_array<uint8_t>({1, 2, 3, 4, 5}); + const StarboardVideoSampleInfo sb_video_config = GetStarboardVideoConfig(); + + // This will be updated whenever the player manager seeks in starboard. + int seek_ticket = -1; + ON_CALL(starboard_, SeekTo(&sb_player_, _, _)) + .WillByDefault(SaveArg<2>(&seek_ticket)); + + // This will be set to the callbacks received by the mock Starboard. + const StarboardPlayerCallbackHandler* callbacks = nullptr; + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = {}, + .video_sample_info = sb_video_config, + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(DoAll(SaveArg<1>(&callbacks), Return(&sb_player_))); + + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kSeekTime.InMicroseconds(), _)) + .Times(1); + + // Set expectations for the video buffer. + scoped_refptr<::media::DecoderBuffer> video_buffer = + ::media::DecoderBuffer::CopyFrom(kVideoData); + video_buffer->set_timestamp(kVideoBufferTs); + const StarboardSampleInfo expected_video_info = { + .type = 1, + .buffer = video_buffer->data(), + .buffer_size = static_cast<int>(video_buffer->size()), + .timestamp = kVideoBufferTs.InMicroseconds(), + .side_data = base::span<const StarboardSampleSideData>(), + .video_sample_info = sb_video_config, + .drm_info = nullptr, + }; + EXPECT_CALL(video_stream_, OnRead) + .WillOnce(RunOnceCallback<0>( + DemuxerStream::Status::kOk, + std::vector<scoped_refptr<::media::DecoderBuffer>>({video_buffer}))); + EXPECT_CALL( + starboard_, + WriteSample(&sb_player_, StarboardMediaType::kStarboardMediaTypeVideo, + ElementsAre(MatchesStarboardSampleInfo(expected_video_info)))) + .Times(1); + + video_stream_.set_video_decoder_config(GetChromiumVideoConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, /*audio_stream=*/nullptr, &video_stream_, + &renderer_client_, base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + + // Simulate Starboard requesting a video buffer. The player manager should + // read from the video stream and provide that buffer to starboard. + ASSERT_THAT(callbacks, NotNull()); + ASSERT_THAT(callbacks->decoder_status_fn, NotNull()); + ASSERT_THAT(callbacks->context, NotNull()); + callbacks->decoder_status_fn( + &sb_player_, callbacks->context, + StarboardMediaType::kStarboardMediaTypeVideo, + StarboardDecoderState::kStarboardDecoderStateNeedsData, seek_ticket); +} + +TEST_F(StarboardPlayerManagerTest, + AudioOnlyReadsFromDemuxerStreamAndWritesBufferToStarboard) { + constexpr auto kSeekTime = base::Seconds(10); + constexpr auto kAudioBufferTs = base::Milliseconds(10002); + constexpr auto kAudioData = std::to_array<uint8_t>({9, 8, 7}); + const StarboardAudioSampleInfo sb_audio_config = GetStarboardAudioConfig(); + + // This will be updated whenever the player manager seeks in starboard. + int seek_ticket = -1; + ON_CALL(starboard_, SeekTo(&sb_player_, _, _)) + .WillByDefault(SaveArg<2>(&seek_ticket)); + + // This will be set to the callbacks received by the mock Starboard. + const StarboardPlayerCallbackHandler* callbacks = nullptr; + EXPECT_CALL( + starboard_, + CreatePlayer( + Pointee(MatchesPlayerCreationParam(StarboardPlayerCreationParam{ + .drm_system = &drm_system_, + .audio_sample_info = sb_audio_config, + .video_sample_info = {}, + .output_mode = StarboardPlayerOutputMode:: + kStarboardPlayerOutputModePunchOut})), + _)) + .WillOnce(DoAll(SaveArg<1>(&callbacks), Return(&sb_player_))); + + EXPECT_CALL(starboard_, SeekTo(&sb_player_, kSeekTime.InMicroseconds(), _)) + .Times(1); + + // Set expectations for the audio buffer. + scoped_refptr<::media::DecoderBuffer> audio_buffer = + ::media::DecoderBuffer::CopyFrom(kAudioData); + audio_buffer->set_timestamp(kAudioBufferTs); + const StarboardSampleInfo expected_audio_info = { + .type = 0, + .buffer = audio_buffer->data(), + .buffer_size = static_cast<int>(audio_buffer->size()), + .timestamp = kAudioBufferTs.InMicroseconds(), + .side_data = base::span<const StarboardSampleSideData>(), + .audio_sample_info = sb_audio_config, + .drm_info = nullptr, + }; + EXPECT_CALL(audio_stream_, OnRead) + .WillOnce(RunOnceCallback<0>( + DemuxerStream::Status::kOk, + std::vector<scoped_refptr<::media::DecoderBuffer>>({audio_buffer}))); + EXPECT_CALL( + starboard_, + WriteSample(&sb_player_, StarboardMediaType::kStarboardMediaTypeAudio, + ElementsAre(MatchesStarboardSampleInfo(expected_audio_info)))) + .Times(1); + + audio_stream_.set_audio_decoder_config(GetChromiumAudioConfig()); + + std::unique_ptr<StarboardPlayerManager> player_manager = + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, /*video_stream=*/nullptr, + &renderer_client_, base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true); + ASSERT_THAT(player_manager, NotNull()); + + player_manager->StartPlayingFrom(kSeekTime); + + // Simulate Starboard requesting a video buffer, then an audio buffer. The + // player manager should read from the video stream and provide that buffer to + // starboard, then read from the audio stream and provide that buffer to + // starboard. + ASSERT_THAT(callbacks, NotNull()); + ASSERT_THAT(callbacks->decoder_status_fn, NotNull()); + ASSERT_THAT(callbacks->context, NotNull()); + + callbacks->decoder_status_fn( + &sb_player_, callbacks->context, + StarboardMediaType::kStarboardMediaTypeAudio, + StarboardDecoderState::kStarboardDecoderStateNeedsData, seek_ticket); +} + +TEST_F(StarboardPlayerManagerTest, + CreatePlayerReturnsNullIfBothDemuxerStreamsAreNull) { + EXPECT_THAT( + StarboardPlayerManager::Create( + &starboard_, /*audio_stream=*/nullptr, /*video_stream=*/nullptr, + &renderer_client_, base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true), + IsNull()); +} + +TEST_F(StarboardPlayerManagerTest, CreatePlayerReturnsNullIfStarboardIsNull) { + EXPECT_THAT( + StarboardPlayerManager::Create( + /*starboard=*/nullptr, &audio_stream_, &video_stream_, + &renderer_client_, base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true), + IsNull()); +} + +TEST_F(StarboardPlayerManagerTest, + CreatePlayerReturnsNullIfRendererClientIsNull) { + EXPECT_THAT( + StarboardPlayerManager::Create( + &starboard_, &audio_stream_, &video_stream_, + /*client=*/nullptr, base::SequencedTaskRunner::GetCurrentDefault(), + /*enable_buffering=*/true), + IsNull()); +} + +TEST_F(StarboardPlayerManagerTest, CreatePlayerReturnsNullIfTaskRunnerIsNull) { + EXPECT_THAT(StarboardPlayerManager::Create(&starboard_, &audio_stream_, + &video_stream_, &renderer_client_, + /*media_task_runner=*/nullptr, + /*enable_buffering=*/true), + IsNull()); +} + +} // namespace +} // namespace media +} // namespace chromecast
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 1480393..82979b63 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16309.0.0-1069370 \ No newline at end of file +16310.0.0-1069388 \ No newline at end of file
diff --git a/chromeos/ash/components/audio/audio_device_id.cc b/chromeos/ash/components/audio/audio_device_id.cc index 3470f63c..67b178ac 100644 --- a/chromeos/ash/components/audio/audio_device_id.cc +++ b/chromeos/ash/components/audio/audio_device_id.cc
@@ -4,6 +4,8 @@ #include "chromeos/ash/components/audio/audio_device_id.h" +#include <sstream> + #include "base/check.h" #include "base/check_op.h" #include "base/containers/flat_set.h"
diff --git a/chromeos/ash/components/audio/audio_device_id.h b/chromeos/ash/components/audio/audio_device_id.h index e845fef..7d788577f 100644 --- a/chromeos/ash/components/audio/audio_device_id.h +++ b/chromeos/ash/components/audio/audio_device_id.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_COMPONENTS_AUDIO_AUDIO_DEVICE_ID_H_ #define CHROMEOS_ASH_COMPONENTS_AUDIO_AUDIO_DEVICE_ID_H_ +#include <optional> + #include "chromeos/ash/components/audio/audio_device.h" namespace ash {
diff --git a/chromeos/ash/components/file_manager/indexing/file_index.cc b/chromeos/ash/components/file_manager/indexing/file_index.cc index 1300aa2..84d089d 100644 --- a/chromeos/ash/components/file_manager/indexing/file_index.cc +++ b/chromeos/ash/components/file_manager/indexing/file_index.cc
@@ -4,6 +4,12 @@ #include "chromeos/ash/components/file_manager/indexing/file_index.h" +#include <algorithm> +#include <iterator> +#include <set> +#include <utility> +#include <vector> + #include "base/time/time.h" namespace ash::file_manager { @@ -144,19 +150,19 @@ if (term_id == -1) { return results; } - const std::set<int64_t> url_ids = storage_->GetUrlIdsForTermId(term_id); + std::set<int64_t> url_ids = storage_->GetUrlIdsForTermId(term_id); if (url_ids.empty()) { return results; } if (first) { - matched_url_ids = url_ids; + matched_url_ids = std::move(url_ids); first = false; } else { std::set<int64_t> intersection; - std::set_intersection(matched_url_ids.begin(), matched_url_ids.end(), - url_ids.begin(), url_ids.end(), - std::inserter(intersection, intersection.begin())); - matched_url_ids = intersection; + std::ranges::set_intersection( + matched_url_ids, url_ids, + std::inserter(intersection, intersection.begin())); + matched_url_ids = std::move(intersection); } if (matched_url_ids.empty()) { break;
diff --git a/chromeos/ash/components/kcer/kcer_nss/kcer_nss_unittest.cc b/chromeos/ash/components/kcer/kcer_nss/kcer_nss_unittest.cc index 602cf88b..77c8e90 100644 --- a/chromeos/ash/components/kcer/kcer_nss/kcer_nss_unittest.cc +++ b/chromeos/ash/components/kcer/kcer_nss/kcer_nss_unittest.cc
@@ -11,6 +11,7 @@ #include "base/base64.h" #include "base/files/file_util.h" #include "base/memory/raw_ref.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/bind_post_task.h" #include "base/test/gmock_callback_support.h" #include "base/test/gmock_move_support.h"
diff --git a/chromeos/ash/components/local_search_service/shared_structs.h b/chromeos/ash/components/local_search_service/shared_structs.h index 1a875ef..f59422d 100644 --- a/chromeos/ash/components/local_search_service/shared_structs.h +++ b/chromeos/ash/components/local_search_service/shared_structs.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_COMPONENTS_LOCAL_SEARCH_SERVICE_SHARED_STRUCTS_H_ #define CHROMEOS_ASH_COMPONENTS_LOCAL_SEARCH_SERVICE_SHARED_STRUCTS_H_ +#include <stdint.h> + #include <string> #include <vector>
diff --git a/chromeos/ash/components/login/auth/recovery/service_constants.h b/chromeos/ash/components/login/auth/recovery/service_constants.h index ab7af4b3..29231e7 100644 --- a/chromeos/ash/components/login/auth/recovery/service_constants.h +++ b/chromeos/ash/components/login/auth/recovery/service_constants.h
@@ -5,8 +5,11 @@ #ifndef CHROMEOS_ASH_COMPONENTS_LOGIN_AUTH_RECOVERY_SERVICE_CONSTANTS_H_ #define CHROMEOS_ASH_COMPONENTS_LOGIN_AUTH_RECOVERY_SERVICE_CONSTANTS_H_ +#include <stdint.h> + #include <string> #include <vector> + #include "base/component_export.h" class GURL;
diff --git a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider.h b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider.h index 6d76409..ac7579d 100644 --- a/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider.h +++ b/chromeos/ash/components/nearby/presence/credentials/local_device_data_provider.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <vector> namespace nearby::internal { class SharedCredential;
diff --git a/chromeos/ash/components/wifi_p2p/wifi_p2p_group.h b/chromeos/ash/components/wifi_p2p/wifi_p2p_group.h index 5b00cda9..e5a5f980c 100644 --- a/chromeos/ash/components/wifi_p2p/wifi_p2p_group.h +++ b/chromeos/ash/components/wifi_p2p/wifi_p2p_group.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_COMPONENTS_WIFI_P2P_WIFI_P2P_GROUP_H_ #define CHROMEOS_ASH_COMPONENTS_WIFI_P2P_WIFI_P2P_GROUP_H_ +#include <stdint.h> + #include <string> #include "base/component_export.h"
diff --git a/chromeos/ash/services/connectivity/public/cpp/fake_passpoint_subscription.h b/chromeos/ash/services/connectivity/public/cpp/fake_passpoint_subscription.h index 804db90..e0fcc039 100644 --- a/chromeos/ash/services/connectivity/public/cpp/fake_passpoint_subscription.h +++ b/chromeos/ash/services/connectivity/public/cpp/fake_passpoint_subscription.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_CONNECTIVITY_PUBLIC_CPP_FAKE_PASSPOINT_SUBSCRIPTION_H_ #define CHROMEOS_ASH_SERVICES_CONNECTIVITY_PUBLIC_CPP_FAKE_PASSPOINT_SUBSCRIPTION_H_ +#include <stdint.h> + #include <optional> #include <string> #include <vector>
diff --git a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h index e59eaf7c..be8051dd 100644 --- a/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h +++ b/chromeos/ash/services/quick_pair/public/cpp/account_key_filter.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_QUICK_PAIR_PUBLIC_CPP_ACCOUNT_KEY_FILTER_H_ #define CHROMEOS_ASH_SERVICES_QUICK_PAIR_PUBLIC_CPP_ACCOUNT_KEY_FILTER_H_ +#include <stdint.h> + #include <vector> namespace ash {
diff --git a/chromeos/ash/services/secure_channel/ble_advertisement_generator.h b/chromeos/ash/services/secure_channel/ble_advertisement_generator.h index 784df63..0ab2a0c 100644 --- a/chromeos/ash/services/secure_channel/ble_advertisement_generator.h +++ b/chromeos/ash/services/secure_channel/ble_advertisement_generator.h
@@ -6,6 +6,7 @@ #define CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_BLE_ADVERTISEMENT_GENERATOR_H_ #include <memory> +#include <string> namespace ash {
diff --git a/chromeos/ash/services/secure_channel/data_with_timestamp.h b/chromeos/ash/services/secure_channel/data_with_timestamp.h index b371d5c..b0d5695 100644 --- a/chromeos/ash/services/secure_channel/data_with_timestamp.h +++ b/chromeos/ash/services/secure_channel/data_with_timestamp.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_DATA_WITH_TIMESTAMP_H_ #define CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_DATA_WITH_TIMESTAMP_H_ +#include <stdint.h> + #include <string> #include <vector>
diff --git a/chromeos/ash/services/secure_channel/raw_eid_generator.h b/chromeos/ash/services/secure_channel/raw_eid_generator.h index 093cc64..5a950ab 100644 --- a/chromeos/ash/services/secure_channel/raw_eid_generator.h +++ b/chromeos/ash/services/secure_channel/raw_eid_generator.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_RAW_EID_GENERATOR_H_ #define CHROMEOS_ASH_SERVICES_SECURE_CHANNEL_RAW_EID_GENERATOR_H_ +#include <stdint.h> + #include <string> namespace ash::secure_channel {
diff --git a/chromeos/utils/pdf_conversion.h b/chromeos/utils/pdf_conversion.h index fc134bc9..6c24f7c 100644 --- a/chromeos/utils/pdf_conversion.h +++ b/chromeos/utils/pdf_conversion.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_UTILS_PDF_CONVERSION_H_ #define CHROMEOS_UTILS_PDF_CONVERSION_H_ +#include <stdint.h> + #include <optional> #include <string> #include <vector>
diff --git a/clank b/clank index 9d5f4e3e..4d4ffc26 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 9d5f4e3ec164804c21a8a7c92eed98c1e0094c13 +Subproject commit 4d4ffc26471ca1d5eb0d122765d87b359956f635
diff --git a/components/autofill/core/browser/data_manager/valuables/valuables_data_manager.cc b/components/autofill/core/browser/data_manager/valuables/valuables_data_manager.cc index 5f2d3e9..6c086bc 100644 --- a/components/autofill/core/browser/data_manager/valuables/valuables_data_manager.cc +++ b/components/autofill/core/browser/data_manager/valuables/valuables_data_manager.cc
@@ -6,6 +6,7 @@ #include <vector> +#include "base/metrics/histogram_macros.h" #include "components/autofill/core/browser/data_model/valuables/loyalty_card.h" #include "components/autofill/core/browser/ui/autofill_image_fetcher_base.h" #include "components/autofill/core/browser/webdata/autofill_change.h" @@ -95,6 +96,10 @@ // for caching loyalty card icons. ProcessLoyaltyCardIconUrlChanges(); NotifyObservers(); + + // Log the overall counts. + UMA_HISTOGRAM_COUNTS_1000("Autofill.LoyaltyCard.StoredCardsCount", + loyalty_cards_.size()); } void ValuablesDataManager::ProcessLoyaltyCardIconUrlChanges() {
diff --git a/components/autofill/core/browser/data_manager/valuables/valuables_data_manager_unittest.cc b/components/autofill/core/browser/data_manager/valuables/valuables_data_manager_unittest.cc index 5dd20ca..8a44664 100644 --- a/components/autofill/core/browser/data_manager/valuables/valuables_data_manager_unittest.cc +++ b/components/autofill/core/browser/data_manager/valuables/valuables_data_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "base/functional/callback_helpers.h" #include "base/scoped_observation.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "components/autofill/core/browser/data_model/valuables/loyalty_card.h" @@ -95,6 +96,7 @@ // Tests that the `ValuablesDataManager` correctly generates loyalty cards to // suggest ordered by merchant name. TEST_F(ValuablesDataManagerTest, GetLoyaltyCardsToSuggest) { + base::HistogramTester histogram_tester; const LoyaltyCard card1 = LoyaltyCard( /*loyalty_card_id=*/ValuableId("loyalty_card_id_1"), /*merchant_name=*/"CVS Pharmacy", @@ -126,11 +128,16 @@ helper().WaitUntilIdle(); EXPECT_THAT(valuables_data_manager.GetLoyaltyCardsToSuggest(), ElementsAre(card1, card3, card2)); + // Validate the basic count metrics. + histogram_tester.ExpectTotalCount("Autofill.LoyaltyCard.StoredCardsCount", 1); + histogram_tester.ExpectBucketCount("Autofill.LoyaltyCard.StoredCardsCount", 3, + 1); } // Verify that the `ValuablesDataManager` correctly updates the list of loyalty // cards when the Chrome Sync writes them to the database. TEST_F(ValuablesDataManagerTest, DataChangedBySync) { + base::HistogramTester histogram_tester; const LoyaltyCard card1 = test::CreateLoyaltyCard(); const LoyaltyCard card2 = test::CreateLoyaltyCard2(); { @@ -179,6 +186,13 @@ helper().WaitUntilIdle(); EXPECT_THAT(valuables_data_manager.GetLoyaltyCards(), UnorderedElementsAre(card1, card2)); + + // Validate the basic count metrics. + histogram_tester.ExpectTotalCount("Autofill.LoyaltyCard.StoredCardsCount", 2); + histogram_tester.ExpectBucketCount("Autofill.LoyaltyCard.StoredCardsCount", 1, + 1); + histogram_tester.ExpectBucketCount("Autofill.LoyaltyCard.StoredCardsCount", 2, + 1); } TEST_F(ValuablesDataManagerTest, GetCachedValuableImageForUrl) {
diff --git a/components/autofill/core/browser/filling/field_filling_util_unittest.cc b/components/autofill/core/browser/filling/field_filling_util_unittest.cc index f32b2de..ab31314 100644 --- a/components/autofill/core/browser/filling/field_filling_util_unittest.cc +++ b/components/autofill/core/browser/filling/field_filling_util_unittest.cc
@@ -7,6 +7,7 @@ #include <optional> #include <string> +#include "base/strings/string_number_conversions.h" #include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/test_utils/autofill_test_utils.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/autofill/core/browser/payments/payments_network_interface_unittest.cc b/components/autofill/core/browser/payments/payments_network_interface_unittest.cc index 781ffb3f..da50c0bf 100644 --- a/components/autofill/core/browser/payments/payments_network_interface_unittest.cc +++ b/components/autofill/core/browser/payments/payments_network_interface_unittest.cc
@@ -16,6 +16,7 @@ #include "base/memory/raw_ptr.h" #include "base/strings/escape.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h"
diff --git a/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager_unittest.cc b/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager_unittest.cc index 72c45c37..253e113 100644 --- a/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager_unittest.cc +++ b/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> #include "base/functional/callback_helpers.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h"
diff --git a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc index ffad19f5..d7c41bb 100644 --- a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc
@@ -4,6 +4,7 @@ #include "components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h"
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.cc b/components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.cc index b680c9c6..a4bcfb9a 100644 --- a/components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.cc +++ b/components/autofill/core/browser/ui/payments/card_unmask_otp_input_dialog_controller_impl.cc
@@ -6,6 +6,7 @@ #include <string> +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "components/autofill/core/browser/metrics/payments/card_unmask_authentication_metrics.h" #include "components/autofill/core/browser/payments/otp_unmask_delegate.h"
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 8f3b809..f07cb97 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -1255,6 +1255,9 @@ <message name="IDS_AUTOFILL_LOYALTY_CARD_AUTOFILL_BUTTON" desc="The label of the button, which would fill in the web form with a loyalty card number." formatter_data="android_java"> Autofill </message> + <message name="IDS_AUTOFILL_LOYALTY_CARD_WALLET_SETTINGS_BUTTON" desc="The label of the button, which redirects the user to the Google Wallet loyalty card settings in Chrome." formatter_data="android_java"> + Wallet settings + </message> <message name="IDS_AUTOFILL_PAYMENT_METHOD_BOTTOM_SHEET_CONTENT_DESCRIPTION" desc="Accessibility string read when the bottom sheet is opened. It describes the bottom sheet where a user can pick a payment method to fill into a form." formatter_data="android_java"> Payment methods available to be filled on touch. Keyboard hidden. </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_LOYALTY_CARD_WALLET_SETTINGS_BUTTON.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_LOYALTY_CARD_WALLET_SETTINGS_BUTTON.png.sha1 new file mode 100644 index 0000000..cdf55eb --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_LOYALTY_CARD_WALLET_SETTINGS_BUTTON.png.sha1
@@ -0,0 +1 @@ +9e24b99eda473bd6ebb658fed011e22ef776556a \ No newline at end of file
diff --git a/components/bookmarks/browser/bookmark_utils_unittest.cc b/components/bookmarks/browser/bookmark_utils_unittest.cc index e33a7be..98c5848 100644 --- a/components/bookmarks/browser/bookmark_utils_unittest.cc +++ b/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -13,6 +13,7 @@ #include "base/memory/raw_ptr.h" #include "base/scoped_observation.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h"
diff --git a/components/bookmarks/browser/model_loader_unittest.cc b/components/bookmarks/browser/model_loader_unittest.cc index 21e9a58..d1bf06d8 100644 --- a/components/bookmarks/browser/model_loader_unittest.cc +++ b/components/bookmarks/browser/model_loader_unittest.cc
@@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/no_destructor.h" #include "base/path_service.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h"
diff --git a/components/browser_sync/sync_to_signin_migration_unittest.cc b/components/browser_sync/sync_to_signin_migration_unittest.cc index 4fc9f7d..40380c8 100644 --- a/components/browser_sync/sync_to_signin_migration_unittest.cc +++ b/components/browser_sync/sync_to_signin_migration_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "base/threading/thread_restrictions.h" #include "components/browser_sync/browser_sync_switches.h" #include "components/prefs/testing_pref_service.h" #include "components/signin/public/base/signin_pref_names.h"
diff --git a/components/capture_mode/DEPS b/components/capture_mode/DEPS index 2e1ccac..28091f9 100644 --- a/components/capture_mode/DEPS +++ b/components/capture_mode/DEPS
@@ -8,7 +8,6 @@ "+gpu/command_buffer/common/shared_image_usage.h", "+gpu/config/gpu_finch_features.h", "+gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h", - "+gpu/ipc/common/gpu_memory_buffer_support.h", "+media", "+mojo/public", "+services/audio/public/cpp/device_factory.h",
diff --git a/components/collaboration/internal/collaboration_controller.cc b/components/collaboration/internal/collaboration_controller.cc index 33d20c6..962f443 100644 --- a/components/collaboration/internal/collaboration_controller.cc +++ b/components/collaboration/internal/collaboration_controller.cc
@@ -27,6 +27,7 @@ namespace collaboration { +using metrics::CollaborationServiceFlowEvent; using metrics::CollaborationServiceJoinEvent; using metrics::CollaborationServiceShareOrManageEvent; @@ -282,6 +283,9 @@ GetLogger(), controller_->flow().type, CollaborationServiceJoinEvent::kAccountInfoNotReadyOnSignin, CollaborationServiceShareOrManageEvent::kAccountInfoNotReadyOnSignin); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kAccountInfoNotReadyOnSignin); pending_status_change_observer_.Observe( controller_->collaboration_service()); return; @@ -299,6 +303,9 @@ GetLogger(), controller_->flow().type, CollaborationServiceJoinEvent::kDevicePolicyDisableSignin, CollaborationServiceShareOrManageEvent::kDevicePolicyDisableSignin); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kDevicePolicyDisableSignin); HandleErrorWithType(ErrorInfo::Type::kSigninDisabledByPolicy); return; } @@ -307,6 +314,9 @@ GetLogger(), controller_->flow().type, CollaborationServiceJoinEvent::kManagedAccountSignin, CollaborationServiceShareOrManageEvent::kManagedAccountSignin); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kManagedAccountSignin); HandleErrorWithType(ErrorInfo::Type::kSyncDisabledByPolicy); } @@ -355,18 +365,12 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); start_time_ = base::Time::Now(); FlowType flow_type = controller_->flow().type; - switch (flow_type) { - case FlowType::kJoin: - RecordJoinEvent(GetLogger(), - CollaborationServiceJoinEvent::kNotSignedIn); - break; - case FlowType::kShareOrManage: - RecordShareOrManageEvent( - GetLogger(), CollaborationServiceShareOrManageEvent::kNotSignedIn); - break; - case FlowType::kLeaveOrDelete: - break; - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kNotSignedIn, + CollaborationServiceShareOrManageEvent::kNotSignedIn); + RecordCollaborationFlowEvent(GetLogger(), flow_type, + CollaborationServiceFlowEvent::kNotSignedIn); controller_->delegate()->ShowAuthenticationUi( flow_type, base::BindOnce(&AuthenticatingState::ProcessOutcome, @@ -376,14 +380,13 @@ void ProcessOutcome(Outcome outcome) override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (Outcome::kCancel == outcome) { - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent(GetLogger(), - CollaborationServiceJoinEvent::kCanceledNotSignedIn); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kCanceledNotSignedIn); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kCanceledNotSignedIn, + CollaborationServiceShareOrManageEvent::kCanceledNotSignedIn); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kCanceledNotSignedIn); } ControllerState::ProcessOutcome(outcome); @@ -398,6 +401,7 @@ return; } + FlowType flow_type = controller_->flow().type; if (!status.IsAuthenticationValid()) { // Set up the timeout exit task. base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( @@ -407,25 +411,22 @@ base::Minutes(30)); collaboration_service_observer_.Observe( controller_->collaboration_service()); - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent( - GetLogger(), - CollaborationServiceJoinEvent::kSigninVerificationFailed); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kSigninVerificationFailed); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kSigninVerificationFailed, + CollaborationServiceShareOrManageEvent::kSigninVerificationFailed); + RecordCollaborationFlowEvent( + GetLogger(), flow_type, + CollaborationServiceFlowEvent::kSigninVerificationFailed); return; } - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent(GetLogger(), - CollaborationServiceJoinEvent::kSigninVerified); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), CollaborationServiceShareOrManageEvent::kSigninVerified); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kSigninVerified, + CollaborationServiceShareOrManageEvent::kSigninVerified); + RecordCollaborationFlowEvent( + GetLogger(), flow_type, CollaborationServiceFlowEvent::kSigninVerified); // TODO(crbug.com/380957996): Handle signin/sync changes during a flow. FinishAndTransition(); } @@ -440,15 +441,13 @@ } if (status.IsAuthenticationValid()) { - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent( - GetLogger(), - CollaborationServiceJoinEvent::kSigninVerifiedInObserver); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kSigninVerifiedInObserver); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kSigninVerifiedInObserver, + CollaborationServiceShareOrManageEvent::kSigninVerifiedInObserver); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kSigninVerifiedInObserver); FinishAndTransition(); } } @@ -498,15 +497,13 @@ if (!is_data_sharing_ready_) { data_sharing_observer_.Observe(controller_->data_sharing_service()); } else { - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent( - GetLogger(), - CollaborationServiceJoinEvent::kDataSharingReadyWhenStarted); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent(GetLogger(), - CollaborationServiceShareOrManageEvent:: - kDataSharingReadyWhenStarted); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kDataSharingReadyWhenStarted, + CollaborationServiceShareOrManageEvent::kDataSharingReadyWhenStarted); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kDataSharingReadyWhenStarted); } tab_group_sync_observer_.Observe(controller_->tab_group_sync_service()); } @@ -523,14 +520,13 @@ // TabGroupSyncService::Observer implementation. void OnInitialized() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent(GetLogger(), - CollaborationServiceJoinEvent::kTabGroupServiceReady); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kTabGroupServiceReady); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kTabGroupServiceReady, + CollaborationServiceShareOrManageEvent::kTabGroupServiceReady); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kTabGroupServiceReady); is_tab_group_sync_ready_ = true; MaybeProceed(); } @@ -538,15 +534,14 @@ // DataSharingService::Observer implementation. void OnGroupDataModelLoaded() override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent( - GetLogger(), - CollaborationServiceJoinEvent::kDataSharingServiceReadyObserved); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent(GetLogger(), - CollaborationServiceShareOrManageEvent:: - kDataSharingServiceReadyObserved); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kDataSharingServiceReadyObserved, + CollaborationServiceShareOrManageEvent:: + kDataSharingServiceReadyObserved); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kDataSharingServiceReadyObserved); is_data_sharing_ready_ = true; MaybeProceed(); @@ -556,15 +551,13 @@ void MaybeProceed() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (is_tab_group_sync_ready_ && is_data_sharing_ready_) { - if (FlowType::kJoin == controller_->flow().type) { - RecordJoinEvent( - GetLogger(), - CollaborationServiceJoinEvent::kAllServicesReadyForFlow); - } else if (FlowType::kShareOrManage == controller_->flow().type) { - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kAllServicesReadyForFlow); - } + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kAllServicesReadyForFlow, + CollaborationServiceShareOrManageEvent::kAllServicesReadyForFlow); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kAllServicesReadyForFlow); OnProcessingFinishedWithSuccess(); } } @@ -587,6 +580,13 @@ void OnEnter(const ErrorInfo& error) override { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + RecordJoinOrShareOrManageEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceJoinEvent::kFlowRequirementsMet, + CollaborationServiceShareOrManageEvent::kFlowRequirementsMet); + RecordCollaborationFlowEvent( + GetLogger(), controller_->flow().type, + CollaborationServiceFlowEvent::kFlowRequirementsMet); switch (controller_->flow().type) { case FlowType::kJoin: CheckJoinFlowRequirements(); @@ -603,9 +603,6 @@ private: void CheckJoinFlowRequirements() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - RecordJoinEvent(GetLogger(), - CollaborationServiceJoinEvent::kFlowRequirementsMet); - const data_sharing::GroupId group_id = controller_->flow().join_token().group_id; // Check if user is already part of the group. @@ -628,10 +625,6 @@ void CheckShareFlowRequirements() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - RecordShareOrManageEvent( - GetLogger(), - CollaborationServiceShareOrManageEvent::kFlowRequirementsMet); - std::optional<tab_groups::SavedTabGroup> sync_group = controller_->tab_group_sync_service()->GetGroup( controller_->flow().either_id()); @@ -1380,6 +1373,12 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); tab_group_sync_service_observer_.Observe(tab_group_sync_service_); + RecordJoinOrShareOrManageEvent( + data_sharing_service_->GetLogger(), flow_.type, + CollaborationServiceJoinEvent::kStarted, + CollaborationServiceShareOrManageEvent::kStarted); + RecordCollaborationFlowEvent(data_sharing_service_->GetLogger(), flow_.type, + CollaborationServiceFlowEvent::kStarted); current_state_ = std::make_unique<PendingState>( StateId::kPending, this, base::BindOnce(&CollaborationController::Exit,
diff --git a/components/collaboration/internal/collaboration_controller_unittest.cc b/components/collaboration/internal/collaboration_controller_unittest.cc index 848081c1..1a5903dc 100644 --- a/components/collaboration/internal/collaboration_controller_unittest.cc +++ b/components/collaboration/internal/collaboration_controller_unittest.cc
@@ -266,8 +266,8 @@ run_loop.Run(); histogram_tester.ExpectBucketCount( - "CollaborationService.JoinFlow", - metrics::CollaborationServiceJoinEvent::kFlowRequirementsMet, 1); + "CollaborationService.JoinFlow.Events", + metrics::CollaborationServiceFlowEvent::kFlowRequirementsMet, 1); histogram_tester.ExpectBucketCount( "CollaborationService.JoinFlow", metrics::CollaborationServiceJoinEvent::kAccepted, 1); @@ -580,14 +580,14 @@ // Verify the not signed in metrics are recorded properly. histogram_tester.ExpectBucketCount( - "CollaborationService.JoinFlow", - metrics::CollaborationServiceJoinEvent::kNotSignedIn, 1); + "CollaborationService.JoinFlow.Events", + metrics::CollaborationServiceFlowEvent::kNotSignedIn, 1); histogram_tester.ExpectBucketCount( - "CollaborationService.JoinFlow", - metrics::CollaborationServiceJoinEvent::kCanceledNotSignedIn, 1); + "CollaborationService.JoinFlow.Events", + metrics::CollaborationServiceFlowEvent::kCanceledNotSignedIn, 1); histogram_tester.ExpectBucketCount( - "CollaborationService.JoinFlow", - metrics::CollaborationServiceJoinEvent::kFlowRequirementsMet, 0); + "CollaborationService.JoinFlow.Events", + metrics::CollaborationServiceFlowEvent::kFlowRequirementsMet, 0); } TEST_F(CollaborationControllerTest, AuthenticationCanceledAfterSignIn) { @@ -801,8 +801,8 @@ // Verify the manage flow metrics are recorded properly. histogram_tester.ExpectBucketCount( - "CollaborationService.ShareOrManageFlow", - metrics::CollaborationServiceShareOrManageEvent::kFlowRequirementsMet, 1); + "CollaborationService.ShareOrManageFlow.Events", + metrics::CollaborationServiceFlowEvent::kFlowRequirementsMet, 1); histogram_tester.ExpectBucketCount( "CollaborationService.ShareOrManageFlow", metrics::CollaborationServiceShareOrManageEvent::kShareDialogShown, 1); @@ -852,8 +852,8 @@ // Verify the manage flow metrics are recorded properly. histogram_tester.ExpectBucketCount( - "CollaborationService.ShareOrManageFlow", - metrics::CollaborationServiceShareOrManageEvent::kFlowRequirementsMet, 1); + "CollaborationService.ShareOrManageFlow.Events", + metrics::CollaborationServiceFlowEvent::kFlowRequirementsMet, 1); histogram_tester.ExpectBucketCount( "CollaborationService.ShareOrManageFlow", metrics::CollaborationServiceShareOrManageEvent::kManageDialogShown, 1); @@ -909,14 +909,14 @@ // Verify the not signed in metrics are recorded properly. histogram_tester.ExpectBucketCount( - "CollaborationService.ShareOrManageFlow", - metrics::CollaborationServiceShareOrManageEvent::kNotSignedIn, 1); + "CollaborationService.ShareOrManageFlow.Events", + metrics::CollaborationServiceFlowEvent::kNotSignedIn, 1); histogram_tester.ExpectBucketCount( - "CollaborationService.ShareOrManageFlow", - metrics::CollaborationServiceShareOrManageEvent::kCanceledNotSignedIn, 1); + "CollaborationService.ShareOrManageFlow.Events", + metrics::CollaborationServiceFlowEvent::kCanceledNotSignedIn, 1); histogram_tester.ExpectBucketCount( - "CollaborationService.ShareOrManageFlow", - metrics::CollaborationServiceShareOrManageEvent::kFlowRequirementsMet, 0); + "CollaborationService.ShareOrManageFlow.Events", + metrics::CollaborationServiceFlowEvent::kFlowRequirementsMet, 0); } TEST_F(CollaborationControllerTest, LeaveFlow) {
diff --git a/components/collaboration/internal/collaboration_service_impl.cc b/components/collaboration/internal/collaboration_service_impl.cc index 4faa78ee..53cd3ba 100644 --- a/components/collaboration/internal/collaboration_service_impl.cc +++ b/components/collaboration/internal/collaboration_service_impl.cc
@@ -36,8 +36,6 @@ using data_sharing::GroupToken; using data_sharing::MemberRole; using Flow = CollaborationController::Flow; -using metrics::CollaborationServiceJoinEvent; -using metrics::CollaborationServiceShareOrManageEvent; using Outcome = signin::AccountManagedStatusFinder::Outcome; using ParseUrlResult = data_sharing::ParseUrlResult; using ParseUrlStatus = data_sharing::ParseUrlStatus; @@ -109,9 +107,6 @@ CancelAllFlows(base::BindOnce( &CollaborationServiceImpl::StartJoinFlowInternal, weak_ptr_factory_.GetWeakPtr(), std::move(delegate), token)); - - RecordJoinEvent(data_sharing_service_->GetLogger(), - CollaborationServiceJoinEvent::kStarted); } void CollaborationServiceImpl::StartShareOrManageFlow( @@ -126,9 +121,6 @@ base::BindOnce(&CollaborationServiceImpl::StartCollaborationFlowInternal, weak_ptr_factory_.GetWeakPtr(), std::move(delegate), either_id, FlowType::kShareOrManage)); - - RecordShareOrManageEvent(data_sharing_service_->GetLogger(), - CollaborationServiceShareOrManageEvent::kStarted); } void CollaborationServiceImpl::StartLeaveOrDeleteFlow(
diff --git a/components/collaboration/internal/messaging/instant_message_processor_impl.cc b/components/collaboration/internal/messaging/instant_message_processor_impl.cc index 54a373f6..e22cc63 100644 --- a/components/collaboration/internal/messaging/instant_message_processor_impl.cc +++ b/components/collaboration/internal/messaging/instant_message_processor_impl.cc
@@ -12,6 +12,7 @@ #include "base/containers/contains.h" #include "base/functional/callback_helpers.h" #include "base/hash/hash.h" +#include "base/strings/to_string.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "components/collaboration/public/messaging/message.h"
diff --git a/components/collaboration/internal/metrics.cc b/components/collaboration/internal/metrics.cc index b5b3469..179376ca 100644 --- a/components/collaboration/internal/metrics.cc +++ b/components/collaboration/internal/metrics.cc
@@ -283,6 +283,53 @@ } } +std::string_view CollaborationServiceFlowEventToString( + CollaborationServiceFlowEvent event) { + switch (event) { + case CollaborationServiceFlowEvent::kUnknown: + return "Unknown"; + case CollaborationServiceFlowEvent::kStarted: + return "Started"; + case CollaborationServiceFlowEvent::kNotSignedIn: + return "NotSignedIn"; + case CollaborationServiceFlowEvent::kCanceledNotSignedIn: + return "CanceledNotSignedIn"; + case CollaborationServiceFlowEvent::kFlowRequirementsMet: + return "FlowRequirementsMet"; + case CollaborationServiceFlowEvent::kSigninVerificationFailed: + return "SigninVerificationFailed"; + case CollaborationServiceFlowEvent::kSigninVerified: + return "SigninVerified"; + case CollaborationServiceFlowEvent::kSigninVerifiedInObserver: + return "SigninVerifiedInObserver"; + case CollaborationServiceFlowEvent::kDataSharingReadyWhenStarted: + return "DataSharingReadyWhenStarted"; + case CollaborationServiceFlowEvent::kDataSharingServiceReadyObserved: + return "DataSharingServiceReadyObserved"; + case CollaborationServiceFlowEvent::kTabGroupServiceReady: + return "TabGroupServiceReady"; + case CollaborationServiceFlowEvent::kAllServicesReadyForFlow: + return "AllServicesReadyForFlow"; + case CollaborationServiceFlowEvent::kDevicePolicyDisableSignin: + return "DevicePolicyDisableSignin"; + case CollaborationServiceFlowEvent::kManagedAccountSignin: + return "ManagedAccountSignin"; + case CollaborationServiceFlowEvent::kAccountInfoNotReadyOnSignin: + return "AccountInfoNotReadyOnSignin"; + } +} + +std::string_view CreateFlowTypeToString(FlowType type) { + switch (type) { + case FlowType::kJoin: + return "JoinFlow"; + case FlowType::kShareOrManage: + return "ShareOrManageFlow"; + case FlowType::kLeaveOrDelete: + return "LeaveOrDeleteFlow"; + } +} + std::string CreateJoinEventLogString(CollaborationServiceJoinEvent event) { return base::StringPrintf("Join Flow Event: %s", CollaborationServiceJoinEventToString(event)); @@ -314,6 +361,7 @@ "Leave or Delete Flow Started\n From: %s\n", CollaborationServiceLeaveOrDeleteEntryPointToString(entry)); } + std::string CreateLatencyLogToString(CollaborationServiceStep step, base::TimeDelta duration) { return base::StringPrintf("Step %s took %dms to complete.", @@ -321,11 +369,15 @@ duration.InMillisecondsRoundedUp()); } +std::string CreateFlowEventLogString(CollaborationServiceFlowEvent event) { + return base::StringPrintf("Flow Event: %s", + CollaborationServiceFlowEventToString(event)); +} + } // namespace void RecordJoinEvent(data_sharing::Logger* logger, CollaborationServiceJoinEvent event) { - VLOG(1) << "RecordJoinEvent:" << (CreateJoinEventLogString(event)); base::UmaHistogramEnumeration("CollaborationService.JoinFlow", event); DATA_SHARING_LOG(logger_common::mojom::LogSource::CollaborationService, logger, CreateJoinEventLogString(event)); @@ -333,8 +385,6 @@ void RecordShareOrManageEvent(data_sharing::Logger* logger, CollaborationServiceShareOrManageEvent event) { - VLOG(1) << "RecordShareOrManageEvent:" - << (CreateShareOrManageEventLogString(event)); base::UmaHistogramEnumeration("CollaborationService.ShareOrManageFlow", event); DATA_SHARING_LOG(logger_common::mojom::LogSource::CollaborationService, @@ -348,7 +398,7 @@ CollaborationServiceShareOrManageEvent share_or_manage_event) { if (type == FlowType::kJoin) { RecordJoinEvent(logger, join_event); - } else { + } else if (type == FlowType::kShareOrManage) { RecordShareOrManageEvent(logger, share_or_manage_event); } } @@ -391,4 +441,15 @@ logger, CreateLatencyLogToString(step, duration)); } +void RecordCollaborationFlowEvent(data_sharing::Logger* logger, + FlowType type, + CollaborationServiceFlowEvent event) { + std::string histogram_name = base::StrCat( + {"CollaborationService.", CreateFlowTypeToString(type), ".Events"}); + + base::UmaHistogramEnumeration(histogram_name, event); + DATA_SHARING_LOG(logger_common::mojom::LogSource::CollaborationService, + logger, CreateFlowEventLogString(event)); +} + } // namespace collaboration::metrics
diff --git a/components/collaboration/internal/metrics.h b/components/collaboration/internal/metrics.h index a615251a..542b700 100644 --- a/components/collaboration/internal/metrics.h +++ b/components/collaboration/internal/metrics.h
@@ -97,6 +97,30 @@ }; // LINT.ThenChange(//tools/metrics/histograms/metadata/collaboration_service/enums.xml:CollaborationServiceShareOrManageEvent) +// Types of collaboration flow events that occur in the collaboration service. +// These values are persisted to logs. Entries should not be renumbered and +// number values should never be reused. +// LINT.IfChange(CollaborationServiceFlowEvent) +enum class CollaborationServiceFlowEvent { + kUnknown = 0, + kStarted = 1, + kNotSignedIn = 2, + kCanceledNotSignedIn = 3, + kFlowRequirementsMet = 4, + kSigninVerificationFailed = 5, + kSigninVerified = 6, + kSigninVerifiedInObserver = 7, + kDataSharingReadyWhenStarted = 8, + kDataSharingServiceReadyObserved = 9, + kTabGroupServiceReady = 10, + kAllServicesReadyForFlow = 11, + kDevicePolicyDisableSignin = 12, + kManagedAccountSignin = 13, + kAccountInfoNotReadyOnSignin = 14, + kMaxValue = kAccountInfoNotReadyOnSignin, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/collaboration_service/enums.xml:CollaborationServiceFlowEvent) + enum class CollaborationServiceStep { kUnknown = 0, kAuthenticationInitToSuccess = 1, @@ -110,14 +134,14 @@ CollaborationServiceJoinEvent event); void RecordShareOrManageEvent(data_sharing::Logger* logger, CollaborationServiceShareOrManageEvent event); -void RecordLeaveOrDeleteEntryPoint( - data_sharing::Logger* logger, - CollaborationServiceLeaveOrDeleteEntryPoint event); void RecordJoinOrShareOrManageEvent( data_sharing::Logger* logger, FlowType type, CollaborationServiceJoinEvent join_event, CollaborationServiceShareOrManageEvent share_or_manage_event); +void RecordLeaveOrDeleteEntryPoint( + data_sharing::Logger* logger, + CollaborationServiceLeaveOrDeleteEntryPoint event); void RecordJoinEntryPoint(data_sharing::Logger* logger, CollaborationServiceJoinEntryPoint entry); void RecordShareOrManageEntryPoint( @@ -126,6 +150,9 @@ void RecordLatency(data_sharing::Logger* logger, CollaborationServiceStep step, base::TimeDelta duration); +void RecordCollaborationFlowEvent(data_sharing::Logger* logger, + FlowType type, + CollaborationServiceFlowEvent event); } // namespace collaboration::metrics #endif // COMPONENTS_COLLABORATION_INTERNAL_METRICS_H_
diff --git a/components/embedder_support/android/util/android_stream_reader_url_loader.cc b/components/embedder_support/android/util/android_stream_reader_url_loader.cc index 8521e3a..1e21760 100644 --- a/components/embedder_support/android/util/android_stream_reader_url_loader.cc +++ b/components/embedder_support/android/util/android_stream_reader_url_loader.cc
@@ -20,7 +20,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/task/thread_pool.h" #include "base/threading/thread.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/embedder_support/android/util/features.h" #include "components/embedder_support/android/util/input_stream.h" #include "components/embedder_support/android/util/input_stream_reader.h"
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc index abed326..27b2638 100644 --- a/components/exo/buffer.cc +++ b/components/exo/buffer.cc
@@ -40,7 +40,6 @@ #include "gpu/command_buffer/common/shared_image_capabilities.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/common/sync_token.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/media_switches.h" #include "ui/aura/env.h" #include "ui/color/color_id.h"
diff --git a/components/exo/display.cc b/components/exo/display.cc index 5d320fba..695d91f 100644 --- a/components/exo/display.cc +++ b/components/exo/display.cc
@@ -31,7 +31,6 @@ #include "components/exo/toast_surface.h" #include "components/exo/toast_surface_manager.h" #include "components/exo/xdg_shell_surface.h" -#include "gpu/command_buffer/common/gpu_memory_buffer_support.h" #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h" #include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2ext.h"
diff --git a/components/exo/shell_surface_util.h b/components/exo/shell_surface_util.h index 79c96b74..1b24a327 100644 --- a/components/exo/shell_surface_util.h +++ b/components/exo/shell_surface_util.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_EXO_SHELL_SURFACE_UTIL_H_ #define COMPONENTS_EXO_SHELL_SURFACE_UTIL_H_ +#include <stdint.h> + #include <memory> #include <optional> #include <string>
diff --git a/components/exo/wayland/test/resource_key.h b/components/exo/wayland/test/resource_key.h index 11ae989..fe00953d 100644 --- a/components/exo/wayland/test/resource_key.h +++ b/components/exo/wayland/test/resource_key.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_EXO_WAYLAND_TEST_RESOURCE_KEY_H_ #define COMPONENTS_EXO_WAYLAND_TEST_RESOURCE_KEY_H_ +#include <stdint.h> + #include <string> namespace exo::wayland::test {
diff --git a/components/exo/wayland/wayland_protocol_logger.h b/components/exo/wayland/wayland_protocol_logger.h index 8eca06d..bea4d01 100644 --- a/components/exo/wayland/wayland_protocol_logger.h +++ b/components/exo/wayland/wayland_protocol_logger.h
@@ -8,6 +8,7 @@ #include <wayland-server-core.h> #include <memory> +#include <string> #include <vector> namespace exo::wayland {
diff --git a/components/history/core/browser/sync/history_sync_bridge_unittest.cc b/components/history/core/browser/sync/history_sync_bridge_unittest.cc index 9ea66ae..e1f842fc 100644 --- a/components/history/core/browser/sync/history_sync_bridge_unittest.cc +++ b/components/history/core/browser/sync/history_sync_bridge_unittest.cc
@@ -13,6 +13,7 @@ #include "base/notreached.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "components/history/core/browser/history_types.h"
diff --git a/components/language_detection/core/background_file_unittest.cc b/components/language_detection/core/background_file_unittest.cc index 253e9bc..a52b8ba 100644 --- a/components/language_detection/core/background_file_unittest.cc +++ b/components/language_detection/core/background_file_unittest.cc
@@ -13,6 +13,7 @@ #include "base/task/thread_pool.h" #include "base/test/run_until.h" #include "base/test/task_environment.h" +#include "base/threading/thread_restrictions.h" #include "components/language_detection/testing/language_detection_test_utils.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/memory_pressure/memory_pressure_voter.cc b/components/memory_pressure/memory_pressure_voter.cc index e077fea..8826e51 100644 --- a/components/memory_pressure/memory_pressure_voter.cc +++ b/components/memory_pressure/memory_pressure_voter.cc
@@ -8,7 +8,7 @@ #include <optional> #include "base/memory/raw_ptr.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace memory_pressure {
diff --git a/components/memory_pressure/multi_source_memory_pressure_monitor.cc b/components/memory_pressure/multi_source_memory_pressure_monitor.cc index 5415f57..1b857d0a 100644 --- a/components/memory_pressure/multi_source_memory_pressure_monitor.cc +++ b/components/memory_pressure/multi_source_memory_pressure_monitor.cc
@@ -9,8 +9,8 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/memory_pressure_level_proto.h" +#include "base/trace_event/trace_event.h" #include "base/tracing_buildflags.h" #include "components/memory_pressure/system_memory_pressure_evaluator.h"
diff --git a/components/omnibox/browser/tab_group_provider.cc b/components/omnibox/browser/tab_group_provider.cc index 9e3f0b8..c11a632 100644 --- a/components/omnibox/browser/tab_group_provider.cc +++ b/components/omnibox/browser/tab_group_provider.cc
@@ -9,7 +9,7 @@ #include "base/i18n/case_conversion.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/omnibox/common/omnibox_features.h" #include "components/saved_tab_groups/public/saved_tab_group.h" #include "components/saved_tab_groups/public/tab_group_sync_service.h"
diff --git a/components/page_load_metrics/google/browser/gws_page_load_metrics_observer.cc b/components/page_load_metrics/google/browser/gws_page_load_metrics_observer.cc index 8c93bca..ca5a6d87 100644 --- a/components/page_load_metrics/google/browser/gws_page_load_metrics_observer.cc +++ b/components/page_load_metrics/google/browser/gws_page_load_metrics_observer.cc
@@ -17,8 +17,8 @@ #include "base/strings/strcat.h" #include "base/strings/string_util.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/named_trigger.h" +#include "base/trace_event/trace_event.h" #include "components/crash/core/common/crash_key.h" #include "components/page_load_metrics/browser/navigation_handle_user_data.h" #include "components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h"
diff --git a/components/persistent_cache/sqlite/sqlite_backend_impl.cc b/components/persistent_cache/sqlite/sqlite_backend_impl.cc index 9d0dd59..8cf02a3 100644 --- a/components/persistent_cache/sqlite/sqlite_backend_impl.cc +++ b/components/persistent_cache/sqlite/sqlite_backend_impl.cc
@@ -9,7 +9,7 @@ #include "base/check_op.h" #include "base/containers/span.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/persistent_cache/sqlite/sqlite_entry_impl.h" #include "components/persistent_cache/sqlite/vfs/sandboxed_file.h" #include "components/persistent_cache/sqlite/vfs/sqlite_sandboxed_vfs.h"
diff --git a/components/policy/core/common/policy_map.cc b/components/policy/core/common/policy_map.cc index e6d846d7f..7f91265 100644 --- a/components/policy/core/common/policy_map.cc +++ b/components/policy/core/common/policy_map.cc
@@ -35,16 +35,18 @@ std::u16string result = std::u16string(); std::u16string line_feed = u"\n"; for (const auto& string_pairs : localized_string_ids) { - if (string_pairs.second) + if (string_pairs.second) { result += l10n_util::GetStringFUTF16( string_pairs.first, string_pairs.second.value(), nullptr); - else + } else { result += lookup.Run(string_pairs.first); + } result += line_feed; } // Remove the trailing newline. - if (!result.empty() && result[result.length() - 1] == line_feed[0]) + if (!result.empty() && result[result.length() - 1] == line_feed[0]) { result.pop_back(); + } return result; } @@ -71,21 +73,21 @@ const PolicyDetails* details) { switch (source) { case POLICY_SOURCE_ENTERPRISE_DEFAULT: - return POLICY_PRIORITY_BROWSER_ENTERPRISE_DEFAULT; + return PolicyPriorityBrowser::kEnterpriseDefault; case POLICY_SOURCE_COMMAND_LINE: - return POLICY_PRIORITY_BROWSER_COMMAND_LINE; + return PolicyPriorityBrowser::kCommandLine; case POLICY_SOURCE_CLOUD: if (scope == POLICY_SCOPE_MACHINE) { // Raise the priority of cloud machine policies only when the metapolicy // CloudPolicyOverridesPlatformPolicy is set to true. return cloud_policy_overrides_platform_policy - ? POLICY_PRIORITY_BROWSER_CLOUD_MACHINE_RAISED - : POLICY_PRIORITY_BROWSER_CLOUD_MACHINE; + ? PolicyPriorityBrowser::kCloudMachineRaised + : PolicyPriorityBrowser::kCloudMachine; } // For policies that can only be set with managed account, raise the // priority of correct source to highest. if (details && details->scope == kSingleProfile) { - return POLICY_PRIORITY_BROWSER_CLOUD_USER_DOUBLE_RAISED; + return PolicyPriorityBrowser::kCloudUserDoubleRaised; } if (cloud_user_policy_overrides_cloud_machine_policy && is_user_affiliated) { @@ -94,16 +96,16 @@ // user is affiliated. Its priority relative to cloud machine policies // also depends on the value of CloudPolicyOverridesPlatformPolicy. return cloud_policy_overrides_platform_policy - ? POLICY_PRIORITY_BROWSER_CLOUD_USER_DOUBLE_RAISED - : POLICY_PRIORITY_BROWSER_CLOUD_USER_RAISED; + ? PolicyPriorityBrowser::kCloudUserDoubleRaised + : PolicyPriorityBrowser::kCloudUserRaised; } - return POLICY_PRIORITY_BROWSER_CLOUD_USER; + return PolicyPriorityBrowser::kCloudUser; case POLICY_SOURCE_PLATFORM: return scope == POLICY_SCOPE_MACHINE - ? POLICY_PRIORITY_BROWSER_PLATFORM_MACHINE - : POLICY_PRIORITY_BROWSER_PLATFORM_USER; + ? PolicyPriorityBrowser::kPlatformMachine + : PolicyPriorityBrowser::kPlatformUser; case POLICY_SOURCE_MERGED: - return POLICY_PRIORITY_BROWSER_MERGED; + return PolicyPriorityBrowser::kMerged; default: NOTREACHED(); } @@ -180,9 +182,10 @@ bool PolicyMap::Entry::Equals(const PolicyMap::Entry& other) const { bool conflicts_are_equal = conflicts.size() == other.conflicts.size(); - for (size_t i = 0; conflicts_are_equal && i < conflicts.size(); ++i) + for (size_t i = 0; conflicts_are_equal && i < conflicts.size(); ++i) { conflicts_are_equal &= conflicts[i].entry().Equals(other.conflicts[i].entry()); + } const bool equals = conflicts_are_equal && level == other.level && scope == other.scope && @@ -213,8 +216,9 @@ return; } message_ids_[type].erase(message_id); - if (message_ids_[type].size() == 0) + if (message_ids_[type].size() == 0) { message_ids_.erase(type); + } } void PolicyMap::Entry::AddConflictingPolicy(Entry&& conflict) { @@ -462,8 +466,9 @@ const PolicyMap& other, bool using_default_precedence) { const Entry* other_policy = other.GetUntrusted(policy_name); - if (!other_policy) + if (!other_policy) { return; + } Entry* policy = GetMutableUntrusted(policy_name); Entry other_policy_copy = other_policy->DeepCopy(); @@ -498,8 +503,9 @@ higher_policy.AddConflictingPolicy(std::move(conflicting_policy)); } - if (other_is_higher_priority) + if (other_is_higher_priority) { *policy = std::move(other_policy_copy); + } } void PolicyMap::MergeFrom(const PolicyMap& other) { @@ -538,8 +544,9 @@ } void PolicyMap::MergeValues(const std::vector<PolicyMerger*>& mergers) { - for (const auto* it : mergers) + for (const auto* it : mergers) { it->Merge(this); + } } void PolicyMap::set_chrome_policy_details_callback_for_test( @@ -549,8 +556,9 @@ bool PolicyMap::IsPolicyExternal(const std::string& policy) { const PolicyDetails* policy_details = GetPolicyDetails(policy); - if (policy_details && policy_details->max_external_data_size > 0) + if (policy_details && policy_details->max_external_data_size > 0) { return true; + } return false; }
diff --git a/components/policy/core/common/policy_types.h b/components/policy/core/common/policy_types.h index ccef8196..0755d18 100644 --- a/components/policy/core/common/policy_types.h +++ b/components/policy/core/common/policy_types.h
@@ -82,37 +82,37 @@ // priority, so source is used directly in the priority comparison. enum PolicyPriorityBrowser { // The policy was set through remapping or debugging. - POLICY_PRIORITY_BROWSER_ENTERPRISE_DEFAULT, + kEnterpriseDefault, // The policy was set by command line flag for testing purposes. - POLICY_PRIORITY_BROWSER_COMMAND_LINE, + kCommandLine, // The policy was set by a cloud source at the user level. - POLICY_PRIORITY_BROWSER_CLOUD_USER, + kCloudUser, // The policy was set by a platform source at the user level. - POLICY_PRIORITY_BROWSER_PLATFORM_USER, + kPlatformUser, // The policy was set by a cloud source at the machine level. - POLICY_PRIORITY_BROWSER_CLOUD_MACHINE, + kCloudMachine, // The policy was set by a cloud source at the user level. Its priority is // raised above that of cloud machine policies. - POLICY_PRIORITY_BROWSER_CLOUD_USER_RAISED, + kCloudUserRaised, // The policy was set by a platform source at the machine level. - POLICY_PRIORITY_BROWSER_PLATFORM_MACHINE, + kPlatformMachine, // The policy was set by a platform source at the machine level. Its priority // is raised above that of platform machine policies. - POLICY_PRIORITY_BROWSER_CLOUD_MACHINE_RAISED, + kCloudMachineRaised, // The policy was set by a cloud source at the user level. Its priority is // raised above that of platform and cloud machine policies. - POLICY_PRIORITY_BROWSER_CLOUD_USER_DOUBLE_RAISED, + kCloudUserDoubleRaised, // The policy coming from multiple sources and its value has been merged. - POLICY_PRIORITY_BROWSER_MERGED, + kMerged, }; // The `PolicyFetchReason` enum is used to tag requests to DMServer. This allows
diff --git a/components/services/on_device_translation/public/cpp/features.cc b/components/services/on_device_translation/public/cpp/features.cc index 2c8eeda..e95bd745 100644 --- a/components/services/on_device_translation/public/cpp/features.cc +++ b/components/services/on_device_translation/public/cpp/features.cc
@@ -15,6 +15,10 @@ namespace { +// Limit the number of downloadable language packs to 5 during OT to mitigate +// the risk of fingerprinting attacks. +constexpr size_t kTranslationAPILimitLanguagePackCountMax = 5; + base::FilePath GetPathFromCommandLine(const char* switch_name) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switch_name)) { @@ -29,6 +33,14 @@ &blink::features::kTranslationAPI, "TranslationAPILibraryMinimumVersion", "2025.1.10.0"}; +const base::FeatureParam<bool> kTranslationAPIAcceptLanguagesCheck{ + &blink::features::kTranslationAPI, "TranslationAPIAcceptLanguagesCheck", + true}; + +const base::FeatureParam<bool> kTranslationAPILimitLanguagePackCount{ + &blink::features::kTranslationAPI, "TranslationAPILimitLanguagePackCount", + true}; + const base::FeatureParam<base::TimeDelta> kTranslationAPIServiceIdleTimeout{ &blink::features::kTranslationAPI, "TranslationAPIServiceIdleTimeout", base::Minutes(1)}; @@ -41,6 +53,17 @@ return GetPathFromCommandLine(kTranslateKitBinaryPath); } +size_t GetInstallablePackageCount(size_t installed_package_count) { + if (base::FeatureList::IsEnabled(blink::features::kTranslationAPIV1) || + !kTranslationAPILimitLanguagePackCount.Get()) { + return std::numeric_limits<size_t>::max(); + } + if (installed_package_count >= kTranslationAPILimitLanguagePackCountMax) { + return 0; + } + return kTranslationAPILimitLanguagePackCountMax - installed_package_count; +} + bool IsValidTranslateKitVersion(std::string_view version_str) { base::Version minimum_version(kTranslationAPILibraryMinimumVersion.Get()); CHECK(minimum_version.IsValid());
diff --git a/components/services/on_device_translation/public/cpp/features.h b/components/services/on_device_translation/public/cpp/features.h index 279e820..1a80c7d 100644 --- a/components/services/on_device_translation/public/cpp/features.h +++ b/components/services/on_device_translation/public/cpp/features.h
@@ -23,6 +23,18 @@ // Any version string longer than this will be truncated. inline constexpr size_t kTranslationAPILibraryVersionStringSize = 14; +// When this feature param is enabled, the Translation API will fail if neither +// the source nor destination language is in the AcceptLanguages. This is +// introduced to mitigate privacy concerns. +extern const base::FeatureParam<bool> kTranslationAPIAcceptLanguagesCheck; + +// This feature limits the number of language components downloaded by +// createTranslator() to 3. +extern const base::FeatureParam<bool> kTranslationAPILimitLanguagePackCount; + +// Returns the number of additionally installable language packs. +size_t GetInstallablePackageCount(size_t installed_package_count); + // The duration that the OnDeviceTranslation service can remain idle before it // is terminated. extern const base::FeatureParam<base::TimeDelta>
diff --git a/components/services/storage/shared_storage/async_shared_storage_database_impl_unittest.cc b/components/services/storage/shared_storage/async_shared_storage_database_impl_unittest.cc index 3bba8e44..2cd6819 100644 --- a/components/services/storage/shared_storage/async_shared_storage_database_impl_unittest.cc +++ b/components/services/storage/shared_storage/async_shared_storage_database_impl_unittest.cc
@@ -17,6 +17,7 @@ #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" #include "base/test/bind.h"
diff --git a/components/tracing/common/background_tracing_utils_unittest.cc b/components/tracing/common/background_tracing_utils_unittest.cc index f8633df7..a250ddb 100644 --- a/components/tracing/common/background_tracing_utils_unittest.cc +++ b/components/tracing/common/background_tracing_utils_unittest.cc
@@ -14,6 +14,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_proto_loader.h" +#include "base/threading/thread_restrictions.h" #include "components/prefs/testing_pref_service.h" #include "components/tracing/common/background_tracing_state_manager.h" #include "components/tracing/common/pref_names.h"
diff --git a/components/update_client/background_downloader_mac_unittest.cc b/components/update_client/background_downloader_mac_unittest.cc index 04e42dd..b55712c 100644 --- a/components/update_client/background_downloader_mac_unittest.cc +++ b/components/update_client/background_downloader_mac_unittest.cc
@@ -17,6 +17,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" +#include "base/hash/hash.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/memory/scoped_refptr.h"
diff --git a/components/viz/common/overlay_state/win/overlay_state_service.cc b/components/viz/common/overlay_state/win/overlay_state_service.cc index e155da6e..2248b58 100644 --- a/components/viz/common/overlay_state/win/overlay_state_service.cc +++ b/components/viz/common/overlay_state/win/overlay_state_service.cc
@@ -10,7 +10,6 @@ #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/thread.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/trace_event.h" namespace viz {
diff --git a/components/viz/host/gpu_client.cc b/components/viz/host/gpu_client.cc index 2c81a757..e85a064 100644 --- a/components/viz/host/gpu_client.cc +++ b/components/viz/host/gpu_client.cc
@@ -15,7 +15,6 @@ #include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/ipc/common/gpu_memory_buffer_impl.h" #include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "services/viz/privileged/mojom/gl/gpu_service.mojom.h" namespace viz {
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc index 9900a93..b40c4bd 100644 --- a/components/viz/host/gpu_host_impl.cc +++ b/components/viz/host/gpu_host_impl.cc
@@ -157,6 +157,7 @@ viz_main_->CreateGpuService( gpu_service_remote_.BindNewPipeAndPassReceiver(task_runner), gpu_host_receiver_.BindNewPipeAndPassRemote(task_runner), + gpu_logging_receiver_.BindNewPipeAndPassRemote(task_runner), std::move(discardable_manager_remote), use_shader_cache_shm_count_.CloneRegion(), std::move(gpu_service_params)); MaybeSendFontRenderParams(); @@ -640,12 +641,6 @@ cache->Cache(key, blob); } -void GpuHostImpl::RecordLogMessage(int32_t severity, - const std::string& header, - const std::string& message) { - delegate_->RecordLogMessage(severity, header, message); -} - void GpuHostImpl::ClearGrShaderDiskCache() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -662,6 +657,12 @@ } } +void GpuHostImpl::RecordLogMessage(int32_t severity, + const std::string& header, + const std::string& message) { + delegate_->RecordLogMessage(severity, header, message); +} + #if BUILDFLAG(USE_VIZ_DEBUGGER) void GpuHostImpl::LogFrame(base::Value frame_data) { if (!viz_debug_output_callback_.is_null())
diff --git a/components/viz/host/gpu_host_impl.h b/components/viz/host/gpu_host_impl.h index ff6bba16..89b59cd6 100644 --- a/components/viz/host/gpu_host_impl.h +++ b/components/viz/host/gpu_host_impl.h
@@ -38,6 +38,7 @@ #include "services/service_manager/public/mojom/service.mojom.h" #include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h" #include "services/viz/privileged/mojom/gl/gpu_host.mojom.h" +#include "services/viz/privileged/mojom/gl/gpu_logging.mojom.h" #include "services/viz/privileged/mojom/gl/gpu_service.mojom.h" #include "services/viz/privileged/mojom/viz_main.mojom.h" #include "ui/gfx/gpu_extra_info.h" @@ -59,7 +60,8 @@ namespace viz { -class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost +class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost, + public mojom::GpuLogging #if BUILDFLAG(USE_VIZ_DEBUGGER) , public mojom::VizDebugOutput @@ -276,10 +278,12 @@ void StoreBlobToDisk(const gpu::GpuDiskCacheHandle& handle, const std::string& key, const std::string& blob) override; + void ClearGrShaderDiskCache() override; + + // mojom::GpuLogging: void RecordLogMessage(int32_t severity, const std::string& header, const std::string& message) override; - void ClearGrShaderDiskCache() override; // Implements mojom::VizDebugOutput and is called by VizDebugger. #if BUILDFLAG(USE_VIZ_DEBUGGER) @@ -298,6 +302,8 @@ info_collection_gpu_service_remote_; #endif mojo::Receiver<mojom::GpuHost> gpu_host_receiver_{this}; + mojo::Receiver<mojom::GpuLogging> gpu_logging_receiver_{this}; + gpu::GpuProcessHostShmCount use_shader_cache_shm_count_; #if BUILDFLAG(USE_VIZ_DEBUGGER)
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index a5e9ffc..f1b1fed3e 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -29,6 +29,7 @@ #include "base/timer/elapsed_timer.h" #include "base/trace_event/common/trace_event_common.h" #include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_id_helper.h" #include "base/trace_event/traced_value.h" #include "base/trace_event/typed_macros.h" #include "build/build_config.h"
diff --git a/components/viz/service/gl/exit_code.cc b/components/viz/service/gl/exit_code.cc index 8a3dc20..251482b3 100644 --- a/components/viz/service/gl/exit_code.cc +++ b/components/viz/service/gl/exit_code.cc
@@ -5,13 +5,16 @@ #include "components/viz/service/gl/exit_code.h" #include "base/logging.h" -#include "base/process/process.h" +#include "components/viz/service/gl/gpu_log_message_manager.h" namespace viz { void RestartGpuProcessForContextLoss(std::string_view reason) { LOG(ERROR) << "Restarting GPU process due to unrecoverable error. " << reason; - base::Process::TerminateCurrentProcessImmediately( + + // Terminate the GPU process on IO thread to ensure previous mojo messages are + // in message queue. + GpuLogMessageManager::GetInstance()->TerminateProcess( static_cast<int>(ExitCode::RESULT_CODE_GPU_EXIT_ON_CONTEXT_LOST)); }
diff --git a/components/viz/service/gl/gpu_log_message_manager.cc b/components/viz/service/gl/gpu_log_message_manager.cc index 9e530a5d..26f56e4 100644 --- a/components/viz/service/gl/gpu_log_message_manager.cc +++ b/components/viz/service/gl/gpu_log_message_manager.cc
@@ -4,7 +4,8 @@ #include "components/viz/service/gl/gpu_log_message_manager.h" -#include "services/viz/privileged/mojom/gl/gpu_host.mojom.h" +#include "base/process/process.h" +#include "base/synchronization/waitable_event.h" namespace viz { @@ -43,55 +44,113 @@ const std::string& header, const std::string& message) { base::AutoLock lock(message_lock_); - // During InstallPostInitializeLogHandler() there's a brief window where a - // call into this function may be waiting on |message_lock_|, so we need to - // check if |log_callback_| was set once we get the lock. - if (log_callback_) { - RouteMessage(severity, std::move(header), std::move(message)); - return; - } - - // Otherwise just queue the message for InstallPostInitializeLogHandler() to - // forward later. - deferred_messages_.emplace_back(severity, std::move(header), - std::move(message)); + deferred_messages_.emplace_back(severity, header, message); } void GpuLogMessageManager::RouteMessage(int severity, const std::string& header, const std::string& message) { - log_callback_.Run(severity, std::move(header), std::move(message)); + // This can be run from any thread, but mojo messages are sent on the IO + // thread. + if (io_task_runner_->BelongsToCurrentThread()) { + if (!gpu_logging_.is_bound()) { + // |InstallPostInitializeLogHandler| set a new log message handler, which + // will call |RouteMessage|. When |RouteMessage| handling log message + // GPULogging may not yet be bound. Cache those log messages until the + // Remote is bound. + base::AutoLock lock(message_lock_); + deferred_messages_.emplace_back(severity, header, message); + return; + } + + gpu_logging_->RecordLogMessage(severity, header, message); + } else { + // Unretained is safe because |this| is valid until the process exits. + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&GpuLogMessageManager::RouteMessage, + base::Unretained(this), severity, + std::move(header), std::move(message))); + } } -void GpuLogMessageManager::FlushMessages(mojom::GpuHost* gpu_host) { +void GpuLogMessageManager::FlushMessages(mojom::GpuLogging* gpu_logging) { base::AutoLock lock(message_lock_); for (auto& log : deferred_messages_) { - gpu_host->RecordLogMessage(log.severity, std::move(log.header), - std::move(log.message)); + gpu_logging->RecordLogMessage(log.severity, std::move(log.header), + std::move(log.message)); } deferred_messages_.clear(); } void GpuLogMessageManager::InstallPreInitializeLogHandler() { - DCHECK(!log_callback_); logging::SetLogMessageHandler(PreInitializeLogHandler); } void GpuLogMessageManager::InstallPostInitializeLogHandler( - LogCallback log_callback) { - base::AutoLock lock(message_lock_); - DCHECK(!log_callback_); - log_callback_ = std::move(log_callback); - for (auto& log : deferred_messages_) { - RouteMessage(log.severity, std::move(log.header), std::move(log.message)); - } - deferred_messages_.clear(); + mojo::PendingRemote<mojom::GpuLogging> pending_remote, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { + Bind(std::move(pending_remote), std::move(io_task_runner)); + logging::SetLogMessageHandler(PostInitializeLogHandler); } void GpuLogMessageManager::ShutdownLogging() { logging::SetLogMessageHandler(nullptr); - log_callback_.Reset(); + + // |io_task_runner_| may be null if GPULogMessageManager hasn't been bound. + // Destroy the remote on the IO thread. + // base::Unretained is safe because this is a singleton. + if (io_task_runner_) { + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&GpuLogMessageManager::ResetLoggingOnIOThread, + base::Unretained(this))); + } +} + +void GpuLogMessageManager::Bind( + mojo::PendingRemote<mojom::GpuLogging> pending_remote, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { + DCHECK(!io_task_runner->BelongsToCurrentThread()); + io_task_runner_ = std::move(io_task_runner); + + // base::Unretained is safe because this is a singleton. + io_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&GpuLogMessageManager::BindOnIOThread, + base::Unretained(this), std::move(pending_remote))); +} + +void GpuLogMessageManager::BindOnIOThread( + mojo::PendingRemote<mojom::GpuLogging> pending_remote) { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(!gpu_logging_.is_bound()); + gpu_logging_.Bind(std::move(pending_remote)); + + FlushMessages(gpu_logging_.get()); +} + +void GpuLogMessageManager::ResetLoggingOnIOThread() { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + gpu_logging_.reset(); +} + +void GpuLogMessageManager::TerminateProcess(int exit_code) { + // Block the calling thread so it doesn't execute any more code before the + // process exits. This function cannot be called from the IO thread. + CHECK(!io_task_runner_->BelongsToCurrentThread()); + base::WaitableEvent wait; + + // base::Unretained is safe because this is a singleton. + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&GpuLogMessageManager::TerminateProcessOnIO, + base::Unretained(this), exit_code)); + + wait.Wait(); +} + +void GpuLogMessageManager::TerminateProcessOnIO(int exit_code) { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + base::Process::TerminateCurrentProcessImmediately(exit_code); } } // namespace viz
diff --git a/components/viz/service/gl/gpu_log_message_manager.h b/components/viz/service/gl/gpu_log_message_manager.h index 663c1b13..f8dc774 100644 --- a/components/viz/service/gl/gpu_log_message_manager.h +++ b/components/viz/service/gl/gpu_log_message_manager.h
@@ -12,62 +12,73 @@ #include "base/functional/callback.h" #include "base/no_destructor.h" #include "base/synchronization/lock.h" +#include "base/task/single_thread_task_runner.h" #include "components/viz/service/viz_service_export.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/viz/privileged/mojom/gl/gpu_logging.mojom.h" namespace viz { - -namespace mojom { -class GpuHost; -} - -// Class which manages LOG() message forwarding before and after GpuServiceImpl -// InitializeWithHost(). Prior to initialize, log messages are deferred and kept -// within the class. During initialize, InstallPostInitializeLogHandler() will -// be called to flush deferred messages and route new ones directly to GpuHost. +// This class is a singleton which manages LOG() message forwarding before and +// after GpuServiceImpl InitializeWithHost(). Prior to initialize, log messages +// are deferred and kept within the class. When initialized GpuServiceImpl, +// InstallPostInitializeLogHandler() will be called to flush deferred messages +// and route new ones directly to browser. This class also makes sure the +// logging mojo interface is bound to the IO thread and terminate process on the +// IO thread. class VIZ_SERVICE_EXPORT GpuLogMessageManager { public: - using LogCallback = base::RepeatingCallback<void(int severity, - const std::string& header, - const std::string& message)>; - static GpuLogMessageManager* GetInstance(); GpuLogMessageManager(const GpuLogMessageManager&) = delete; GpuLogMessageManager& operator=(const GpuLogMessageManager&) = delete; // Queues a deferred LOG() message into |deferred_messages_| unless - // |log_callback_| has been set -- in which case RouteMessage() is called. + // |should_route_messages_| has been set to true -- in which case + // RouteMessage() is called. void AddDeferredMessage(int severity, const std::string& header, const std::string& message); // Used after InstallPostInitializeLogHandler() to route messages directly to - // |log_callback_|; avoids the need for a global lock. + // the GPU logging mojo interface, mojo interface send messages on IO thread. void RouteMessage(int severity, const std::string& header, const std::string& message); // If InstallPostInitializeLogHandler() will never be called, this method is // called prior to process exit to ensure logs are forwarded. - void FlushMessages(mojom::GpuHost* gpu_host); + void FlushMessages(mojom::GpuLogging* gpu_logging); - // Used prior to InitializeWithHost() during GpuMain startup to ensure logs - // aren't lost before initialize. + // Used prior to GpuServiceImpl initialization during GpuMain startup to + // ensure logs aren't lost before initialize. void InstallPreInitializeLogHandler(); - // Called when GPUService created to take over logging from the + // Called when GpuServiceImpl is initialized, to take over logging from the // PostInitializeLogHandler(). Flushes all deferred messages. - void InstallPostInitializeLogHandler(LogCallback log_callback); + void InstallPostInitializeLogHandler( + mojo::PendingRemote<mojom::GpuLogging> pending_remote, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); - // Called when it's no longer safe to invoke |log_callback_|. + // Called when GpuServiceImpl is shutting down. void ShutdownLogging(); + // Terminate the process on IO thread and block the main thread. + void TerminateProcess(int exit_code); + private: friend class base::NoDestructor<GpuLogMessageManager>; GpuLogMessageManager(); ~GpuLogMessageManager() = delete; + // Bind GpuLogging mojo interface to specified |task_runner|. + void Bind(mojo::PendingRemote<mojom::GpuLogging> pending_remote, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + void BindOnIOThread(mojo::PendingRemote<mojom::GpuLogging> pending_remote); + void ResetLoggingOnIOThread(); + + void TerminateProcessOnIO(int exit_code); + struct LogMessage { LogMessage(int severity, const std::string& header, @@ -83,9 +94,9 @@ base::Lock message_lock_; std::vector<LogMessage> deferred_messages_ GUARDED_BY(message_lock_); - // Set once under |mesage_lock_|, but may be accessed without lock after that. - LogCallback log_callback_; + mojo::Remote<mojom::GpuLogging> gpu_logging_; + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; }; - } // namespace viz + #endif // COMPONENTS_VIZ_SERVICE_GL_GPU_LOG_MESSAGE_MANAGER_H_
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index ec870a83..9c0faf2 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -311,10 +311,6 @@ bind_task_tracker_.TryCancelAll(); - if (!in_host_process()) { - GpuLogMessageManager::GetInstance()->ShutdownLogging(); - } - #if BUILDFLAG(IS_WIN) gl::DirectCompositionOverlayCapsMonitor::GetInstance()->RemoveObserver(this); #endif @@ -523,14 +519,6 @@ gpu_info_for_hardware_gpu_, gpu_feature_info_for_hardware_gpu_, gpu_extra_info_); gpu_host_ = mojo::SharedRemote<mojom::GpuHost>(gpu_host.Unbind(), io_runner_); - if (!in_host_process()) { - // The global callback is reset from the dtor. So Unretained() here is safe. - // Note that the callback can be called from any thread. Consequently, the - // callback cannot use a WeakPtr. - GpuLogMessageManager::GetInstance()->InstallPostInitializeLogHandler( - base::BindRepeating(&GpuServiceImpl::RecordLogMessage, - base::Unretained(this))); - } // Defer creation of the render thread. This is to prevent it from handling // IPC messages before the sandbox has been enabled and all other necessary @@ -608,13 +596,6 @@ visibility_changed_callback_ = std::move(callback); } -void GpuServiceImpl::RecordLogMessage(int severity, - const std::string& header, - const std::string& message) { - // This can be run from any thread. - gpu_host_->RecordLogMessage(severity, std::move(header), std::move(message)); -} - #if BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) void GpuServiceImpl::CreateArcVideoDecodeAccelerator(
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h index c38375d0..3b3e1f348 100644 --- a/components/viz/service/gl/gpu_service_impl.h +++ b/components/viz/service/gl/gpu_service_impl.h
@@ -428,9 +428,6 @@ bool IsNativeBufferSupported(gfx::BufferFormat format, gfx::BufferUsage usage); - void RecordLogMessage(int severity, - const std::string& header, - const std::string& message); #if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) void CreateArcVideoDecodeAcceleratorOnMainThread(
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc index ab02d8f6db..77eed595 100644 --- a/components/viz/service/layers/layer_context_impl.cc +++ b/components/viz/service/layers/layer_context_impl.cc
@@ -48,6 +48,13 @@ namespace { +#define RETURN_IF_FALSE(expr, error) \ + do { \ + if (!(expr)) { \ + return base::unexpected(error); \ + } \ + } while (false) + int GenerateNextDisplayTreeId() { static int next_id = 1; return next_id++; @@ -61,75 +68,92 @@ return settings; } -std::unique_ptr<cc::LayerImpl> CreateLayer(cc::LayerTreeHostImpl& host_impl, - cc::LayerTreeImpl& tree, - const mojom::Layer& wire) { +base::expected<void, std::string> CreateLayer( + cc::LayerTreeHostImpl& host_impl, + cc::LayerTreeImpl& tree, + const mojom::Layer& wire, + std::unique_ptr<cc::LayerImpl>& layer) { cc::mojom::LayerType type = wire.type; int id = wire.id; switch (type) { case cc::mojom::LayerType::kLayer: - return cc::LayerImpl::Create(&tree, id); + layer = cc::LayerImpl::Create(&tree, id); + break; case cc::mojom::LayerType::kMirror: - return cc::MirrorLayerImpl::Create(&tree, id); + layer = cc::MirrorLayerImpl::Create(&tree, id); + break; case cc::mojom::LayerType::kNinePatchThumbScrollbar: { + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); auto& extra = wire.layer_extra->get_nine_patch_thumb_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = extra->scrollbar_base_extra->is_horizontal_orientation ? cc::ScrollbarOrientation::kHorizontal : cc::ScrollbarOrientation::kVertical; - return cc::NinePatchThumbScrollbarLayerImpl::Create( + layer = cc::NinePatchThumbScrollbarLayerImpl::Create( &tree, id, orientation, extra->scrollbar_base_extra->is_left_side_vertical_scrollbar); + break; } case cc::mojom::LayerType::kPaintedScrollbar: { + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); auto& extra = wire.layer_extra->get_painted_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = extra->scrollbar_base_extra->is_horizontal_orientation ? cc::ScrollbarOrientation::kHorizontal : cc::ScrollbarOrientation::kVertical; - return cc::PaintedScrollbarLayerImpl::Create( + layer = cc::PaintedScrollbarLayerImpl::Create( &tree, id, orientation, extra->scrollbar_base_extra->is_left_side_vertical_scrollbar, extra->scrollbar_base_extra->is_overlay_scrollbar); + break; } case cc::mojom::LayerType::kTileDisplay: - return std::make_unique<cc::TileDisplayLayerImpl>(tree, id); + layer = std::make_unique<cc::TileDisplayLayerImpl>(tree, id); + break; case cc::mojom::LayerType::kSolidColorScrollbar: { + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); auto& extra = wire.layer_extra->get_solid_color_scrollbar_layer_extra(); cc::ScrollbarOrientation orientation = extra->scrollbar_base_extra->is_horizontal_orientation ? cc::ScrollbarOrientation::kHorizontal : cc::ScrollbarOrientation::kVertical; - return cc::SolidColorScrollbarLayerImpl::Create( + layer = cc::SolidColorScrollbarLayerImpl::Create( &tree, id, orientation, extra->thumb_thickness, extra->track_start, extra->scrollbar_base_extra->is_left_side_vertical_scrollbar); + break; } case cc::mojom::LayerType::kSurface: // The callback is triggered in the renderer side during WillDraw(), // and there is no need to do it in viz. - return cc::SurfaceLayerImpl::Create(&tree, id, base::NullCallback()); + layer = cc::SurfaceLayerImpl::Create(&tree, id, base::NullCallback()); + break; case cc::mojom::LayerType::kTexture: - return cc::TextureLayerImpl::Create(&tree, id); + layer = cc::TextureLayerImpl::Create(&tree, id); + break; case cc::mojom::LayerType::kViewTransitionContent: { + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); auto& extra = wire.layer_extra->get_view_transition_content_layer_extra(); - return cc::ViewTransitionContentLayerImpl::Create( + layer = cc::ViewTransitionContentLayerImpl::Create( &tree, id, extra->resource_id, extra->is_live_content_layer, extra->max_extents_rect); + break; } default: // TODO(rockot): Support other layer types. - return cc::SolidColorLayerImpl::Create(&tree, id); + layer = cc::SolidColorLayerImpl::Create(&tree, id); + break; } + return base::ok(); } template <typename TreeType> @@ -574,6 +598,12 @@ base::expected<void, std::string> UpdateLayer(const mojom::Layer& wire, cc::LayerImpl& layer) { + if (wire.contents_opaque && !wire.contents_opaque_for_text) { + return base::unexpected( + "Invalid contents_opaque_for_text: cannot be false if contents_opaque " + "is true."); + } + layer.SetBounds(wire.bounds); layer.SetContentsOpaque(wire.contents_opaque); layer.SetContentsOpaqueForText(wire.contents_opaque_for_text); @@ -640,33 +670,40 @@ switch (wire.type) { case cc::mojom::LayerType::kMirror: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateMirrorLayerExtra(wire.layer_extra->get_mirror_layer_extra(), static_cast<cc::MirrorLayerImpl&>(layer)); break; case cc::mojom::LayerType::kNinePatchThumbScrollbar: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateNinePatchThumbScrollbarLayerExtra( wire.layer_extra->get_nine_patch_thumb_scrollbar_layer_extra(), static_cast<cc::NinePatchThumbScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kPaintedScrollbar: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdatePaintedScrollbarLayerExtra( wire.layer_extra->get_painted_scrollbar_layer_extra(), static_cast<cc::PaintedScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kSolidColorScrollbar: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateSolidColorScrollbarLayerExtra( wire.layer_extra->get_solid_color_scrollbar_layer_extra(), static_cast<cc::SolidColorScrollbarLayerImpl&>(layer)); break; case cc::mojom::LayerType::kSurface: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateSurfaceLayerExtra(wire.layer_extra->get_surface_layer_extra(), static_cast<cc::SurfaceLayerImpl&>(layer)); break; case cc::mojom::LayerType::kTexture: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateTextureLayerExtra(wire.layer_extra->get_texture_layer_extra(), static_cast<cc::TextureLayerImpl&>(layer)); break; case cc::mojom::LayerType::kViewTransitionContent: + RETURN_IF_FALSE(wire.layer_extra, "Invalid layer_extra"); UpdateViewTransitionContentLayerExtra( wire.layer_extra->get_view_transition_content_layer_extra(), static_cast<cc::ViewTransitionContentLayerImpl&>(layer)); @@ -705,7 +742,7 @@ for (auto& wire : updates) { auto& layer = layer_map[wire->id]; if (!layer) { - layer = CreateLayer(host_impl, layers, *wire); + RETURN_IF_ERROR(CreateLayer(host_impl, layers, *wire, layer)); } // TODO(crbug.com/418022040): Make sure we support re-creating Layers with // a previously used Id. @@ -1429,10 +1466,18 @@ void LayerContextImpl::UpdateDisplayTree(mojom::LayerTreeUpdatePtr update) { CHECK(receiver_); + + const BeginFrameArgs begin_frame_args = update->begin_frame_args; auto result = DoUpdateDisplayTree(std::move(update)); if (!result.has_value()) { receiver_->ReportBadMessage(result.error()); } + + // After a tree update, either Draw or schedule animations. + DoDraw(begin_frame_args); + + // We may have resources to return after a tree update and draw. + DoReturnResources(); } base::expected<void, std::string> LayerContextImpl::DoUpdateDisplayTree( @@ -1652,28 +1697,26 @@ RETURN_IF_ERROR(DeserializeAnimationUpdates(*update, *animation_host)); host_impl_->ActivateAnimations(); + return base::ok(); +} + +void LayerContextImpl::DoDraw(const BeginFrameArgs& begin_frame_args) { if (base::FeatureList::IsEnabled(features::kTreeAnimationsInViz)) { compositor_sink_->SetLayerContextWantsBeginFrames(true); } else { if (host_impl_->CanDraw()) { - host_impl_->WillBeginImplFrame(update->begin_frame_args); + host_impl_->WillBeginImplFrame(begin_frame_args); cc::LayerTreeHostImpl::FrameData frame; const bool has_damage = true; - frame.begin_frame_ack = - BeginFrameAck(update->begin_frame_args, has_damage); - frame.origin_begin_main_frame_args = update->begin_frame_args; + frame.begin_frame_ack = BeginFrameAck(begin_frame_args, has_damage); + frame.origin_begin_main_frame_args = begin_frame_args; host_impl_->PrepareToDraw(&frame); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - host_impl_->DidFinishImplFrame(update->begin_frame_args); + host_impl_->DidFinishImplFrame(begin_frame_args); } } - - // We may have resources to return after a tree update and draw. - DoReturnResources(); - - return base::ok(); } void LayerContextImpl::UpdateDisplayTiling(mojom::TilingPtr tiling,
diff --git a/components/viz/service/layers/layer_context_impl.h b/components/viz/service/layers/layer_context_impl.h index dff049c..4f21211 100644 --- a/components/viz/service/layers/layer_context_impl.h +++ b/components/viz/service/layers/layer_context_impl.h
@@ -57,6 +57,7 @@ base::expected<void, std::string> DoUpdateDisplayTree( mojom::LayerTreeUpdatePtr update); + void DoDraw(const BeginFrameArgs& begin_frame_args); // Receive exported resources returned from the frame sink. void ReceiveReturnsFromParent(std::vector<ReturnedResource> resources);
diff --git a/components/viz/service/layers/layer_context_impl_unittest.cc b/components/viz/service/layers/layer_context_impl_unittest.cc index 2669e30..362e0da 100644 --- a/components/viz/service/layers/layer_context_impl_unittest.cc +++ b/components/viz/service/layers/layer_context_impl_unittest.cc
@@ -22,6 +22,7 @@ #include "components/viz/test/fake_compositor_frame_sink_client.h" #include "gpu/GLES2/gl2extchromium.h" #include "services/viz/public/mojom/compositing/layer_context.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rect.h" @@ -49,6 +50,12 @@ compositor_frame_sink_support_.get(), /*draw_mode_is_gpu=*/true); } + void ResetTestState() { + // Property tree node IDs and layers are reinitialized in + // CreateDefaultUpdate if first_update_ is true. + first_update_ = true; + } + mojom::LayerTreeUpdatePtr CreateDefaultUpdate() { auto update = mojom::LayerTreeUpdate::New(); @@ -102,6 +109,14 @@ } void AddFirstTimeDefaultProperties(mojom::LayerTreeUpdate* update) { + // Set internal state to defaults. + next_layer_id_ = 1; + next_transform_id_ = 0; + next_clip_id_ = 0; + next_effect_id_ = 0; + next_scroll_id_ = 0; + layer_order_.clear(); + // Root & Secondary transform nodes are always expected 1st AddTransformNode(update, cc::kInvalidPropertyNodeId); AddTransformNode(update, cc::kRootPropertyNodeId); @@ -256,7 +271,820 @@ } // namespace -TEST_F(LayerContextImplTest, EmptyScrollingContentsCullRectsByDefault) { +class LayerContextImplUpdateDisplayTreeTransformNodeTest + : public LayerContextImplTest { + protected: + cc::TransformNode* GetTransformNodeFromActiveTree(int node_id) { + if (node_id < static_cast<int>(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree() + .size())) { + return layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree_mutable() + .Node(node_id); + } + return nullptr; + } +}; + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + UpdateExistingTransformNodeProperties) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + auto update2 = CreateDefaultUpdate(); + auto node_update = mojom::TransformNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; + // Keep parent_id same as default. + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->local = gfx::Transform::MakeScale(2.0f); + node_update->origin = gfx::Point3F(1.f, 2.f, 3.f); + node_update->post_translation = gfx::Vector2dF(10.f, 20.f); + node_update->scroll_offset = gfx::PointF(5.f, 6.f); + node_update->sorting_context_id = 1; + node_update->flattens_inherited_transform = true; + node_update->will_change_transform = true; + node_update->damage_reasons_bit_mask = + (cc::DamageReasonSet{cc::DamageReason::kUntracked}).ToEnumBitmask(); + node_update->moved_by_safe_area_bottom = true; + + update2->transform_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update2)); + ASSERT_TRUE(result.has_value()); + + cc::TransformNode* node_impl = + GetTransformNodeFromActiveTree(cc::kSecondaryRootPropertyNodeId); + ASSERT_TRUE(node_impl); + EXPECT_EQ(node_impl->local, gfx::Transform::MakeScale(2.0f)); + EXPECT_EQ(node_impl->origin, gfx::Point3F(1.f, 2.f, 3.f)); + EXPECT_EQ(node_impl->post_translation, gfx::Vector2dF(10.f, 20.f)); + EXPECT_EQ(node_impl->scroll_offset(), gfx::PointF(5.f, 6.f)); + EXPECT_EQ(node_impl->sorting_context_id, 1); + EXPECT_TRUE(node_impl->flattens_inherited_transform); + EXPECT_TRUE(node_impl->will_change_transform); + EXPECT_TRUE(node_impl->damage_reasons().Has(cc::DamageReason::kUntracked)); + EXPECT_TRUE(node_impl->moved_by_safe_area_bottom); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + AddRemoveTransformNodes) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + uint32_t initial_node_count = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree() + .nodes() + .size(); + + // Add a new node. + auto update_add = CreateDefaultUpdate(); + int new_node_id = + AddTransformNode(update_add.get(), cc::kSecondaryRootPropertyNodeId); + EXPECT_EQ(update_add->num_transform_nodes, initial_node_count + 1); + + auto result_add = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add)); + ASSERT_TRUE(result_add.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree() + .nodes() + .size(), + initial_node_count + 1); + cc::TransformNode* added_node_impl = + GetTransformNodeFromActiveTree(new_node_id); + ASSERT_TRUE(added_node_impl); + EXPECT_EQ(added_node_impl->parent_id, cc::kSecondaryRootPropertyNodeId); + + // Remove the added node. + auto update_remove = CreateDefaultUpdate(); + update_remove->num_transform_nodes = initial_node_count; + // To remove, we just send fewer nodes in num_transform_nodes. + // The actual nodes in transform_nodes vector can be empty or partial. + // Here we send an empty list for simplicity. + update_remove->transform_nodes.clear(); + + auto result_remove = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove)); + ASSERT_TRUE(result_remove.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree() + .nodes() + .size(), + initial_node_count); + EXPECT_FALSE(GetTransformNodeFromActiveTree(new_node_id)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + UpdateTransformTreeProperties) { + auto update = CreateDefaultUpdate(); + auto tree_props = mojom::TransformTreeUpdate::New(); + tree_props->page_scale_factor = 1.5f; + tree_props->device_scale_factor = 2.0f; + tree_props->device_transform_scale_factor = 2.5f; + tree_props->nodes_affected_by_outer_viewport_bounds_delta = { + cc::kSecondaryRootPropertyNodeId}; + tree_props->nodes_affected_by_safe_area_bottom = { + cc::kSecondaryRootPropertyNodeId}; + update->transform_tree_update = std::move(tree_props); + + // The top level page_scale_factor overrides whatever we set + // in the transform tree, so set it to the same value. + // TODO(vmiura): See if we could just remove syncing the + // transform tree scale factors? + update->page_scale_factor = 1.5f; + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_TRUE(result.has_value()); + + const auto& transform_tree = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree(); + EXPECT_EQ(transform_tree.page_scale_factor(), 1.5f); + EXPECT_EQ(transform_tree.device_scale_factor(), 2.0f); + EXPECT_EQ(transform_tree.device_transform_scale_factor(), 2.5f); + EXPECT_THAT(transform_tree.nodes_affected_by_outer_viewport_bounds_delta(), + testing::ElementsAre(cc::kSecondaryRootPropertyNodeId)); + EXPECT_THAT(transform_tree.nodes_affected_by_safe_area_bottom(), + testing::ElementsAre(cc::kSecondaryRootPropertyNodeId)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + StickyPositionDataValid) { + auto update = CreateDefaultUpdate(); + int scroll_node_id = AddScrollNode(update.get(), cc::kRootPropertyNodeId); + + auto tree_props = mojom::TransformTreeUpdate::New(); + auto sticky_data = mojom::StickyPositionNodeData::New(); + sticky_data->scroll_ancestor = scroll_node_id; + sticky_data->is_anchored_top = true; + sticky_data->top_offset = 10.f; + tree_props->sticky_position_data.push_back(std::move(sticky_data)); + update->transform_tree_update = std::move(tree_props); + + // Add a transform node that will use this sticky data. + auto transform_node_update = mojom::TransformNode::New(); + transform_node_update->id = + AddTransformNode(update.get(), cc::kRootPropertyNodeId); + transform_node_update->parent_id = cc::kRootPropertyNodeId; + transform_node_update->sticky_position_constraint_id = 0; + update->transform_nodes.push_back(std::move(transform_node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_TRUE(result.has_value()); + + const auto& transform_tree = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree(); + ASSERT_EQ(transform_tree.sticky_position_data().size(), 1u); + EXPECT_EQ(transform_tree.sticky_position_data()[0].scroll_ancestor, + scroll_node_id); + EXPECT_TRUE( + transform_tree.sticky_position_data()[0].constraints.is_anchored_top); + EXPECT_EQ(transform_tree.sticky_position_data()[0].constraints.top_offset, + 10.f); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + StickyPositionDataInvalidScrollAncestor) { + auto update = CreateDefaultUpdate(); + auto tree_props = mojom::TransformTreeUpdate::New(); + auto sticky_data = mojom::StickyPositionNodeData::New(); + sticky_data->scroll_ancestor = 99; // Invalid scroll node ID + tree_props->sticky_position_data.push_back(std::move(sticky_data)); + update->transform_tree_update = std::move(tree_props); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid scroll ancestor ID"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + AnchorPositionDataValid) { + auto update = CreateDefaultUpdate(); + int adjustment_container_id = + AddTransformNode(update.get(), cc::kRootPropertyNodeId); + + auto tree_props = mojom::TransformTreeUpdate::New(); + auto anchor_data = mojom::AnchorPositionScrollData::New(); + anchor_data->adjustment_container_ids.push_back( + cc::ElementId(adjustment_container_id)); + anchor_data->accumulated_scroll_origin = gfx::Vector2d(5, 5); + tree_props->anchor_position_scroll_data.push_back(std::move(anchor_data)); + update->transform_tree_update = std::move(tree_props); + + // Add a transform node that will use this anchor data. + auto transform_node_update = mojom::TransformNode::New(); + transform_node_update->id = + AddTransformNode(update.get(), cc::kRootPropertyNodeId); + transform_node_update->parent_id = cc::kRootPropertyNodeId; + transform_node_update->anchor_position_scroll_data_id = 0; + update->transform_nodes.push_back(std::move(transform_node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_TRUE(result.has_value()); + + const auto& transform_tree = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->transform_tree(); + ASSERT_EQ(transform_tree.anchor_position_scroll_data().size(), 1u); + EXPECT_THAT( + transform_tree.anchor_position_scroll_data()[0].adjustment_container_ids, + testing::ElementsAre(cc::ElementId(adjustment_container_id))); + EXPECT_EQ( + transform_tree.anchor_position_scroll_data()[0].accumulated_scroll_origin, + gfx::Vector2d(5, 5)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + InvalidTransformNodeParentId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::TransformNode::New(); + node_update->id = next_transform_id_++; // New node + node_update->parent_id = 99; // Invalid parent ID + update->transform_nodes.push_back(std::move(node_update)); + update->num_transform_nodes = next_transform_id_; + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid property tree node parent_id"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeTransformNodeTest, + InvalidTransformNodeIdOnUpdate) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::TransformNode::New(); + node_update->id = 99; // Invalid node ID to update + node_update->parent_id = cc::kRootPropertyNodeId; + update->transform_nodes.push_back(std::move(node_update)); + // num_transform_nodes remains the same as default. + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid property tree node ID"); +} + +class LayerContextImplUpdateDisplayTreeClipNodeTest + : public LayerContextImplTest { + protected: + cc::ClipNode* GetClipNodeFromActiveTree(int node_id) { + if (node_id < static_cast<int>(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->clip_tree() + .size())) { + return layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->clip_tree_mutable() + .Node(node_id); + } + return nullptr; + } +}; + +TEST_F(LayerContextImplUpdateDisplayTreeClipNodeTest, + UpdateExistingClipNodeProperties) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + auto update2 = CreateDefaultUpdate(); + auto node_update = mojom::ClipNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; + // Keep parent_id same as default. + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->clip = gfx::RectF(10.f, 20.f, 30.f, 40.f); + // Use a valid existing transform node ID. + node_update->transform_id = cc::kSecondaryRootPropertyNodeId; + update2->clip_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update2)); + ASSERT_TRUE(result.has_value()); + + cc::ClipNode* node_impl = + GetClipNodeFromActiveTree(cc::kSecondaryRootPropertyNodeId); + ASSERT_TRUE(node_impl); + EXPECT_EQ(node_impl->clip, gfx::RectF(10.f, 20.f, 30.f, 40.f)); + EXPECT_EQ(node_impl->transform_id, cc::kSecondaryRootPropertyNodeId); +} + +TEST_F(LayerContextImplUpdateDisplayTreeClipNodeTest, AddRemoveClipNodes) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + uint32_t initial_node_count = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->clip_tree() + .nodes() + .size(); + + // Add a new node. + auto update_add = CreateDefaultUpdate(); + int new_node_id = + AddClipNode(update_add.get(), cc::kSecondaryRootPropertyNodeId); + EXPECT_EQ(update_add->num_clip_nodes, initial_node_count + 1); + + auto result_add = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add)); + ASSERT_TRUE(result_add.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->clip_tree() + .nodes() + .size(), + initial_node_count + 1); + cc::ClipNode* added_node_impl = GetClipNodeFromActiveTree(new_node_id); + ASSERT_TRUE(added_node_impl); + EXPECT_EQ(added_node_impl->parent_id, cc::kSecondaryRootPropertyNodeId); + + // Remove the added node. + auto update_remove = CreateDefaultUpdate(); + update_remove->num_clip_nodes = initial_node_count; + update_remove->clip_nodes.clear(); + + auto result_remove = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove)); + ASSERT_TRUE(result_remove.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->clip_tree() + .nodes() + .size(), + initial_node_count); + EXPECT_FALSE(GetClipNodeFromActiveTree(new_node_id)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeClipNodeTest, InvalidClipNodeParentId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::ClipNode::New(); + node_update->id = next_clip_id_++; // New node + node_update->parent_id = 99; // Invalid parent ID + node_update->transform_id = cc::kRootPropertyNodeId; + update->clip_nodes.push_back(std::move(node_update)); + update->num_clip_nodes = next_clip_id_; + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid property tree node parent_id"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeClipNodeTest, + InvalidClipNodeTransformId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::ClipNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = 99; // Invalid transform ID + update->clip_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid transform_id for clip node"); +} + +class LayerContextImplUpdateDisplayTreeEffectNodeTest + : public LayerContextImplTest { + protected: + cc::EffectNode* GetEffectNodeFromActiveTree(int node_id) { + if (node_id < static_cast<int>(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree() + .size())) { + return layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree_mutable() + .Node(node_id); + } + return nullptr; + } +}; + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + UpdateExistingEffectNodeProperties) { + // Apply a default valid update, with a new effect node. + auto update1 = CreateDefaultUpdate(); + int effect_node_id = + AddEffectNode(update1.get(), cc::kSecondaryRootPropertyNodeId); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + auto update2 = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = effect_node_id; + // Keep parent_id same as default. + node_update->parent_id = cc::kSecondaryRootPropertyNodeId; + node_update->opacity = 0.5f; + node_update->filters.Append(cc::FilterOperation::CreateBlurFilter(2.f)); + node_update->backdrop_filters.Append( + cc::FilterOperation::CreateGrayscaleFilter(0.8f)); + node_update->blend_mode = static_cast<uint32_t>(SkBlendMode::kMultiply); + node_update->render_surface_reason = cc::RenderSurfaceReason::kTest; + + // TODO(vmiura): If we have a render_surface_reason, without a valid + // element_id, we can trigger crashes during property tree update. Fix that. + node_update->element_id = cc::ElementId(42); + + node_update->cache_render_surface = true; + + const auto view_transition_token = blink::ViewTransitionToken(); + node_update->view_transition_element_resource_id = + ViewTransitionElementResourceId(view_transition_token, 1, false); + // Use valid existing transform and clip node IDs. + node_update->transform_id = cc::kSecondaryRootPropertyNodeId; + node_update->clip_id = cc::kSecondaryRootPropertyNodeId; + node_update->target_id = cc::kRootPropertyNodeId; + + update2->effect_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update2)); + ASSERT_TRUE(result.has_value()); + + cc::EffectNode* node_impl = GetEffectNodeFromActiveTree(effect_node_id); + ASSERT_TRUE(node_impl); + EXPECT_EQ(node_impl->opacity, 0.5f); + EXPECT_EQ(node_impl->filters.size(), 1u); + EXPECT_EQ(node_impl->filters.at(0).type(), + cc::FilterOperation::FilterType::BLUR); + EXPECT_EQ(node_impl->backdrop_filters.size(), 1u); + EXPECT_EQ(node_impl->backdrop_filters.at(0).type(), + cc::FilterOperation::FilterType::GRAYSCALE); + EXPECT_EQ(node_impl->blend_mode, SkBlendMode::kMultiply); + EXPECT_EQ(node_impl->render_surface_reason, cc::RenderSurfaceReason::kTest); + EXPECT_TRUE(node_impl->cache_render_surface); + EXPECT_EQ(node_impl->view_transition_element_resource_id, + ViewTransitionElementResourceId(view_transition_token, 1, false)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, AddRemoveEffectNodes) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + uint32_t initial_node_count = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree() + .nodes() + .size(); + + // Add a new node. + auto update_add = CreateDefaultUpdate(); + int new_node_id = + AddEffectNode(update_add.get(), cc::kSecondaryRootPropertyNodeId); + EXPECT_EQ(update_add->num_effect_nodes, initial_node_count + 1); + + auto result_add = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add)); + ASSERT_TRUE(result_add.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree() + .nodes() + .size(), + initial_node_count + 1); + cc::EffectNode* added_node_impl = GetEffectNodeFromActiveTree(new_node_id); + ASSERT_TRUE(added_node_impl); + EXPECT_EQ(added_node_impl->parent_id, cc::kSecondaryRootPropertyNodeId); + + // Remove the added node. + auto update_remove = CreateDefaultUpdate(); + update_remove->num_effect_nodes = initial_node_count; + update_remove->effect_nodes.clear(); + + auto result_remove = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove)); + ASSERT_TRUE(result_remove.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree() + .nodes() + .size(), + initial_node_count); + EXPECT_FALSE(GetEffectNodeFromActiveTree(new_node_id)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + AddRemoveCopyOutputRequests) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + // Add a copy request. + auto update_add_request = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = cc::kSecondaryRootPropertyNodeId; + node_update->clip_id = cc::kSecondaryRootPropertyNodeId; + node_update->target_id = cc::kRootPropertyNodeId; + node_update->copy_output_requests.push_back( + CopyOutputRequest::CreateStubForTesting()); + update_add_request->effect_nodes.push_back(std::move(node_update)); + + auto result_add = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add_request)); + ASSERT_TRUE(result_add.has_value()); + auto copy_requests = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree_mutable() + .TakeCopyRequests(); + EXPECT_EQ(copy_requests.count(cc::kSecondaryRootPropertyNodeId), 1u); + + // Remove the copy request (by not sending it). + auto update_remove_request = CreateDefaultUpdate(); + auto node_update_no_request = mojom::EffectNode::New(); + node_update_no_request->id = cc::kSecondaryRootPropertyNodeId; + node_update_no_request->parent_id = cc::kRootPropertyNodeId; + node_update_no_request->transform_id = cc::kSecondaryRootPropertyNodeId; + node_update_no_request->clip_id = cc::kSecondaryRootPropertyNodeId; + node_update_no_request->target_id = cc::kRootPropertyNodeId; + update_remove_request->effect_nodes.push_back( + std::move(node_update_no_request)); + + auto result_remove = layer_context_impl_->DoUpdateDisplayTree( + std::move(update_remove_request)); + ASSERT_TRUE(result_remove.has_value()); + auto copy_requests_after_remove = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->effect_tree_mutable() + .TakeCopyRequests(); + EXPECT_EQ(copy_requests_after_remove.count(cc::kSecondaryRootPropertyNodeId), + 0u); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + InvalidEffectNodeParentId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = next_effect_id_++; // New node + node_update->parent_id = 99; // Invalid parent ID + node_update->transform_id = cc::kRootPropertyNodeId; + node_update->clip_id = cc::kRootPropertyNodeId; + node_update->target_id = cc::kRootPropertyNodeId; + update->effect_nodes.push_back(std::move(node_update)); + update->num_effect_nodes = next_effect_id_; + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid property tree node parent_id"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + InvalidEffectNodeTransformId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = 99; // Invalid transform ID + node_update->clip_id = cc::kRootPropertyNodeId; + node_update->target_id = cc::kRootPropertyNodeId; + update->effect_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid transform_id for effect node"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + InvalidEffectNodeClipId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = cc::kRootPropertyNodeId; + node_update->clip_id = 99; // Invalid clip ID + node_update->target_id = cc::kRootPropertyNodeId; + update->effect_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid clip_id for effect node"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, + InvalidEffectNodeTargetId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = cc::kRootPropertyNodeId; + node_update->clip_id = cc::kRootPropertyNodeId; + node_update->target_id = 99; // Invalid target ID + update->effect_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid target_id for effect node"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest, InvalidBlendMode) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::EffectNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = cc::kRootPropertyNodeId; + node_update->clip_id = cc::kRootPropertyNodeId; + node_update->target_id = cc::kRootPropertyNodeId; + node_update->blend_mode = 999; // Invalid blend mode + update->effect_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid blend_mode for effect node"); +} + +class LayerContextImplUpdateDisplayTreeScrollNodeTest + : public LayerContextImplTest { + protected: + cc::ScrollNode* GetScrollNodeFromActiveTree(int node_id) { + if (node_id < static_cast<int>(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree() + .size())) { + return layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree_mutable() + .Node(node_id); + } + return nullptr; + } +}; + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, + UpdateExistingScrollNodeProperties) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + + auto update2 = CreateDefaultUpdate(); + auto node_update = mojom::ScrollNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; + // Keep parent_id same as default. + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->container_bounds = gfx::Size(50, 60); + node_update->bounds = gfx::Size(70, 80); + node_update->user_scrollable_horizontal = true; + node_update->user_scrollable_vertical = true; + node_update->element_id = cc::ElementId(123); + // Use a valid existing transform node ID. + node_update->transform_id = cc::kSecondaryRootPropertyNodeId; + update2->scroll_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update2)); + ASSERT_TRUE(result.has_value()); + + cc::ScrollNode* node_impl = + GetScrollNodeFromActiveTree(cc::kSecondaryRootPropertyNodeId); + ASSERT_TRUE(node_impl); + EXPECT_EQ(node_impl->container_bounds, gfx::Size(50, 60)); + EXPECT_EQ(node_impl->bounds, gfx::Size(70, 80)); + EXPECT_TRUE(node_impl->user_scrollable_horizontal); + EXPECT_TRUE(node_impl->user_scrollable_vertical); + EXPECT_EQ(node_impl->element_id, cc::ElementId(123)); + EXPECT_EQ(node_impl->transform_id, cc::kSecondaryRootPropertyNodeId); +} + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, AddRemoveScrollNodes) { + // Apply a default valid update first. + auto update1 = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update1)).has_value()); + uint32_t initial_node_count = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree() + .nodes() + .size(); + + // Add a new node. + auto update_add = CreateDefaultUpdate(); + int new_node_id = + AddScrollNode(update_add.get(), cc::kSecondaryRootPropertyNodeId); + EXPECT_EQ(update_add->num_scroll_nodes, initial_node_count + 1); + + auto result_add = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_add)); + ASSERT_TRUE(result_add.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree() + .nodes() + .size(), + initial_node_count + 1); + cc::ScrollNode* added_node_impl = GetScrollNodeFromActiveTree(new_node_id); + ASSERT_TRUE(added_node_impl); + EXPECT_EQ(added_node_impl->parent_id, cc::kSecondaryRootPropertyNodeId); + + // Remove the added node. + auto update_remove = CreateDefaultUpdate(); + update_remove->num_scroll_nodes = initial_node_count; + update_remove->scroll_nodes.clear(); + + auto result_remove = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove)); + ASSERT_TRUE(result_remove.has_value()); + EXPECT_EQ(layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree() + .nodes() + .size(), + initial_node_count); + EXPECT_FALSE(GetScrollNodeFromActiveTree(new_node_id)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, + InvalidScrollNodeParentId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::ScrollNode::New(); + node_update->id = next_scroll_id_++; // New node + node_update->parent_id = 99; // Invalid parent ID + node_update->transform_id = cc::kRootPropertyNodeId; + update->scroll_nodes.push_back(std::move(node_update)); + update->num_scroll_nodes = next_scroll_id_; + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid property tree node parent_id"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, + InvalidScrollNodeTransformId) { + auto update = CreateDefaultUpdate(); + auto node_update = mojom::ScrollNode::New(); + node_update->id = cc::kSecondaryRootPropertyNodeId; // Existing node + node_update->parent_id = cc::kRootPropertyNodeId; + node_update->transform_id = 99; // Invalid transform ID + update->scroll_nodes.push_back(std::move(node_update)); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid transform_id for scroll node"); +} + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, + UpdateScrollTreeProperties) { + auto update = CreateDefaultUpdate(); + auto tree_props = mojom::ScrollTreeUpdate::New(); + cc::ElementId element_id(123); + tree_props->synced_scroll_offsets[element_id] = + base::MakeRefCounted<cc::SyncedScrollOffset>(); + tree_props->synced_scroll_offsets[element_id]->SetCurrent( + gfx::PointF(10.f, 20.f)); + tree_props->scrolling_contents_cull_rects[element_id] = + gfx::Rect(5, 5, 15, 15); + update->scroll_tree_update = std::move(tree_props); + + auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); + ASSERT_TRUE(result.has_value()); + + const auto& scroll_tree = layer_context_impl_->host_impl() + ->active_tree() + ->property_trees() + ->scroll_tree(); + EXPECT_EQ(scroll_tree.synced_scroll_offset_map() + .at(element_id) + ->Current( + /*is_active_tree=*/true), + gfx::PointF(10.f, 20.f)); + EXPECT_EQ(scroll_tree.scrolling_contents_cull_rects().at(element_id), + gfx::Rect(5, 5, 15, 15)); +} + +TEST_F(LayerContextImplUpdateDisplayTreeScrollNodeTest, + EmptyScrollingContentsCullRectsByDefault) { EXPECT_TRUE(layer_context_impl_->host_impl() ->active_tree() ->property_trees() @@ -275,32 +1103,6 @@ .empty()); } -TEST_F(LayerContextImplTest, ScrollingContentsCullRectsAreSynchronized) { - constexpr cc::ElementId kElementId = cc::ElementId(42); - constexpr gfx::Rect kCullRect = gfx::Rect{100, 100}; - base::flat_map<cc::ElementId, gfx::Rect> scrolling_contents_cull_rects; - scrolling_contents_cull_rects[kElementId] = kCullRect; - - auto scroll_tree_update = mojom::ScrollTreeUpdate::New(); - scroll_tree_update->scrolling_contents_cull_rects = - scrolling_contents_cull_rects; - - auto update = CreateDefaultUpdate(); - update->scroll_tree_update = std::move(scroll_tree_update); - - auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update)); - EXPECT_TRUE(result.has_value()); - - auto synchronized_scrolling_contents_cull_rects = - layer_context_impl_->host_impl() - ->active_tree() - ->property_trees() - ->scroll_tree() - .scrolling_contents_cull_rects(); - EXPECT_EQ(scrolling_contents_cull_rects, - synchronized_scrolling_contents_cull_rects); -} - class LayerContextImplUpdateDisplayTreePageScaleFactorTest : public LayerContextImplTest, public ::testing::WithParamInterface<std::tuple<float, bool>> {}; @@ -815,7 +1617,8 @@ const gfx::Size& bounds = gfx::Size(10, 10), int transform_idx = cc::kSecondaryRootPropertyNodeId, int clip_idx = cc::kRootPropertyNodeId, - int effect_idx = cc::kSecondaryRootPropertyNodeId) { + int effect_idx = cc::kSecondaryRootPropertyNodeId, + int scroll_idx = cc::kSecondaryRootPropertyNodeId) { auto layer = mojom::Layer::New(); layer->id = id; layer->type = type; @@ -823,6 +1626,7 @@ layer->transform_tree_index = transform_idx; layer->clip_tree_index = clip_idx; layer->effect_tree_index = effect_idx; + layer->scroll_tree_index = scroll_idx; return layer; } }; @@ -1047,4 +1851,443 @@ VerifyLayerOrder({1, kLayerId3, kLayerId1}); } +TEST_F(LayerContextImplLayerLifecycleTest, CreateLayersOfAllTypes) { + auto update = CreateDefaultUpdate(); + + // Test a subset of layer types that have distinct LayerImpl classes or + // specific handling in CreateLayer. + const std::vector<cc::mojom::LayerType> types_to_test = { + cc::mojom::LayerType::kLayer, + cc::mojom::LayerType::kMirror, + cc::mojom::LayerType::kNinePatchThumbScrollbar, + cc::mojom::LayerType::kPaintedScrollbar, + cc::mojom::LayerType::kTileDisplay, + cc::mojom::LayerType::kSolidColorScrollbar, + cc::mojom::LayerType::kSurface, + cc::mojom::LayerType::kTexture, + cc::mojom::LayerType::kViewTransitionContent, + // Add other relevant types here. + }; + + std::vector<int> layer_ids; + for (cc::mojom::LayerType type : types_to_test) { + int layer_id = next_layer_id_++; + layer_ids.push_back(layer_id); + auto layer = CreateManualLayer(layer_id, type); + switch (type) { + case cc::mojom::LayerType::kMirror: { + auto extra = mojom::MirrorLayerExtra::New(); + // Mirroring the root layer (ID 1) by default for simplicity. + extra->mirrored_layer_id = 1; + layer->layer_extra = + mojom::LayerExtra::NewMirrorLayerExtra(std::move(extra)); + break; + } + case cc::mojom::LayerType::kNinePatchThumbScrollbar: { + auto extra = mojom::NinePatchThumbScrollbarLayerExtra::New(); + extra->scrollbar_base_extra = mojom::ScrollbarLayerBaseExtra::New(); + layer->layer_extra = + mojom::LayerExtra::NewNinePatchThumbScrollbarLayerExtra( + std::move(extra)); + break; + } + case cc::mojom::LayerType::kPaintedScrollbar: { + auto extra = mojom::PaintedScrollbarLayerExtra::New(); + extra->scrollbar_base_extra = mojom::ScrollbarLayerBaseExtra::New(); + layer->layer_extra = + mojom::LayerExtra::NewPaintedScrollbarLayerExtra(std::move(extra)); + break; + } + case cc::mojom::LayerType::kSolidColorScrollbar: { + auto extra = mojom::SolidColorScrollbarLayerExtra::New(); + extra->scrollbar_base_extra = mojom::ScrollbarLayerBaseExtra::New(); + layer->layer_extra = + mojom::LayerExtra::NewSolidColorScrollbarLayerExtra( + std::move(extra)); + break; + } + case cc::mojom::LayerType::kSurface: { + auto extra = mojom::SurfaceLayerExtra::New(); + extra->surface_range = SurfaceRange( + std::nullopt, + SurfaceId(kDefaultFrameSinkId, default_local_surface_id_)); + extra->deadline_in_frames = 0u; + layer->layer_extra = + mojom::LayerExtra::NewSurfaceLayerExtra(std::move(extra)); + break; + } + case cc::mojom::LayerType::kTexture: { + auto extra = mojom::TextureLayerExtra::New(); + // TextureLayer can have an optional TransferableResource. + // For this basic creation test, leaving it null is fine. + layer->layer_extra = + mojom::LayerExtra::NewTextureLayerExtra(std::move(extra)); + break; + } + case cc::mojom::LayerType::kViewTransitionContent: { + auto extra = mojom::ViewTransitionContentLayerExtra::New(); + extra->resource_id = ViewTransitionElementResourceId( + blink::ViewTransitionToken(), 1, false); + layer->layer_extra = + mojom::LayerExtra::NewViewTransitionContentLayerExtra( + std::move(extra)); + break; + } + default: + // No layer_extra needed for other types in this test. + break; + } + update->layers.push_back(std::move(layer)); + layer_order_.push_back(layer_id); + } + update->layer_order = layer_order_; + + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + + for (size_t i = 0; i < types_to_test.size(); ++i) { + VerifyLayerExists(layer_ids[i], true); + cc::LayerImpl* layer = GetLayerFromActiveTree(layer_ids[i]); + ASSERT_NE(nullptr, layer); + EXPECT_EQ(layer->GetLayerType(), types_to_test[i]); + } +} + +TEST_F(LayerContextImplLayerLifecycleTest, UpdateMultipleLayerProperties) { + auto update = CreateDefaultUpdate(); + int layer_id1 = AddDefaultLayerToUpdate(update.get()); + int layer_id2 = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + + auto update_props = CreateDefaultUpdate(); + auto layer1_props = CreateManualLayer(layer_id1); + layer1_props->bounds = gfx::Size(50, 50); + layer1_props->contents_opaque = true; + layer1_props->contents_opaque_for_text = true; + layer1_props->background_color = SkColors::kRed; + layer1_props->transform_tree_index = cc::kRootPropertyNodeId; + update_props->layers.push_back(std::move(layer1_props)); + + auto layer2_props = CreateManualLayer(layer_id2); + layer2_props->is_drawable = false; + layer2_props->clip_tree_index = cc::kSecondaryRootPropertyNodeId; + layer2_props->effect_tree_index = cc::kRootPropertyNodeId; + update_props->layers.push_back(std::move(layer2_props)); + + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_props)) + .has_value()); + + cc::LayerImpl* layer1_impl = GetLayerFromActiveTree(layer_id1); + ASSERT_NE(nullptr, layer1_impl); + EXPECT_EQ(layer1_impl->bounds(), gfx::Size(50, 50)); + EXPECT_TRUE(layer1_impl->contents_opaque()); + EXPECT_TRUE(layer1_impl->contents_opaque_for_text()); + EXPECT_EQ(layer1_impl->background_color(), SkColors::kRed); + EXPECT_EQ(layer1_impl->transform_tree_index(), cc::kRootPropertyNodeId); + + cc::LayerImpl* layer2_impl = GetLayerFromActiveTree(layer_id2); + ASSERT_NE(nullptr, layer2_impl); + EXPECT_FALSE(layer2_impl->draws_content()); + EXPECT_EQ(layer2_impl->clip_tree_index(), cc::kSecondaryRootPropertyNodeId); + EXPECT_EQ(layer2_impl->effect_tree_index(), cc::kRootPropertyNodeId); +} + +TEST_F(LayerContextImplLayerLifecycleTest, ReorderLayers) { + auto update = CreateDefaultUpdate(); + int layer_id1 = AddDefaultLayerToUpdate(update.get()); + int layer_id2 = AddDefaultLayerToUpdate(update.get()); + int layer_id3 = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + VerifyLayerOrder({1, layer_id1, layer_id2, layer_id3}); + + // Move layer_id1 to the end. + auto update_reorder1 = CreateDefaultUpdate(); + layer_order_ = {1, layer_id2, layer_id3, layer_id1}; + update_reorder1->layer_order = layer_order_; + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_reorder1)) + .has_value()); + VerifyLayerOrder({1, layer_id2, layer_id3, layer_id1}); + + // Move layer_id3 to the beginning (after root). + auto update_reorder2 = CreateDefaultUpdate(); + layer_order_ = {1, layer_id3, layer_id2, layer_id1}; + update_reorder2->layer_order = layer_order_; + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_reorder2)) + .has_value()); + VerifyLayerOrder({1, layer_id3, layer_id2, layer_id1}); +} + +TEST_F(LayerContextImplLayerLifecycleTest, RemoveLayers) { + auto update = CreateDefaultUpdate(); + int layer_id1 = AddDefaultLayerToUpdate(update.get()); + int layer_id2 = AddDefaultLayerToUpdate(update.get()); + int layer_id3 = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + VerifyLayerOrder({1, layer_id1, layer_id2, layer_id3}); + + // Remove from the middle. + auto update_remove1 = CreateDefaultUpdate(); + RemoveLayerInUpdate(update_remove1.get(), layer_id2); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove1)) + .has_value()); + VerifyLayerExists(layer_id2, false); + VerifyLayerOrder({1, layer_id1, layer_id3}); + + // Remove from the beginning (after root). + auto update_remove2 = CreateDefaultUpdate(); + RemoveLayerInUpdate(update_remove2.get(), layer_id1); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove2)) + .has_value()); + VerifyLayerExists(layer_id1, false); + VerifyLayerOrder({1, layer_id3}); + + // Remove from the end. + auto update_remove3 = CreateDefaultUpdate(); + RemoveLayerInUpdate(update_remove3.get(), layer_id3); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update_remove3)) + .has_value()); + VerifyLayerExists(layer_id3, false); + VerifyLayerOrder({1}); +} + +TEST_F(LayerContextImplLayerLifecycleTest, LayerPropertyChangedFlags) { + auto update = CreateDefaultUpdate(); + int layer_id = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + + // Test layer_property_changed_not_from_property_trees + auto update_flag1 = CreateDefaultUpdate(); + auto layer_props1 = CreateManualLayer(layer_id); + layer_props1->layer_property_changed_not_from_property_trees = true; + update_flag1->layers.push_back(std::move(layer_props1)); + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_flag1)) + .has_value()); + cc::LayerImpl* layer_impl_flag1 = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_flag1); + EXPECT_TRUE(layer_impl_flag1->LayerPropertyChangedNotFromPropertyTrees()); + + // Test layer_property_changed_from_property_trees + auto update_flag2 = CreateDefaultUpdate(); + auto layer_props2 = CreateManualLayer(layer_id); + layer_props2->layer_property_changed_from_property_trees = true; + update_flag2->layers.push_back(std::move(layer_props2)); + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_flag2)) + .has_value()); + // This flag is reset after processing, so we can't directly verify it here + // without more complex state tracking or inspecting internal LayerImpl + // states that are affected by it. For now, we ensure the update passes. + // A more thorough test would involve checking if draw properties were + // actually updated. + ASSERT_NE(nullptr, GetLayerFromActiveTree(layer_id)); +} + +TEST_F(LayerContextImplLayerLifecycleTest, RareProperties) { + auto update = CreateDefaultUpdate(); + int layer_id = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + + const auto kFirstId = RegionCaptureCropId::CreateRandom(); + const auto kSecondId = RegionCaptureCropId::CreateRandom(); + const RegionCaptureBounds kLayerBounds{ + {{kFirstId, gfx::Rect{0, 0, 250, 250}}, {kSecondId, gfx::Rect{}}}}; + + auto update_rare = CreateDefaultUpdate(); + auto layer_props = CreateManualLayer(layer_id); + layer_props->rare_properties = mojom::RareProperties::New(); + layer_props->rare_properties->filter_quality = + cc::PaintFlags::FilterQuality::kMedium; + layer_props->rare_properties->dynamic_range_limit = + cc::PaintFlags::DynamicRangeLimitMixture(1.f, 0.5f); + layer_props->rare_properties->capture_bounds = kLayerBounds; + update_rare->layers.push_back(std::move(layer_props)); + + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_rare)) + .has_value()); + + cc::LayerImpl* layer_impl_rare = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_rare); + EXPECT_EQ(layer_impl_rare->GetFilterQuality(), + cc::PaintFlags::FilterQuality::kMedium); + EXPECT_EQ(layer_impl_rare->GetDynamicRangeLimit(), + cc::PaintFlags::DynamicRangeLimitMixture(1.f, 0.5f)); + ASSERT_TRUE(layer_impl_rare->capture_bounds()); + EXPECT_EQ(*layer_impl_rare->capture_bounds(), kLayerBounds); +} + +TEST_F(LayerContextImplLayerLifecycleTest, ContentsOpaqueFlags) { + ResetTestState(); + auto update = CreateDefaultUpdate(); + int layer_id = AddDefaultLayerToUpdate(update.get()); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(update)).has_value()); + + // Valid: contents_opaque = true, contents_opaque_for_text = true + auto update_valid1 = CreateDefaultUpdate(); + auto layer_props_valid1 = CreateManualLayer(layer_id); + layer_props_valid1->contents_opaque = true; + layer_props_valid1->contents_opaque_for_text = true; + update_valid1->layers.push_back(std::move(layer_props_valid1)); + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_valid1)) + .has_value()); + cc::LayerImpl* layer_impl_valid1 = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_valid1); + EXPECT_TRUE(layer_impl_valid1->contents_opaque()); + EXPECT_TRUE(layer_impl_valid1->contents_opaque_for_text()); + + // Invalid: contents_opaque = true, contents_opaque_for_text = false + auto update_invalid = CreateDefaultUpdate(); + auto layer_props_invalid = CreateManualLayer(layer_id); + layer_props_invalid->contents_opaque = true; + layer_props_invalid->contents_opaque_for_text = false; + update_invalid->layers.push_back(std::move(layer_props_invalid)); + auto result_invalid = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_invalid)); + ASSERT_FALSE(result_invalid.has_value()); + EXPECT_EQ(result_invalid.error(), + "Invalid contents_opaque_for_text: cannot be false if " + "contents_opaque is true."); + // Verify properties remain from the last valid update + cc::LayerImpl* layer_impl_invalid = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_invalid); + EXPECT_TRUE(layer_impl_invalid->contents_opaque()); + EXPECT_TRUE(layer_impl_invalid->contents_opaque_for_text()); + + // Valid: contents_opaque = false, contents_opaque_for_text = true + auto update_valid2 = CreateDefaultUpdate(); + auto layer_props_valid2 = CreateManualLayer(layer_id); + layer_props_valid2->contents_opaque = false; + layer_props_valid2->contents_opaque_for_text = true; + update_valid2->layers.push_back(std::move(layer_props_valid2)); + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_valid2)) + .has_value()); + cc::LayerImpl* layer_impl_valid2 = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_valid2); + EXPECT_FALSE(layer_impl_valid2->contents_opaque()); + EXPECT_TRUE(layer_impl_valid2->contents_opaque_for_text()); + + // Valid: contents_opaque = false, contents_opaque_for_text = false + auto update_valid3 = CreateDefaultUpdate(); + auto layer_props_valid3 = CreateManualLayer(layer_id); + layer_props_valid3->contents_opaque = false; + layer_props_valid3->contents_opaque_for_text = false; + update_valid3->layers.push_back(std::move(layer_props_valid3)); + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(update_valid3)) + .has_value()); + cc::LayerImpl* layer_impl_valid3 = GetLayerFromActiveTree(layer_id); + ASSERT_NE(nullptr, layer_impl_valid3); + EXPECT_FALSE(layer_impl_valid3->contents_opaque()); + EXPECT_FALSE(layer_impl_valid3->contents_opaque_for_text()); +} + +TEST_F(LayerContextImplLayerLifecycleTest, MissingLayerExtra) { + const std::vector<cc::mojom::LayerType> types_requiring_extra = { + cc::mojom::LayerType::kMirror, + cc::mojom::LayerType::kNinePatchThumbScrollbar, + cc::mojom::LayerType::kPaintedScrollbar, + cc::mojom::LayerType::kSolidColorScrollbar, + cc::mojom::LayerType::kSurface, + cc::mojom::LayerType::kTexture, + cc::mojom::LayerType::kViewTransitionContent, + }; + + for (cc::mojom::LayerType type : types_requiring_extra) { + SCOPED_TRACE(testing::Message() + << "Testing LayerType: " << static_cast<int>(type)); + ResetTestState(); + // Create a valid root layer first. + auto initial_update = CreateDefaultUpdate(); + EXPECT_TRUE( + layer_context_impl_->DoUpdateDisplayTree(std::move(initial_update)) + .has_value()); + + auto update_missing_extra = CreateDefaultUpdate(); + int layer_id = next_layer_id_++; + // Create the layer manually without setting layer_extra. + auto layer = CreateManualLayer(layer_id, type); + // Ensure layer_extra is indeed null. + layer->layer_extra = nullptr; + + update_missing_extra->layers.push_back(std::move(layer)); + update_missing_extra->layer_order = layer_order_; + update_missing_extra->layer_order->push_back(layer_id); + + auto result = layer_context_impl_->DoUpdateDisplayTree( + std::move(update_missing_extra)); + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), "Invalid layer_extra"); + } +} + +TEST_F(LayerContextImplLayerLifecycleTest, + UpdateExistingLayerWithInvalidPropertyTreeIndicesFails) { + constexpr int kLayerId = 2; + constexpr int kValidIndex = 1; // Assumes root (0) and secondary_root (1) + constexpr int kInvalidIndex = 99; // An index that will be out of bounds. + + // Setup: Create a layer with valid indices and small property trees. + auto setup_update = CreateDefaultUpdate(); + + AddDefaultLayerToUpdate(setup_update.get(), cc::mojom::LayerType::kLayer, + kLayerId); + // Set initial valid indices for the layer. + setup_update->layers.back()->transform_tree_index = kValidIndex; + setup_update->layers.back()->clip_tree_index = kValidIndex; + setup_update->layers.back()->effect_tree_index = kValidIndex; + setup_update->layers.back()->scroll_tree_index = kValidIndex; + + EXPECT_TRUE(layer_context_impl_->DoUpdateDisplayTree(std::move(setup_update)) + .has_value()); + VerifyLayerExists(kLayerId, true); + + // Test Case 1: Update with invalid transform_tree_index. + auto update_invalid_transform = CreateDefaultUpdate(); + update_invalid_transform->layers.push_back(CreateManualLayer( + kLayerId, cc::mojom::LayerType::kLayer, gfx::Size(10, 10), kInvalidIndex, + kValidIndex, kValidIndex, kValidIndex)); + auto result_transform = layer_context_impl_->DoUpdateDisplayTree( + std::move(update_invalid_transform)); + ASSERT_FALSE(result_transform.has_value()); + EXPECT_THAT(result_transform.error(), + testing::StartsWith("Invalid transform tree ID")); + + // Test Case 2: Update with invalid clip_tree_index. + auto update_invalid_clip = CreateDefaultUpdate(); + update_invalid_clip->layers.push_back(CreateManualLayer( + kLayerId, cc::mojom::LayerType::kLayer, gfx::Size(10, 10), kValidIndex, + kInvalidIndex, kValidIndex, kValidIndex)); + auto result_clip = + layer_context_impl_->DoUpdateDisplayTree(std::move(update_invalid_clip)); + ASSERT_FALSE(result_clip.has_value()); + EXPECT_THAT(result_clip.error(), testing::StartsWith("Invalid clip tree ID")); + + // Test Case 3: Update with invalid effect_tree_index (similar for scroll). + auto update_invalid_effect = CreateDefaultUpdate(); + update_invalid_effect->layers.push_back(CreateManualLayer( + kLayerId, cc::mojom::LayerType::kLayer, gfx::Size(10, 10), kValidIndex, + kValidIndex, kInvalidIndex, kValidIndex)); + auto result_effect = layer_context_impl_->DoUpdateDisplayTree( + std::move(update_invalid_effect)); + ASSERT_FALSE(result_effect.has_value()); + EXPECT_THAT(result_effect.error(), + testing::StartsWith("Invalid effect tree ID")); + + // Verify layer properties remain from the last successful update. + cc::LayerImpl* layer_impl_after_invalid = GetLayerFromActiveTree(kLayerId); + ASSERT_NE(nullptr, layer_impl_after_invalid); + EXPECT_EQ(layer_impl_after_invalid->transform_tree_index(), kValidIndex); + EXPECT_EQ(layer_impl_after_invalid->clip_tree_index(), kValidIndex); + EXPECT_EQ(layer_impl_after_invalid->effect_tree_index(), kValidIndex); + EXPECT_EQ(layer_impl_after_invalid->scroll_tree_index(), kValidIndex); +} + } // namespace viz
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc index d79bdcff..379e069 100644 --- a/components/viz/service/main/viz_main_impl.cc +++ b/components/viz/service/main/viz_main_impl.cc
@@ -158,6 +158,10 @@ if (dependencies_.ukm_recorder) ukm::DelegatingUkmRecorder::Get()->RemoveDelegate( dependencies_.ukm_recorder.get()); + + if (!gpu_init_->gpu_info().in_process_gpu) { + GpuLogMessageManager::GetInstance()->ShutdownLogging(); + } } void VizMainImpl::Bind(mojo::PendingReceiver<mojom::VizMain> receiver) { @@ -167,6 +171,7 @@ void VizMainImpl::CreateGpuService( mojo::PendingReceiver<mojom::GpuService> pending_receiver, mojo::PendingRemote<mojom::GpuHost> pending_gpu_host, + mojo::PendingRemote<mojom::GpuLogging> pending_gpu_logging, mojo::PendingRemote< discardable_memory::mojom::DiscardableSharedMemoryManager> discardable_memory_manager, @@ -182,7 +187,9 @@ if (!gpu_init_->init_successful()) { LOG(ERROR) << "Exiting GPU process due to errors during initialization"; - GpuLogMessageManager::GetInstance()->FlushMessages(gpu_host.get()); + mojo::Remote<mojom::GpuLogging> gpu_logging(std::move(pending_gpu_logging)); + GpuLogMessageManager::GetInstance()->FlushMessages(gpu_logging.get()); + gpu_service_.reset(); gpu_host->DidFailInitialize(); if (delegate_) @@ -198,6 +205,10 @@ std::move(discardable_memory_manager), io_task_runner()); base::DiscardableMemoryAllocator::SetInstance( discardable_shared_memory_manager_.get()); + + // Setup GPU Log message hook and bind the GPU logging interface. + GpuLogMessageManager::GetInstance()->InstallPostInitializeLogHandler( + std::move(pending_gpu_logging), io_task_runner()); } #if BUILDFLAG(IS_ANDROID)
diff --git a/components/viz/service/main/viz_main_impl.h b/components/viz/service/main/viz_main_impl.h index 84b3eb3..1d3bdb60 100644 --- a/components/viz/service/main/viz_main_impl.h +++ b/components/viz/service/main/viz_main_impl.h
@@ -15,6 +15,7 @@ #include "build/build_config.h" #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" #include "components/viz/common/buildflags.h" +#include "components/viz/service/gl/gpu_log_message_manager.h" #include "components/viz/service/gl/gpu_service_impl.h" #include "components/viz/service/main/viz_compositor_thread_runner_impl.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -123,6 +124,7 @@ void CreateGpuService( mojo::PendingReceiver<mojom::GpuService> pending_receiver, mojo::PendingRemote<mojom::GpuHost> pending_gpu_host, + mojo::PendingRemote<mojom::GpuLogging> pending_gpu_loggging, mojo::PendingRemote< discardable_memory::mojom::DiscardableSharedMemoryManager> discardable_memory_manager,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 575f837..c7adbd86 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1921,6 +1921,8 @@ "renderer_host/navigation_request_info.h", "renderer_host/navigation_state_keep_alive.cc", "renderer_host/navigation_state_keep_alive.h", + "renderer_host/navigation_throttle_registry_impl.cc", + "renderer_host/navigation_throttle_registry_impl.h", "renderer_host/navigation_throttle_runner.cc", "renderer_host/navigation_throttle_runner.h", "renderer_host/navigation_transitions/navigation_entry_screenshot.cc",
diff --git a/content/browser/background_fetch/background_fetch_test_base.cc b/content/browser/background_fetch/background_fetch_test_base.cc index 2843ddb..e197c7c 100644 --- a/content/browser/background_fetch/background_fetch_test_base.cc +++ b/content/browser/background_fetch/background_fetch_test_base.cc
@@ -138,7 +138,7 @@ { base::RunLoop run_loop; - embedded_worker_test_helper_.context()->registry()->FindRegistrationForId( + embedded_worker_test_helper_.context()->registry().FindRegistrationForId( service_worker_registration_id, key, base::BindOnce(&DidFindServiceWorkerRegistration, &service_worker_registration, run_loop.QuitClosure()));
diff --git a/content/browser/content_index/content_index_database_unittest.cc b/content/browser/content_index/content_index_database_unittest.cc index 896d0ed..343936b 100644 --- a/content/browser/content_index/content_index_database_unittest.cc +++ b/content/browser/content_index/content_index_database_unittest.cc
@@ -270,7 +270,7 @@ { base::RunLoop run_loop; - embedded_worker_test_helper_.context()->registry()->FindRegistrationForId( + embedded_worker_test_helper_.context()->registry().FindRegistrationForId( service_worker_registration_id, blink::StorageKey::CreateFirstParty(origin), base::BindOnce(&DidFindServiceWorkerRegistration,
diff --git a/content/browser/devtools/devtools_background_services_context_impl_unittest.cc b/content/browser/devtools/devtools_background_services_context_impl_unittest.cc index c269cb1..e33db4db 100644 --- a/content/browser/devtools/devtools_background_services_context_impl_unittest.cc +++ b/content/browser/devtools/devtools_background_services_context_impl_unittest.cc
@@ -125,7 +125,7 @@ mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage_control() { return embedded_worker_test_helper_.context() ->registry() - ->GetRemoteStorageControl(); + .GetRemoteStorageControl(); } protected: @@ -247,7 +247,7 @@ { base::RunLoop run_loop; - embedded_worker_test_helper_.context()->registry()->FindRegistrationForId( + embedded_worker_test_helper_.context()->registry().FindRegistrationForId( service_worker_registration_id, key, base::BindOnce(&DidFindServiceWorkerRegistration, &service_worker_registration_,
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc index d78eecc..5616fe18 100644 --- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc +++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
@@ -42,7 +42,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/threading/platform_thread.h" #include "base/threading/scoped_blocking_call.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected.h" #include "build/build_config.h" #include "content/browser/file_system_access/features.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 7f4c54c7..e6ffa2b 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -812,7 +812,8 @@ message += "was killed by you! Why?"; break; case base::TERMINATION_STATUS_PROCESS_CRASHED: - message += "crashed!"; + message += + base::StringPrintf("crashed! Exit code: %d.", info.exit_code); unexpected_exit = true; break; case base::TERMINATION_STATUS_STILL_RUNNING:
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index 44524240..bd3149d 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -39,8 +39,7 @@ #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" -#include "base/trace_event/common/trace_event_common.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected.h" #include "base/types/strong_alias.h" #include "build/build_config.h"
diff --git a/content/browser/indexed_db/instance/connection.cc b/content/browser/indexed_db/instance/connection.cc index 1630fc23..e763b8c 100644 --- a/content/browser/indexed_db/instance/connection.cc +++ b/content/browser/indexed_db/instance/connection.cc
@@ -24,7 +24,7 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/cxx23_to_underlying.h" #include "base/unguessable_token.h" #include "components/services/storage/indexed_db/locks/partitioned_lock_id.h"
diff --git a/content/browser/indexed_db/instance/cursor.cc b/content/browser/indexed_db/instance/cursor.cc index f582a474..9d1cae24 100644 --- a/content/browser/indexed_db/instance/cursor.cc +++ b/content/browser/indexed_db/instance/cursor.cc
@@ -16,7 +16,7 @@ #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "content/browser/indexed_db/indexed_db_database_error.h" #include "content/browser/indexed_db/indexed_db_external_object.h" #include "content/browser/indexed_db/indexed_db_value.h"
diff --git a/content/browser/indexed_db/instance/database.cc b/content/browser/indexed_db/instance/database.cc index b98c82d..880a1878 100644 --- a/content/browser/indexed_db/instance/database.cc +++ b/content/browser/indexed_db/instance/database.cc
@@ -29,7 +29,7 @@ #include "base/notreached.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected_macros.h" #include "base/unguessable_token.h" #include "components/services/storage/indexed_db/locks/partitioned_lock_id.h"
diff --git a/content/browser/indexed_db/instance/leveldb/backing_store.cc b/content/browser/indexed_db/instance/leveldb/backing_store.cc index 43d0238..6fb1222 100644 --- a/content/browser/indexed_db/instance/leveldb/backing_store.cc +++ b/content/browser/indexed_db/instance/leveldb/backing_store.cc
@@ -43,8 +43,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/system/sys_info.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected_macros.h" #include "build/build_config.h" #include "components/services/storage/indexed_db/locks/partitioned_lock.h"
diff --git a/content/browser/indexed_db/instance/leveldb/compaction_task.cc b/content/browser/indexed_db/instance/leveldb/compaction_task.cc index 8674474..73f69fa 100644 --- a/content/browser/indexed_db/instance/leveldb/compaction_task.cc +++ b/content/browser/indexed_db/instance/leveldb/compaction_task.cc
@@ -4,7 +4,7 @@ #include "content/browser/indexed_db/instance/leveldb/compaction_task.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" namespace content::indexed_db::level_db {
diff --git a/content/browser/indexed_db/instance/leveldb/tombstone_sweeper_unittest.cc b/content/browser/indexed_db/instance/leveldb/tombstone_sweeper_unittest.cc index 2b17c24b..374d8bf3 100644 --- a/content/browser/indexed_db/instance/leveldb/tombstone_sweeper_unittest.cc +++ b/content/browser/indexed_db/instance/leveldb/tombstone_sweeper_unittest.cc
@@ -9,6 +9,7 @@ #include <utility> #include "base/files/scoped_temp_dir.h" +#include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" #include "base/test/task_environment.h" #include "components/services/storage/indexed_db/leveldb/mock_level_db.h"
diff --git a/content/browser/indexed_db/instance/transaction.cc b/content/browser/indexed_db/instance/transaction.cc index f5f6fc6..68ce8e2 100644 --- a/content/browser/indexed_db/instance/transaction.cc +++ b/content/browser/indexed_db/instance/transaction.cc
@@ -26,7 +26,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/expected_macros.h" #include "base/unguessable_token.h" #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
diff --git a/content/browser/indexed_db/instance/transaction_unittest.cc b/content/browser/indexed_db/instance/transaction_unittest.cc index 9ac590a6..1639ddfc 100644 --- a/content/browser/indexed_db/instance/transaction_unittest.cc +++ b/content/browser/indexed_db/instance/transaction_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/task/updateable_sequenced_task_runner.h" #include "base/test/run_until.h"
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc index dd3834b..8ff5508ff 100644 --- a/content/browser/media/session/media_session_impl_browsertest.cc +++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -16,6 +16,7 @@ #include "base/metrics/histogram_samples.h" #include "base/run_loop.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h"
diff --git a/content/browser/network_sandbox.cc b/content/browser/network_sandbox.cc index 223ae083..32941720 100644 --- a/content/browser/network_sandbox.cc +++ b/content/browser/network_sandbox.cc
@@ -11,7 +11,7 @@ #include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/task/thread_pool.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "content/browser/network_sandbox_grant_result.h" #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc index 49a60e0a..6909b86e 100644 --- a/content/browser/notifications/blink_notification_service_impl_unittest.cc +++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc
@@ -187,7 +187,7 @@ { base::RunLoop run_loop; - embedded_worker_helper_->context()->registry()->FindRegistrationForId( + embedded_worker_helper_->context()->registry().FindRegistrationForId( service_worker_registration_id, storage_key_, base::BindOnce(&BlinkNotificationServiceImplTest:: DidFindServiceWorkerRegistration,
diff --git a/content/browser/notifications/notification_storage_unittest.cc b/content/browser/notifications/notification_storage_unittest.cc index 32b7dbf..a4ae524 100644 --- a/content/browser/notifications/notification_storage_unittest.cc +++ b/content/browser/notifications/notification_storage_unittest.cc
@@ -90,7 +90,7 @@ { base::RunLoop run_loop; - helper_->context()->registry()->FindRegistrationForId( + helper_->context()->registry().FindRegistrationForId( service_worker_registration_id_, key, base::BindOnce( &NotificationStorageTest::DidFindServiceWorkerRegistration,
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc index 79ea857f..794f5b78 100644 --- a/content/browser/preloading/preloading_decider.cc +++ b/content/browser/preloading/preloading_decider.cc
@@ -99,17 +99,12 @@ blink::features::kPreloadingModelPrerenderModerateThreshold.Get(), 0, 100)} { - static const base::FeatureParam<std::string> kPointerDownEagerness{ - &blink::features::kSpeculationRulesPointerDownHeuristics, - "pointer_down_eagerness", "conservative,moderate"}; pointer_down_eagerness_ = - EagernessSetFromFeatureParam(kPointerDownEagerness.Get()); + EagernessSet{blink::mojom::SpeculationEagerness::kConservative, + blink::mojom::SpeculationEagerness::kModerate}; - static const base::FeatureParam<std::string> kPointerHoverEagerness{ - &blink::features::kSpeculationRulesPointerHoverHeuristics, - "pointer_hover_eagerness", "moderate"}; pointer_hover_eagerness_ = - EagernessSetFromFeatureParam(kPointerHoverEagerness.Get()); + EagernessSet{blink::mojom::SpeculationEagerness::kModerate}; static const base::FeatureParam<std::string> kViewportHeuristicEagerness{ &blink::features::kPreloadingViewportHeuristics,
diff --git a/content/browser/preloading/preloading_decider_unittest.cc b/content/browser/preloading/preloading_decider_unittest.cc index 1ba56c2..91a5abc 100644 --- a/content/browser/preloading/preloading_decider_unittest.cc +++ b/content/browser/preloading/preloading_decider_unittest.cc
@@ -500,62 +500,6 @@ testing::Values(blink::mojom::SpeculationEagerness::kModerate, blink::mojom::SpeculationEagerness::kConservative))); -TEST_F(PreloadingDeciderTest, CanOverridePointerDownEagerness) { - // PreloadingDecider defaults to allowing it for conservative candidates, - // but for this test we'll allow it only for moderate. - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeatureWithParameters( - blink::features::kSpeculationRulesPointerDownHeuristics, - {{"pointer_down_eagerness", "moderate"}}); - - MockContentBrowserClient browser_client; - auto* preloading_decider = - PreloadingDecider::GetOrCreateForCurrentDocument(&GetPrimaryMainFrame()); - ASSERT_TRUE(preloading_decider); - - auto candidate = - MakeCandidate(GetSameOriginUrl("/candidate1.html"), - blink::mojom::SpeculationAction::kPrefetch, - blink::mojom::SpeculationEagerness::kConservative); - std::vector<blink::mojom::SpeculationCandidatePtr> candidates; - candidates.push_back(std::move(candidate)); - - preloading_decider->UpdateSpeculationCandidates(candidates); - EXPECT_EQ(0u, GetPrefetchService()->prefetches_.size()); - - preloading_decider->OnPointerDown(GetSameOriginUrl("/candidate1.html")); - EXPECT_EQ(0u, GetPrefetchService()->prefetches_.size()); -} - -TEST_F(PreloadingDeciderTest, CanOverridePointerHoverEagerness) { - // PreloadingDecider defaults to allowing it for moderate candidates, - // but for this test we'll allow it only for conservative candidates too. - base::test::ScopedFeatureList scoped_features; - scoped_features.InitAndEnableFeatureWithParameters( - blink::features::kSpeculationRulesPointerHoverHeuristics, - {{"pointer_hover_eagerness", "moderate,conservative"}}); - - MockContentBrowserClient browser_client; - auto* preloading_decider = - PreloadingDecider::GetOrCreateForCurrentDocument(&GetPrimaryMainFrame()); - ASSERT_TRUE(preloading_decider); - - auto candidate = - MakeCandidate(GetSameOriginUrl("/candidate1.html"), - blink::mojom::SpeculationAction::kPrefetch, - blink::mojom::SpeculationEagerness::kConservative); - std::vector<blink::mojom::SpeculationCandidatePtr> candidates; - candidates.push_back(std::move(candidate)); - - preloading_decider->UpdateSpeculationCandidates(candidates); - EXPECT_EQ(0u, GetPrefetchService()->prefetches_.size()); - - preloading_decider->OnPointerHover( - GetSameOriginUrl("/candidate1.html"), - blink::mojom::AnchorElementPointerData::New(false, 0.0, 0.0)); - EXPECT_EQ(1u, GetPrefetchService()->prefetches_.size()); -} - TEST_F(PreloadingDeciderTest, UmaRecallStats) { base::HistogramTester histogram_tester; auto* preloading_decider =
diff --git a/content/browser/renderer_host/cookie_browsertest.cc b/content/browser/renderer_host/cookie_browsertest.cc index f121b35..8ccad04 100644 --- a/content/browser/renderer_host/cookie_browsertest.cc +++ b/content/browser/renderer_host/cookie_browsertest.cc
@@ -198,7 +198,7 @@ static_cast<WebContentsImpl*>(shell2->web_contents()); WebContentsImpl* web_contents_http = static_cast<WebContentsImpl*>(shell()->web_contents()); - if (AreAllSitesIsolatedForTesting()) { + if (AreStrictSiteInstancesEnabled()) { EXPECT_EQ("http://a.test/", web_contents_http->GetSiteInstance()->GetSiteURL().spec()); // Create expected site url, including port if origin isolation is enabled.
diff --git a/content/browser/renderer_host/ipc_utils.h b/content/browser/renderer_host/ipc_utils.h index 254d2a74..e5591c9 100644 --- a/content/browser/renderer_host/ipc_utils.h +++ b/content/browser/renderer_host/ipc_utils.h
@@ -7,6 +7,7 @@ #include "base/memory/ref_counted.h" #include "content/common/frame.mojom.h" +#include "content/public/browser/render_process_host.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "third_party/blink/public/mojom/frame/frame.mojom.h" #include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h"
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc index 36651b27..3d91e2c8 100644 --- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -22976,12 +22976,12 @@ EXPECT_EQ(origin_to_commit.value(), committed_origin); GURL site_url = contents()->GetSiteInstance()->GetSiteURL(); - if (AreAllSitesIsolatedForTesting()) { + if (AreStrictSiteInstancesEnabled()) { EXPECT_EQ(site_url.spec(), "data:" + origin_to_commit->GetNonceForTesting()->ToString()); } else { - // Without site isolation, the data: URL ends up in the default - // SiteInstance. + // Without site isolation and without DefaultSiteInstanceGroups, the data: + // URL ends up in the default SiteInstance. EXPECT_EQ(site_url.spec(), "http://unisolated.invalid/"); } }
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 7567b56a7..2026d29 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -38,7 +38,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "base/types/optional_util.h" #include "base/types/pass_key.h" #include "build/build_config.h" @@ -3178,8 +3178,9 @@ modified_request_headers_.Clear(); removed_request_headers_.clear(); + throttle_registry_ = std::make_unique<NavigationThrottleRegistryImpl>(this); throttle_runner_ = std::make_unique<NavigationThrottleRunner>( - this, navigation_id_, IsInPrimaryMainFrame()); + throttle_registry_.get(), navigation_id_, IsInPrimaryMainFrame()); // For prerendered page activation, CommitDeferringConditions have already run // at the beginning of the navigation, so we won't run them again. @@ -3258,6 +3259,11 @@ } } + // Reset `throttle_runner_` and `throttle_registry_` in the reversed order of + // their creation as `throttle_runner_` has a pointer to `throttle_registry_`. + throttle_runner_.reset(); + throttle_registry_.reset(); + // Reset the state of the NavigationRequest, and the navigation_handle_id. StopCommitTimeout(); SetState(NOT_STARTED); @@ -5374,9 +5380,8 @@ #if DCHECK_IS_ON() if (result.action() == NavigationThrottle::BLOCK_REQUEST) { DCHECK(net::IsRequestBlockedError(result.net_error_code())); - } - // TODO(clamy): distinguish between CANCEL and CANCEL_AND_IGNORE. - else if (result.action() == NavigationThrottle::CANCEL_AND_IGNORE) { + } else if (result.action() == NavigationThrottle::CANCEL_AND_IGNORE) { + // TODO(clamy): distinguish between CANCEL and CANCEL_AND_IGNORE. DCHECK_EQ(result.net_error_code(), net::ERR_ABORTED); } #endif @@ -5667,7 +5672,6 @@ } void NavigationRequest::MaybeAddResourceTimingEntryForCancelledNavigation() { - // Some navigation are cancelled even before requesting and receiving a // response. Those cases are not supported and the ResourceTiming is not // reported to the parent. @@ -6121,7 +6125,7 @@ // DO NOT ADD CODE after this. The previous call to CommitNavigation // destroyed the NavigationRequest. return; - }; + } RunCommitDeferringConditions(); // DO NOT ADD CODE after this. The previous call to @@ -7698,26 +7702,26 @@ } void NavigationRequest::OnNavigationEventProcessed( - NavigationThrottleRunner::Event event, + NavigationThrottleEvent event, NavigationThrottle::ThrottleCheckResult result) { DCHECK_NE(NavigationThrottle::DEFER, result.action()); switch (event) { - case NavigationThrottleRunner::Event::kNoEvent: + case NavigationThrottleEvent::kNoEvent: DUMP_WILL_BE_NOTREACHED(); return; - case NavigationThrottleRunner::Event::kWillStartRequest: + case NavigationThrottleEvent::kWillStartRequest: OnWillStartRequestProcessed(result); return; - case NavigationThrottleRunner::Event::kWillRedirectRequest: + case NavigationThrottleEvent::kWillRedirectRequest: OnWillRedirectRequestProcessed(result); return; - case NavigationThrottleRunner::Event::kWillFailRequest: + case NavigationThrottleEvent::kWillFailRequest: OnWillFailRequestProcessed(result); return; - case NavigationThrottleRunner::Event::kWillProcessResponse: + case NavigationThrottleEvent::kWillProcessResponse: OnWillProcessResponseProcessed(result); return; - case NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader: + case NavigationThrottleEvent::kWillCommitWithoutUrlLoader: OnWillCommitWithoutUrlLoaderProcessed(result); return; } @@ -7906,7 +7910,7 @@ DCHECK(!IsPageActivation()) << "Attempted to register a NavigationThrottle for an activating " "navigation which will not work."; - throttle_runner_->AddThrottle(std::move(navigation_throttle)); + throttle_registry_->AddThrottle(std::move(navigation_throttle)); } bool NavigationRequest::IsDeferredForTesting() { return IsDeferred(); @@ -7997,7 +8001,7 @@ // won't run them again on activation. if (!IsPageActivation()) { base::ElapsedTimer duration; - throttle_runner_->RegisterNavigationThrottles(); + throttle_registry_->RegisterNavigationThrottles(); base::UmaHistogramTimes( base::StrCat({"Navigation.RegisterNavigationThrottlesTime.", IsInMainFrame() ? "MainFrame" : "Subframe"}), @@ -8017,7 +8021,7 @@ IsInMainFrame() ? "MainFrame" : "SubFrame"})); // Notify each throttle of the request. throttle_runner_->ProcessNavigationEvent( - NavigationThrottleRunner::Event::kWillStartRequest); + NavigationThrottleEvent::kWillStartRequest); // DO NOT ADD CODE AFTER THIS, as the NavigationHandle might have been deleted // by the previous call. } @@ -8050,7 +8054,7 @@ // Notify each throttle of the request. throttle_runner_->ProcessNavigationEvent( - NavigationThrottleRunner::Event::kWillRedirectRequest); + NavigationThrottleEvent::kWillRedirectRequest); // DO NOT ADD CODE AFTER THIS, as the NavigationHandle might have been deleted // by the previous call. } @@ -8063,7 +8067,7 @@ // Notify each throttle of the request. throttle_runner_->ProcessNavigationEvent( - NavigationThrottleRunner::Event::kWillFailRequest); + NavigationThrottleEvent::kWillFailRequest); // DO NOT ADD CODE AFTER THIS, as the NavigationHandle might have been deleted // by the previous call. } @@ -8082,7 +8086,7 @@ // Notify each throttle of the response. throttle_runner_->ProcessNavigationEvent( - NavigationThrottleRunner::Event::kWillProcessResponse); + NavigationThrottleEvent::kWillProcessResponse); // `this` may have been deleted by the previous call. if (!this_ptr) { @@ -8101,7 +8105,7 @@ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); EnterChildTraceEvent("WillCommitWithoutUrlLoader", this); - throttle_runner_->RegisterNavigationThrottlesForCommitWithoutUrlLoader(); + throttle_registry_->RegisterNavigationThrottlesForCommitWithoutUrlLoader(); // `CommitNavigation()` expects to be called once the request has reached // at least `WILL_PROCESS_REPSONSE`. `WILL_COMMIT_WITHOUT_URL_LOADER` meets @@ -8111,7 +8115,7 @@ processing_navigation_throttle_ = true; throttle_runner_->ProcessNavigationEvent( - NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader); + NavigationThrottleEvent::kWillCommitWithoutUrlLoader); } bool NavigationRequest::IsSelfReferentialURL() { @@ -9889,9 +9893,10 @@ // // 2. By a document in the <fencedframe> frame tree. In this case the // initiator policies are properly plumbed and should be used. - // TODO(crbug.com/40258851): Use the initiator policies. On can - // use `is_embedder_initiated_fenced_frame_navigation_` to discriminate - // (1) from (2). + // + // TODO(crbug.com/40258851): Use the initiator policies. On can use + // `is_embedder_initiated_fenced_frame_navigation_` to discriminate (1) from + // (2). // // NOTE: For an embedder initiated fenced frame navigation that is subject // to private network access checks:
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index 132550fc..9160620 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h
@@ -32,6 +32,7 @@ #include "content/browser/renderer_host/cookie_access_observers.h" #include "content/browser/renderer_host/navigation_controller_impl.h" #include "content/browser/renderer_host/navigation_policy_container_builder.h" +#include "content/browser/renderer_host/navigation_throttle_registry_impl.h" #include "content/browser/renderer_host/navigation_throttle_runner.h" #include "content/browser/renderer_host/navigation_type.h" #include "content/browser/renderer_host/render_frame_host_impl.h" @@ -111,7 +112,6 @@ class CONTENT_EXPORT NavigationRequest : public NavigationHandle, public NavigationURLLoaderDelegate, - public NavigationThrottleRunner::Delegate, public CommitDeferringConditionRunner::Delegate, public FencedFrameURLMapping::MappingResultObserver, public mojom::NavigationRendererCancellationListener, @@ -756,6 +756,11 @@ return throttle_runner_.get(); } + // Returns the underlying NavigationThrottleRegistry for tests to manipulate. + NavigationThrottleRegistry* GetNavigationThrottleRegistryForTesting() { + return throttle_registry_.get(); + } + // Simulates renderer cancelling the navigation. void RendererRequestedNavigationCancellationForTesting(); @@ -1720,6 +1725,13 @@ std::optional<ukm::builders::NavigationTimeline> GetNavigationTimelineUkmBuilder(); + // Called when the NavigationThrottleRunner is done processing the navigation + // event of type `event`. `result` is the final + // NavigationThrottle::ThrottleCheckResult for this event. + void OnNavigationEventProcessed( + NavigationThrottleEvent event, + NavigationThrottle::ThrottleCheckResult result); + private: friend class NavigationRequestTest; FRIEND_TEST_ALL_PREFIXES(NavigationRequestTest, SanitizeRedirectsForCommit); @@ -2053,11 +2065,6 @@ // filtered by download_policy. void RecordDownloadUseCountersPostPolicyCheck(); - // NavigationThrottleRunner::Delegate: - void OnNavigationEventProcessed( - NavigationThrottleRunner::Event event, - NavigationThrottle::ThrottleCheckResult result) override; - void OnWillStartRequestProcessed( NavigationThrottle::ThrottleCheckResult result); void OnWillRedirectRequestProcessed( @@ -2653,6 +2660,10 @@ // The offset of the new document in the history. const int navigation_entry_offset_ = 0; + // Owns the NavigationThrottleRegistry associated with this navigation. + // This should outlive `throttle_runner_`. + std::unique_ptr<NavigationThrottleRegistryImpl> throttle_registry_; + // Owns the NavigationThrottles associated with this navigation, and is // responsible for notifying them about the various navigation events. std::unique_ptr<NavigationThrottleRunner> throttle_runner_;
diff --git a/content/browser/renderer_host/navigation_request_unittest.cc b/content/browser/renderer_host/navigation_request_unittest.cc index f78672b..7ded5ed 100644 --- a/content/browser/renderer_host/navigation_request_unittest.cc +++ b/content/browser/renderer_host/navigation_request_unittest.cc
@@ -165,7 +165,7 @@ TestNavigationThrottle* CreateTestNavigationThrottle( NavigationThrottle::ThrottleCheckResult result) { TestNavigationThrottle* test_throttle = new TestNavigationThrottle( - *GetNavigationRequest()->GetNavigationThrottleRunnerForTesting()); + *GetNavigationRequest()->GetNavigationThrottleRegistryForTesting()); test_throttle->SetResponseForAllMethods(TestNavigationThrottle::SYNCHRONOUS, result); GetNavigationRequest()->RegisterThrottleForTesting( @@ -1225,7 +1225,6 @@ public: PersistentOriginTrialNavigationRequestTest() : delegate_mock_(std::make_unique<OriginTrialsControllerDelegateMock>()) { - } ~PersistentOriginTrialNavigationRequestTest() override = default;
diff --git a/content/browser/renderer_host/navigation_throttle_registry_impl.cc b/content/browser/renderer_host/navigation_throttle_registry_impl.cc new file mode 100644 index 0000000..5966e63 --- /dev/null +++ b/content/browser/renderer_host/navigation_throttle_registry_impl.cc
@@ -0,0 +1,196 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/navigation_throttle_registry_impl.h" + +#include "base/check_deref.h" +#include "base/metrics/histogram_functions.h" +#include "base/trace_event/trace_event.h" +#include "build/build_config.h" +#include "content/browser/devtools/devtools_instrumentation.h" +#include "content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h" +#include "content/browser/preloading/prerender/prerender_navigation_throttle.h" +#include "content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h" +#include "content/browser/renderer_host/ancestor_throttle.h" +#include "content/browser/renderer_host/back_forward_cache_subframe_navigation_throttle.h" +#include "content/browser/renderer_host/blocked_scheme_navigation_throttle.h" +#include "content/browser/renderer_host/http_error_navigation_throttle.h" +#include "content/browser/renderer_host/isolated_web_app_throttle.h" +#include "content/browser/renderer_host/mixed_content_navigation_throttle.h" +#include "content/browser/renderer_host/navigation_request.h" +#include "content/browser/renderer_host/navigator_delegate.h" +#include "content/browser/renderer_host/partitioned_popins/partitioned_popins_navigation_throttle.h" +#include "content/browser/renderer_host/renderer_cancellation_throttle.h" +#include "content/browser/renderer_host/subframe_history_navigation_throttle.h" +#include "content/public/browser/navigation_handle.h" + +#if !BUILDFLAG(IS_ANDROID) +#include "content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h" +#endif // !BUILDFLAG(IS_ANDROID) + +namespace content { + +NavigationThrottleRegistryBase::~NavigationThrottleRegistryBase() = default; + +NavigationThrottleRegistryImpl::NavigationThrottleRegistryImpl( + NavigationRequest* navigation_request) + : navigation_request_(CHECK_DEREF(navigation_request)) {} + +NavigationThrottleRegistryImpl::~NavigationThrottleRegistryImpl() = default; + +void NavigationThrottleRegistryImpl::RegisterNavigationThrottles() { + TRACE_EVENT0("navigation", + "NavigationThrottleRegistryImpl::RegisterNavigationThrottles"); + // Note: `throttles_` might not be empty. Some NavigationThrottles might have + // been registered with RegisterThrottleForTesting. These must reside at the + // end of `throttles_`. TestNavigationManagerThrottle expects that the + // NavigationThrottles added for test are the last NavigationThrottles to + // execute. Take them out while appending the rest of the + // NavigationThrottles. + std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles = + std::move(throttles_); + + // The NavigationRequest associated with the NavigationThrottles this + // NavigationThrottleRunner manages. + navigation_request_->GetDelegate()->CreateThrottlesForNavigation(*this); + + // Check for renderer-inititated main frame navigations to blocked URL schemes + // (data, filesystem). This is done early as it may block the main frame + // navigation altogether. + BlockedSchemeNavigationThrottle::MaybeCreateAndAdd(*this); + +#if !BUILDFLAG(IS_ANDROID) + // Prevent cross-document navigations from document picture-in-picture + // windows. + DocumentPictureInPictureNavigationThrottle::MaybeCreateAndAdd(*this); +#endif // !BUILDFLAG(IS_ANDROID) + + AncestorThrottle::CreateAndAdd(*this); + + // Check for mixed content. This is done after the AncestorThrottle and the + // FormSubmissionThrottle so that when folks block mixed content with a CSP + // policy, they don't get a warning. They'll still get a warning in the + // console about CSP blocking the load. + MixedContentNavigationThrottle::CreateAndAdd(*this); + + // Delay response processing for certain prefetch responses where it might + // otherwise reveal information about cross-site state. + ContaminationDelayNavigationThrottle::MaybeCreateAndAdd(*this); + + // Block certain requests that are not permitted for prerendering. + PrerenderNavigationThrottle::MaybeCreateAndAdd(*this); + + // Defer cross-origin subframe loading during prerendering state. + PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this); + + // Prevent navigations to/from Isolated Web Apps. + IsolatedWebAppThrottle::MaybeCreateAndAdd(*this); + + devtools_instrumentation::CreateAndAddNavigationThrottles(*this); + + // Make main frame navigations with error HTTP status code and an empty body + // commit an error page instead. Note that this should take lower priority + // than other throttles that might care about those navigations, e.g. + // throttles handling pages with 407 errors that require extra authentication. + HttpErrorNavigationThrottle::MaybeCreateAndAdd(*this); + + // Wait for renderer-initiated navigation cancelation window to end. This will + // wait for the JS task that starts the navigation to finish, so add it close + // to the end to not delay running other throttles. + RendererCancellationThrottle::MaybeCreateAndAdd(*this); + + // Defer any cross-document subframe history navigations if there is an + // associated main-frame same-document history navigation in progress, until + // the main frame has had an opportunity to fire a navigate event in the + // renderer. If the navigate event cancels the history navigation, the + // subframe navigations should not proceed. + SubframeHistoryNavigationThrottle::MaybeCreateAndAdd(*this); + + // Defer subframe navigation in bfcached page if it hasn't sent a network + // request. + // This must be the last throttle to run. See https://crrev.com/c/5316738. + BackForwardCacheSubframeNavigationThrottle::MaybeCreateAndAdd(*this); + + // Add a throttle to manage top-frame navigations from a partitioned popin. + // See https://explainers-by-googlers.github.io/partitioned-popins/ + PartitionedPopinsNavigationThrottle::MaybeCreateAndAdd(*this); + // DO NOT ADD any throttles after this line. + + // Insert all testing NavigationThrottles last. + throttles_.insert(throttles_.end(), + std::make_move_iterator(testing_throttles.begin()), + std::make_move_iterator(testing_throttles.end())); + + base::UmaHistogramCounts100("Navigation.ThrottleCount", throttles_.size()); +} + +void NavigationThrottleRegistryImpl:: + RegisterNavigationThrottlesForCommitWithoutUrlLoader() { + // Note: `throttles_` might not be empty. Some NavigationThrottles might have + // been registered with RegisterThrottleForTesting. These must reside at the + // end of `throttles_`. TestNavigationManagerThrottle expects that the + // NavigationThrottles added for test are the last NavigationThrottles to + // execute. Take them out while appending the rest of the + // NavigationThrottles. + std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles = + std::move(throttles_); + + // Defer any same-document subframe history navigations if there is an + // associated main-frame same-document history navigation in progress, until + // the main frame has had an opportunity to fire a navigate event in the + // renderer. If the navigate event cancels the history navigation, the + // subframe navigations should not proceed. + SubframeHistoryNavigationThrottle::MaybeCreateAndAdd(*this); + + // Defer cross-origin about:srcdoc subframe loading during prerendering state. + PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this); + + // Defer subframe navigation in bfcached page. + BackForwardCacheSubframeNavigationThrottle::MaybeCreateAndAdd(*this); + + RendererCancellationThrottle::MaybeCreateAndAdd(*this); + + // Insert all testing NavigationThrottles last. + throttles_.insert(throttles_.end(), + std::make_move_iterator(testing_throttles.begin()), + std::make_move_iterator(testing_throttles.end())); +} + +NavigationHandle& NavigationThrottleRegistryImpl::GetNavigationHandle() { + return *navigation_request_; +} + +void NavigationThrottleRegistryImpl::AddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) { + CHECK(navigation_throttle); + TRACE_EVENT1("navigation", "NavigationThrottleRegistryImpl::AddThrottle", + "navigation_throttle", navigation_throttle->GetNameForLogging()); + throttles_.push_back(std::move(navigation_throttle)); +} + +void NavigationThrottleRegistryImpl::MaybeAddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) { + if (navigation_throttle) { + AddThrottle(std::move(navigation_throttle)); + } +} + +void NavigationThrottleRegistryImpl::OnEventProcessed( + NavigationThrottleEvent event, + NavigationThrottle::ThrottleCheckResult result) { + navigation_request_->OnNavigationEventProcessed(event, result); +} + +std::vector<std::unique_ptr<NavigationThrottle>>& +NavigationThrottleRegistryImpl::GetThrottles() { + return throttles_; +} + +NavigationThrottle& NavigationThrottleRegistryImpl::GetThrottleAtIndex( + size_t index) { + CHECK_LT(index, throttles_.size()); + return *throttles_[index]; +} + +} // namespace content
diff --git a/content/browser/renderer_host/navigation_throttle_registry_impl.h b/content/browser/renderer_host/navigation_throttle_registry_impl.h new file mode 100644 index 0000000..a327e5e --- /dev/null +++ b/content/browser/renderer_host/navigation_throttle_registry_impl.h
@@ -0,0 +1,108 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_REGISTRY_IMPL_H_ +#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_REGISTRY_IMPL_H_ + +#include <memory> +#include <vector> + +#include "base/memory/raw_ref.h" +#include "base/memory/safety_checks.h" +#include "content/common/content_export.h" +#include "content/public/browser/navigation_throttle.h" +#include "content/public/browser/navigation_throttle_registry.h" + +namespace content { + +class NavigationHandle; +class NavigationRequest; + +// The different event types that can be processed by NavigationThrottles. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// This type is also used in the UKM as set in the RecordDeferTimeUKM(). +// +// LINT.IfChange(NavigationThrottleEvent) +enum class NavigationThrottleEvent { + kNoEvent = 0, + kWillStartRequest = 1, + kWillRedirectRequest = 2, + kWillFailRequest = 3, + kWillProcessResponse = 4, + kWillCommitWithoutUrlLoader = 5, + kMaxValue = kWillCommitWithoutUrlLoader, +}; +// LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:NavigationThrottleEvent) + + +class CONTENT_EXPORT NavigationThrottleRegistryBase + : public NavigationThrottleRegistry { + public: + ~NavigationThrottleRegistryBase() override; + + // Called when the NavigationThrottleRunner is done processing the navigation + // event of type `event`. `result` is the final + // NavigationThrottle::ThrottleCheckResult for this event. + virtual void OnEventProcessed( + NavigationThrottleEvent event, + NavigationThrottle::ThrottleCheckResult result) = 0; + + // Returns the list of NavigationThrottles registered for this navigation. + virtual std::vector<std::unique_ptr<NavigationThrottle>>& GetThrottles() = 0; + + // Returns the NavigationThrottle at the given `index`. The `index` should + // be in a valid range. + virtual NavigationThrottle& GetThrottleAtIndex(size_t index) = 0; +}; + +class NavigationThrottleRegistryImpl : public NavigationThrottleRegistryBase { + // Do not remove this macro! + // The macro is maintained by the memory safety team. + ADVANCED_MEMORY_SAFETY_CHECKS(); + + public: + explicit NavigationThrottleRegistryImpl( + NavigationRequest* navigation_request); + NavigationThrottleRegistryImpl(const NavigationThrottleRegistryImpl&) = + delete; + NavigationThrottleRegistryImpl& operator=( + const NavigationThrottleRegistryImpl&) = delete; + ~NavigationThrottleRegistryImpl() override; + + // Registers the appropriate NavigationThrottles for a "standard" navigation + // (i.e., one with a URLLoader that goes through the + // WillSendRequest/WillProcessResponse callback sequence). + void RegisterNavigationThrottles(); + + // Registers the appropriate NavigationThrottles for a navigation that can + // immediately commit because no URLLoader is required (about:blank, + // about:srcdoc, and most same-document navigations). + void RegisterNavigationThrottlesForCommitWithoutUrlLoader(); + + // Implements NavigationThrottleRegistry: + NavigationHandle& GetNavigationHandle() override; + void AddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) override; + void MaybeAddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) override; + + // Implements NavigationThrottleRegistryBase: + void OnEventProcessed( + NavigationThrottleEvent event, + NavigationThrottle::ThrottleCheckResult result) override; + std::vector<std::unique_ptr<NavigationThrottle>>& GetThrottles() override; + NavigationThrottle& GetThrottleAtIndex(size_t index) override; + + private: + // Holds a reference to the NavigationRequest that owns this instance. + const raw_ref<NavigationRequest> navigation_request_; + + // A list of Throttles registered for this navigation. + std::vector<std::unique_ptr<NavigationThrottle>> throttles_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_REGISTRY_IMPL_H_
diff --git a/content/browser/renderer_host/navigation_throttle_runner.cc b/content/browser/renderer_host/navigation_throttle_runner.cc index b027e6d9..a97af3e 100644 --- a/content/browser/renderer_host/navigation_throttle_runner.cc +++ b/content/browser/renderer_host/navigation_throttle_runner.cc
@@ -11,94 +11,75 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/metrics_hashes.h" #include "base/strings/strcat.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "content/browser/devtools/devtools_instrumentation.h" -#include "content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h" -#include "content/browser/preloading/prerender/prerender_navigation_throttle.h" -#include "content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h" -#include "content/browser/renderer_host/ancestor_throttle.h" -#include "content/browser/renderer_host/back_forward_cache_subframe_navigation_throttle.h" -#include "content/browser/renderer_host/blocked_scheme_navigation_throttle.h" -#include "content/browser/renderer_host/http_error_navigation_throttle.h" -#include "content/browser/renderer_host/isolated_web_app_throttle.h" -#include "content/browser/renderer_host/mixed_content_navigation_throttle.h" -#include "content/browser/renderer_host/navigation_request.h" -#include "content/browser/renderer_host/navigator_delegate.h" -#include "content/browser/renderer_host/partitioned_popins/partitioned_popins_navigation_throttle.h" -#include "content/browser/renderer_host/renderer_cancellation_throttle.h" -#include "content/browser/renderer_host/subframe_history_navigation_throttle.h" -#include "content/public/browser/navigation_handle.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_source_id.h" -#if !BUILDFLAG(IS_ANDROID) -#include "content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h" -#endif // !BUILDFLAG(IS_ANDROID) - namespace content { namespace { NavigationThrottle::ThrottleCheckResult ExecuteNavigationEvent( NavigationThrottle* throttle, - NavigationThrottleRunner::Event event) { + NavigationThrottleEvent event) { switch (event) { - case NavigationThrottleRunner::Event::kNoEvent: + case NavigationThrottleEvent::kNoEvent: DUMP_WILL_BE_NOTREACHED(); return NavigationThrottle::CANCEL_AND_IGNORE; - case NavigationThrottleRunner::Event::kWillStartRequest: + case NavigationThrottleEvent::kWillStartRequest: return throttle->WillStartRequest(); - case NavigationThrottleRunner::Event::kWillRedirectRequest: + case NavigationThrottleEvent::kWillRedirectRequest: return throttle->WillRedirectRequest(); - case NavigationThrottleRunner::Event::kWillFailRequest: + case NavigationThrottleEvent::kWillFailRequest: return throttle->WillFailRequest(); - case NavigationThrottleRunner::Event::kWillProcessResponse: + case NavigationThrottleEvent::kWillProcessResponse: return throttle->WillProcessResponse(); - case NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader: + case NavigationThrottleEvent::kWillCommitWithoutUrlLoader: return throttle->WillCommitWithoutUrlLoader(); } NOTREACHED(); } -const char* GetEventName(NavigationThrottleRunner::Event event) { +const char* GetEventName(NavigationThrottleEvent event) { switch (event) { - case NavigationThrottleRunner::Event::kNoEvent: + case NavigationThrottleEvent::kNoEvent: DUMP_WILL_BE_NOTREACHED(); return ""; - case NavigationThrottleRunner::Event::kWillStartRequest: + case NavigationThrottleEvent::kWillStartRequest: return "NavigationThrottle::WillStartRequest"; - case NavigationThrottleRunner::Event::kWillRedirectRequest: + case NavigationThrottleEvent::kWillRedirectRequest: return "NavigationThrottle::WillRedirectRequest"; - case NavigationThrottleRunner::Event::kWillFailRequest: + case NavigationThrottleEvent::kWillFailRequest: return "NavigationThrottle::WillFailRequest"; - case NavigationThrottleRunner::Event::kWillProcessResponse: + case NavigationThrottleEvent::kWillProcessResponse: return "NavigationThrottle::WillProcessResponse"; - case NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader: + case NavigationThrottleEvent::kWillCommitWithoutUrlLoader: return "NavigationThrottle::WillCommitWithoutUrlLoader"; } NOTREACHED(); } -const char* GetEventNameForHistogram(NavigationThrottleRunner::Event event) { +const char* GetEventNameForHistogram(NavigationThrottleEvent event) { switch (event) { - case NavigationThrottleRunner::Event::kNoEvent: + case NavigationThrottleEvent::kNoEvent: DUMP_WILL_BE_NOTREACHED(); return ""; - case NavigationThrottleRunner::Event::kWillStartRequest: + case NavigationThrottleEvent::kWillStartRequest: return "WillStartRequest"; - case NavigationThrottleRunner::Event::kWillRedirectRequest: + case NavigationThrottleEvent::kWillRedirectRequest: return "WillRedirectRequest"; - case NavigationThrottleRunner::Event::kWillFailRequest: + case NavigationThrottleEvent::kWillFailRequest: return "WillFailRequest"; - case NavigationThrottleRunner::Event::kWillProcessResponse: + case NavigationThrottleEvent::kWillProcessResponse: return "WillProcessResponse"; - case NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader: + case NavigationThrottleEvent::kWillCommitWithoutUrlLoader: return "WillCommitWithoutUrlLoader"; } NOTREACHED(); } -base::TimeDelta RecordHistogram(NavigationThrottleRunner::Event event, +base::TimeDelta RecordHistogram(NavigationThrottleEvent event, base::Time start, const std::string& metric_type) { base::TimeDelta delta = base::Time::Now() - start; @@ -108,26 +89,25 @@ return delta; } -base::TimeDelta RecordDeferTimeHistogram(NavigationThrottleRunner::Event event, +base::TimeDelta RecordDeferTimeHistogram(NavigationThrottleEvent event, base::Time start) { return RecordHistogram(event, start, "DeferTime"); } -void RecordExecutionTimeHistogram(NavigationThrottleRunner::Event event, +void RecordExecutionTimeHistogram(NavigationThrottleEvent event, base::Time start) { RecordHistogram(event, start, "ExecutionTime"); } } // namespace -NavigationThrottleRunner::NavigationThrottleRunner(Delegate* delegate, - int64_t navigation_id, - bool is_primary_main_frame) - : delegate_(delegate), +NavigationThrottleRunner::NavigationThrottleRunner( + NavigationThrottleRegistryBase* registry, + int64_t navigation_id, + bool is_primary_main_frame) + : registry_(CHECK_DEREF(registry)), navigation_id_(navigation_id), - is_primary_main_frame_(is_primary_main_frame) { - CHECK(delegate_); -} + is_primary_main_frame_(is_primary_main_frame) {} NavigationThrottleRunner::~NavigationThrottleRunner() { base::UmaHistogramTimes("Navigation.ThrottleTotalDeferTime", @@ -140,31 +120,9 @@ defer_count_for_request_); } -NavigationHandle& NavigationThrottleRunner::GetNavigationHandle() { - // TODO(https://crbug.com/412524375): Change the NavigationThrottleRunner - // to take a NavigationRequest instead of a Delegate. Then use the request - // to get the NavigationHandle safely here. - // See https://crrev.com/c/6478853/comment/4217a4c3_3e0f336b/. - return *static_cast<NavigationRequest*>(delegate_); -} - -void NavigationThrottleRunner::AddThrottle( - std::unique_ptr<NavigationThrottle> navigation_throttle) { - CHECK(navigation_throttle); - TRACE_EVENT1("navigation", "NavigationThrottleRunner::AddThrottle", - "navigation_throttle", navigation_throttle->GetNameForLogging()); - throttles_.push_back(std::move(navigation_throttle)); -} - -void NavigationThrottleRunner::MaybeAddThrottle( - std::unique_ptr<NavigationThrottle> navigation_throttle) { - if (navigation_throttle) { - AddThrottle(std::move(navigation_throttle)); - } -} - -void NavigationThrottleRunner::ProcessNavigationEvent(Event event) { - CHECK_NE(Event::kNoEvent, event); +void NavigationThrottleRunner::ProcessNavigationEvent( + NavigationThrottleEvent event) { + CHECK_NE(NavigationThrottleEvent::kNoEvent, event); current_event_ = event; next_index_ = 0; ProcessInternal(); @@ -187,8 +145,8 @@ RecordDeferTimeHistogram(current_event_, defer_start_time_); total_defer_duration_time_ += defer_time; defer_count_++; - if (current_event_ == Event::kWillStartRequest || - current_event_ == Event::kWillRedirectRequest) { + if (current_event_ == NavigationThrottleEvent::kWillStartRequest || + current_event_ == NavigationThrottleEvent::kWillRedirectRequest) { total_defer_duration_time_for_request_ += defer_time; defer_count_for_request_++; } @@ -203,139 +161,16 @@ ProcessInternal(); } -void NavigationThrottleRunner::RegisterNavigationThrottles() { - TRACE_EVENT0("navigation", - "NavigationThrottleRunner::RegisterNavigationThrottles"); - // Note: |throttle_| might not be empty. Some NavigationThrottles might have - // been registered with RegisterThrottleForTesting. These must reside at the - // end of |throttles_|. TestNavigationManagerThrottle expects that the - // NavigationThrottles added for test are the last NavigationThrottles to - // execute. Take them out while appending the rest of the - // NavigationThrottles. - std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles = - std::move(throttles_); - - // The NavigationRequest associated with the NavigationThrottles this - // NavigationThrottleRunner manages. - // Unit tests that do not use NavigationRequest should never call - // RegisterNavigationThrottles as this function expects |delegate_| to be a - // NavigationRequest. - static_cast<NavigationRequest*>(delegate_) - ->GetDelegate() - ->CreateThrottlesForNavigation(*this); - - // Check for renderer-inititated main frame navigations to blocked URL schemes - // (data, filesystem). This is done early as it may block the main frame - // navigation altogether. - BlockedSchemeNavigationThrottle::MaybeCreateAndAdd(*this); - -#if !BUILDFLAG(IS_ANDROID) - // Prevent cross-document navigations from document picture-in-picture - // windows. - DocumentPictureInPictureNavigationThrottle::MaybeCreateAndAdd(*this); -#endif // !BUILDFLAG(IS_ANDROID) - - AncestorThrottle::CreateAndAdd(*this); - - // Check for mixed content. This is done after the AncestorThrottle and the - // FormSubmissionThrottle so that when folks block mixed content with a CSP - // policy, they don't get a warning. They'll still get a warning in the - // console about CSP blocking the load. - MixedContentNavigationThrottle::CreateAndAdd(*this); - - // Delay response processing for certain prefetch responses where it might - // otherwise reveal information about cross-site state. - ContaminationDelayNavigationThrottle::MaybeCreateAndAdd(*this); - - // Block certain requests that are not permitted for prerendering. - PrerenderNavigationThrottle::MaybeCreateAndAdd(*this); - - // Defer cross-origin subframe loading during prerendering state. - PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this); - - // Prevent navigations to/from Isolated Web Apps. - IsolatedWebAppThrottle::MaybeCreateAndAdd(*this); - - devtools_instrumentation::CreateAndAddNavigationThrottles(*this); - - // Make main frame navigations with error HTTP status code and an empty body - // commit an error page instead. Note that this should take lower priority - // than other throttles that might care about those navigations, e.g. - // throttles handling pages with 407 errors that require extra authentication. - HttpErrorNavigationThrottle::MaybeCreateAndAdd(*this); - - // Wait for renderer-initiated navigation cancelation window to end. This will - // wait for the JS task that starts the navigation to finish, so add it close - // to the end to not delay running other throttles. - RendererCancellationThrottle::MaybeCreateAndAdd(*this); - - // Defer any cross-document subframe history navigations if there is an - // associated main-frame same-document history navigation in progress, until - // the main frame has had an opportunity to fire a navigate event in the - // renderer. If the navigate event cancels the history navigation, the - // subframe navigations should not proceed. - SubframeHistoryNavigationThrottle::MaybeCreateAndAdd(*this); - - // Defer subframe navigation in bfcached page if it hasn't sent a network - // request. - // This must be the last throttle to run. See https://crrev.com/c/5316738. - BackForwardCacheSubframeNavigationThrottle::MaybeCreateAndAdd(*this); - - // Add a throttle to manage top-frame navigations from a partitioned popin. - // See https://explainers-by-googlers.github.io/partitioned-popins/ - PartitionedPopinsNavigationThrottle::MaybeCreateAndAdd(*this); - // DO NOT ADD any throttles after this line. - - // Insert all testing NavigationThrottles last. - throttles_.insert(throttles_.end(), - std::make_move_iterator(testing_throttles.begin()), - std::make_move_iterator(testing_throttles.end())); - - base::UmaHistogramCounts100("Navigation.ThrottleCount", throttles_.size()); -} - -void NavigationThrottleRunner:: - RegisterNavigationThrottlesForCommitWithoutUrlLoader() { - // Note: |throttle_| might not be empty. Some NavigationThrottles might have - // been registered with RegisterThrottleForTesting. These must reside at the - // end of |throttles_|. TestNavigationManagerThrottle expects that the - // NavigationThrottles added for test are the last NavigationThrottles to - // execute. Take them out while appending the rest of the - // NavigationThrottles. - std::vector<std::unique_ptr<NavigationThrottle>> testing_throttles = - std::move(throttles_); - - // Defer any same-document subframe history navigations if there is an - // associated main-frame same-document history navigation in progress, until - // the main frame has had an opportunity to fire a navigate event in the - // renderer. If the navigate event cancels the history navigation, the - // subframe navigations should not proceed. - SubframeHistoryNavigationThrottle::MaybeCreateAndAdd(*this); - - // Defer cross-origin about:srcdoc subframe loading during prerendering state. - PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this); - - // Defer subframe navigation in bfcached page. - BackForwardCacheSubframeNavigationThrottle::MaybeCreateAndAdd(*this); - - RendererCancellationThrottle::MaybeCreateAndAdd(*this); - - // Insert all testing NavigationThrottles last. - throttles_.insert(throttles_.end(), - std::make_move_iterator(testing_throttles.begin()), - std::make_move_iterator(testing_throttles.end())); -} - NavigationThrottle* NavigationThrottleRunner::GetDeferringThrottle() const { if (next_index_ == 0) { return nullptr; } - return throttles_[next_index_ - 1].get(); + return ®istry_->GetThrottleAtIndex(next_index_ - 1); } void NavigationThrottleRunner::ProcessInternal() { TRACE_EVENT0("navigation", "NavigationThrottleRunner::ProcessInternal"); - CHECK_NE(Event::kNoEvent, current_event_); + CHECK_NE(NavigationThrottleEvent::kNoEvent, current_event_); base::Time start_time = base::Time::Now(); if (!event_process_start_time_.has_value()) { event_process_start_time_ = start_time; @@ -348,16 +183,17 @@ // events need to be able to use the navigation id safely in such a case. int64_t local_navigation_id = navigation_id_; - for (size_t i = next_index_; i < throttles_.size(); ++i) { + auto& throttles = registry_->GetThrottles(); + for (size_t i = next_index_; i < throttles.size(); ++i) { TRACE_EVENT0("navigation", "NavigationThrottleRunner::ProcessInternal.loop"); TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( "navigation", GetEventName(current_event_), local_navigation_id, - "throttle", throttles_[i]->GetNameForLogging()); + "throttle", throttles[i]->GetNameForLogging()); base::Time start = base::Time::Now(); NavigationThrottle::ThrottleCheckResult result = - ExecuteNavigationEvent(throttles_[i].get(), current_event_); + ExecuteNavigationEvent(throttles[i].get(), current_event_); if (!weak_ref) { // The NavigationThrottle execution has destroyed this // NavigationThrottleRunner. Return immediately. @@ -381,7 +217,7 @@ case NavigationThrottle::CANCEL_AND_IGNORE: next_index_ = 0; event_process_start_time_.reset(); - InformDelegate(result); + InformRegistry(result); return; case NavigationThrottle::DEFER: @@ -407,18 +243,18 @@ end_time - *event_process_start_time_); event_process_start_time_.reset(); next_index_ = 0; - InformDelegate(NavigationThrottle::PROCEED); + InformRegistry(NavigationThrottle::PROCEED); } -void NavigationThrottleRunner::InformDelegate( +void NavigationThrottleRunner::InformRegistry( const NavigationThrottle::ThrottleCheckResult& result) { // Now that the event has executed, reset the current event to kNoEvent since // we're no longer processing any event. Do it before the call to the // delegate, as it might lead to the deletion of this // NavigationThrottleRunner. - Event event = current_event_; - current_event_ = Event::kNoEvent; - delegate_->OnNavigationEventProcessed(event, result); + NavigationThrottleEvent event = current_event_; + current_event_ = NavigationThrottleEvent::kNoEvent; + registry_->OnEventProcessed(event, result); // DO NOT ADD CODE AFTER THIS. The NavigationThrottleRunner might have been // deleted by the previous call. }
diff --git a/content/browser/renderer_host/navigation_throttle_runner.h b/content/browser/renderer_host/navigation_throttle_runner.h index 21f7fb2..6976574 100644 --- a/content/browser/renderer_host/navigation_throttle_runner.h +++ b/content/browser/renderer_host/navigation_throttle_runner.h
@@ -14,74 +14,35 @@ #include "base/memory/safety_checks.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" +#include "content/browser/renderer_host/navigation_throttle_registry_impl.h" #include "content/common/content_export.h" #include "content/public/browser/navigation_throttle.h" -#include "content/public/browser/navigation_throttle_registry.h" namespace content { -class NavigationHandle; - -// This class owns the set of NavigationThrottles added to a NavigationHandle. -// It is responsible for calling the various sets of events on its -// NavigationThrottle, and notifying its delegate of the results of said events. -// TODO(https://crbug.com/412524375): Currently this class implements -// NavigationThrottleRegistry, but this will be factored out to a separate -// NavigationThrottleRegistryImpl class, and will hold common logic for the -// legacy NavigationThrottleRunner, and the new NavigationThrottleRunner2. -class CONTENT_EXPORT NavigationThrottleRunner - : public NavigationThrottleRegistry { +// This class collaborates with NavigationThrottleRegistry that owns the set of +// NavigationThrottles added to an underlying navigation, and is responsible for +// calling the various sets of events on its NavigationThrottles, and notifying +// its delegate of the results of said events. +class CONTENT_EXPORT NavigationThrottleRunner { // Do not remove this macro! // The macro is maintained by the memory safety team. ADVANCED_MEMORY_SAFETY_CHECKS(); public: - // The different event types that can be processed by NavigationThrottles. - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - // This type is also used in the UKM as set in the RecordDeferTimeUKM(). - // - // LINT.IfChange(Event) - enum class Event { - kNoEvent = 0, - kWillStartRequest = 1, - kWillRedirectRequest = 2, - kWillFailRequest = 3, - kWillProcessResponse = 4, - kWillCommitWithoutUrlLoader = 5, - kMaxValue = kWillCommitWithoutUrlLoader, - }; - // LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:NavigationThrottleEvent) - - class Delegate { - public: - // Called when the NavigationThrottleRunner is done processing the - // navigation event of type |event|. |result| is the final - // NavigationThrottle::ThrottleCheckResult for this event. - virtual void OnNavigationEventProcessed( - Event event, - NavigationThrottle::ThrottleCheckResult result) = 0; - }; - - NavigationThrottleRunner(Delegate* delegate, + // `registry` should outlive this instance. + NavigationThrottleRunner(NavigationThrottleRegistryBase* registry, int64_t navigation_id, bool is_primary_main_frame); NavigationThrottleRunner(const NavigationThrottleRunner&) = delete; NavigationThrottleRunner& operator=(const NavigationThrottleRunner&) = delete; - ~NavigationThrottleRunner() override; - - // Implements NavigationThrottleRegistry: - NavigationHandle& GetNavigationHandle() override; - void AddThrottle( - std::unique_ptr<NavigationThrottle> navigation_throttle) override; - void MaybeAddThrottle( - std::unique_ptr<NavigationThrottle> navigation_throttle) override; + ~NavigationThrottleRunner(); // Will call the appropriate NavigationThrottle function based on |event| on // all NavigationThrottles owned by this NavigationThrottleRunner. - void ProcessNavigationEvent(Event event); + void ProcessNavigationEvent(NavigationThrottleEvent event); // Resumes calling the appropriate NavigationThrottle functions for |event_| // on all NavigationThrottles that have not yet been notified. @@ -94,16 +55,6 @@ // deferring NavigationThrottle do the resuming. void CallResumeForTesting(); - // Registers the appropriate NavigationThrottles are added for a "standard" - // navigation (i.e., one with a URLLoader that goes through the - // WillSendRequest/WillProcessResponse callback sequence). - void RegisterNavigationThrottles(); - - // Registers the appropriate NavigationThrottles for a navigation that can - // immediately commit because no URLLoader is required (about:blank, - // about:srcdoc, and most same-document navigations). - void RegisterNavigationThrottlesForCommitWithoutUrlLoader(); - // Returns the throttle that is currently deferring the navigation (i.e. the // throttle at index |next_index_ -1|). If the handle is not deferred, returns // nullptr; @@ -115,15 +66,12 @@ private: void ProcessInternal(); - void InformDelegate(const NavigationThrottle::ThrottleCheckResult& result); + void InformRegistry(const NavigationThrottle::ThrottleCheckResult& result); // Records UKM about the deferring throttle when the navigation is resumed. void RecordDeferTimeUKM(); - const raw_ptr<Delegate> delegate_; - - // A list of Throttles registered for this navigation. - std::vector<std::unique_ptr<NavigationThrottle>> throttles_; + const raw_ref<NavigationThrottleRegistryBase> registry_; // The index of the next throttle to check. size_t next_index_; @@ -156,7 +104,8 @@ base::OnceClosure first_deferral_callback_for_testing_; // The event currently being processed. - Event current_event_ = Event::kNoEvent; + NavigationThrottleEvent current_event_ = + NavigationThrottleEvent::kNoEvent; // Whether the navigation is in the primary main frame. bool is_primary_main_frame_ = false;
diff --git a/content/browser/renderer_host/navigation_throttle_runner_unittest.cc b/content/browser/renderer_host/navigation_throttle_runner_unittest.cc index 78c742a..a44c16da 100644 --- a/content/browser/renderer_host/navigation_throttle_runner_unittest.cc +++ b/content/browser/renderer_host/navigation_throttle_runner_unittest.cc
@@ -9,10 +9,10 @@ #include "base/functional/bind.h" #include "base/metrics/metrics_hashes.h" #include "components/ukm/test_ukm_recorder.h" +#include "content/browser/renderer_host/navigation_throttle_registry_impl.h" #include "content/public/browser/navigation_throttle.h" #include "content/public/common/url_constants.h" #include "content/public/test/mock_navigation_handle.h" -#include "content/public/test/mock_navigation_throttle_registry.h" #include "content/public/test/test_navigation_throttle.h" #include "content/public/test/test_renderer_host.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -63,10 +63,11 @@ }; class NavigationThrottleRunnerTest : public RenderViewHostTestHarness, - public NavigationThrottleRunner::Delegate { + public NavigationThrottleRegistryBase { public: NavigationThrottleRunnerTest() : delegate_result_(NavigationThrottle::DEFER) {} + ~NavigationThrottleRunnerTest() override = default; void SetUp() override { RenderViewHostTestHarness::SetUp(); @@ -75,10 +76,10 @@ void Resume() { runner_->CallResumeForTesting(); } - void SimulateEvent(NavigationThrottleRunner::Event event) { + void SimulateEvent(NavigationThrottleEvent event) { was_delegate_notified_ = false; delegate_result_ = NavigationThrottle::DEFER; - observer_last_event_ = NavigationThrottleRunner::Event::kNoEvent; + observer_last_event_ = NavigationThrottleEvent::kNoEvent; runner_->ProcessNavigationEvent(event); } @@ -90,7 +91,7 @@ return delegate_result_; } - NavigationThrottleRunner::Event observer_last_event() const { + NavigationThrottleEvent observer_last_event() const { return observer_last_event_; } @@ -110,36 +111,36 @@ } void CheckNotifiedOfEvent(TestNavigationThrottle* throttle, - NavigationThrottleRunner::Event event) { - if (event == NavigationThrottleRunner::Event::kWillStartRequest) { + NavigationThrottleEvent event) { + if (event == NavigationThrottleEvent::kWillStartRequest) { CHECK_EQ(1, throttle->GetCallCount( TestNavigationThrottle::WILL_START_REQUEST)); } else { CHECK_EQ(0, throttle->GetCallCount( TestNavigationThrottle::WILL_START_REQUEST)); } - if (event == NavigationThrottleRunner::Event::kWillRedirectRequest) { + if (event == NavigationThrottleEvent::kWillRedirectRequest) { CHECK_EQ(1, throttle->GetCallCount( TestNavigationThrottle::WILL_REDIRECT_REQUEST)); } else { CHECK_EQ(0, throttle->GetCallCount( TestNavigationThrottle::WILL_REDIRECT_REQUEST)); } - if (event == NavigationThrottleRunner::Event::kWillFailRequest) { + if (event == NavigationThrottleEvent::kWillFailRequest) { CHECK_EQ( 1, throttle->GetCallCount(TestNavigationThrottle::WILL_FAIL_REQUEST)); } else { CHECK_EQ( 0, throttle->GetCallCount(TestNavigationThrottle::WILL_FAIL_REQUEST)); } - if (event == NavigationThrottleRunner::Event::kWillProcessResponse) { + if (event == NavigationThrottleEvent::kWillProcessResponse) { CHECK_EQ(1, throttle->GetCallCount( TestNavigationThrottle::WILL_PROCESS_RESPONSE)); } else { CHECK_EQ(0, throttle->GetCallCount( TestNavigationThrottle::WILL_PROCESS_RESPONSE)); } - if (event == NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader) { + if (event == NavigationThrottleEvent::kWillCommitWithoutUrlLoader) { CHECK_EQ(1, throttle->GetCallCount( TestNavigationThrottle::WILL_COMMIT_WITHOUT_URL_LOADER)); } else { @@ -152,12 +153,10 @@ // synchronously return |result| on checks by default. TestNavigationThrottle* CreateTestNavigationThrottle( NavigationThrottle::ThrottleCheckResult result) { - TestNavigationThrottle* test_throttle = - new TestNavigationThrottle(registry_); + TestNavigationThrottle* test_throttle = new TestNavigationThrottle(*this); test_throttle->SetResponseForAllMethods(TestNavigationThrottle::SYNCHRONOUS, result); - runner_->AddThrottle( - std::unique_ptr<TestNavigationThrottle>(test_throttle)); + AddThrottle(std::unique_ptr<TestNavigationThrottle>(test_throttle)); return test_throttle; } @@ -177,39 +176,51 @@ // Creates and register a NavigationThrottle that will delete the // NavigationHandle in checks. void AddDeletingNavigationThrottle() { - runner_->AddThrottle(std::make_unique<DeletingNavigationThrottle>( - registry_, - base::BindRepeating( - &NavigationThrottleRunnerTest::ResetNavigationThrottleRunner, - base::Unretained(this)))); + AddThrottle(std::make_unique<DeletingNavigationThrottle>( + *this, base::BindRepeating( + &NavigationThrottleRunnerTest::ResetNavigationThrottleRunner, + base::Unretained(this)))); } ukm::TestUkmRecorder& test_ukm_recorder() { return test_ukm_recorder_; } private: - // NavigationThrottleRunner::Delegate: - void OnNavigationEventProcessed( - NavigationThrottleRunner::Event event, + // NavigationThrottleRegistry: + NavigationHandle& GetNavigationHandle() override { return handle_; } + void AddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) override { + throttles_.push_back(std::move(navigation_throttle)); + } + void MaybeAddThrottle( + std::unique_ptr<NavigationThrottle> navigation_throttle) override { + if (navigation_throttle) { + AddThrottle(std::move(navigation_throttle)); + } + } + // NavigationThrottleRegistryBase: + void OnEventProcessed( + NavigationThrottleEvent event, NavigationThrottle::ThrottleCheckResult result) override { DCHECK(!was_delegate_notified_); delegate_result_ = result; was_delegate_notified_ = true; observer_last_event_ = event; } + std::vector<std::unique_ptr<NavigationThrottle>>& GetThrottles() override { + return throttles_; + } + NavigationThrottle& GetThrottleAtIndex(size_t index) override { + EXPECT_LT(index, throttles_.size()); + return *throttles_[index]; + } void ResetNavigationThrottleRunner() { runner_.reset(); } MockNavigationHandle handle_; - // Used to construct NavigationThrottle inheritances as the `runner` instance - // created in this test doesn't handle GetNavigationHandle() correctly for an - // unexpected downcast. - // TODO(https://crbug.com/412524375) Should be fixed together with the - // `Delegate` issue, tried at https://crrev.com/c/6508568. - MockNavigationThrottleRegistry registry_ = - MockNavigationThrottleRegistry(&handle_); + std::vector<std::unique_ptr<NavigationThrottle>> throttles_; std::unique_ptr<NavigationThrottleRunner> runner_; - NavigationThrottleRunner::Event observer_last_event_ = - NavigationThrottleRunner::Event::kNoEvent; + NavigationThrottleEvent observer_last_event_ = + NavigationThrottleEvent::kNoEvent; bool was_delegate_notified_ = false; NavigationThrottle::ThrottleCheckResult delegate_result_; ukm::TestAutoSetUkmRecorder test_ukm_recorder_; @@ -217,23 +228,23 @@ class NavigationThrottleRunnerTestWithEvent : public NavigationThrottleRunnerTest, - public testing::WithParamInterface<NavigationThrottleRunner::Event> { + public testing::WithParamInterface<NavigationThrottleEvent> { public: - NavigationThrottleRunnerTestWithEvent() : NavigationThrottleRunnerTest() {} - ~NavigationThrottleRunnerTestWithEvent() override {} + NavigationThrottleRunnerTestWithEvent() = default; + ~NavigationThrottleRunnerTestWithEvent() override = default; void SetUp() override { NavigationThrottleRunnerTest::SetUp(); event_ = GetParam(); } - NavigationThrottleRunner::Event event() const { return event_; } + NavigationThrottleEvent event() const { return event_; } void CheckNotified(TestNavigationThrottle* throttle) { CheckNotifiedOfEvent(throttle, event()); } private: - NavigationThrottleRunner::Event event_; + NavigationThrottleEvent event_; }; // Checks that a navigation deferred by a NavigationThrottle can be properly @@ -286,27 +297,25 @@ INSTANTIATE_TEST_SUITE_P( AllEvents, NavigationThrottleRunnerTestWithEvent, - ::testing::Values( - NavigationThrottleRunner::Event::kWillStartRequest, - NavigationThrottleRunner::Event::kWillRedirectRequest, - NavigationThrottleRunner::Event::kWillFailRequest, - NavigationThrottleRunner::Event::kWillProcessResponse, - NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader)); + ::testing::Values(NavigationThrottleEvent::kWillStartRequest, + NavigationThrottleEvent::kWillRedirectRequest, + NavigationThrottleEvent::kWillFailRequest, + NavigationThrottleEvent::kWillProcessResponse, + NavigationThrottleEvent::kWillCommitWithoutUrlLoader)); class NavigationThrottleRunnerTestWithEventAndAction : public NavigationThrottleRunnerTest, public testing::WithParamInterface< - std::tuple<NavigationThrottleRunner::Event, + std::tuple<NavigationThrottleEvent, NavigationThrottle::ThrottleAction>> { public: - NavigationThrottleRunnerTestWithEventAndAction() - : NavigationThrottleRunnerTest() {} - ~NavigationThrottleRunnerTestWithEventAndAction() override {} + NavigationThrottleRunnerTestWithEventAndAction() = default; + ~NavigationThrottleRunnerTestWithEventAndAction() override = default; void SetUp() override { NavigationThrottleRunnerTest::SetUp(); std::tie(event_, action_) = GetParam(); } - NavigationThrottleRunner::Event event() const { return event_; } + NavigationThrottleEvent event() const { return event_; } NavigationThrottle::ThrottleAction action() const { return action_; } void CheckNotified(TestNavigationThrottle* throttle) { @@ -314,7 +323,7 @@ } private: - NavigationThrottleRunner::Event event_; + NavigationThrottleEvent event_; NavigationThrottle::ThrottleAction action_; }; @@ -437,12 +446,11 @@ AllEvents, NavigationThrottleRunnerTestWithEventAndAction, ::testing::Combine( - ::testing::Values( - NavigationThrottleRunner::Event::kWillStartRequest, - NavigationThrottleRunner::Event::kWillRedirectRequest, - NavigationThrottleRunner::Event::kWillFailRequest, - NavigationThrottleRunner::Event::kWillProcessResponse, - NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader), + ::testing::Values(NavigationThrottleEvent::kWillStartRequest, + NavigationThrottleEvent::kWillRedirectRequest, + NavigationThrottleEvent::kWillFailRequest, + NavigationThrottleEvent::kWillProcessResponse, + NavigationThrottleEvent::kWillCommitWithoutUrlLoader), ::testing::Values(NavigationThrottle::PROCEED, NavigationThrottle::CANCEL, NavigationThrottle::CANCEL_AND_IGNORE, @@ -453,18 +461,17 @@ class NavigationThrottleRunnerTestWithEventAndError : public NavigationThrottleRunnerTest, public testing::WithParamInterface< - std::tuple<NavigationThrottleRunner::Event, + std::tuple<NavigationThrottleEvent, net::Error, std::optional<std::string>>> { public: - NavigationThrottleRunnerTestWithEventAndError() - : NavigationThrottleRunnerTest() {} - ~NavigationThrottleRunnerTestWithEventAndError() override {} + NavigationThrottleRunnerTestWithEventAndError() = default; + ~NavigationThrottleRunnerTestWithEventAndError() override = default; void SetUp() override { NavigationThrottleRunnerTest::SetUp(); std::tie(event_, error_, custom_error_page_) = GetParam(); } - NavigationThrottleRunner::Event event() const { return event_; } + NavigationThrottleEvent event() const { return event_; } net::Error error() const { return error_; } const std::optional<std::string>& custom_error_page() const { return custom_error_page_; @@ -475,7 +482,7 @@ } private: - NavigationThrottleRunner::Event event_; + NavigationThrottleEvent event_; net::Error error_; std::optional<std::string> custom_error_page_ = std::nullopt; }; @@ -518,12 +525,11 @@ AllEvents, NavigationThrottleRunnerTestWithEventAndError, ::testing::Combine( - ::testing::Values( - NavigationThrottleRunner::Event::kWillStartRequest, - NavigationThrottleRunner::Event::kWillRedirectRequest, - NavigationThrottleRunner::Event::kWillFailRequest, - NavigationThrottleRunner::Event::kWillProcessResponse, - NavigationThrottleRunner::Event::kWillCommitWithoutUrlLoader), + ::testing::Values(NavigationThrottleEvent::kWillStartRequest, + NavigationThrottleEvent::kWillRedirectRequest, + NavigationThrottleEvent::kWillFailRequest, + NavigationThrottleEvent::kWillProcessResponse, + NavigationThrottleEvent::kWillCommitWithoutUrlLoader), ::testing::Values(net::ERR_BLOCKED_BY_ADMINISTRATOR, net::ERR_ABORTED), ::testing::Values(std::nullopt, "<html><body>test</body></html>")));
diff --git a/content/browser/renderer_host/navigator_delegate.h b/content/browser/renderer_host/navigator_delegate.h index 645edb8..5ba2ce39 100644 --- a/content/browser/renderer_host/navigator_delegate.h +++ b/content/browser/renderer_host/navigator_delegate.h
@@ -35,6 +35,7 @@ class NavigationRequest; class NavigationThrottleRegistry; class RenderFrameHostImpl; +class WebContents; struct LoadCommittedDetails; struct OpenURLParams;
diff --git a/content/browser/renderer_host/p2p/socket_dispatcher_host.h b/content/browser/renderer_host/p2p/socket_dispatcher_host.h index bf918d9f..d1300efd 100644 --- a/content/browser/renderer_host/p2p/socket_dispatcher_host.h +++ b/content/browser/renderer_host/p2p/socket_dispatcher_host.h
@@ -13,6 +13,7 @@ #include "base/memory/weak_ptr.h" #include "base/task/sequenced_task_runner.h" +#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/public/browser/render_process_host.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h"
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 00ef9be..113ce66 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -55,6 +55,7 @@ #include "base/timer/timer.h" #include "base/trace_event/optional_trace_event.h" #include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_id_helper.h" #include "base/types/optional_util.h" #include "base/uuid.h" #include "build/build_config.h"
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index 2e91a52..a24665b 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -24,9 +24,7 @@ #include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/named_trigger.h" -#include "base/trace_event/trace_event.h" #include "base/trace_event/typed_macros.h" #include "base/types/cxx23_to_underlying.h" #include "base/types/expected.h"
diff --git a/content/browser/renderer_host/spare_render_process_host_manager_impl.cc b/content/browser/renderer_host/spare_render_process_host_manager_impl.cc index debe95af..69682bb 100644 --- a/content/browser/renderer_host/spare_render_process_host_manager_impl.cc +++ b/content/browser/renderer_host/spare_render_process_host_manager_impl.cc
@@ -51,6 +51,8 @@ "kSpareRPHKeepOneAliveOnMemoryPressure", base::FEATURE_DISABLED_BY_DEFAULT); +constexpr char kSpareProcessMaybeTakeActionUmaName[] = + "BrowserRenderProcessHost.SpareProcessMaybeTakeAction"; constexpr char kSpareRendererTakenTimeSinceCreation[] = "BrowserRenderProcessHost.SpareRendererTaken.TimeSinceCreation"; constexpr char kSpareRendererTakenIsReady[] = @@ -266,10 +268,18 @@ } } -void LogSpareProcessTakeActionUMAs(RenderProcessHost* host, - SpareProcessMaybeTakeAction action) { - base::UmaHistogramEnumeration( - "BrowserRenderProcessHost.SpareProcessMaybeTakeAction", action); +void LogSpareProcessTakeActionUMAs( + RenderProcessHost* host, + SpareProcessMaybeTakeAction action, + const ProcessAllocationContext& allocation_context) { + base::UmaHistogramEnumeration(kSpareProcessMaybeTakeActionUmaName, action); + if (allocation_context.source == + ProcessAllocationSource::kNavigationRequest) { + base::UmaHistogramEnumeration( + base::StrCat( + {kSpareProcessMaybeTakeActionUmaName, ".NavigationRequest"}), + action); + } if (action == SpareProcessMaybeTakeAction::kSpareTaken) { CHECK(host); base::UmaHistogramBoolean(kSpareRendererTakenIsReady, host->IsReady()); @@ -593,7 +603,7 @@ } else { action = SpareProcessMaybeTakeAction::kSpareTaken; } - LogSpareProcessTakeActionUMAs(next_spare_rph, action); + LogSpareProcessTakeActionUMAs(next_spare_rph, action, allocation_context); if (spare_renderer_maybe_take_timer_) { auto maybe_take_time = spare_renderer_maybe_take_timer_->Elapsed();
diff --git a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc index 863b1ac2..c4f9851 100644 --- a/content/browser/renderer_host/unassigned_site_instance_browsertest.cc +++ b/content/browser/renderer_host/unassigned_site_instance_browsertest.cc
@@ -410,7 +410,7 @@ EXPECT_TRUE(popup_si->HasSite()); EXPECT_EQ(popup_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); } @@ -444,7 +444,7 @@ EXPECT_TRUE(popup_si->HasSite()); EXPECT_EQ(popup_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); } @@ -477,7 +477,7 @@ EXPECT_TRUE(popup_si->HasSite()); EXPECT_EQ(popup_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); } @@ -514,7 +514,7 @@ EXPECT_TRUE(popup_si->HasSite()); EXPECT_EQ(popup_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); } @@ -613,7 +613,7 @@ EXPECT_TRUE(iframe_si->HasSite()); EXPECT_EQ(iframe_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(iframe_si->IsDefaultSiteInstance()); } @@ -647,7 +647,7 @@ EXPECT_TRUE(iframe_si->HasSite()); EXPECT_EQ(iframe_si, original_si); - if (!AreAllSitesIsolatedForTesting()) { + if (!AreStrictSiteInstancesEnabled()) { EXPECT_TRUE(iframe_si->IsDefaultSiteInstance()); } @@ -658,7 +658,7 @@ scoped_refptr<SiteInstanceImpl> post_navigation_si = original_rfh->child_at(0)->current_frame_host()->GetSiteInstance(); - if (AreAllSitesIsolatedForTesting()) { + if (AreStrictSiteInstancesEnabled()) { EXPECT_FALSE(post_navigation_si->HasSite()); EXPECT_TRUE(post_navigation_si->IsRelatedSiteInstance(original_si.get())); } else { @@ -690,7 +690,7 @@ EXPECT_EQ(instance1, web_contents()->GetPrimaryMainFrame()->GetSiteInstance()); EXPECT_TRUE(instance1->HasSite()); - if (AreAllSitesIsolatedForTesting()) { + if (AreStrictSiteInstancesEnabled()) { EXPECT_EQ(RegularUrlOriginMaybeWithPort(), instance1->GetSiteURL()); } else { EXPECT_TRUE(instance1->IsDefaultSiteInstance()); @@ -724,7 +724,7 @@ EXPECT_TRUE(NavigateToURL(shell(), other_regular_url)); exit_observer.Wait(); - if (AreAllSitesIsolatedForTesting()) { + if (AreStrictSiteInstancesEnabled()) { EXPECT_NE(instance1, web_contents()->GetPrimaryMainFrame()->GetSiteInstance()); } else { @@ -746,6 +746,12 @@ // In site-per-process, we cannot use foo.com's SiteInstance for a.com. EXPECT_FALSE(instance1->IsSuitableForUrlInfo( UrlInfo::CreateForTesting(embedder_defined_unassigned_url()))); + } else if (AreStrictSiteInstancesEnabled()) { + // If neither foo.com nor a.com require dedicated processes, and we're using + // default SiteInstanceGroup instead of default SiteInstance, then we can + // use the same process. + EXPECT_TRUE(instance1->IsSuitableForUrlInfo( + UrlInfo::CreateForTesting(embedder_defined_unassigned_url()))); } else { // Since |instance1| is a default SiteInstance AND this test explicitly // ensures that ShouldAssignSiteForURL(url1) will return false, |url1|
diff --git a/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc b/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc index beec338d..e1a59ee2 100644 --- a/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc +++ b/content/browser/security/coop/cross_origin_opener_policy_browsertest.cc
@@ -4139,8 +4139,34 @@ ->GetProcess() ->GetProcessLock() .is_locked_to_site()); - histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.None", - false, 1); + + // The metric for why we failed to reuse the process will be reported + // differently depending on whether default SiteInstanceGroups are enabled. + // For more information, see how "Navigation.ProcessReuseOnCOOP" is emitted + // in `RenderFrameHostManager::GetSiteInstanceForNavigation()`. Importantly, + // the sample (i.e., whether actual process reuse happened) should be + // reported as false in both cases. + if (ShouldUseDefaultSiteInstanceGroup()) { + // With default SiteInstanceGroups, if we created a new candidate + // SiteInstance at the start of the navigation to `url_2`, then the reason + // will be recorded as "DifferentSiteInstance". This is the case when a + // speculative RFH is created, which requires either bfcache or + // RenderDocument (see also `speculative_rfh` expectations above). + // Otherwise, the reason will be recorded as + // "SameSiteNavigationInSingleWebContents". + if (IsBackForwardCacheEnabled() || ShouldCreateNewHostForAllFrames()) { + histogram_tester.ExpectUniqueSample( + "Navigation.ProcessReuseOnCOOP.DifferentSiteInstance", false, 1); + } else { + histogram_tester.ExpectUniqueSample( + "Navigation.ProcessReuseOnCOOP." + "SameSiteNavigationInSingleWebContents", + false, 1); + } + } else { + histogram_tester.ExpectUniqueSample("Navigation.ProcessReuseOnCOOP.None", + false, 1); + } } else { EXPECT_EQ(rph_id_2, rph_id_3);
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index c09abca5..d623c53 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -433,7 +433,7 @@ wrapper() ->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() .FlushForTesting(); content::RunAllTasksUntilIdle(); wrapper_ = nullptr;
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc index 3adfd43..aededd7 100644 --- a/content/browser/service_worker/service_worker_container_host.cc +++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -230,7 +230,7 @@ service_worker_security_utils::GetCorrectStorageKeyForWebSecurityState( service_worker_client().key(), client_url); - context()->registry()->FindRegistrationForClientUrl( + context()->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, client_url, key, base::BindOnce( &ServiceWorkerContainerHostForClient::GetRegistrationComplete, @@ -263,7 +263,7 @@ "ServiceWorker", "ServiceWorkerContainerHost::GetRegistrations", TRACE_ID_WITH_SCOPE("ServiceWorkerContainerHost::GetRegistrations", trace_id)); - context()->registry()->GetRegistrationsForStorageKey( + context()->registry().GetRegistrationsForStorageKey( service_worker_client().key(), base::BindOnce( &ServiceWorkerContainerHostForClient::GetRegistrationsComplete,
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index 8164648..6477b21 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -629,7 +629,7 @@ void ServiceWorkerContextCore::DeleteForStorageKey(const blink::StorageKey& key, StatusCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - registry()->GetRegistrationsForStorageKey( + registry().GetRegistrationsForStorageKey( key, base::BindOnce( &ServiceWorkerContextCore::DidGetRegistrationsForDeleteForStorageKey, @@ -651,7 +651,7 @@ // unload. std::vector<scoped_refptr<ServiceWorkerRegistration>> uninstalling_registrations = - registry()->GetUninstallingRegistrationsForStorageKey(key); + registry().GetUninstallingRegistrationsForStorageKey(key); for (const auto& uninstalling_registration : uninstalling_registrations) { job_coordinator_->Abort(uninstalling_registration->scope(), key); uninstalling_registration->DeleteAndClearImmediately(); @@ -1069,7 +1069,7 @@ } } - registry()->DeleteAndStartOver(std::move(callback)); + registry().DeleteAndStartOver(std::move(callback)); } void ServiceWorkerContextCore::ClearAllServiceWorkersForTest( @@ -1082,7 +1082,7 @@ return; } was_service_worker_registered_ = false; - registry()->GetAllRegistrationsInfos( + registry().GetAllRegistrationsInfos( base::BindOnce(&ClearAllServiceWorkersHelper::DidGetAllRegistrations, helper, AsWeakPtr())); } @@ -1091,7 +1091,7 @@ const GURL& url, const blink::StorageKey& key, ServiceWorkerContext::CheckHasServiceWorkerCallback callback) { - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, url, key, base::BindOnce(&ServiceWorkerContextCore:: DidFindRegistrationForCheckHasServiceWorker,
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index 0d05dd7..3d0d86a3 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h
@@ -386,7 +386,7 @@ const GURL& source_url) override; ServiceWorkerContextWrapper* wrapper() const { return wrapper_; } - ServiceWorkerRegistry* registry() { return ®istry_; } + ServiceWorkerRegistry& registry() { return registry_; } mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& GetStorageControl(); ServiceWorkerProcessManager* process_manager();
diff --git a/content/browser/service_worker/service_worker_context_core_unittest.cc b/content/browser/service_worker/service_worker_context_core_unittest.cc index 4db6975..fcbd8b4e 100644 --- a/content/browser/service_worker/service_worker_context_core_unittest.cc +++ b/content/browser/service_worker/service_worker_context_core_unittest.cc
@@ -100,7 +100,7 @@ const blink::StorageKey& key) { base::RunLoop loop; blink::ServiceWorkerStatusCode status; - context()->registry()->FindRegistrationForScope( + context()->registry().FindRegistrationForScope( scope, key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode result_status, @@ -332,7 +332,7 @@ })); // Disable storage before it finishes. This causes the Unregister job to // complete with an error. - context()->registry()->DisableStorageForTesting(base::DoNothing()); + context()->registry().DisableStorageForTesting(base::DoNothing()); loop.Run(); // The operation should still complete.
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc index c31d30e..b2e4b9e 100644 --- a/content/browser/service_worker/service_worker_context_unittest.cc +++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -686,7 +686,7 @@ EXPECT_EQ(scope, notifications_[1].scope); EXPECT_EQ(registration_id, notifications_[1].registration_id); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, blink::StorageKey::CreateFirstParty(url::Origin::Create(scope)), base::BindOnce(&ExpectRegisteredWorkers, @@ -741,7 +741,7 @@ EXPECT_EQ(scope, notifications_[0].scope); EXPECT_EQ(registration_id, notifications_[0].registration_id); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, blink::StorageKey::CreateFirstParty(url::Origin::Create(scope)), base::BindOnce(&ExpectRegisteredWorkers, @@ -797,7 +797,7 @@ EXPECT_EQ(scope, notifications_[1].scope); EXPECT_EQ(registration_id, notifications_[1].registration_id); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, blink::StorageKey::CreateFirstParty(url::Origin::Create(scope)), base::BindOnce(&ExpectRegisteredWorkers, @@ -836,7 +836,7 @@ base::RunLoop().RunUntilIdle(); ASSERT_TRUE(called); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, blink::StorageKey::CreateFirstParty(url::Origin::Create(scope)), base::BindOnce(&ExpectRegisteredWorkers, @@ -953,23 +953,23 @@ base::RunLoop().RunUntilIdle(); ASSERT_TRUE(called); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id1, key1, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kErrorNotFound, false /* expect_waiting */, false /* expect_active */)); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id2, key1, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kErrorNotFound, false /* expect_waiting */, false /* expect_active */)); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id3, key2, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kOk, false /* expect_waiting */, true /* expect_active */)); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id4, key3, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kOk, @@ -1229,7 +1229,7 @@ content::RunAllTasksUntilIdle(); EXPECT_TRUE(called); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, key, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kOk, @@ -1247,7 +1247,7 @@ // The storage is disabled while the recovery process is running, so the // operation should be aborted. - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, key, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kErrorAbort, @@ -1256,7 +1256,7 @@ // The context started over and the storage was re-initialized, so the // registration should not be found. - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, key, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kErrorNotFound, @@ -1297,7 +1297,7 @@ content::RunAllTasksUntilIdle(); EXPECT_TRUE(called); - context()->registry()->FindRegistrationForId( + context()->registry().FindRegistrationForId( registration_id, key, base::BindOnce(&ExpectRegisteredWorkers, blink::ServiceWorkerStatusCode::kOk,
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index bc49553..8f13f7d5 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -80,9 +80,13 @@ namespace { -BASE_FEATURE(kBackgroundUpdateForRegisteredStorageKeys, - "BackgroundUpdateForRegisteredStorageKeys", - base::FEATURE_DISABLED_BY_DEFAULT); +// Another switch for `kServiceWorkerBackgroundUpdateForRegisteredStorageKeys` +// intended to be controlled from Field Trial (e.g. kill-switch). The original +// flag may be overridden by `AwFieldTrials::RegisterFeatureOverrides`. +BASE_FEATURE( + kServiceWorkerBackgroundUpdateForRegisteredStorageKeysFieldTrialControlled, + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeysFieldTrialControlled", + base::FEATURE_ENABLED_BY_DEFAULT); // Translate a ServiceWorkerVersion::Status to a // ServiceWorkerRunningInfo::ServiceWorkerVersionStatus. @@ -274,7 +278,10 @@ process_manager_(std::make_unique<ServiceWorkerProcessManager>()), storage_shared_buffer_( base::FeatureList::IsEnabled( - kBackgroundUpdateForRegisteredStorageKeys) + features:: + kServiceWorkerBackgroundUpdateForRegisteredStorageKeys) && + base::FeatureList::IsEnabled( + kServiceWorkerBackgroundUpdateForRegisteredStorageKeysFieldTrialControlled) ? base::MakeRefCounted< storage::ServiceWorkerStorage::StorageSharedBuffer>( /*enable_registered_storage_keys=*/true) @@ -754,7 +761,7 @@ base::BindOnce(std::move(callback), std::vector<StorageUsageInfo>())); return; } - context()->registry()->GetAllRegistrationsInfos(base::BindOnce( + context()->registry().GetAllRegistrationsInfos(base::BindOnce( &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllStorageKeys, this, std::move(callback))); } @@ -973,7 +980,7 @@ TRACE_EVENT1("ServiceWorker", "StartServiceWorkerForNavigationHint", "document_url", document_url.spec()); - context_core_->registry()->FindRegistrationForClientUrl( + context_core_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, net::SimplifyUrlForRequest(document_url), key, base::BindOnce( @@ -1186,7 +1193,7 @@ nullptr); return; } - context_core_->registry()->FindRegistrationForClientUrl( + context_core_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, net::SimplifyUrlForRequest(client_url), key, base::BindOnce( @@ -1205,7 +1212,7 @@ return; } const bool include_installing_version = false; - context_core_->registry()->FindRegistrationForScope( + context_core_->registry().FindRegistrationForScope( net::SimplifyUrlForRequest(scope), key, base::BindOnce( &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, @@ -1232,7 +1239,7 @@ nullptr); return; } - context_core_->registry()->FindRegistrationForId( + context_core_->registry().FindRegistrationForId( registration_id, key, base::BindOnce( &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, @@ -1248,7 +1255,7 @@ nullptr); return; } - context_core_->registry()->FindRegistrationForIdOnly( + context_core_->registry().FindRegistrationForIdOnly( registration_id, base::BindOnce( &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, @@ -1266,7 +1273,7 @@ std::vector<ServiceWorkerRegistrationInfo>())); return; } - context_core_->registry()->GetAllRegistrationsInfos(std::move(callback)); + context_core_->registry().GetAllRegistrationsInfos(std::move(callback)); } void ServiceWorkerContextWrapper::GetRegistrationsForStorageKey( @@ -1281,8 +1288,8 @@ std::vector<scoped_refptr<ServiceWorkerRegistration>>())); return; } - context_core_->registry()->GetRegistrationsForStorageKey(key, - std::move(callback)); + context_core_->registry().GetRegistrationsForStorageKey(key, + std::move(callback)); } void ServiceWorkerContextWrapper::GetRegistrationUserData( @@ -1298,8 +1305,8 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->GetUserData(registration_id, keys, - std::move(callback)); + context_core_->registry().GetUserData(registration_id, keys, + std::move(callback)); } void ServiceWorkerContextWrapper::GetRegistrationUserDataByKeyPrefix( @@ -1315,8 +1322,8 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->GetUserDataByKeyPrefix(registration_id, key_prefix, - std::move(callback)); + context_core_->registry().GetUserDataByKeyPrefix(registration_id, key_prefix, + std::move(callback)); } void ServiceWorkerContextWrapper::GetRegistrationUserKeysAndDataByKeyPrefix( @@ -1332,7 +1339,7 @@ base::flat_map<std::string, std::string>())); return; } - context_core_->registry()->GetUserKeysAndDataByKeyPrefix( + context_core_->registry().GetUserKeysAndDataByKeyPrefix( registration_id, key_prefix, std::move(callback)); } @@ -1349,8 +1356,8 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->StoreUserData( - registration_id, key, key_value_pairs, std::move(callback)); + context_core_->registry().StoreUserData(registration_id, key, key_value_pairs, + std::move(callback)); } void ServiceWorkerContextWrapper::ClearRegistrationUserData( @@ -1366,8 +1373,8 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->ClearUserData(registration_id, keys, - std::move(callback)); + context_core_->registry().ClearUserData(registration_id, keys, + std::move(callback)); } void ServiceWorkerContextWrapper::ClearRegistrationUserDataByKeyPrefixes( @@ -1382,7 +1389,7 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->ClearUserDataByKeyPrefixes( + context_core_->registry().ClearUserDataByKeyPrefixes( registration_id, key_prefixes, std::move(callback)); } @@ -1397,8 +1404,8 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->GetUserDataForAllRegistrations( - key, std::move(callback)); + context_core_->registry().GetUserDataForAllRegistrations(key, + std::move(callback)); } void ServiceWorkerContextWrapper::GetUserDataForAllRegistrationsByKeyPrefix( @@ -1416,7 +1423,7 @@ return; } - context_core_->registry()->GetUserDataForAllRegistrationsByKeyPrefix( + context_core_->registry().GetUserDataForAllRegistrationsByKeyPrefix( key_prefix, std::move(callback)); } @@ -1432,7 +1439,7 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->ClearUserDataForAllRegistrationsByKeyPrefix( + context_core_->registry().ClearUserDataForAllRegistrationsByKeyPrefix( key_prefix, std::move(callback)); } @@ -1447,7 +1454,7 @@ blink::ServiceWorkerStatusCode::kErrorAbort)); return; } - context_core_->registry()->FindRegistrationForScope( + context_core_->registry().FindRegistrationForScope( net::SimplifyUrlForRequest(scope), key, base::BindOnce(&DidFindRegistrationForStartActiveWorker, std::move(callback))); @@ -1459,7 +1466,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!context_core_) return; - context_core_->registry()->FindRegistrationForScope( + context_core_->registry().FindRegistrationForScope( net::SimplifyUrlForRequest(scope), key, base::BindOnce([](blink::ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration) { @@ -1478,7 +1485,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!context_core_) return; - context_core_->registry()->FindRegistrationForScope( + context_core_->registry().FindRegistrationForScope( net::SimplifyUrlForRequest(scope), key, base::BindOnce(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate, this)); @@ -1529,7 +1536,7 @@ nullptr); return; } - context_core_->registry()->FindRegistrationForScope( + context_core_->registry().FindRegistrationForScope( net::SimplifyUrlForRequest(scope), key, base::BindOnce( &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, @@ -1559,7 +1566,7 @@ "ServiceWorkerContextWrapper::MaybeProcessPendingWarmUpRequest", "document_url", document_url.spec()); - context_core_->registry()->FindRegistrationForClientUrl( + context_core_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, net::SimplifyUrlForRequest(document_url), key, base::BindOnce(&ServiceWorkerContextWrapper::DidFindRegistrationForWarmUp,
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index 86a9488..d0e8d44 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -443,10 +443,6 @@ // Sets a callback to bind ServiceWorkerStorageControl for testing. void SetStorageControlBinderForTest(StorageControlBinder binder); - ServiceWorkerContextCore* GetContextCoreForTest() { - return context_core_.get(); - } - void SetForceUpdateOnPageLoadForTesting( bool force_update_on_page_load) override;
diff --git a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc index 7d1b685..c6ac09d 100644 --- a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc +++ b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc
@@ -75,13 +75,13 @@ } ServiceWorkerContextCore* context() { return wrapper_->context(); } - ServiceWorkerRegistry* registry() { return context()->registry(); } + ServiceWorkerRegistry& registry() { return context()->registry(); } blink::ServiceWorkerStatusCode StoreRegistration( scoped_refptr<ServiceWorkerRegistration> registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->StoreRegistration( + registry().StoreRegistration( registration.get(), registration->waiting_version(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -95,7 +95,7 @@ scoped_refptr<ServiceWorkerRegistration> registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->DeleteRegistration( + registry().DeleteRegistration( registration, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -136,7 +136,7 @@ // Store it. base::RunLoop loop; - registry()->StoreRegistration( + registry().StoreRegistration( registration.get(), registration->waiting_version(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) {
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index a63bd4c..0a045bc 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -194,7 +194,7 @@ tentative_resource_request.url.spec()); // Look up a registration. - context_->registry()->FindRegistrationForClientUrl( + context_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNavigation, service_worker_client_->url(), service_worker_client_->key(), base::BindOnce( @@ -548,7 +548,7 @@ !original_registration->installing_version()) { // Update failed. Look up the registration again since the original // registration was possibly unregistered in the meantime. - context_->registry()->FindRegistrationForClientUrl( + context_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, service_worker_client_->url(), service_worker_client_->key(), base::BindOnce( @@ -606,7 +606,7 @@ // When the status is REDUNDANT, the update failed (eg: script error), we // continue with the incumbent version. // In case unregister job may have run, look up the registration again. - context_->registry()->FindRegistrationForClientUrl( + context_->registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, service_worker_client_->url(), service_worker_client_->key(), base::BindOnce(
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc index aac71b3..3313dd5 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -261,7 +261,7 @@ registration_->SetActiveVersion(version_); { base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindOnce( [](base::OnceClosure closure, @@ -307,7 +307,7 @@ TEST_F(ServiceWorkerControlleeRequestHandlerTest, Error) { // Disabling the storage makes looking up the registration return an error. - context()->registry()->DisableStorageForTesting(base::DoNothing()); + context()->registry().DisableStorageForTesting(base::DoNothing()); // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( @@ -334,7 +334,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -366,7 +366,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -393,7 +393,7 @@ version_->SetStatus(ServiceWorkerVersion::INSTALLED); registration_->SetWaitingVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -423,7 +423,7 @@ version_->set_fetch_handler_type( ServiceWorkerVersion::FetchHandlerType::kNotSkippable); registration_->SetInstallingVersion(version_); - context()->registry()->NotifyInstallingRegistration(registration_.get()); + context()->registry().NotifyInstallingRegistration(registration_.get()); // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( @@ -452,7 +452,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -482,7 +482,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -523,7 +523,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -569,7 +569,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); })); @@ -594,7 +594,7 @@ version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); base::RunLoop loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_.get(), base::BindLambdaForTesting( [&loop](blink::ServiceWorkerStatusCode status) { loop.Quit(); }));
diff --git a/content/browser/service_worker/service_worker_device_delegate_observer_unittest.cc b/content/browser/service_worker/service_worker_device_delegate_observer_unittest.cc index e78af3ea..cc8d0acc 100644 --- a/content/browser/service_worker/service_worker_device_delegate_observer_unittest.cc +++ b/content/browser/service_worker/service_worker_device_delegate_observer_unittest.cc
@@ -123,8 +123,8 @@ void ServiceWorkerDeviceDelegateObserverTest::StoreRegistration( const RegistrationAndVersionPair& pair) { TestFuture<blink::ServiceWorkerStatusCode> status; - registry()->StoreRegistration(pair.first.get(), pair.second.get(), - status.GetCallback()); + registry().StoreRegistration(pair.first.get(), pair.second.get(), + status.GetCallback()); ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status.Get()); } @@ -189,7 +189,7 @@ EXPECT_FALSE(context()->GetLiveRegistration(registration_id)); base::test::TestFuture<storage::mojom::ServiceWorkerDatabaseStatus> delete_future; - registry()->GetRemoteStorageControl()->Delete(delete_future.GetCallback()); + registry().GetRemoteStorageControl()->Delete(delete_future.GetCallback()); EXPECT_EQ(delete_future.Take(), storage::mojom::ServiceWorkerDatabaseStatus::kOk);
diff --git a/content/browser/service_worker/service_worker_device_delegate_observer_unittest.h b/content/browser/service_worker/service_worker_device_delegate_observer_unittest.h index e0a5c2c..7b22270 100644 --- a/content/browser/service_worker/service_worker_device_delegate_observer_unittest.h +++ b/content/browser/service_worker/service_worker_device_delegate_observer_unittest.h
@@ -36,7 +36,7 @@ EmbeddedWorkerTestHelper* helper() { return helper_.get(); } ServiceWorkerContextCore* context() { return helper_->context(); } - ServiceWorkerRegistry* registry() { return context()->registry(); } + ServiceWorkerRegistry& registry() { return context()->registry(); } private: void InitializeTestHelper();
diff --git a/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc b/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc index ed9722e..d4abc57a 100644 --- a/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc +++ b/content/browser/service_worker/service_worker_hid_delegate_observer_unittest.cc
@@ -288,8 +288,8 @@ TestFuture<blink::ServiceWorkerStatusCode, scoped_refptr<ServiceWorkerRegistration>> future; - registry()->FindRegistrationForId(registration_id, key, - future.GetCallback()); + registry().FindRegistrationForId(registration_id, key, + future.GetCallback()); return future.Take(); }
diff --git a/content/browser/service_worker/service_worker_installed_scripts_sender.cc b/content/browser/service_worker/service_worker_installed_scripts_sender.cc index 817934f..350e507 100644 --- a/content/browser/service_worker/service_worker_installed_scripts_sender.cc +++ b/content/browser/service_worker/service_worker_installed_scripts_sender.cc
@@ -84,11 +84,8 @@ current_sending_url_ = script_url; mojo::Remote<storage::mojom::ServiceWorkerResourceReader> resource_reader; - owner_->context() - ->registry() - ->GetRemoteStorageControl() - ->CreateResourceReader(resource_id, - resource_reader.BindNewPipeAndPassReceiver()); + owner_->context()->registry().GetRemoteStorageControl()->CreateResourceReader( + resource_id, resource_reader.BindNewPipeAndPassReceiver()); TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("ServiceWorker", "SendingScript", this, "script_url", current_sending_url_.spec()); reader_ = std::make_unique<ServiceWorkerInstalledScriptReader>(
diff --git a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc index 74801d4..4e34e211 100644 --- a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc +++ b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
@@ -154,7 +154,7 @@ EmbeddedWorkerTestHelper* helper() { return helper_.get(); } ServiceWorkerContextCore* context() { return helper_->context(); } - ServiceWorkerRegistry* registry() { return context()->registry(); } + ServiceWorkerRegistry& registry() { return context()->registry(); } ServiceWorkerVersion* version() { return version_.get(); } private: @@ -707,7 +707,7 @@ version()->script_cache_map()->SetResources(records); base::RunLoop loop; - registry()->DisableStorageForTesting(loop.QuitClosure()); + registry().DisableStorageForTesting(loop.QuitClosure()); loop.Run(); auto sender =
diff --git a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc index b6f02714..0c06fba 100644 --- a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc +++ b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
@@ -236,7 +236,7 @@ wrapper() ->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() .FlushForTesting(); content::RunAllTasksUntilIdle(); wrapper_ = nullptr;
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index 1c3da97..af84a3a5 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -199,7 +199,7 @@ ServiceWorkerJobCoordinator* job_coordinator() const { return context()->job_coordinator(); } - ServiceWorkerRegistry* registry() const { return context()->registry(); } + ServiceWorkerRegistry& registry() const { return context()->registry(); } bool UseFirstPartyStorageKey() { return GetParam() == StorageKeyTestCase::kFirstParty; @@ -309,7 +309,7 @@ blink::ServiceWorkerStatusCode expected_status) { scoped_refptr<ServiceWorkerRegistration> registration; base::RunLoop run_loop; - registry()->FindRegistrationForScope( + registry().FindRegistrationForScope( scope, key, SaveFoundRegistration(expected_status, ®istration, run_loop.QuitClosure())); @@ -378,12 +378,12 @@ base::RunLoop run_loop; base::RepeatingClosure barrier_closure = base::BarrierClosure(2, run_loop.QuitClosure()); - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, url, key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration1, barrier_closure)); scoped_refptr<ServiceWorkerRegistration> registration2; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, url, key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2, barrier_closure)); @@ -409,14 +409,14 @@ base::RunLoop run_loop; base::RepeatingClosure barrier_closure = base::BarrierClosure(2, run_loop.QuitClosure()); - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, GURL("https://www.example.com/one"), key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration1, barrier_closure)); scoped_refptr<ServiceWorkerRegistration> registration2; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, GURL("https://www.example.com/two"), key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2, @@ -443,12 +443,12 @@ base::RunLoop run_loop; base::RepeatingClosure barrier_closure = base::BarrierClosure(2, run_loop.QuitClosure()); - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, scope1, key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration1, barrier_closure)); scoped_refptr<ServiceWorkerRegistration> registration2; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, scope2, key, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2, barrier_closure)); @@ -536,7 +536,7 @@ RunUnregisterJob(options.scope, key); WaitForVersionRunningStatus(version, blink::EmbeddedWorkerStatus::kStopped); - registry()->GetRemoteStorageControl().FlushForTesting(); + registry().GetRemoteStorageControl().FlushForTesting(); base::RunLoop().RunUntilIdle(); // The service worker registration object host and service worker object host
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc index c1f0b84..443f628 100644 --- a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
@@ -518,7 +518,7 @@ registration_->set_last_update_check(base::Time::Now()); std::optional<blink::ServiceWorkerStatusCode> status; base::RunLoop run_loop; - registry()->StoreRegistration( + registry().StoreRegistration( registration_.get(), version_.get(), ReceiveServiceWorkerStatus(&status, run_loop.QuitClosure())); run_loop.Run(); @@ -548,7 +548,7 @@ } } - ServiceWorkerRegistry* registry() { return helper_->context()->registry(); } + ServiceWorkerRegistry& registry() { return helper_->context()->registry(); } mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& GetStorageControl() { return helper_->context()->GetStorageControl();
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc index dbb5b24..da38e60 100644 --- a/content/browser/service_worker/service_worker_new_script_loader.cc +++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -156,7 +156,7 @@ mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer; version_->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() ->CreateResourceWriter(cache_resource_id, writer.BindNewPipeAndPassReceiver());
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc index b66995f..08ada3bb 100644 --- a/content/browser/service_worker/service_worker_object_host_unittest.cc +++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -145,7 +145,7 @@ // Make the registration findable via storage functions. std::optional<blink::ServiceWorkerStatusCode> status; base::RunLoop run_loop; - helper_->context()->registry()->StoreRegistration( + helper_->context()->registry().StoreRegistration( registration_.get(), version_.get(), ReceiveServiceWorkerStatus(&status, run_loop.QuitClosure())); run_loop.Run();
diff --git a/content/browser/service_worker/service_worker_quota_client.cc b/content/browser/service_worker/service_worker_quota_client.cc index afd55e7..31d32039 100644 --- a/content/browser/service_worker/service_worker_quota_client.cc +++ b/content/browser/service_worker/service_worker_quota_client.cc
@@ -56,7 +56,7 @@ std::move(callback).Run(0); return; } - context_->registry()->GetStorageUsageForStorageKey( + context_->registry().GetStorageUsageForStorageKey( bucket.storage_key, base::BindOnce(&FindUsageForStorageKey, std::move(callback))); } @@ -64,7 +64,7 @@ void ServiceWorkerQuotaClient::GetDefaultStorageKeys( GetDefaultStorageKeysCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - context_->registry()->GetRegisteredStorageKeys(std::move(callback)); + context_->registry().GetRegisteredStorageKeys(std::move(callback)); } void ServiceWorkerQuotaClient::DeleteBucketData( @@ -87,7 +87,7 @@ void ServiceWorkerQuotaClient::PerformStorageCleanup( PerformStorageCleanupCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - context_->registry()->PerformStorageCleanup(std::move(callback)); + context_->registry().PerformStorageCleanup(std::move(callback)); } } // namespace content
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc index e4471d7..97a71db 100644 --- a/content/browser/service_worker/service_worker_register_job.cc +++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -163,15 +163,15 @@ } scoped_refptr<ServiceWorkerRegistration> registration = - context_->registry()->GetUninstallingRegistration(scope_, key_); + context_->registry().GetUninstallingRegistration(scope_, key_); if (registration.get()) base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(next_step), blink::ServiceWorkerStatusCode::kOk, registration)); else - context_->registry()->FindRegistrationForScope(scope_, key_, - std::move(next_step)); + context_->registry().FindRegistrationForScope(scope_, key_, + std::move(next_step)); } void ServiceWorkerRegisterJob::Abort() { @@ -393,7 +393,7 @@ // Update resource list on the database. Pass a no-op callback as the // checksums are only used for an optimization and we don't need to wait // for the completion. - context_->registry()->UpdateResourceSha256Checksums( + context_->registry().UpdateResourceSha256Checksums( registration()->id(), key_, updated_checksum_map, base::BindOnce([](blink::ServiceWorkerStatusCode status) { UMA_HISTOGRAM_ENUMERATION( @@ -408,8 +408,8 @@ return; } - context_->registry()->NotifyInstallingRegistration(registration()); - context_->registry()->CreateNewVersion( + context_->registry().NotifyInstallingRegistration(registration()); + context_->registry().CreateNewVersion( registration(), script_url_, worker_script_type_, base::BindOnce(&ServiceWorkerRegisterJob::StartWorkerForUpdate, weak_factory_.GetWeakPtr())); @@ -421,7 +421,7 @@ blink::mojom::ServiceWorkerRegistrationOptions options( scope_, worker_script_type_, update_via_cache_); - context_->registry()->CreateNewRegistration( + context_->registry().CreateNewRegistration( options, key_, ancestor_frame_type_, base::BindOnce(&ServiceWorkerRegisterJob::ContinueWithNewRegistration, weak_factory_.GetWeakPtr())); @@ -636,14 +636,13 @@ } if (!IsUpdateCheckNeeded()) { - context_->registry()->NotifyInstallingRegistration(registration()); + context_->registry().NotifyInstallingRegistration(registration()); base::OnceCallback<void(scoped_refptr<ServiceWorkerVersion>)> next_task = base::BindOnce(&ServiceWorkerRegisterJob:: MaybeThrottleForDevToolsBeforeStartingScriptFetch, weak_factory_.GetWeakPtr()); - context_->registry()->CreateNewVersion( - registration(), script_url_, worker_script_type_, - std::move(next_task)); + context_->registry().CreateNewVersion( + registration(), script_url_, worker_script_type_, std::move(next_task)); return; } @@ -770,7 +769,7 @@ SetPhase(STORE); DCHECK(!registration()->last_update_check().is_null()); - context_->registry()->StoreRegistration( + context_->registry().StoreRegistration( registration(), new_version(), base::BindOnce(&ServiceWorkerRegisterJob::OnStoreRegistrationComplete, weak_factory_.GetWeakPtr())); @@ -865,9 +864,9 @@ if (!registration()->newest_installed_version()) { registration()->NotifyRegistrationFailed(); if (!registration()->is_deleted()) { - context_->registry()->DeleteRegistration(registration(), - base::DoNothing()); - context_->registry()->NotifyDoneUninstallingRegistration( + context_->registry().DeleteRegistration(registration(), + base::DoNothing()); + context_->registry().NotifyDoneUninstallingRegistration( registration(), ServiceWorkerRegistration::Status::kUninstalled); } } @@ -877,7 +876,7 @@ } DCHECK(callbacks_.empty()); if (registration()) { - context_->registry()->NotifyDoneInstallingRegistration( + context_->registry().NotifyDoneInstallingRegistration( registration(), new_version(), status); #if DCHECK_IS_ON() switch (registration()->status()) { @@ -965,7 +964,7 @@ registration()->set_last_update_check(base::Time::Now()); if (registration()->newest_installed_version()) { - context_->registry()->UpdateLastUpdateCheckTime( + context_->registry().UpdateLastUpdateCheckTime( registration()->id(), registration()->key(), registration()->last_update_check(), base::BindOnce([](blink::ServiceWorkerStatusCode status) {
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc index 79dff88..6f065a1c 100644 --- a/content/browser/service_worker/service_worker_registration.cc +++ b/content/browser/service_worker/service_worker_registration.cc
@@ -362,7 +362,7 @@ return; } - context_->registry()->DeleteRegistration( + context_->registry().DeleteRegistration( this, base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, this)); if (!active_version() || !active_version()->HasControllee()) @@ -372,7 +372,7 @@ void ServiceWorkerRegistration::DeleteAndClearImmediately() { DCHECK(context_); if (!is_deleted()) { - context_->registry()->DeleteRegistration( + context_->registry().DeleteRegistration( this, base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, this)); } @@ -395,14 +395,14 @@ << "attempt to resurrect a completely uninstalled registration"; } - context_->registry()->NotifyDoneUninstallingRegistration(this, - Status::kIntact); + context_->registry().NotifyDoneUninstallingRegistration(this, + Status::kIntact); scoped_refptr<ServiceWorkerVersion> most_recent_version = waiting_version() ? waiting_version() : active_version(); DCHECK(most_recent_version.get()); - context_->registry()->NotifyInstallingRegistration(this); - context_->registry()->StoreRegistration( + context_->registry().NotifyInstallingRegistration(this); + context_->registry().StoreRegistration( this, most_recent_version.get(), base::BindOnce(&ServiceWorkerRegistration::OnRestoreFinished, this, std::move(callback), most_recent_version)); @@ -613,13 +613,13 @@ // Delete the registration and its state from storage. if (status() == Status::kIntact) { - context_->registry()->DeleteRegistration( + context_->registry().DeleteRegistration( this, base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, protect)); } DCHECK(is_uninstalling()); - context_->registry()->NotifyDoneUninstallingRegistration( - this, Status::kUninstalled); + context_->registry().NotifyDoneUninstallingRegistration(this, + Status::kUninstalled); // Tell observers that this registration is gone. NotifyRegistrationFailed(); @@ -714,7 +714,7 @@ activating_version->router_evaluator()->RecordRouterRuleInfo(); } - context_->registry()->UpdateToActiveState(id(), key_, base::DoNothing()); + context_->registry().UpdateToActiveState(id(), key_, base::DoNothing()); } void ServiceWorkerRegistration::OnDeleteFinished( @@ -736,7 +736,7 @@ auto protect = base::WrapRefCounted(this); if (context_) { - context_->registry()->NotifyDoneUninstallingRegistration( + context_->registry().NotifyDoneUninstallingRegistration( this, Status::kUninstalled); } @@ -781,8 +781,8 @@ std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort); return; } - context_->registry()->NotifyDoneInstallingRegistration(this, version.get(), - status); + context_->registry().NotifyDoneInstallingRegistration(this, version.get(), + status); std::move(callback).Run(status); }
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc index a1dffc8..c339c2d 100644 --- a/content/browser/service_worker/service_worker_registration_object_host.cc +++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -176,7 +176,7 @@ return; } - context_->registry()->UpdateNavigationPreloadEnabled( + context_->registry().UpdateNavigationPreloadEnabled( registration_->id(), registration_->key(), enable, base::BindOnce(&ServiceWorkerRegistrationObjectHost:: DidUpdateNavigationPreloadEnabled, @@ -226,7 +226,7 @@ return; } - context_->registry()->UpdateNavigationPreloadHeader( + context_->registry().UpdateNavigationPreloadHeader( registration_->id(), registration_->key(), value, base::BindOnce(&ServiceWorkerRegistrationObjectHost:: DidUpdateNavigationPreloadHeader,
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index 66da5c87..7589751 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -189,7 +189,7 @@ } ServiceWorkerContextCore* context() { return helper_->context(); } - ServiceWorkerRegistry* registry() { return helper_->context()->registry(); } + ServiceWorkerRegistry& registry() { return helper_->context()->registry(); } class RegistrationListener : public ServiceWorkerRegistration::Listener { public: @@ -427,7 +427,7 @@ EmbeddedWorkerTestHelper::CreateMainScriptResponse()); std::optional<blink::ServiceWorkerStatusCode> status; base::RunLoop run_loop; - context()->registry()->StoreRegistration( + context()->registry().StoreRegistration( registration_.get(), version_1.get(), ReceiveServiceWorkerStatus(&status, run_loop.QuitClosure())); run_loop.Run(); @@ -883,7 +883,7 @@ int64_t registration_id, const blink::StorageKey& key) { std::optional<blink::ServiceWorkerStatusCode> status; - registry()->FindRegistrationForId( + registry().FindRegistrationForId( registration_id, key, base::BindOnce( [](std::optional<blink::ServiceWorkerStatusCode>* out_status, @@ -936,7 +936,7 @@ bool called = false; blink::ServiceWorkerStatusCode status = blink::ServiceWorkerStatusCode::kErrorFailed; - registry()->StoreRegistration( + registry().StoreRegistration( registration.get(), version.get(), base::BindOnce(&SaveStatusCallback, &called, &status)); base::RunLoop().RunUntilIdle();
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc index 3027502..37320d26 100644 --- a/content/browser/service_worker/service_worker_registry.cc +++ b/content/browser/service_worker/service_worker_registry.cc
@@ -225,10 +225,10 @@ ServiceWorkerRegistry::ServiceWorkerRegistry( ServiceWorkerContextCore& context, - ServiceWorkerRegistry* old_registry) + ServiceWorkerRegistry& old_registry) : ServiceWorkerRegistry(context, - old_registry->quota_manager_proxy_.get(), - old_registry->special_storage_policy_.get()) {} + old_registry.quota_manager_proxy_.get(), + old_registry.special_storage_policy_.get()) {} ServiceWorkerRegistry::~ServiceWorkerRegistry() = default;
diff --git a/content/browser/service_worker/service_worker_registry.h b/content/browser/service_worker/service_worker_registry.h index 2c5e879..16c24cd2 100644 --- a/content/browser/service_worker/service_worker_registry.h +++ b/content/browser/service_worker/service_worker_registry.h
@@ -105,7 +105,7 @@ // For re-creating the registry from the old one. This is called when // something went wrong during storage access. ServiceWorkerRegistry(ServiceWorkerContextCore& context, - ServiceWorkerRegistry* old_registry); + ServiceWorkerRegistry& old_registry); ~ServiceWorkerRegistry();
diff --git a/content/browser/service_worker/service_worker_registry_unittest.cc b/content/browser/service_worker/service_worker_registry_unittest.cc index 270cf03..e732ad7b 100644 --- a/content/browser/service_worker/service_worker_registry_unittest.cc +++ b/content/browser/service_worker/service_worker_registry_unittest.cc
@@ -287,9 +287,9 @@ EmbeddedWorkerTestHelper* helper() { return helper_.get(); } ServiceWorkerContextCore* context() { return helper_->context(); } - ServiceWorkerRegistry* registry() { return context()->registry(); } + ServiceWorkerRegistry& registry() { return context()->registry(); } mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage_control() { - return registry()->GetRemoteStorageControl(); + return registry().GetRemoteStorageControl(); } storage::MockSpecialStoragePolicy* special_storage_policy() { @@ -297,19 +297,19 @@ } storage::QuotaManagerProxy* quota_manager_proxy() { - return registry()->quota_manager_proxy_.get(); + return registry().quota_manager_proxy_.get(); } - size_t inflight_call_count() { return registry()->inflight_calls_.size(); } + size_t inflight_call_count() { return registry().inflight_calls_.size(); } base::LRUCache<blink::StorageKey, std::set<GURL>>& registration_scope_cache() { - return registry()->registration_scope_cache_; + return registry().registration_scope_cache_; } std::set<blink::StorageKey> registration_scope_cache_keys() { std::set<blink::StorageKey> keys; - for (const auto& it : registry()->registration_scope_cache_) { + for (const auto& it : registry().registration_scope_cache_) { keys.insert(it.first); } return keys; @@ -317,12 +317,12 @@ base::LRUCache<std::tuple<GURL, blink::StorageKey>, int64_t>& registration_id_cache() { - return registry()->registration_id_cache_; + return registry().registration_id_cache_; } std::set<GURL> registration_id_cache_urls() { std::set<GURL> set; - for (const auto& it : registry()->registration_id_cache_) { + for (const auto& it : registry().registration_id_cache_) { set.insert(std::get<0>(it.first)); } return set; @@ -352,7 +352,7 @@ std::vector<blink::StorageKey> GetRegisteredStorageKeys() { std::vector<blink::StorageKey> result; base::RunLoop loop; - registry()->GetRegisteredStorageKeys(base::BindLambdaForTesting( + registry().GetRegisteredStorageKeys(base::BindLambdaForTesting( [&](const std::vector<blink::StorageKey>& storage_keys) { result = storage_keys; loop.Quit(); @@ -367,7 +367,7 @@ scoped_refptr<ServiceWorkerRegistration>& out_registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, document_url, key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -386,7 +386,7 @@ scoped_refptr<ServiceWorkerRegistration>& out_registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->FindRegistrationForScope( + registry().FindRegistrationForScope( scope, key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -405,7 +405,7 @@ scoped_refptr<ServiceWorkerRegistration>& out_registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->FindRegistrationForId( + registry().FindRegistrationForId( registration_id, key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -423,7 +423,7 @@ scoped_refptr<ServiceWorkerRegistration>& out_registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->FindRegistrationForIdOnly( + registry().FindRegistrationForIdOnly( registration_id, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -441,7 +441,7 @@ scoped_refptr<ServiceWorkerVersion> version) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->StoreRegistration( + registry().StoreRegistration( registration.get(), version.get(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -455,7 +455,7 @@ scoped_refptr<ServiceWorkerRegistration> registration) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->DeleteRegistration( + registry().DeleteRegistration( registration, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -469,7 +469,7 @@ const ServiceWorkerRegistration* registration) { base::RunLoop loop; blink::ServiceWorkerStatusCode result; - registry()->UpdateToActiveState( + registry().UpdateToActiveState( registration->id(), registration->key(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -483,7 +483,7 @@ const ServiceWorkerRegistration* registration) { base::RunLoop loop; blink::ServiceWorkerStatusCode result; - registry()->UpdateLastUpdateCheckTime( + registry().UpdateLastUpdateCheckTime( registration->id(), registration->key(), registration->last_update_check(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { @@ -499,7 +499,7 @@ ServiceWorkerVersion::FetchHandlerType fetch_handler_type) { base::RunLoop loop; blink::ServiceWorkerStatusCode result; - registry()->UpdateFetchHandlerType( + registry().UpdateFetchHandlerType( registration->id(), registration->key(), fetch_handler_type, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -514,7 +514,7 @@ const base::flat_map<int64_t, std::string>& updated_sha256_checksums) { base::RunLoop loop; blink::ServiceWorkerStatusCode result; - registry()->UpdateResourceSha256Checksums( + registry().UpdateResourceSha256Checksums( registration->id(), registration->key(), updated_sha256_checksums, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { result = status; @@ -528,7 +528,7 @@ const blink::StorageKey& key) { GetStorageUsageForStorageKeyResult result; base::RunLoop loop; - registry()->GetStorageUsageForStorageKey( + registry().GetStorageUsageForStorageKey( key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, int64_t usage) { result.status = status; @@ -543,7 +543,7 @@ std::vector<ServiceWorkerRegistrationInfo>* registrations) { std::optional<blink::ServiceWorkerStatusCode> result; base::RunLoop loop; - registry()->GetAllRegistrationsInfos(base::BindLambdaForTesting( + registry().GetAllRegistrationsInfos(base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, const std::vector<ServiceWorkerRegistrationInfo>& infos) { result = status; @@ -560,7 +560,7 @@ std::vector<scoped_refptr<ServiceWorkerRegistration>>& registrations) { blink::ServiceWorkerStatusCode result; base::RunLoop loop; - registry()->GetRegistrationsForStorageKey( + registry().GetRegistrationsForStorageKey( key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -698,7 +698,7 @@ quota_manager_proxy()); base::RunLoop loop; - registry()->CreateNewRegistration( + registry().CreateNewRegistration( std::move(options), kKey, blink::mojom::AncestorFrameType::kNormalFrame, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerRegistration> new_registration) { @@ -732,7 +732,7 @@ quota_manager_proxy()); base::RunLoop loop; - registry()->CreateNewRegistration( + registry().CreateNewRegistration( std::move(options), kKey, blink::mojom::AncestorFrameType::kNormalFrame, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerRegistration> new_registration) { @@ -1035,7 +1035,7 @@ EXPECT_TRUE(registrations_for_storage_key.empty()); // Notify storage of it being installed. - registry()->NotifyInstallingRegistration(live_registration.get()); + registry().NotifyInstallingRegistration(live_registration.get()); // Now should be findable. EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, @@ -1079,7 +1079,7 @@ EXPECT_TRUE(registrations_for_storage_key.empty()); // Notify storage of installation no longer happening. - registry()->NotifyDoneInstallingRegistration( + registry().NotifyDoneInstallingRegistration( live_registration.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); // Once again, should not be findable. @@ -1150,9 +1150,9 @@ /*resource_id=*/3); // Notify storage of them being installed. - registry()->NotifyInstallingRegistration(live_registration1.get()); - registry()->NotifyInstallingRegistration(live_registration2.get()); - registry()->NotifyInstallingRegistration(live_registration3.get()); + registry().NotifyInstallingRegistration(live_registration1.get()); + registry().NotifyInstallingRegistration(live_registration2.get()); + registry().NotifyInstallingRegistration(live_registration3.get()); // Registrations in the installing state shouldn't trigger a modified // notification. @@ -1180,11 +1180,11 @@ EXPECT_EQ(3, helper()->quota_manager_proxy()->notify_bucket_modified_count()); // Notify storage of installations no longer happening. - registry()->NotifyDoneInstallingRegistration( + registry().NotifyDoneInstallingRegistration( live_registration1.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); - registry()->NotifyDoneInstallingRegistration( + registry().NotifyDoneInstallingRegistration( live_registration2.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); - registry()->NotifyDoneInstallingRegistration( + registry().NotifyDoneInstallingRegistration( live_registration3.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); EXPECT_EQ(0, helper()->quota_manager_proxy()->notify_bucket_accessed_count()); @@ -1234,7 +1234,7 @@ int done_count = 0; base::RunLoop loop; for (int i = 0; i < kCallCount; i++) { - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, kScope, kKey, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -1301,7 +1301,7 @@ int expected_registration_id_cache_size, const base::Location& location = FROM_HERE) { base::RunLoop loop; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, scope, blink::StorageKey::CreateFirstParty(url::Origin::Create(scope)), base::BindLambdaForTesting( @@ -1790,7 +1790,7 @@ registration->EnableNavigationPreload(true); registration->SetNavigationPreloadHeader("header"); - registry()->NotifyInstallingRegistration(registration.get()); + registry().NotifyInstallingRegistration(registration.get()); ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), blink::ServiceWorkerStatusCode::kOk); @@ -2040,7 +2040,7 @@ ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), blink::ServiceWorkerStatusCode::kOk); - EXPECT_FALSE(registry()->ShouldPurgeOnShutdownForTesting(kKey)); + EXPECT_FALSE(registry().ShouldPurgeOnShutdownForTesting(kKey)); { // Update storage policy to mark the origin should be purged on shutdown. @@ -2049,7 +2049,7 @@ base::RunLoop().RunUntilIdle(); } - EXPECT_TRUE(registry()->ShouldPurgeOnShutdownForTesting(kKey)); + EXPECT_TRUE(registry().ShouldPurgeOnShutdownForTesting(kKey)); } // Tests that callbacks of storage operations are always called even when the @@ -2111,7 +2111,7 @@ helper()->SimulateStorageRestartForTesting(); base::RunLoop loop1; - registry()->StoreRegistration( + registry().StoreRegistration( registration1.get(), registration1->waiting_version(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2121,7 +2121,7 @@ helper()->SimulateStorageRestartForTesting(); base::RunLoop loop2; - registry()->StoreRegistration( + registry().StoreRegistration( registration2.get(), registration2->waiting_version(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2139,7 +2139,7 @@ // Get registered storage keys. { base::RunLoop loop; - registry()->GetRegisteredStorageKeys(base::BindLambdaForTesting( + registry().GetRegisteredStorageKeys(base::BindLambdaForTesting( [&](const std::vector<blink::StorageKey>& storage_keys) { EXPECT_THAT(storage_keys, testing::UnorderedElementsAreArray({kKey1, kKey2})); @@ -2156,7 +2156,7 @@ // Finding registrations stored in the previous block. { base::RunLoop loop1; - registry()->FindRegistrationForClientUrl( + registry().FindRegistrationForClientUrl( ServiceWorkerRegistry::Purpose::kNotForNavigation, kScope1, kKey1, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -2168,7 +2168,7 @@ base::RunLoop loop2; const GURL kNotInScope("http://www.example.com/not-in-scope"); - registry()->FindRegistrationForScope( + registry().FindRegistrationForScope( kNotInScope, blink::StorageKey::CreateFirstParty(url::Origin::Create(kNotInScope)), base::BindLambdaForTesting( @@ -2190,7 +2190,7 @@ // Get both of the registrations by these APIs. { base::RunLoop loop1; - registry()->GetRegistrationsForStorageKey( + registry().GetRegistrationsForStorageKey( kKey1, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -2202,7 +2202,7 @@ })); base::RunLoop loop2; - registry()->GetAllRegistrationsInfos(base::BindLambdaForTesting( + registry().GetAllRegistrationsInfos(base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, const std::vector<ServiceWorkerRegistrationInfo>& registrations) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2221,7 +2221,7 @@ // Delete `registrations` from the storage. { base::RunLoop loop; - registry()->DeleteRegistration( + registry().DeleteRegistration( registration2, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2238,7 +2238,7 @@ // Update fields of `registration1` in the storage. { base::RunLoop loop1; - registry()->UpdateToActiveState( + registry().UpdateToActiveState( registration1->id(), kKey1, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2246,7 +2246,7 @@ })); base::RunLoop loop2; - registry()->UpdateLastUpdateCheckTime( + registry().UpdateLastUpdateCheckTime( registration1->id(), kKey1, base::Time::Now(), base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2254,7 +2254,7 @@ })); base::RunLoop loop3; - registry()->UpdateNavigationPreloadEnabled( + registry().UpdateNavigationPreloadEnabled( registration1->id(), kKey1, /*enable=*/true, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2262,7 +2262,7 @@ })); base::RunLoop loop4; - registry()->UpdateNavigationPreloadHeader( + registry().UpdateNavigationPreloadHeader( registration1->id(), kKey1, "header", base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2318,7 +2318,7 @@ StoreRegistrationData(std::move(data2), std::move(resources2)); base::RunLoop loop1; - registry()->FindRegistrationForId( + registry().FindRegistrationForId( registration_id1, key1, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -2329,7 +2329,7 @@ })); base::RunLoop loop2; - registry()->FindRegistrationForIdOnly( + registry().FindRegistrationForIdOnly( registration_id2, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -2365,7 +2365,7 @@ quota_manager_proxy()); base::RunLoop loop; - registry()->CreateNewRegistration( + registry().CreateNewRegistration( std::move(options), kKey, blink::mojom::AncestorFrameType::kNormalFrame, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerRegistration> new_registration) { @@ -2391,7 +2391,7 @@ { base::RunLoop loop; - registry()->CreateNewVersion( + registry().CreateNewVersion( registration, kScriptUrl, blink::mojom::ScriptType::kClassic, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerVersion> new_version) { @@ -2435,7 +2435,7 @@ // Store some user data. { base::RunLoop loop1; - registry()->StoreUserData( + registry().StoreUserData( registration1->id(), kKey1, {{"key1", "value1"}, {"prefixed_key1", "prefixed_value1"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { @@ -2444,7 +2444,7 @@ })); base::RunLoop loop2; - registry()->StoreUserData( + registry().StoreUserData( registration2->id(), kKey2, {{"key2", "value2"}, {"prefixed_key2", "prefixed_value2"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { @@ -2463,7 +2463,7 @@ // Tests that get methods for `registration1` work. { base::RunLoop loop1; - registry()->GetUserData( + registry().GetUserData( registration1->id(), {{"key1"}}, base::BindLambdaForTesting([&](const std::vector<std::string>& values, blink::ServiceWorkerStatusCode status) { @@ -2473,7 +2473,7 @@ })); base::RunLoop loop2; - registry()->GetUserDataByKeyPrefix( + registry().GetUserDataByKeyPrefix( registration1->id(), "prefixed", base::BindLambdaForTesting([&](const std::vector<std::string>& values, blink::ServiceWorkerStatusCode status) { @@ -2483,7 +2483,7 @@ })); base::RunLoop loop3; - registry()->GetUserKeysAndDataByKeyPrefix( + registry().GetUserKeysAndDataByKeyPrefix( registration1->id(), "prefixed", base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, @@ -2505,7 +2505,7 @@ // Tests that get methods for all registrations work. { base::RunLoop loop1; - registry()->GetUserDataForAllRegistrations( + registry().GetUserDataForAllRegistrations( "key2", base::BindLambdaForTesting( [&](const std::vector<std::pair<int64_t, std::string>>& user_data, @@ -2516,7 +2516,7 @@ })); base::RunLoop loop2; - registry()->GetUserDataForAllRegistrationsByKeyPrefix( + registry().GetUserDataForAllRegistrationsByKeyPrefix( "prefixed", base::BindLambdaForTesting( [&](const std::vector<std::pair<int64_t, std::string>>& user_data, @@ -2537,7 +2537,7 @@ // Tests that clear methods work. { base::RunLoop loop1; - registry()->ClearUserData( + registry().ClearUserData( registration1->id(), {{"key1"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2545,7 +2545,7 @@ })); base::RunLoop loop2; - registry()->ClearUserDataByKeyPrefixes( + registry().ClearUserDataByKeyPrefixes( registration2->id(), {{"key2"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2553,7 +2553,7 @@ })); base::RunLoop loop3; - registry()->ClearUserDataForAllRegistrationsByKeyPrefix( + registry().ClearUserDataForAllRegistrationsByKeyPrefix( "prefixed", base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kOk); @@ -2587,7 +2587,7 @@ ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), blink::ServiceWorkerStatusCode::kOk); - EXPECT_FALSE(registry()->ShouldPurgeOnShutdownForTesting(kKey)); + EXPECT_FALSE(registry().ShouldPurgeOnShutdownForTesting(kKey)); // Update storage policy to mark the origin should be purged on shutdown. special_storage_policy()->AddSessionOnly(kOrigin.GetURL()); @@ -2599,7 +2599,7 @@ // All Mojo calls must be done at this point. EXPECT_EQ(inflight_call_count(), 0U); - EXPECT_TRUE(registry()->ShouldPurgeOnShutdownForTesting(kKey)); + EXPECT_TRUE(registry().ShouldPurgeOnShutdownForTesting(kKey)); } // Regression test for https://crbug.com/1165784. @@ -2609,7 +2609,7 @@ TEST_F(ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall) { { base::RunLoop loop; - registry()->GetRegisteredStorageKeys(base::BindLambdaForTesting( + registry().GetRegisteredStorageKeys(base::BindLambdaForTesting( [&](const std::vector<blink::StorageKey>& storage_keys) { EXPECT_TRUE(storage_keys.empty()); loop.Quit(); @@ -2620,7 +2620,7 @@ { base::RunLoop loop; - registry()->GetStorageUsageForStorageKey( + registry().GetStorageUsageForStorageKey( blink::StorageKey::CreateFromStringForTesting("https://example.com/"), base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode status, int64_t usage) { @@ -2633,7 +2633,7 @@ { base::RunLoop loop; - registry()->PerformStorageCleanup(loop.QuitClosure()); + registry().PerformStorageCleanup(loop.QuitClosure()); SimulateRestart(); loop.Run(); } @@ -2642,7 +2642,7 @@ TEST_F(ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_StoreUserData) { base::RunLoop loop; - registry()->StoreUserData( + registry().StoreUserData( /*registration_id=*/1, blink::StorageKey::CreateFromStringForTesting("https://example.com/"), {{"key", "value"}}, @@ -2657,7 +2657,7 @@ TEST_F(ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_ClearUserData) { base::RunLoop loop; - registry()->ClearUserData( + registry().ClearUserData( /*registration_id=*/1, {{"key"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kErrorFailed); @@ -2670,7 +2670,7 @@ TEST_F(ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_ClearUserDataByKeyPrefixes) { base::RunLoop loop; - registry()->ClearUserDataByKeyPrefixes( + registry().ClearUserDataByKeyPrefixes( /*registration_id=*/1, {{"prefix"}}, base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kErrorFailed); @@ -2684,7 +2684,7 @@ ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_ClearUserDataForAllRegistrationsByKeyPrefix) { base::RunLoop loop; - registry()->ClearUserDataForAllRegistrationsByKeyPrefix( + registry().ClearUserDataForAllRegistrationsByKeyPrefix( "prefix", base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { EXPECT_EQ(status, blink::ServiceWorkerStatusCode::kErrorFailed); @@ -2697,7 +2697,7 @@ TEST_F(ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_GetUserDataForAllRegistrations) { base::RunLoop loop; - registry()->GetUserDataForAllRegistrations( + registry().GetUserDataForAllRegistrations( "key", base::BindLambdaForTesting( [&](const std::vector<std::pair<int64_t, std::string>>& user_data, @@ -2713,7 +2713,7 @@ ServiceWorkerRegistryTest, DestroyRegistryDuringInflightCall_GetUserDataForAllRegistrationsByKeyPrefix) { base::RunLoop loop; - registry()->GetUserDataForAllRegistrationsByKeyPrefix( + registry().GetUserDataForAllRegistrationsByKeyPrefix( "prefix", base::BindLambdaForTesting( [&](const std::vector<std::pair<int64_t, std::string>>& user_data, @@ -3013,8 +3013,8 @@ // Add the resources ids to the uncommitted list. const blink::StorageKey key = blink::StorageKey::CreateFirstParty(url::Origin::Create(scope_)); - registry()->StoreUncommittedResourceId(resource_id1_, key); - registry()->StoreUncommittedResourceId(resource_id2_, key); + registry().StoreUncommittedResourceId(resource_id1_, key); + registry().StoreUncommittedResourceId(resource_id2_, key); EnsureRemoteCallsAreExecuted(); std::vector<int64_t> verify_ids = GetUncommittedResourceIds(); @@ -3180,8 +3180,8 @@ // Promote the worker to active and add a controllee. registration_->SetActiveVersion(registration_->waiting_version()); registration_->active_version()->SetStatus(ServiceWorkerVersion::ACTIVATED); - registry()->UpdateToActiveState(registration_->id(), registration_->key(), - base::DoNothing()); + registry().UpdateToActiveState(registration_->id(), registration_->key(), + base::DoNothing()); ScopedServiceWorkerClient service_worker_client = CreateServiceWorkerClient(context()); registration_->active_version()->AddControllee(service_worker_client.get()); @@ -3212,8 +3212,8 @@ // Promote the worker to active worker and add a controllee. registration_->SetActiveVersion(registration_->waiting_version()); registration_->active_version()->SetStatus(ServiceWorkerVersion::ACTIVATED); - registry()->UpdateToActiveState(registration_->id(), registration_->key(), - base::DoNothing()); + registry().UpdateToActiveState(registration_->id(), registration_->key(), + base::DoNothing()); ScopedServiceWorkerClient service_worker_client = CreateServiceWorkerClient(context()); registration_->active_version()->AddControllee(service_worker_client.get()); @@ -3261,8 +3261,8 @@ TEST_F(ServiceWorkerRegistryResourceTest, UpdateRegistration_NoLiveVersion) { // Promote the worker to active worker and add a controllee. registration_->SetActiveVersion(registration_->waiting_version()); - registry()->UpdateToActiveState(registration_->id(), registration_->key(), - base::DoNothing()); + registry().UpdateToActiveState(registration_->id(), registration_->key(), + base::DoNothing()); // Make an updated registration. scoped_refptr<ServiceWorkerVersion> live_version = @@ -3300,8 +3300,8 @@ registration_->SetActiveVersion(registration_->waiting_version()); registration_->active_version()->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetWaitingVersion(nullptr); - registry()->UpdateToActiveState(registration_->id(), registration_->key(), - base::DoNothing()); + registry().UpdateToActiveState(registration_->id(), registration_->key(), + base::DoNothing()); ScopedServiceWorkerClient service_worker_client = CreateServiceWorkerClient(context()); registration_->active_version()->AddControllee(service_worker_client.get()); @@ -3318,8 +3318,8 @@ // Also add an uncommitted resource. int64_t kStaleUncommittedResourceId = GetNewResourceIdSync(storage_control()); - registry()->StoreUncommittedResourceId(kStaleUncommittedResourceId, - registration_->key()); + registry().StoreUncommittedResourceId(kStaleUncommittedResourceId, + registration_->key()); EnsureRemoteCallsAreExecuted(); verify_ids = GetUncommittedResourceIds(); EXPECT_EQ(1u, verify_ids.size()); @@ -3336,7 +3336,7 @@ storage_control()->SetPurgingCompleteCallbackForTest(loop.QuitClosure()); int64_t kNewResourceId = GetNewResourceIdSync(storage_control()); WriteBasicResponse(storage_control(), kNewResourceId); - registry()->StoreUncommittedResourceId(kNewResourceId, registration_->key()); + registry().StoreUncommittedResourceId(kNewResourceId, registration_->key()); loop.Run(); // The stale resources should be purged, but the new resource should persist. @@ -3403,7 +3403,7 @@ TEST_F(ServiceWorkerRegistryResourceTest, RetryInflightCalls_Resources) { const int64_t kResourceId = GetNewResourceIdSync(storage_control()); - registry()->StoreUncommittedResourceId(kResourceId, registration_->key()); + registry().StoreUncommittedResourceId(kResourceId, registration_->key()); EXPECT_EQ(inflight_call_count(), 1U); helper()->SimulateStorageRestartForTesting(); @@ -3413,7 +3413,7 @@ EXPECT_THAT(GetUncommittedResourceIds(), testing::UnorderedElementsAreArray({kResourceId})); - registry()->DoomUncommittedResource(kResourceId); + registry().DoomUncommittedResource(kResourceId); EXPECT_EQ(inflight_call_count(), 1U); helper()->SimulateStorageRestartForTesting();
diff --git a/content/browser/service_worker/service_worker_script_cache_map.cc b/content/browser/service_worker/service_worker_script_cache_map.cc index 37902dd..3267d2e 100644 --- a/content/browser/service_worker/service_worker_script_cache_map.cc +++ b/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -53,7 +53,7 @@ } resource_map_[url] = storage::mojom::ServiceWorkerResourceRecord::New( resource_id, url, -1, /*sha256_checksum=*/""); - context_->registry()->StoreUncommittedResourceId(resource_id, owner_->key()); + context_->registry().StoreUncommittedResourceId(resource_id, owner_->key()); } void ServiceWorkerScriptCacheMap::NotifyFinishedCaching( @@ -72,7 +72,7 @@ return; // Our storage has been wiped via DeleteAndStartOver. if (net_error != net::OK) { - context_->registry()->DoomUncommittedResource(LookupResourceId(url)); + context_->registry().DoomUncommittedResource(LookupResourceId(url)); resource_map_.erase(url); if (owner_->script_url() == url) { main_script_net_error_ = net_error;
diff --git a/content/browser/service_worker/service_worker_script_loader_factory.cc b/content/browser/service_worker/service_worker_script_loader_factory.cc index 5d2f6fa..536e96a 100644 --- a/content/browser/service_worker/service_worker_script_loader_factory.cc +++ b/content/browser/service_worker/service_worker_script_loader_factory.cc
@@ -82,7 +82,7 @@ version->script_cache_map()->LookupResourceId(resource_request.url); if (resource_id != blink::mojom::kInvalidServiceWorkerResourceId) { mojo::Remote<storage::mojom::ServiceWorkerResourceReader> resource_reader; - context_->registry()->GetRemoteStorageControl()->CreateResourceReader( + context_->registry().GetRemoteStorageControl()->CreateResourceReader( resource_id, resource_reader.BindNewPipeAndPassReceiver()); mojo::MakeSelfOwnedReceiver( std::make_unique<ServiceWorkerInstalledScriptLoader>( @@ -199,10 +199,10 @@ return; } mojo::Remote<storage::mojom::ServiceWorkerResourceReader> reader; - context_->registry()->GetRemoteStorageControl()->CreateResourceReader( + context_->registry().GetRemoteStorageControl()->CreateResourceReader( resource_id, reader.BindNewPipeAndPassReceiver()); mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer; - context_->registry()->GetRemoteStorageControl()->CreateResourceWriter( + context_->registry().GetRemoteStorageControl()->CreateResourceWriter( new_resource_id, writer.BindNewPipeAndPassReceiver()); cache_writer_ = ServiceWorkerCacheWriter::CreateForCopy( @@ -260,7 +260,7 @@ // Use ServiceWorkerInstalledScriptLoader to load the new copy. mojo::Remote<storage::mojom::ServiceWorkerResourceReader> resource_reader; - context_->registry()->GetRemoteStorageControl()->CreateResourceReader( + context_->registry().GetRemoteStorageControl()->CreateResourceReader( new_resource_id, resource_reader.BindNewPipeAndPassReceiver()); mojo::MakeSelfOwnedReceiver( std::make_unique<ServiceWorkerInstalledScriptLoader>(
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc index 25d4d345..e62011c4 100644 --- a/content/browser/service_worker/service_worker_test_utils.cc +++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -459,7 +459,7 @@ } scoped_refptr<ServiceWorkerRegistration> CreateNewServiceWorkerRegistration( - ServiceWorkerRegistry* registry, + ServiceWorkerRegistry& registry, const blink::mojom::ServiceWorkerRegistrationOptions& options, const blink::StorageKey& key) { scoped_refptr<ServiceWorkerRegistration> registration; @@ -473,7 +473,7 @@ // TODO(bashi): Figure out a way to avoid using nested loop as it's // problematic. base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); - registry->CreateNewRegistration( + registry.CreateNewRegistration( options, key, blink::mojom::AncestorFrameType::kNormalFrame, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerRegistration> new_registration) { @@ -486,7 +486,7 @@ } scoped_refptr<ServiceWorkerVersion> CreateNewServiceWorkerVersion( - ServiceWorkerRegistry* registry, + ServiceWorkerRegistry& registry, scoped_refptr<ServiceWorkerRegistration> registration, const GURL& script_url, blink::mojom::ScriptType script_type) { @@ -494,7 +494,7 @@ // See comments in CreateNewServiceWorkerRegistration() why nestable tasks // allowed. base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); - registry->CreateNewVersion( + registry.CreateNewVersion( std::move(registration), script_url, script_type, base::BindLambdaForTesting( [&](scoped_refptr<ServiceWorkerVersion> new_version) { @@ -789,21 +789,21 @@ mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader; worker_test_helper->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() ->CreateResourceReader(old_resource_id, compare_reader.BindNewPipeAndPassReceiver()); mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader; worker_test_helper->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() ->CreateResourceReader(old_resource_id, copy_reader.BindNewPipeAndPassReceiver()); mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer; worker_test_helper->context() ->registry() - ->GetRemoteStorageControl() + .GetRemoteStorageControl() ->CreateResourceWriter(new_resource_id, writer.BindNewPipeAndPassReceiver());
diff --git a/content/browser/service_worker/service_worker_test_utils.h b/content/browser/service_worker/service_worker_test_utils.h index 30d48ec..ae7b079 100644 --- a/content/browser/service_worker/service_worker_test_utils.h +++ b/content/browser/service_worker/service_worker_test_utils.h
@@ -155,13 +155,13 @@ // Calls CreateNewRegistration() synchronously. scoped_refptr<ServiceWorkerRegistration> CreateNewServiceWorkerRegistration( - ServiceWorkerRegistry* registry, + ServiceWorkerRegistry& registry, const blink::mojom::ServiceWorkerRegistrationOptions& options, const blink::StorageKey& key); // Calls CreateNewVersion() synchronously. scoped_refptr<ServiceWorkerVersion> CreateNewServiceWorkerVersion( - ServiceWorkerRegistry* registry, + ServiceWorkerRegistry& registry, scoped_refptr<ServiceWorkerRegistration> registration, const GURL& script_url, blink::mojom::ScriptType script_type);
diff --git a/content/browser/service_worker/service_worker_unregister_job.cc b/content/browser/service_worker/service_worker_unregister_job.cc index 7dac757c..a903336 100644 --- a/content/browser/service_worker/service_worker_unregister_job.cc +++ b/content/browser/service_worker/service_worker_unregister_job.cc
@@ -34,7 +34,7 @@ } void ServiceWorkerUnregisterJob::Start() { - context_->registry()->FindRegistrationForScope( + context_->registry().FindRegistrationForScope( scope_, key_, base::BindOnce(&ServiceWorkerUnregisterJob::OnRegistrationFound, weak_factory_.GetWeakPtr()));
diff --git a/content/browser/service_worker/service_worker_update_checker.cc b/content/browser/service_worker/service_worker_update_checker.cc index 1c83ca6..8ad2efa9 100644 --- a/content/browser/service_worker/service_worker_update_checker.cc +++ b/content/browser/service_worker/service_worker_update_checker.cc
@@ -227,19 +227,19 @@ // cache map and it doesn't issue network request. const bool is_main_script = url == main_script_url_; - ServiceWorkerRegistry* registry = version_to_update_->context()->registry(); + ServiceWorkerRegistry& registry = version_to_update_->context()->registry(); // We need two identical readers for comparing and reading the resource for // |resource_id| from the storage. mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader; - registry->GetRemoteStorageControl()->CreateResourceReader( + registry.GetRemoteStorageControl()->CreateResourceReader( resource_id, compare_reader.BindNewPipeAndPassReceiver()); mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader; - registry->GetRemoteStorageControl()->CreateResourceReader( + registry.GetRemoteStorageControl()->CreateResourceReader( resource_id, copy_reader.BindNewPipeAndPassReceiver()); mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer; - registry->GetRemoteStorageControl()->CreateResourceWriter( + registry.GetRemoteStorageControl()->CreateResourceWriter( new_resource_id, writer.BindNewPipeAndPassReceiver()); running_checker_ = std::make_unique<ServiceWorkerSingleScriptUpdateChecker>(
diff --git a/content/browser/service_worker/service_worker_usb_delegate_observer_unittest.cc b/content/browser/service_worker/service_worker_usb_delegate_observer_unittest.cc index 07078310..6634da25 100644 --- a/content/browser/service_worker/service_worker_usb_delegate_observer_unittest.cc +++ b/content/browser/service_worker/service_worker_usb_delegate_observer_unittest.cc
@@ -227,8 +227,8 @@ TestFuture<blink::ServiceWorkerStatusCode, scoped_refptr<ServiceWorkerRegistration>> future; - registry()->FindRegistrationForId(registration_id, key, - future.GetCallback()); + registry().FindRegistrationForId(registration_id, key, + future.GetCallback()); return future.Take(); }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 3755b288..706c95d4 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -591,7 +591,7 @@ // Ensure the live registration during starting worker so that the worker can // get associated with it in // ServiceWorkerHost::CompleteStartWorkerPreparation. - context_->registry()->FindRegistrationForId( + context_->registry().FindRegistrationForId( registration_id_, key_, base::BindOnce( &ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker, @@ -713,7 +713,7 @@ if (!context_) { return; } - context_->registry()->FindRegistrationForId( + context_->registry().FindRegistrationForId( registration_id_, key_, base::BindOnce(&ServiceWorkerVersion::FoundRegistrationForUpdate, weak_factory_.GetWeakPtr())); @@ -1489,7 +1489,7 @@ if (status == blink::ServiceWorkerStatusCode::kOk) { if (fetch_handler_type_ && fetch_handler_type_ != new_fetch_handler_type) { - context_->registry()->UpdateFetchHandlerType( + context_->registry().UpdateFetchHandlerType( registration_id_, key_, new_fetch_handler_type, // Ignore errors; bumping the update fetch handler type is // just best-effort.
diff --git a/content/browser/service_worker/service_worker_version_browsertest.cc b/content/browser/service_worker/service_worker_version_browsertest.cc index 7690c5db..f7bc704f 100644 --- a/content/browser/service_worker/service_worker_version_browsertest.cc +++ b/content/browser/service_worker/service_worker_version_browsertest.cc
@@ -448,7 +448,7 @@ wrapper()->context()->registry(), registration_.get(), embedded_test_server()->GetURL(worker_url), script_type); // Make the registration findable via storage functions. - wrapper()->context()->registry()->NotifyInstallingRegistration( + wrapper()->context()->registry().NotifyInstallingRegistration( registration_.get()); } @@ -509,7 +509,7 @@ blink::ServiceWorkerStatusCode status; ServiceWorkerVersion* version = wrapper()->context()->GetLiveVersion(version_id); - wrapper()->context()->registry()->StoreRegistration( + wrapper()->context()->registry().StoreRegistration( registration_.get(), version, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode actual_status) { @@ -519,7 +519,7 @@ })); run_loop.Run(); - wrapper()->context()->registry()->NotifyDoneInstallingRegistration( + wrapper()->context()->registry().NotifyDoneInstallingRegistration( registration_.get(), version_.get(), status); } @@ -555,7 +555,7 @@ blink::ServiceWorkerStatusCode status = blink::ServiceWorkerStatusCode::kErrorFailed; base::RunLoop run_loop; - wrapper()->context()->registry()->FindRegistrationForId( + wrapper()->context()->registry().FindRegistrationForId( id, key, base::BindLambdaForTesting( [&](blink::ServiceWorkerStatusCode actual_status,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 51d82ce9..5bdae766 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -137,7 +137,7 @@ // Make the registration findable via storage functions. std::optional<blink::ServiceWorkerStatusCode> status; base::RunLoop run_loop; - helper_->context()->registry()->StoreRegistration( + helper_->context()->registry().StoreRegistration( registration_.get(), version_.get(), ReceiveServiceWorkerStatus(&status, run_loop.QuitClosure())); run_loop.Run(); @@ -442,7 +442,7 @@ // Delete the registration. std::optional<blink::ServiceWorkerStatusCode> status; base::RunLoop run_loop; - helper_->context()->registry()->DeleteRegistration( + helper_->context()->registry().DeleteRegistration( registration_, ReceiveServiceWorkerStatus(&status, run_loop.QuitClosure())); run_loop.Run(); @@ -1798,7 +1798,7 @@ const std::string kMetadata("Test metadata"); base::RunLoop loop; - helper_->context()->registry()->DisableStorageForTesting(loop.QuitClosure()); + helper_->context()->registry().DisableStorageForTesting(loop.QuitClosure()); loop.Run(); net::TestCompletionCallback completion;
diff --git a/content/browser/shared_storage/shared_storage_event_params.cc b/content/browser/shared_storage/shared_storage_event_params.cc index 64fd512..bc42bfa 100644 --- a/content/browser/shared_storage/shared_storage_event_params.cc +++ b/content/browser/shared_storage/shared_storage_event_params.cc
@@ -15,6 +15,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/strings/to_string.h" #include "content/browser/private_aggregation/private_aggregation_host.h" #include "third_party/blink/public/mojom/shared_storage/shared_storage.mojom.h"
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc index 85cb069..2d1d2eb 100644 --- a/content/browser/tracing/background_tracing_manager_browsertest.cc +++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -32,8 +32,9 @@ #include "base/test/test_proto_loader.h" #include "base/test/trace_event_analyzer.h" #include "base/threading/thread_restrictions.h" +#include "base/trace_event/interned_args_helper.h" #include "base/trace_event/named_trigger.h" -#include "base/trace_event/trace_event.h" +#include "base/trace_event/typed_macros.h" #include "build/build_config.h" #include "content/browser/devtools/protocol/devtools_protocol_test_support.h" #include "content/browser/renderer_host/render_frame_host_impl.h" @@ -57,6 +58,7 @@ #include "services/tracing/public/cpp/tracing_features.h" #include "third_party/perfetto/include/perfetto/ext/trace_processor/export_json.h" #include "third_party/perfetto/include/perfetto/trace_processor/trace_processor_storage.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h" #include "third_party/re2/src/re2/re2.h" #include "third_party/zlib/google/compression_utils.h" #include "third_party/zlib/zlib.h"
diff --git a/content/browser/tracing/background_tracing_manager_unittest.cc b/content/browser/tracing/background_tracing_manager_unittest.cc index db92380c..b0cfb65 100644 --- a/content/browser/tracing/background_tracing_manager_unittest.cc +++ b/content/browser/tracing/background_tracing_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_proto_loader.h" +#include "base/threading/thread_restrictions.h" #include "base/token.h" #include "base/values.h" #include "build/build_config.h"
diff --git a/content/browser/tracing/file_tracing_provider_impl.cc b/content/browser/tracing/file_tracing_provider_impl.cc index 01f762ec..bd243431 100644 --- a/content/browser/tracing/file_tracing_provider_impl.cc +++ b/content/browser/tracing/file_tracing_provider_impl.cc
@@ -5,7 +5,7 @@ #include "content/browser/tracing/file_tracing_provider_impl.h" #include "base/files/file_path.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" namespace content {
diff --git a/content/browser/url_info.cc b/content/browser/url_info.cc index c6a0218..f29ee58 100644 --- a/content/browser/url_info.cc +++ b/content/browser/url_info.cc
@@ -4,6 +4,8 @@ #include "content/browser/url_info.h" +#include <sstream> + #include "content/browser/isolation_context.h" namespace content {
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessRanking.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessRanking.java index 5706cff..8f0df10 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessRanking.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessRanking.java
@@ -69,7 +69,7 @@ public boolean shouldBeInLowRankGroup() { boolean inViewport = visible && (frameDepth == 0 || intersectsViewport); return (isSpareRenderer && ChildProcessRanking.isSpareRendererOfLowestRanking()) - || (importance == ChildProcessImportance.NORMAL && !inViewport); + || (importance <= ChildProcessImportance.PERCEPTIBLE && !inViewport); } } @@ -93,9 +93,11 @@ // Ranking order: // * (visible and main frame) or ChildProcessImportance.IMPORTANT // * (visible and subframe and intersect viewport) or ChildProcessImportance.MODERATE - // * ChildProcessImportance.PERCEPTIBLE // ---- cutoff for shouldBeInLowRankGroup ---- // * visible subframe and not intersect viewport + // * These processes are bound with NotPerceptibleBinding by BindingManager in + // * practice. + // * ChildProcessImportance.PERCEPTIBLE // * invisible main and sub frames (not ranked by frame depth) // * spare renderer (if lowest-ranking parameter is set). // Within each group, ties are broken by intersect viewport and then frame depth where @@ -131,6 +133,14 @@ return 1; } + if (o1.visible && o2.visible) { + return compareByIntersectsViewportAndDepth(o1, o2); + } else if (o1.visible && !o2.visible) { + return -1; + } else if (!o1.visible && o2.visible) { + return 1; + } + boolean o1Perceptible = o1.importance == ChildProcessImportance.PERCEPTIBLE; boolean o2Perceptible = o2.importance == ChildProcessImportance.PERCEPTIBLE; if (o1Perceptible && o2Perceptible) { @@ -141,14 +151,6 @@ return 1; } - if (o1.visible && o2.visible) { - return compareByIntersectsViewportAndDepth(o1, o2); - } else if (o1.visible && !o2.visible) { - return -1; - } else if (!o1.visible && o2.visible) { - return 1; - } - if (isSpareRendererOfLowestRanking()) { if (!o1.isSpareRenderer && o2.isSpareRenderer) { return -1;
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java index caaf87f..96933e9 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/media/capture/ScreenCapture.java
@@ -4,6 +4,8 @@ package org.chromium.content_public.browser.media.capture; +import androidx.activity.result.ActivityResult; + import org.jni_zero.CalledByNative; import org.jni_zero.JNINamespace; import org.jni_zero.NativeMethods; @@ -11,6 +13,7 @@ import org.chromium.build.annotations.NullMarked; import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicReference; /** See comments on `DesktopCapturerAndroid`. */ @NullMarked @@ -18,12 +21,29 @@ public class ScreenCapture { private static final String TAG = "ScreenCapture"; + // Starting a MediaProjection session involves plumbing the results from the content picker, + // which is done via ActivityResult. This class does not handle how that is achieved, but + // requires the ActivityResult to begin the session. + private static final AtomicReference<ActivityResult> sNextResult = new AtomicReference(null); + private long mNativeDesktopCapturerAndroid; private ScreenCapture(long nativeDesktopCapturerAndroid) { mNativeDesktopCapturerAndroid = nativeDesktopCapturerAndroid; } + /** + * Called before attempting to start a ScreenCapture session. + * + * <p>The {@link ActivityResult} is consumed by a subsequent call to {@link #startCapture()}. + * + * @param nextResult The {@link ActivityResult} from the MediaProjection API. + */ + public static void onPick(ActivityResult nextResult) { + var oldResult = sNextResult.getAndSet(nextResult); + assert oldResult == null; + } + @CalledByNative static ScreenCapture create(long nativeDesktopCapturerAndroid) { return new ScreenCapture(nativeDesktopCapturerAndroid);
diff --git a/content/public/android/junit/src/org/chromium/content/browser/ChildProcessRankingTest.java b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessRankingTest.java index e251358..e9fbc5f 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/ChildProcessRankingTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessRankingTest.java
@@ -174,8 +174,10 @@ ChildProcessConnection c3 = createConnection(); ChildProcessConnection c4 = createConnection(); ChildProcessConnection c5 = createConnection(); + ChildProcessConnection c6 = createConnection(); + ChildProcessConnection c7 = createConnection(); - ChildProcessRanking ranking = new ChildProcessRanking(5); + ChildProcessRanking ranking = new ChildProcessRanking(7); ranking.enableServiceGroupImportance(); // Insert in lowest ranked to highest ranked order. @@ -195,28 +197,45 @@ ChildProcessImportance.PERCEPTIBLE); ranking.addConnection( c3, + /* visible= */ true, + /* frameDepth= */ 1, + /* intersectsViewport= */ false, + /* isSpareRenderer= */ false, + ChildProcessImportance.NORMAL); + ranking.addConnection( + c4, /* visible= */ false, /* frameDepth= */ 0, /* intersectsViewport= */ false, /* isSpareRenderer= */ false, ChildProcessImportance.MODERATE); ranking.addConnection( - c4, + c5, /* visible= */ false, /* frameDepth= */ 1, /* intersectsViewport= */ false, /* isSpareRenderer= */ false, ChildProcessImportance.IMPORTANT); ranking.addConnection( - c5, + c6, /* visible= */ false, /* frameDepth= */ 0, /* intersectsViewport= */ false, /* isSpareRenderer= */ false, ChildProcessImportance.IMPORTANT); + // Visible main frame should be ChildProcessImportance.MODERATE or higher. But there can be + // a race of inconsistency. + ranking.addConnection( + c7, + /* visible= */ true, + /* frameDepth= */ 0, + /* intersectsViewport= */ false, + /* isSpareRenderer= */ false, + ChildProcessImportance.PERCEPTIBLE); - assertRankingAndRemoveAll(ranking, new ChildProcessConnection[] {c5, c4, c3, c2, c1}); - assertNotInGroup(new ChildProcessConnection[] {c5, c4, c3, c2}); + assertRankingAndRemoveAll( + ranking, new ChildProcessConnection[] {c7, c6, c5, c4, c3, c2, c1}); + assertNotInGroup(new ChildProcessConnection[] {c7, c6, c5, c4}); assertInGroupOrderedByImportance(new ChildProcessConnection[] {c1}); }
diff --git a/content/public/browser/android/child_process_importance.h b/content/public/browser/android/child_process_importance.h index 389f5d1..e5049669 100644 --- a/content/public/browser/android/child_process_importance.h +++ b/content/public/browser/android/child_process_importance.h
@@ -21,6 +21,10 @@ // Android version, PERCEPTIBLE importance falls back to NORMAL importance and // the corresponding waived service binding. // +// Note that the numerical order in ChildProcessImportance should be consistent +// because ChildProcessImportance is compared numerically in +// ChildProcessRanking.java. +// // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content_public.browser enum class ChildProcessImportance { // NORMAL is the default value.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 5bddb6e..15fe16a 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -1000,6 +1000,13 @@ "ServiceWorkerPaymentApps", base::FEATURE_ENABLED_BY_DEFAULT); +// If enabled, UI thread tasks can check ServiceWorker registration information +// from the thread pool without waiting for running the receiving task. Please +// see crbug.com/421530699 for more details. +BASE_FEATURE(kServiceWorkerBackgroundUpdateForRegisteredStorageKeys, + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeys", + base::FEATURE_DISABLED_BY_DEFAULT); + // http://tc39.github.io/ecmascript_sharedmem/shmem.html // This feature is also enabled independently of this flag for cross-origin // isolated renderers.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 8c17e37..bf7a6c36 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -224,6 +224,8 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kSecurePaymentConfirmation); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSecurePaymentConfirmationDebug); CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerPaymentApps); +CONTENT_EXPORT BASE_DECLARE_FEATURE( + kServiceWorkerBackgroundUpdateForRegisteredStorageKeys); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSharedArrayBuffer); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSiteInstanceGroupsForDataUrls); CONTENT_EXPORT BASE_DECLARE_FEATURE(kDefaultSiteInstanceGroups);
diff --git a/content/public/test/embedded_worker_instance_test_harness.cc b/content/public/test/embedded_worker_instance_test_harness.cc index ed280d7b..2ca298c6 100644 --- a/content/public/test/embedded_worker_instance_test_harness.cc +++ b/content/public/test/embedded_worker_instance_test_harness.cc
@@ -73,7 +73,7 @@ // Make the registration findable via storage functions. base::test::TestFuture<blink::ServiceWorkerStatusCode> status; - helper_->context()->registry()->StoreRegistration( + helper_->context()->registry().StoreRegistration( pair.first.get(), pair.second.get(), status.GetCallback()); ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk, status.Get());
diff --git a/content/public/test/service_worker_test_helpers.cc b/content/public/test/service_worker_test_helpers.cc index 5cdc80f..a046fef 100644 --- a/content/public/test/service_worker_test_helpers.cc +++ b/content/public/test/service_worker_test_helpers.cc
@@ -229,7 +229,7 @@ static_cast<ServiceWorkerContextWrapper*>(context)); version_created_watcher_ = std::make_unique<ServiceWorkerVersionCreatedWatcher>( - context_wrapper->GetContextCoreForTest(), this); + context_wrapper->context(), this); } void ServiceWorkerTestHelper::RegisterStateObserver(
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc index ebdc156f..9824760f 100644 --- a/content/public/test/test_launcher.cc +++ b/content/public/test/test_launcher.cc
@@ -22,6 +22,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/functional/callback_helpers.h" +#include "base/hash/hash.h" #include "base/i18n/icu_util.h" #include "base/logging.h" #include "base/memory/raw_ptr.h"
diff --git a/content/public/test/test_navigation_throttle_inserter.cc b/content/public/test/test_navigation_throttle_inserter.cc index 0c544aa9..9d5332ce 100644 --- a/content/public/test/test_navigation_throttle_inserter.cc +++ b/content/public/test/test_navigation_throttle_inserter.cc
@@ -22,7 +22,7 @@ NavigationHandle* navigation_handle) { if (callback_) { callback_.Run(*NavigationRequest::From(navigation_handle) - ->GetNavigationThrottleRunnerForTesting()); + ->GetNavigationThrottleRegistryForTesting()); } }
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc index d166cb2..e3b3a52 100644 --- a/content/services/auction_worklet/bidder_worklet_unittest.cc +++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -18,6 +18,7 @@ #include "base/feature_list.h" #include "base/format_macros.h" #include "base/functional/bind.h" +#include "base/hash/hash.h" #include "base/json/json_writer.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h"
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc index 5a29dc6f..76da81af 100644 --- a/content/test/navigation_simulator_impl.cc +++ b/content/test/navigation_simulator_impl.cc
@@ -1135,7 +1135,7 @@ NavigationThrottleRegistry& NavigationSimulatorImpl::GetNavigationThrottleRegistry() { - return *GetNavigationHandle()->GetNavigationThrottleRunnerForTesting(); + return *GetNavigationHandle()->GetNavigationThrottleRegistryForTesting(); } content::GlobalRequestID NavigationSimulatorImpl::GetGlobalRequestID() {
diff --git a/device/vr/android/cardboard/cardboard_render_loop.cc b/device/vr/android/cardboard/cardboard_render_loop.cc index b971646..87163df 100644 --- a/device/vr/android/cardboard/cardboard_render_loop.cc +++ b/device/vr/android/cardboard/cardboard_render_loop.cc
@@ -5,9 +5,11 @@ #include "device/vr/android/cardboard/cardboard_render_loop.h" #include <time.h> + #include <memory> #include "base/task/bind_post_task.h" +#include "base/trace_event/trace_event.h" #include "device/vr/android/cardboard/cardboard_image_transport.h" #include "device/vr/android/cardboard/cardboard_sdk.h" #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
diff --git a/docs/navigation.md b/docs/navigation.md index 3e4a425..0cdd19c7 100644 --- a/docs/navigation.md +++ b/docs/navigation.md
@@ -157,7 +157,7 @@ simulating a redirect), as discussed in [Navigation Concepts](navigation_concepts.md#rules-for-canceling-navigations). They are typically registered in -`NavigationThrottleRunner::RegisterNavigationThrottles` or +`NavigationThrottleRegistryImpl::RegisterNavigationThrottles` or `ContentBrowserClient::CreateThrottlesForNavigation`. The most common NavigationThrottles events are `WillStartRequest`, @@ -167,7 +167,7 @@ require a URLLoader (see NavigationRequest::NeedsUrlLoader). A NavigationThrottle that wishes to intercept a non-URLLoader navigation (same-document navigations, about:blank, etc.) should register itself in -`NavigationThrottleRunner::RegisterNavigationThrottlesForCommitWithoutUrlLoader`, +`NavigationThrottleRegistryImpl::RegisterNavigationThrottlesForCommitWithoutUrlLoader`, and will get a single `WillCommitWithoutUrlLoader` event instead of the full set of events centered on network requests. Page-activation navigations, such as activating a prerendered page or restoring a page from the back-forward
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index 8b6a4d8e..321617a 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc
@@ -2231,10 +2231,6 @@ return ExtensionSystem::Get(browser_context_)->app_sorting(); } -bool ExtensionPrefs::NeedsStorageGarbageCollection() const { - return prefs_->GetBoolean(pref_names::kStorageGarbageCollect); -} - // static void ExtensionPrefs::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -2250,7 +2246,6 @@ registry->RegisterDictionaryPref(pref_names::kOAuthRedirectUrls); registry->RegisterListPref(pref_names::kAllowedTypes); registry->RegisterIntegerPref(pref_names::kManifestV2Availability, 0); - registry->RegisterBooleanPref(pref_names::kStorageGarbageCollect, false); registry->RegisterListPref(pref_names::kAllowedInstallSites); registry->RegisterStringPref(pref_names::kLastChromeVersion, std::string()); registry->RegisterDictionaryPref(kInstallSignature);
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h index 6aff1b6..7c95120 100644 --- a/extensions/browser/extension_prefs.h +++ b/extensions/browser/extension_prefs.h
@@ -710,11 +710,6 @@ // The underlying AppSorting. AppSorting* app_sorting() const; - // Schedules garbage collection of an extension's on-disk data on the next - // start of this ExtensionService. Applies only to extensions with isolated - // storage. - bool NeedsStorageGarbageCollection() const; - // Used by AppWindowGeometryCache to persist its cache. These methods // should not be called directly. const base::Value::Dict* GetGeometryCache(
diff --git a/extensions/browser/pref_names.h b/extensions/browser/pref_names.h index 785ce7a..2aec75677 100644 --- a/extensions/browser/pref_names.h +++ b/extensions/browser/pref_names.h
@@ -116,12 +116,6 @@ // object stored in the Preferences file. The extensions are stored by ID. inline constexpr char kPinnedExtensions[] = "extensions.pinned_extensions"; -// Indicates on-disk data might have skeletal data that needs to be cleaned -// on the next start of the browser. -// TODO(crbug.com/40922689): Delete ExtensionsPref::kStorageGarbageCollect. -inline constexpr char kStorageGarbageCollect[] = - "extensions.storage.garbagecollect"; - // Pref for policy to enable/disable loading extension from command line inline constexpr char kExtensionInstallTypeBlocklist[] = "extensions.extension_install_type_blocklist";
diff --git a/gin/array_buffer.cc b/gin/array_buffer.cc index 1f86b7b..4a8807c 100644 --- a/gin/array_buffer.cc +++ b/gin/array_buffer.cc
@@ -86,11 +86,6 @@ opts.backup_ref_ptr = partition_alloc::PartitionOptions::kDisabled; opts.use_configurable_pool = partition_alloc::PartitionOptions::kAllowed; - // TODO(crbug.com/333443437): Remove this user-configurable toggle and - // default all buckets to "small" single-slot spans. - opts.use_small_single_slot_spans = - partition_alloc::PartitionOptions::kEnabled; - static base::NoDestructor<partition_alloc::PartitionAllocator> partition_allocator(opts);
diff --git a/gin/v8_platform_thread_isolated_allocator.cc b/gin/v8_platform_thread_isolated_allocator.cc index 11e2f65b..26331d0 100644 --- a/gin/v8_platform_thread_isolated_allocator.cc +++ b/gin/v8_platform_thread_isolated_allocator.cc
@@ -30,11 +30,6 @@ partition_alloc::PartitionOptions opts; opts.thread_isolation = partition_alloc::ThreadIsolationOption(pkey_); - // TODO(crbug.com/333443437): Remove this user-configurable toggle and - // default all buckets to "small" single-slot spans. - opts.use_small_single_slot_spans = - partition_alloc::PartitionOptions::kEnabled; - allocator_.init(opts); }
diff --git a/infra/config/generated/builders/ci/android-15-tablet-x64-rel/properties.json b/infra/config/generated/builders/ci/android-15-tablet-x64-rel/properties.json index 1b422b4..1ff3a9b4 100644 --- a/infra/config/generated/builders/ci/android-15-tablet-x64-rel/properties.json +++ b/infra/config/generated/builders/ci/android-15-tablet-x64-rel/properties.json
@@ -77,5 +77,11 @@ ] }, "builder_group": "chromium.android", - "recipe": "chromium" + "gardener_rotations": [ + "android" + ], + "recipe": "chromium", + "sheriff_rotations": [ + "android" + ] } \ No newline at end of file
diff --git a/infra/config/generated/cq-usage/mega_cq_bots.txt b/infra/config/generated/cq-usage/mega_cq_bots.txt index af1e5a5..1657042 100644 --- a/infra/config/generated/cq-usage/mega_cq_bots.txt +++ b/infra/config/generated/cq-usage/mega_cq_bots.txt
@@ -9,6 +9,7 @@ chromium/try/android-14-arm64-rel chromium/try/android-14-tablet-landscape-arm64-rel chromium/try/android-15-tablet-landscape-x64-rel +chromium/try/android-15-tablet-x64-rel chromium/try/android-15-x64-rel chromium/try/android-arm-compile-dbg chromium/try/android-arm64-rel
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index a510fc2..adf063c7 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -38349,8 +38349,14 @@ ' }' ' },' ' "builder_group": "chromium.android",' + ' "gardener_rotations": [' + ' "android"' + ' ],' ' "led_builder_is_bootstrapped": true,' - ' "recipe": "chromium"' + ' "recipe": "chromium",' + ' "sheriff_rotations": [' + ' "android"' + ' ]' '}' execution_timeout_secs: 14400 build_numbers: YES
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 14ee11e7..e75cfa0 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -3514,6 +3514,11 @@ short_name: "13" } builders { + name: "buildbucket/luci.chromium.ci/android-15-tablet-x64-rel" + category: "chromium.android|builder_tester|x64" + short_name: "15T" + } + builders { name: "buildbucket/luci.chromium.ci/android-15-tablet-landscape-x64-rel" category: "chromium.android|builder_tester|x64" short_name: "15T-L" @@ -4022,6 +4027,11 @@ short_name: "13" } builders { + name: "buildbucket/luci.chromium.ci/android-15-tablet-x64-rel" + category: "chromium.android|builder_tester|x64" + short_name: "15T" + } + builders { name: "buildbucket/luci.chromium.ci/android-15-tablet-landscape-x64-rel" category: "chromium.android|builder_tester|x64" short_name: "15T-L"
diff --git a/infra/config/generated/luci/luci-notify.cfg b/infra/config/generated/luci/luci-notify.cfg index 39d5fca..622cc77 100644 --- a/infra/config/generated/luci/luci-notify.cfg +++ b/infra/config/generated/luci/luci-notify.cfg
@@ -2039,6 +2039,25 @@ } builders { bucket: "ci" + name: "android-15-tablet-x64-rel" + repository: "https://chromium.googlesource.com/chromium/src" + } + tree_closers { + tree_status_host: "chromium-status.appspot.com" + failed_step_regexp: "\\b(bot_update|compile|gclient runhooks|generate_build_files|runhooks|update|\\w*nocompile_test)\\b" + } +} +notifiers { + notifications { + on_occurrence: FAILURE + failed_step_regexp: "\\b(bot_update|compile|gclient runhooks|generate_build_files|runhooks|update|\\w*nocompile_test)\\b" + email { + rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff" + } + template: "tree_closure_email_template" + } + builders { + bucket: "ci" name: "android-15-x64-rel" repository: "https://chromium.googlesource.com/chromium/src" }
diff --git a/infra/config/generated/sheriff-rotations/android.txt b/infra/config/generated/sheriff-rotations/android.txt index e63a4a2..d5f68cd 100644 --- a/infra/config/generated/sheriff-rotations/android.txt +++ b/infra/config/generated/sheriff-rotations/android.txt
@@ -19,6 +19,7 @@ ci/android-14-arm64-rel ci/android-14-tablet-landscape-arm64-rel ci/android-15-tablet-landscape-x64-rel +ci/android-15-tablet-x64-rel ci/android-15-x64-rel ci/android-androidx-packager ci/android-bfcache-rel
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star index 75f1a51c1..54ab2bc 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -4407,9 +4407,7 @@ targets_settings = targets.settings( os_type = targets.os_type.ANDROID, ), - # TODO(crbug.com/376748979 ): Enable gardening once tests are stable - gardener_rotations = args.ignore_default(None), - # tree_closing = True, + tree_closing = True, console_view_entry = consoles.console_view_entry( category = "builder_tester|x64", short_name = "15T",
diff --git a/ios/chrome/browser/credential_provider/model/ios_credential_provider_infobar_delegate_unittest.mm b/ios/chrome/browser/credential_provider/model/ios_credential_provider_infobar_delegate_unittest.mm index e903df42..04f8f0e 100644 --- a/ios/chrome/browser/credential_provider/model/ios_credential_provider_infobar_delegate_unittest.mm +++ b/ios/chrome/browser/credential_provider/model/ios_credential_provider_infobar_delegate_unittest.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/credential_provider/model/ios_credential_provider_infobar_delegate.h" #import "base/strings/sys_string_conversions.h" +#import "base/strings/utf_string_conversions.h" #import "base/test/task_environment.h" #import "components/sync/protocol/webauthn_credential_specifics.pb.h" #import "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/price_notifications/ui_bundled/price_notifications_price_tracking_mediator_unittest.mm b/ios/chrome/browser/price_notifications/ui_bundled/price_notifications_price_tracking_mediator_unittest.mm index 018109c..96204fb7 100644 --- a/ios/chrome/browser/price_notifications/ui_bundled/price_notifications_price_tracking_mediator_unittest.mm +++ b/ios/chrome/browser/price_notifications/ui_bundled/price_notifications_price_tracking_mediator_unittest.mm
@@ -12,6 +12,7 @@ #import "base/memory/raw_ptr.h" #import "base/strings/string_number_conversions.h" #import "base/strings/sys_string_conversions.h" +#import "base/strings/utf_string_conversions.h" #import "base/test/ios/wait_util.h" #import "components/bookmarks/test/bookmark_test_helpers.h" #import "components/commerce/core/mock_shopping_service.h"
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_test.mm b/ios/chrome/browser/reader_mode/model/reader_mode_test.mm index a2f404ce..5e761bf 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_test.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_test.mm
@@ -6,6 +6,7 @@ #import <memory> +#import "base/strings/utf_string_conversions.h" #import "components/dom_distiller/core/extraction_utils.h" #import "ios/chrome/browser/reader_mode/model/features.h" #import "ios/chrome/browser/reader_mode/model/reader_mode_java_script_feature.h"
diff --git a/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_non_eea_unittest.mm b/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_non_eea_unittest.mm index c1894c4..2cfc44f 100644 --- a/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_non_eea_unittest.mm +++ b/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_non_eea_unittest.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #import "base/command_line.h" +#import "base/strings/utf_string_conversions.h" #import "base/test/scoped_feature_list.h" #import "components/regional_capabilities/regional_capabilities_switches.h" #import "components/search_engines/template_url_data_util.h"
diff --git a/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_unittest.mm index 4bf24c3..bca31b3 100644 --- a/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_unittest.mm +++ b/ios/chrome/browser/settings/ui_bundled/search_engine_table_view_controller_unittest.mm
@@ -6,6 +6,7 @@ #import "base/apple/foundation_util.h" #import "base/strings/sys_string_conversions.h" +#import "base/strings/utf_string_conversions.h" #import "base/test/ios/wait_util.h" #import "ios/chrome/browser/favicon/model/favicon_service_factory.h" #import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index 74d6f92..1a0451f9 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -14,6 +14,7 @@ #import "base/functional/callback_helpers.h" #import "base/logging.h" #import "base/strings/sys_string_conversions.h" +#import "base/strings/utf_string_conversions.h" #import "base/task/sequenced_task_runner.h" #import "base/test/gmock_callback_support.h" #import "base/test/ios/wait_util.h"
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm index 9660090..43bd83b 100644 --- a/ios/web/web_state/web_state_unittest.mm +++ b/ios/web/web_state/web_state_unittest.mm
@@ -10,6 +10,7 @@ #import "base/path_service.h" #import "base/run_loop.h" #import "base/strings/stringprintf.h" +#import "base/strings/utf_string_conversions.h" #import "base/test/ios/wait_util.h" #import "base/test/metrics/histogram_tester.h" #import "base/values.h"
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc index e60b3b9..75056be 100644 --- a/ipc/ipc_mojo_bootstrap.cc +++ b/ipc/ipc_mojo_bootstrap.cc
@@ -21,6 +21,7 @@ #include "base/feature_list.h" #include "base/functional/bind.h" #include "base/functional/callback.h" +#include "base/hash/hash.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/no_destructor.h"
diff --git a/media/audio/mac/catap_audio_input_stream.mm b/media/audio/mac/catap_audio_input_stream.mm index cb1bb16..a54026f8 100644 --- a/media/audio/mac/catap_audio_input_stream.mm +++ b/media/audio/mac/catap_audio_input_stream.mm
@@ -51,19 +51,11 @@ "MacCatapProbeTapOnCreation", base::FEATURE_ENABLED_BY_DEFAULT); -// When `kMacCatapCaptureAllDevices` is disabled: -// -// CatapAudioInputStream captures audio from the default output device. However, -// if the device ID is explicitly set to `kLoopbackAllDevicesId`, it will -// capture all system audio regardless of the specific output device used for -// playback. -// -// When `kMacCatapCaptureAllDevices` is enabled: -// -// CatapAudioInputStream captures all system audio, irrespective of the specific -// output device it's played on or the device ID set. -BASE_FEATURE(kMacCatapCaptureAllDevices, - "MacCatapCaptureAllDevices", +// If this feature is enabled, we will only capture the default output device. +// If the feature is disabled, all system audio is captured regardless of which +// output device the audio is played on. +BASE_FEATURE(kMacCatapCaptureDefaultDevice, + "MacCatapCaptureDefaultDevice", base::FEATURE_DISABLED_BY_DEFAULT); API_AVAILABLE(macos(14.2)) @@ -226,13 +218,7 @@ } } - if (device_id_ == AudioDeviceDescription::kLoopbackAllDevicesId || - base::FeatureList::IsEnabled(kMacCatapCaptureAllDevices)) { - // Mix all processes to a stereo stream except the given processes. - tap_description_ = - [[CATapDescription alloc] initStereoGlobalTapButExcludeProcesses: - process_audio_device_ids_to_exclude]; - } else { + if (base::FeatureList::IsEnabled(kMacCatapCaptureDefaultDevice)) { // Mix all process audio streams destined for the selected device stream // except the given processes. tap_description_ = [[CATapDescription alloc] @@ -240,6 +226,11 @@ andDeviceUID:[NSString stringWithUTF8String: default_output_device_id_.c_str()] withStream:0]; + } else { + // Mix all processes to a stereo stream except the given processes. + tap_description_ = + [[CATapDescription alloc] initStereoGlobalTapButExcludeProcesses: + process_audio_device_ids_to_exclude]; } if (params_.channels() == 1) {
diff --git a/media/audio/mac/catap_audio_input_stream_unittest.mm b/media/audio/mac/catap_audio_input_stream_unittest.mm index 088da49..b2d3a3a 100644 --- a/media/audio/mac/catap_audio_input_stream_unittest.mm +++ b/media/audio/mac/catap_audio_input_stream_unittest.mm
@@ -3,16 +3,12 @@ // found in the LICENSE file. #include "media/audio/mac/catap_audio_input_stream.h" -#import <Foundation/Foundation.h> - #include <memory> #include <set> -#include <string> #include <utility> #include "base/memory/raw_ptr.h" #include "base/run_loop.h" -#include "base/strings/sys_string_conversions.h" #include "media/audio/audio_device_description.h" #include "media/audio/audio_manager.h" #include "media/audio/mac/audio_loopback_input_mac.h" @@ -152,19 +148,12 @@ // Set up expectations for a successful open. EXPECT_CALL(mock_catap_api(), AudioHardwareCreateProcessTap) - .WillOnce([](CATapDescription* in_description, - AudioObjectID* out_tap) { - // Default device selected. - EXPECT_EQ(std::string( - base::SysNSStringToUTF8([in_description deviceUID])), - media::AudioDeviceDescription::kDefaultDeviceId); - // Expect the first stream to be selected. - EXPECT_EQ([[in_description stream] intValue], 0); - // Not muted during capture. - EXPECT_EQ([in_description isMuted], CATapUnmuted); - *out_tap = kTap; - return noErr; - }); + .WillOnce( + [](CATapDescription* in_description, AudioObjectID* out_tap) { + EXPECT_EQ([in_description isMuted], CATapUnmuted); + *out_tap = kTap; + return noErr; + }); EXPECT_CALL(mock_catap_api(), AudioHardwareCreateAggregateDevice) .WillOnce([](CFDictionaryRef in_device_properties, AudioDeviceID* out_device) { @@ -505,54 +494,4 @@ } } -TEST_F(CatapAudioInputStreamTest, LoopbackWithAllDevices) { - if (@available(macOS 14.2, *)) { - auto mock_catap_api_object = std::make_unique<MockCatapApi>(); - // Keep a raw pointer to set expectations. - mock_catap_api_ = mock_catap_api_object.get(); - - // Create a CatapAudioInputStream for testing with - // kLoopbackWithMuteDeviceId. - stream_ = CreateCatapAudioInputStreamForTesting( - AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, - ChannelLayoutConfig::Stereo(), kLoopbackSampleRate, - kCatapLoopbackDefaultFramesPerBuffer), - media::AudioDeviceDescription::kLoopbackAllDevicesId, base::DoNothing(), - base::DoNothing(), media::AudioDeviceDescription::kDefaultDeviceId, - std::move(mock_catap_api_object)); - EXPECT_TRUE(stream_); - - // Set up expectations for a successful open. - EXPECT_CALL(mock_catap_api(), AudioHardwareCreateProcessTap) - .WillOnce([](CATapDescription* in_description, AudioObjectID* out_tap) { - // Device UID and stream not set indicates that we're capturing all - // devices. - EXPECT_EQ([in_description deviceUID], nullptr); - EXPECT_EQ([in_description stream], nullptr); - *out_tap = kTap; - return noErr; - }); - - EXPECT_CALL(mock_catap_api(), AudioHardwareCreateAggregateDevice) - .WillOnce([](CFDictionaryRef in_device_properties, - AudioDeviceID* out_device) { - *out_device = kAggregateDeviceId; - return noErr; - }); - EXPECT_CALL(mock_catap_api(), AudioDeviceCreateIOProcID) - .WillOnce([this](AudioDeviceID in_device, AudioDeviceIOProc proc, - void* in_client_data, - AudioDeviceIOProcID* out_proc_id) { - EXPECT_EQ(in_device, kAggregateDeviceId); - audio_proc_ = proc; - EXPECT_EQ(in_client_data, stream_); - *out_proc_id = kTapIoProcId; - return noErr; - }); - - // Initialize the stream. - EXPECT_EQ(stream_->Open(), AudioInputStream::OpenOutcome::kSuccess); - } -} - } // namespace media
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index 4114098..5e007131 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -23,7 +23,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/bind_post_task.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/typed_macros.h" #include "base/win/scoped_propvariant.h" #include "media/audio/audio_device_description.h" #include "media/audio/win/audio_manager_win.h"
diff --git a/media/base/cdm_factory.h b/media/base/cdm_factory.h index b82a601..c5a5e49 100644 --- a/media/base/cdm_factory.h +++ b/media/base/cdm_factory.h
@@ -49,8 +49,8 @@ kDisconnectionError = 13, // EME use is not allowed on unique origins. kNotAllowedOnUniqueOrigin = 14, - // Android: MediaDrmBridge creation failed. - kMediaDrmBridgeCreationFailed = 15, + // 15 was kMediaDrmBridgeCreationFailed; no longer used as we now use more + // detailed statuses. // Android: MediaCrypto not available. kMediaCryptoNotAvailable = 16, // CrOs: Only one instance allowed.
diff --git a/media/capture/video/chromeos/camera_buffer_factory.h b/media/capture/video/chromeos/camera_buffer_factory.h index f1320ccf..99ec1ca 100644 --- a/media/capture/video/chromeos/camera_buffer_factory.h +++ b/media/capture/video/chromeos/camera_buffer_factory.h
@@ -8,12 +8,12 @@ #include <map> #include <memory> -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/capture/video/chromeos/mojom/camera3.mojom.h" #include "media/capture/video/chromeos/pixel_format_utils.h" #include "media/capture/video_capture_types.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/color_space.h" +#include "ui/gfx/gpu_memory_buffer_handle.h" namespace gpu { class ClientSharedImage;
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc index 2fce4d9d..13bca97 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -22,29 +22,10 @@ // This class is designed as a singleton because it holds resources that needs // to be accessed globally. This ensures consistent state and minimizes memory // usage by sharing resources across components. -class GpuResources : public gpu::GpuMemoryBufferManagerObserver { +class GpuResources { public: GpuResources() = default; - void OnGpuMemoryBufferManagerDestroyed() override { - base::AutoLock lock(lock_); - // Invalidate the pointer to avoid dangling reference. - gpu_buffer_manager_ = nullptr; - } - - gpu::GpuMemoryBufferManager* GetBufferManager() const { - base::AutoLock lock(lock_); - return gpu_buffer_manager_; - } - - void SetBufferManager(gpu::GpuMemoryBufferManager* buffer_manager) { - base::AutoLock lock(lock_); - gpu_buffer_manager_ = buffer_manager; - if (buffer_manager) { - buffer_manager->AddObserver(this); - } - } - scoped_refptr<gpu::SharedImageInterface> GetSharedImageInterface() const { base::AutoLock lock(lock_); return shared_image_interface_; @@ -73,8 +54,6 @@ private: mutable base::Lock lock_; - raw_ptr<gpu::GpuMemoryBufferManager> gpu_buffer_manager_ GUARDED_BY(lock_) = - nullptr; scoped_refptr<gpu::SharedImageInterface> shared_image_interface_ GUARDED_BY(lock_); scoped_refptr<gpu::GpuChannelHost> gpu_channel_host_ GUARDED_BY(lock_);
diff --git a/media/gpu/chromeos/oop_video_decoder.cc b/media/gpu/chromeos/oop_video_decoder.cc index 991d68a..29e7c8a 100644 --- a/media/gpu/chromeos/oop_video_decoder.cc +++ b/media/gpu/chromeos/oop_video_decoder.cc
@@ -11,7 +11,6 @@ #include "base/task/sequenced_task_runner.h" #include "build/build_config.h" #include "chromeos/components/cdm_factory_daemon/cdm_context_for_oopvd_impl.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/format_utils.h" #include "media/base/video_util.h" #include "media/gpu/buffer_validation.h"
diff --git a/media/gpu/chromeos/vd_video_decode_accelerator.cc b/media/gpu/chromeos/vd_video_decode_accelerator.cc index 5ef359e..0f8c3527 100644 --- a/media/gpu/chromeos/vd_video_decode_accelerator.cc +++ b/media/gpu/chromeos/vd_video_decode_accelerator.cc
@@ -14,7 +14,6 @@ #include "base/not_fatal_until.h" #include "base/task/sequenced_task_runner.h" #include "gpu/config/gpu_driver_bug_workarounds.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/format_utils.h" #include "media/base/media_util.h" #include "media/base/video_color_space.h"
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc index fda5266..0125150 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -27,7 +27,6 @@ #include "base/task/sequenced_task_runner.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/format_utils.h" #include "media/base/media_log.h" #include "media/base/media_switches.h"
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom index 108ff17..82428c5 100644 --- a/media/mojo/mojom/media_types.mojom +++ b/media/mojo/mojom/media_types.mojom
@@ -675,7 +675,7 @@ kUnsupportedKeySystem = 12, kDisconnectionError = 13, kNotAllowedOnUniqueOrigin = 14, - kMediaDrmBridgeCreationFailed = 15, + //kMediaDrmBridgeCreationFailed = 15, // Deprecated kMediaCryptoNotAvailable = 16, kNoMoreInstances = 17, kInsufficientGpuResources = 18,
diff --git a/media/mojo/mojom/media_types_enum_mojom_traits.h b/media/mojo/mojom/media_types_enum_mojom_traits.h index 88278d6..edb001b 100644 --- a/media/mojo/mojom/media_types_enum_mojom_traits.h +++ b/media/mojo/mojom/media_types_enum_mojom_traits.h
@@ -521,8 +521,6 @@ return media::mojom::CreateCdmStatus::kDisconnectionError; case media::CreateCdmStatus::kNotAllowedOnUniqueOrigin: return media::mojom::CreateCdmStatus::kNotAllowedOnUniqueOrigin; - case media::CreateCdmStatus::kMediaDrmBridgeCreationFailed: - return media::mojom::CreateCdmStatus::kMediaDrmBridgeCreationFailed; case media::CreateCdmStatus::kMediaCryptoNotAvailable: return media::mojom::CreateCdmStatus::kMediaCryptoNotAvailable; case media::CreateCdmStatus::kNoMoreInstances: @@ -604,9 +602,6 @@ case media::mojom::CreateCdmStatus::kNotAllowedOnUniqueOrigin: *output = media::CreateCdmStatus::kNotAllowedOnUniqueOrigin; return true; - case media::mojom::CreateCdmStatus::kMediaDrmBridgeCreationFailed: - *output = media::CreateCdmStatus::kMediaDrmBridgeCreationFailed; - return true; case media::mojom::CreateCdmStatus::kMediaCryptoNotAvailable: *output = media::CreateCdmStatus::kMediaCryptoNotAvailable; return true;
diff --git a/media/mojo/services/oop_video_decoder_service_unittest.cc b/media/mojo/services/oop_video_decoder_service_unittest.cc index 93bc8ec..d465732 100644 --- a/media/mojo/services/oop_video_decoder_service_unittest.cc +++ b/media/mojo/services/oop_video_decoder_service_unittest.cc
@@ -9,7 +9,6 @@ #include "base/posix/eintr_wrapper.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/mojo/common/media_type_converters.h" #include "media/mojo/common/mojo_decoder_buffer_converter.h" #include "media/mojo/mojom/media_log.mojom.h"
diff --git a/media/renderers/win/media_foundation_stream_wrapper.cc b/media/renderers/win/media_foundation_stream_wrapper.cc index a3bd653..61420a6 100644 --- a/media/renderers/win/media_foundation_stream_wrapper.cc +++ b/media/renderers/win/media_foundation_stream_wrapper.cc
@@ -8,7 +8,7 @@ #include "base/functional/bind.h" #include "base/task/sequenced_task_runner.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "media/base/media_switches.h" #include "media/base/video_codecs.h" #include "media/base/win/mf_helpers.h"
diff --git a/net/BUILD.gn b/net/BUILD.gn index 4f9c88d..989dc44 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1787,6 +1787,8 @@ if (enable_disk_cache_sql_backend) { sources += [ + "disk_cache/sql/cache_entry_key.cc", + "disk_cache/sql/cache_entry_key.h", "disk_cache/sql/sql_backend_impl.cc", "disk_cache/sql/sql_backend_impl.h", ] @@ -3490,7 +3492,10 @@ } if (enable_disk_cache_sql_backend) { - sources += [ "disk_cache/sql/sql_backend_impl_unittest.cc" ] + sources += [ + "disk_cache/sql/cache_entry_key_unittest.cc", + "disk_cache/sql/sql_backend_impl_unittest.cc", + ] } }
diff --git a/net/base/features.cc b/net/base/features.cc index ace8fb63..348f9d0 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -303,6 +303,10 @@ "TcpPortRandomizationWinVersionMinimum", static_cast<int>(base::win::Version::WIN10_20H1)); +BASE_FEATURE(kTcpPortReuseMetricsWin, + "TcpPortReuseMetricsWin", + base::FEATURE_ENABLED_BY_DEFAULT); + BASE_FEATURE(kTcpSocketIoCompletionPortWin, "TcpSocketIoCompletionPortWin", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/net/base/features.h b/net/base/features.h index dae0829..89beac6 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -325,6 +325,10 @@ NET_EXPORT BASE_DECLARE_FEATURE_PARAM(int, kTcpPortRandomizationWinVersionMinimum); +// Whether or not TCP port reuse timing metrics are recorded. +// See crbug.com/40744069 for more details. +NET_EXPORT BASE_DECLARE_FEATURE(kTcpPortReuseMetricsWin); + // Whether to use a TCP socket implementation which uses an IO completion // handler to be notified of completed reads and writes, instead of an event. NET_EXPORT BASE_DECLARE_FEATURE(kTcpSocketIoCompletionPortWin);
diff --git a/net/base/trace_constants.h b/net/base/trace_constants.h index 0b77024..0460c7fe 100644 --- a/net/base/trace_constants.h +++ b/net/base/trace_constants.h
@@ -5,7 +5,7 @@ #ifndef NET_BASE_TRACE_CONSTANTS_H_ #define NET_BASE_TRACE_CONSTANTS_H_ -#include "base/trace_event/common/trace_event_common.h" +#include "base/trace_event/trace_event.h" namespace net {
diff --git a/net/base/tracing.h b/net/base/tracing.h index 340f2fbb..4b9f7a9c 100644 --- a/net/base/tracing.h +++ b/net/base/tracing.h
@@ -5,9 +5,8 @@ #ifndef NET_BASE_TRACING_H_ #define NET_BASE_TRACING_H_ +#include "base/trace_event/trace_event.h" // IWYU pragma: export #include "build/build_config.h" #include "net/base/cronet_buildflags.h" -#include "base/trace_event/base_tracing.h" // IWYU pragma: export - #endif // NET_BASE_TRACING_H_
diff --git a/net/disk_cache/sql/cache_entry_key.cc b/net/disk_cache/sql/cache_entry_key.cc new file mode 100644 index 0000000..575d114 --- /dev/null +++ b/net/disk_cache/sql/cache_entry_key.cc
@@ -0,0 +1,34 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/disk_cache/sql/cache_entry_key.h" + +#include "base/check.h" + +namespace disk_cache { + +CacheEntryKey::CacheEntryKey(std::string str) + : data_(base::MakeRefCounted<base::RefCountedString>(std::move(str))) {} + +CacheEntryKey::~CacheEntryKey() = default; + +CacheEntryKey::CacheEntryKey(const CacheEntryKey& other) = default; +CacheEntryKey::CacheEntryKey(CacheEntryKey&& other) = default; +CacheEntryKey& CacheEntryKey::operator=(const CacheEntryKey& other) = default; +CacheEntryKey& CacheEntryKey::operator=(CacheEntryKey&& other) = default; + +bool CacheEntryKey::operator<(const CacheEntryKey& other) const { + return data_ != other.data_ && string() < other.string(); +} + +bool CacheEntryKey::operator==(const CacheEntryKey& other) const { + return data_ == other.data_ || string() == other.string(); +} + +const std::string& CacheEntryKey::string() const { + DCHECK(data_); + return data_->as_string(); +} + +} // namespace disk_cache
diff --git a/net/disk_cache/sql/cache_entry_key.h b/net/disk_cache/sql/cache_entry_key.h new file mode 100644 index 0000000..97810b6f --- /dev/null +++ b/net/disk_cache/sql/cache_entry_key.h
@@ -0,0 +1,71 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_DISK_CACHE_SQL_CACHE_ENTRY_KEY_H_ +#define NET_DISK_CACHE_SQL_CACHE_ENTRY_KEY_H_ + +#include <optional> +#include <string> + +#include "base/memory/ref_counted.h" +#include "base/memory/ref_counted_memory.h" +#include "net/base/net_export.h" + +namespace disk_cache { + +// Represents the key for a cache entry in the SQL disk cache backend. +// +// This class is a wrapper around the cache key string, which is generated by +// HttpCache::GenerateCacheKeyForRequest(). These keys can be long, and the +// SQL backend uses them as keys in multiple in-memory maps (e.g., for tracking +// active, doomed, and recently used entries). The key is also passed between +// threads for database operations. +// +// To avoid high memory consumption from duplicating these long strings, this +// class holds the key in a `scoped_refptr<base::RefCountedString>`. This +// allows multiple data structures to share the same underlying string data +// cheaply, reducing overall memory usage. +// +// The class provides comparison operators and a `std::hash` specialization so +// it can be used efficiently as a key in both ordered and unordered STL +// containers. +// +// Future Work: For the Renderer-Accessible HTTP Cache project, this class is +// expected to be extended to also hold a cache isolation key, in addition to +// the main cache key string. +class NET_EXPORT_PRIVATE CacheEntryKey { + public: + explicit CacheEntryKey(std::string str = ""); + ~CacheEntryKey(); + + CacheEntryKey(const CacheEntryKey& other); + CacheEntryKey(CacheEntryKey&& other); + CacheEntryKey& operator=(const CacheEntryKey& other); + CacheEntryKey& operator=(CacheEntryKey&& other); + + bool operator<(const CacheEntryKey& other) const; + bool operator==(const CacheEntryKey& other) const; + + const std::string& string() const; + + private: + scoped_refptr<const base::RefCountedString> data_; +}; + +} // namespace disk_cache + +namespace std { + +// Implement hashing of CacheEntryKey, so it can be used as key in STL +// containers. +template <> +struct hash<disk_cache::CacheEntryKey> { + std::size_t operator()(const disk_cache::CacheEntryKey& k) const { + return std::hash<std::string>{}(k.string()); + } +}; + +} // namespace std + +#endif // NET_DISK_CACHE_SQL_CACHE_ENTRY_KEY_H_
diff --git a/net/disk_cache/sql/cache_entry_key_unittest.cc b/net/disk_cache/sql/cache_entry_key_unittest.cc new file mode 100644 index 0000000..cdd31f6be --- /dev/null +++ b/net/disk_cache/sql/cache_entry_key_unittest.cc
@@ -0,0 +1,146 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "net/disk_cache/sql/cache_entry_key.h" + +#include <string> +#include <unordered_set> +#include <utility> + +#include "testing/gtest/include/gtest/gtest.h" + +namespace disk_cache { +namespace { + +TEST(CacheEntryKeyTest, DefaultConstructor) { + CacheEntryKey key; + EXPECT_EQ(key.string(), ""); +} + +TEST(CacheEntryKeyTest, ValueConstructor) { + const std::string kValue = "my_key"; + CacheEntryKey key(kValue); + EXPECT_EQ(key.string(), kValue); +} + +TEST(CacheEntryKeyTest, CopyConstructor) { + const std::string kValue = "my_key"; + CacheEntryKey key1(kValue); + CacheEntryKey key2(key1); + + EXPECT_EQ(key1.string(), kValue); + EXPECT_EQ(key2.string(), kValue); + // The copy should be equal, and this also tests the fast-path where the + // underlying RefCountedString pointers are identical. + EXPECT_EQ(key1, key2); +} + +TEST(CacheEntryKeyTest, MoveConstructor) { + const std::string kValue = "my_key"; + CacheEntryKey key1(kValue); + CacheEntryKey key2(std::move(key1)); + + // The moved-to key should have the original value. + EXPECT_EQ(key2.string(), kValue); +} + +TEST(CacheEntryKeyTest, CopyAssignment) { + const std::string kValue1 = "key1"; + const std::string kValue2 = "key2"; + CacheEntryKey key1(kValue1); + CacheEntryKey key2(kValue2); + + EXPECT_NE(key1, key2); + + key2 = key1; + EXPECT_EQ(key1.string(), kValue1); + EXPECT_EQ(key2.string(), kValue1); + EXPECT_EQ(key1, key2); +} + +TEST(CacheEntryKeyTest, MoveAssignment) { + const std::string kValue1 = "key1"; + const std::string kValue2 = "key2"; + CacheEntryKey key1(kValue1); + CacheEntryKey key2(kValue2); + + EXPECT_NE(key1, key2); + + key2 = std::move(key1); + // The moved-to key should have the original value. + EXPECT_EQ(key2.string(), kValue1); +} + +TEST(CacheEntryKeyTest, ComparisonOperators) { + CacheEntryKey key_a("a"); + CacheEntryKey key_a_copy("a"); + CacheEntryKey key_b("b"); + CacheEntryKey empty_key(""); + + // Operator== + EXPECT_EQ(key_a, key_a_copy); + EXPECT_FALSE(key_a == key_b); + EXPECT_FALSE(key_a == empty_key); + EXPECT_EQ(CacheEntryKey(), empty_key); + + // Operator< + EXPECT_LT(key_a, key_b); + EXPECT_LT(empty_key, key_a); + EXPECT_FALSE(key_b < key_a); + EXPECT_FALSE(key_a < key_a); + EXPECT_FALSE(key_a < key_a_copy); +} + +TEST(CacheEntryKeyTest, LessThanOperatorFastPath) { + // 1. Test with two keys sharing the exact same underlying data object. + // The new `data_ != other.data_` check should short-circuit to false. + const std::string kValue = "my_key"; + CacheEntryKey key1(kValue); + CacheEntryKey key2(key1); + + ASSERT_EQ(key1, key2); + // An object cannot be less than itself. + EXPECT_FALSE(key1 < key2); + EXPECT_FALSE(key2 < key1); + + // 2. Test with two keys having different data objects but the same string + // value. The `data_ != other.data_` check passes, but the string + // comparison 'kValue < kValue' is correctly false. + CacheEntryKey key3(kValue); + + ASSERT_EQ(key1, key3); + // The pointers are different, but the strings are equal. + EXPECT_FALSE(key1 < key3); + EXPECT_FALSE(key3 < key1); +} + +TEST(CacheEntryKeyTest, StdHash) { + std::unordered_set<CacheEntryKey> key_set; + + CacheEntryKey key1("key1"); + CacheEntryKey key2("key2"); + CacheEntryKey key1_copy("key1"); + + // Insert keys. + auto result1 = key_set.insert(key1); + EXPECT_TRUE(result1.second); // Insertion should succeed. + EXPECT_EQ(key_set.size(), 1u); + + auto result2 = key_set.insert(key2); + EXPECT_TRUE(result2.second); + EXPECT_EQ(key_set.size(), 2u); + + // Try inserting a duplicate. + auto result3 = key_set.insert(key1_copy); + EXPECT_FALSE(result3.second); // Insertion should fail. + EXPECT_EQ(key_set.size(), 2u); + + // Find keys. + EXPECT_EQ(key_set.count(key1), 1u); + EXPECT_EQ(key_set.count(key2), 1u); + EXPECT_EQ(key_set.count(key1_copy), 1u); + EXPECT_EQ(key_set.count(CacheEntryKey("non_existent_key")), 0u); +} + +} // namespace +} // namespace disk_cache
diff --git a/net/log/net_log_util.cc b/net/log/net_log_util.cc index 1b86631..6bd306f 100644 --- a/net/log/net_log_util.cc +++ b/net/log/net_log_util.cc
@@ -17,7 +17,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" // IWYU pragma: export +#include "base/trace_event/trace_event.h" // IWYU pragma: export #include "base/values.h" #include "net/base/address_family.h" #include "net/base/load_states.h"
diff --git a/net/log/net_log_util.h b/net/log/net_log_util.h index 2d8f50bf..5b013dee93 100644 --- a/net/log/net_log_util.h +++ b/net/log/net_log_util.h
@@ -8,7 +8,7 @@ #include <memory> #include <set> -#include "base/trace_event/base_tracing.h" // IWYU pragma: export +#include "base/trace_event/trace_event.h" // IWYU pragma: export #include "net/base/net_export.h" #include "net/log/net_log.h"
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc index af9708d..bed3071 100644 --- a/net/socket/tcp_socket_win.cc +++ b/net/socket/tcp_socket_win.cc
@@ -17,7 +17,9 @@ #include "base/functional/callback_helpers.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" +#include "base/metrics/histogram_functions.h" #include "base/notimplemented.h" +#include "base/strings/string_util.h" #include "base/win/windows_version.h" #include "net/base/address_list.h" #include "net/base/features.h" @@ -107,6 +109,75 @@ features::kTcpPortRandomizationWinVersionMinimum.Get()); } +// [crbug.com/40744069] This function and the two below are used to track +// metrics on port reuse so that when SO_RANDOMIZE_PORT is enabled on windows +// we will know if the distribution skews in a way likely to cause errors. +std::map<std::string, base::Time>& GetLocalEndPointToLastSocketCloseTimeMap() { + static base::NoDestructor<std::map<std::string, base::Time>> map; + return *map; +} + +// See comment on GetLocalEndPointToLastSocketCloseTimeMap. +void RecordSocketConnectForReuseMetrics(TCPSocketWin* socket, bool success) { + if (!base::FeatureList::IsEnabled(features::kTcpPortReuseMetricsWin)) { + return; + } + net::IPEndPoint local_address; + int net_error = socket->GetLocalAddress(&local_address); + if (net_error != net::OK || local_address.address().IsZero() || + local_address.port() == 0) { + return; + } + base::Time last_closed_after_successful_open; + if (success) { + // If the port was successfully opened, then we should clear the last closed + // time and wait for it to be closed again. + const auto node = GetLocalEndPointToLastSocketCloseTimeMap().extract( + local_address.ToString()); + if (!node) { + return; + } + last_closed_after_successful_open = node.mapped(); + } else { + // If the port was not successfully opened, then we should just read the + // last closed time without clearing it so we can measure from last success. + const auto it = GetLocalEndPointToLastSocketCloseTimeMap().find( + local_address.ToString()); + if (it == GetLocalEndPointToLastSocketCloseTimeMap().end()) { + return; + } + last_closed_after_successful_open = it->second; + } + std::string ip_address_type = "Other"; + if (local_address.address().IsLoopback()) { + ip_address_type = "Loopback"; + } else if (local_address.address().IsLinkLocal()) { + ip_address_type = "LinkLocal"; + } + base::UmaHistogramTimes( + base::JoinString({"Net.TCPSocket.PortReuseTimeWindows", ip_address_type, + success ? "Success" : "Failure"}, + "."), + base::Time::Now() - last_closed_after_successful_open); +} + +// See comment on GetLocalEndPointToLastSocketCloseTimeMap. +void RecordSocketCloseForReuseMetrics(TCPSocketWin* socket) { + if (!base::FeatureList::IsEnabled(features::kTcpPortReuseMetricsWin)) { + return; + } + net::IPEndPoint local_address; + int net_error = socket->GetLocalAddress(&local_address); + if (net_error != net::OK || local_address.address().IsZero() || + local_address.port() == 0) { + return; + } + // If the map already contains an entry for `local_address` then the last open + // was unsuccessful and we should reuse the last close time instead. + GetLocalEndPointToLastSocketCloseTimeMap().try_emplace( + local_address.ToString(), base::Time::Now()); +} + } // namespace //----------------------------------------------------------------------------- @@ -807,6 +878,9 @@ // Only log the close event if there's actually a socket to close. net_log_.AddEvent(NetLogEventType::SOCKET_CLOSED); + // [crbug.com/40744069] Log port reuse metrics. + RecordSocketCloseForReuseMetrics(this); + // Note: don't use CancelIo to cancel pending IO because it doesn't work // when there is a Winsock layered service provider. @@ -1015,6 +1089,9 @@ net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT); } + // [crbug.com/40744069] Log port reuse metrics. + RecordSocketConnectForReuseMetrics(this, /*success=*/result == OK); + if (!logging_multiple_connect_attempts_) LogConnectEnd(result); }
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src index 35b5350..f0a8dce 160000 --- a/net/third_party/quiche/src +++ b/net/third_party/quiche/src
@@ -1 +1 @@ -Subproject commit 35b5350ab0afe83a60dbf23ac0f4585e901db7f8 +Subproject commit f0a8dcea08196573119875267b4f8303241a24d9
diff --git a/services/on_device_model/on_device_model_service_unittest.cc b/services/on_device_model/on_device_model_service_unittest.cc index 7cacebe..70849fe2 100644 --- a/services/on_device_model/on_device_model_service_unittest.cc +++ b/services/on_device_model/on_device_model_service_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" +#include "base/threading/thread_restrictions.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/on_device_model/fake/fake_chrome_ml_api.h" #include "services/on_device_model/fake/on_device_model_fake.h"
diff --git a/services/tracing/public/cpp/background_tracing/background_tracing_agent_impl.cc b/services/tracing/public/cpp/background_tracing/background_tracing_agent_impl.cc index bbe29ea..e8f341cc 100644 --- a/services/tracing/public/cpp/background_tracing/background_tracing_agent_impl.cc +++ b/services/tracing/public/cpp/background_tracing/background_tracing_agent_impl.cc
@@ -10,6 +10,7 @@ #include "base/metrics/statistics_recorder.h" #include "base/trace_event/histogram_scope.h" #include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_id_helper.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "services/tracing/public/cpp/perfetto/macros.h" #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.h"
diff --git a/services/viz/privileged/mojom/gl/BUILD.gn b/services/viz/privileged/mojom/gl/BUILD.gn index 0c4ce5c..991caeaa 100644 --- a/services/viz/privileged/mojom/gl/BUILD.gn +++ b/services/viz/privileged/mojom/gl/BUILD.gn
@@ -10,6 +10,7 @@ sources = [ "context_lost_reason.mojom", "gpu_host.mojom", + "gpu_logging.mojom", "gpu_service.mojom", ]
diff --git a/services/viz/privileged/mojom/gl/gpu_host.mojom b/services/viz/privileged/mojom/gl/gpu_host.mojom index 6030596..ac72fdb8 100644 --- a/services/viz/privileged/mojom/gl/gpu_host.mojom +++ b/services/viz/privileged/mojom/gl/gpu_host.mojom
@@ -73,8 +73,6 @@ mojo_base.mojom.ByteString key, mojo_base.mojom.ByteString blob); - RecordLogMessage(int32 severity, string header, string message); - // Tells the GPU host to clear the shader disk cache. ClearGrShaderDiskCache(); };
diff --git a/services/viz/privileged/mojom/gl/gpu_logging.mojom b/services/viz/privileged/mojom/gl/gpu_logging.mojom new file mode 100644 index 0000000..be64dca --- /dev/null +++ b/services/viz/privileged/mojom/gl/gpu_logging.mojom
@@ -0,0 +1,15 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module viz.mojom; + +// This is used for sending GPU process log messages to the browser process. +// This mojom file is extracted from gpu_host.mojom, to have a separate mojo +// channel to handle log messages. The Remote side is running on GPU IO thread. +// When GPU context is lost, terminate GPU process on IO thread to make sure +// GPU log messages are sent to browser process as much as possible. +interface GpuLogging { + // Record GPU process log messages. The messages are shown on chrome://gpu. + RecordLogMessage(int32 severity, string header, string message); +};
diff --git a/services/viz/privileged/mojom/viz_main.mojom b/services/viz/privileged/mojom/viz_main.mojom index e0002e50..6650895a 100644 --- a/services/viz/privileged/mojom/viz_main.mojom +++ b/services/viz/privileged/mojom/viz_main.mojom
@@ -12,6 +12,7 @@ import "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom"; import "services/viz/privileged/mojom/compositing/renderer_settings.mojom"; import "services/viz/privileged/mojom/gl/gpu_host.mojom"; +import "services/viz/privileged/mojom/gl/gpu_logging.mojom"; [EnableIf=is_win] import "services/viz/privileged/mojom/gl/info_collection_gpu_service.mojom"; import "services/viz/privileged/mojom/gl/gpu_service.mojom"; @@ -52,6 +53,7 @@ CreateGpuService( pending_receiver<GpuService> gpu_service, pending_remote<GpuHost> gpu_host, + pending_remote<GpuLogging> gpu_logging, pending_remote<discardable_memory.mojom.DiscardableSharedMemoryManager> discardable_memory_manager, mojo_base.mojom.UnsafeSharedMemoryRegion? use_shader_cache_shm_count,
diff --git a/sql/statement.cc b/sql/statement.cc index 4648ef4..52e8270 100644 --- a/sql/statement.cc +++ b/sql/statement.cc
@@ -34,7 +34,7 @@ #include "base/threading/scoped_blocking_call.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "sql/database.h" #include "sql/sqlite_result_code.h" #include "sql/sqlite_result_code_values.h"
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc index 6d1d8f3..d5b6b4b 100644 --- a/storage/browser/quota/quota_manager_unittest.cc +++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -33,6 +33,7 @@ #include "base/test/simple_test_clock.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" +#include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "components/services/storage/public/cpp/buckets/bucket_info.h" #include "components/services/storage/public/cpp/buckets/bucket_locator.h"
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index bad25f7..d72e37a 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3164,29 +3164,6 @@ ] } ], - "BackgroundUpdateForRegisteredStorageKeys": [ - { - "platforms": [ - "android", - "android_webview", - "chromeos", - "chromeos_lacros", - "fuchsia", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "BackgroundUpdateForRegisteredStorageKeys", - "enable_features": [ - "ServiceWorkerBackgroundUpdateForRegisteredStorageKeys", - "ServiceWorkerBackgroundUpdateForRegisteredStorageKeysFinchControlled" - ] - } - ] - } - ], "BatchNativeEventsInMessagePumpEpoll": [ { "platforms": [ @@ -7397,6 +7374,26 @@ ] } ], + "DefaultSiteInstanceGroups": [ + { + "platforms": [ + "android", + "chromeos", + "fuchsia", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "DefaultSiteInstanceGroups" + ] + } + ] + } + ], "DeferConciergeStartup": [ { "platforms": [ @@ -22415,6 +22412,42 @@ ] } ], + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeys": [ + { + "platforms": [ + "android", + "chromeos", + "chromeos_lacros", + "fuchsia", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "ServiceWorkerBackgroundUpdateForRegisteredStorageKeys", + "enable_features": [ + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeys" + ] + } + ] + } + ], + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeysForWebView": [ + { + "platforms": [ + "android_webview" + ], + "experiments": [ + { + "name": "ServiceWorkerBackgroundUpdateForRegisteredStorageKeysForWebView", + "enable_features": [ + "ServiceWorkerBackgroundUpdateForRegisteredStorageKeysFieldTrialControlled" + ] + } + ] + } + ], "ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index f6b40bc..db96240 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit f6b40bc8397af944cb09ecb606b2d809466a5f02 +Subproject commit db9624073324a2e5b485df7ba24c4cd45d9dceab
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index b39b3e7..8d612733 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -4700,6 +4700,11 @@ protanopia tritanopia + # Emulates the given OS text scale. + command setEmulatedOSTextScale + parameters + optional number scale + # Overrides the Geolocation Position or Error. Omitting latitude, longitude or # accuracy emulates position unavailable. command setGeolocationOverride
diff --git a/third_party/blink/public/mojom/on_device_translation/translation_manager.mojom b/third_party/blink/public/mojom/on_device_translation/translation_manager.mojom index 455ac51..44cb7b66 100644 --- a/third_party/blink/public/mojom/on_device_translation/translation_manager.mojom +++ b/third_party/blink/public/mojom/on_device_translation/translation_manager.mojom
@@ -38,16 +38,23 @@ // language pair is not supported. kNoNotSupportedLanguage = 5, + // The translator cannot be created because the Accept-Language check failed. + kNoAcceptLanguagesCheckFailed = 6, + + // The translator cannot be created. New models need to be downloaded, + // but the number of downloaded language packs will exceedd the limit. + kNoExceedsLanguagePackCountLimitation = 7, + // The translator cannot be created, because the translator service crashed. - kNoServiceCrashed = 6, + kNoServiceCrashed = 8, // The translator cannot be created, because the use of Translator API is // disallowed by `TranslatorAPIAllowed` Enterprise policy - kNoDisallowedByPolicy = 7, + kNoDisallowedByPolicy = 9, // The translator cannot be created, because the number of services exceeds // the limitation. - kNoExceedsServiceCountLimitation = 8, + kNoExceedsServiceCountLimitation = 10, }; // The error of TranslationManager's CreateTranslator IPC. @@ -67,23 +74,30 @@ // translator. kFailedToCreateTranslator = 4, + // The translator cannot be created because the Accept-Language check failed. + kAcceptLanguagesCheckFailed = 5, + + // The translator cannot be created. New models need to be downloaded, + // but the number of downloaded language packs will exceedd the limit. + kExceedsLanguagePackCountLimitation = 6, + // The translator cannot be created, because the translator service crashed. - kServiceCrashed = 5, + kServiceCrashed = 7, // The translator cannot be created, because the use of Translator API is // disallowed by `TranslatorAPIAllowed` Enterprise policy - kDisallowedByPolicy = 6, + kDisallowedByPolicy = 8, // The translator cannot be created, because the number of services exceeds // the limitation. - kExceedsServiceCountLimitation = 7, + kExceedsServiceCountLimitation = 9, // The translator cannot be created, because the number of pending tasks // exceeds the limitation. - kExceedsPendingTaskCountLimitation = 8, + kExceedsPendingTaskCountLimitation = 10, // The translator cannot be created because the library version is invalid. - kInvalidVersion = 9, + kInvalidVersion = 11, }; // The result of TranslationManager's CreateTranslator IPC.
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc index 90692da7..3d700ee 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.cc +++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -161,8 +161,9 @@ dev_tools_emulator_->SetTextAutosizingEnabled(enabled); } +// TODO(pdr): Rename this OSTextScaleFactor. void WebSettingsImpl::SetAccessibilityFontScaleFactor(float font_scale_factor) { - settings_->SetAccessibilityFontScaleFactor(font_scale_factor); + dev_tools_emulator_->SetAccessibilityFontScaleFactor(font_scale_factor); } void WebSettingsImpl::SetAccessibilityTextSizeContrastFactor(
diff --git a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc index 066b050..a40102a 100644 --- a/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc +++ b/third_party/blink/renderer/core/frame/animation_frame_timing_monitor.cc
@@ -5,7 +5,7 @@ #include "third_party/blink/renderer/core/frame/animation_frame_timing_monitor.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "components/viz/common/frame_timing_details.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h"
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc index 4a1b4c4..82497f2 100644 --- a/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc +++ b/third_party/blink/renderer/core/html/anchor_element_metrics_sender_test.cc
@@ -1030,7 +1030,7 @@ constexpr gfx::Vector2dF velocity{20, 20}; constexpr base::TimeDelta timestep = base::Milliseconds(20); for (base::TimeDelta t; - t <= 2 * AnchorElementInteractionTracker::GetHoverDwellTime(); + t <= 2 * AnchorElementInteractionTracker::kModerateHoverDwellTime; t += timestep) { gfx::PointF coordinates = origin + gfx::ScaleVector2d(velocity, t.InSecondsF());
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc index 9bf1156..2e8a2c7 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -146,11 +146,6 @@ CanvasResourceProvider* CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderForCanvas2D() { CHECK(IsRenderingContext2D()); - - // NOTE: When further reorganizing this code, it is important to preserve the - // flow of HTMLCanvasElement overriding - // GetOrCreateCanvasResourceProviderImpl() to customize the creation of - // Canvas2D resource providers. return GetOrCreateCanvasResourceProviderImpl(); }
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h index ffa01b6..6fce9f99 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
@@ -148,7 +148,7 @@ scoped_refptr<StaticBitmapImage> CreateTransparentImage() const; - CanvasResourceProvider* GetOrCreateCanvasResourceProviderImpl() override; + CanvasResourceProvider* GetOrCreateCanvasResourceProviderImpl() final; bool ContextHasOpenLayers(const CanvasRenderingContext*) const;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index f410bf9..51a7932 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -2218,7 +2218,7 @@ // Bail out if it's not possible to create a new provider. CanvasResourceProvider* new_provider = - RecreateCanvasResourceProviderFor2DContext( + RecreateCanvasResourceProviderForCanvas2D( CHECK_DEREF(hibernation_handler_.get())); if (!new_provider) { return; @@ -2231,69 +2231,67 @@ } CanvasResourceProvider* -HTMLCanvasElement::GetOrCreateCanvasResourceProviderImpl() { - if (IsRenderingContext2D()) { - CanvasResourceProvider* resource_provider = - GetResourceProviderForCanvas2D(); - if (context_->isContextLost() && !context_->IsContextBeingRestored()) { - DCHECK(!resource_provider); +HTMLCanvasElement::GetOrCreateCanvasResourceProviderForCanvas2D() { + CHECK(IsRenderingContext2D()); + CanvasResourceProvider* resource_provider = GetResourceProviderForCanvas2D(); + if (context_->isContextLost() && !context_->IsContextBeingRestored()) { + DCHECK(!resource_provider); + return nullptr; + } + + if (resource_provider) { + if (!resource_provider->IsValid()) { + // The canvas context is not lost but the provider is invalid. This + // happens if the GPU process dies in the middle of a render task. The + // canvas is notified of GPU context losses via the + // `NotifyGpuContextLost` callback and restoration happens in + // `TryRestoreContextEvent`. Both callbacks are executed in their own + // separate task. If the GPU context goes invalid in the middle of a + // render task, the canvas won't immediately know about it and canvas + // APIs will continue using the provider that is now invalid. We can + // early return here, trying to re-create the provider right away would + // just fail. We need to let `TryRestoreContextEvent` wait for the GPU + // process to up again. return nullptr; } - - if (resource_provider) { - if (!resource_provider->IsValid()) { - // The canvas context is not lost but the provider is invalid. This - // happens if the GPU process dies in the middle of a render task. The - // canvas is notified of GPU context losses via the - // `NotifyGpuContextLost` callback and restoration happens in - // `TryRestoreContextEvent`. Both callbacks are executed in their own - // separate task. If the GPU context goes invalid in the middle of a - // render task, the canvas won't immediately know about it and canvas - // APIs will continue using the provider that is now invalid. We can - // early return here, trying to re-create the provider right away would - // just fail. We need to let `TryRestoreContextEvent` wait for the GPU - // process to up again. - return nullptr; - } - return resource_provider; - } - - if (did_fail_to_create_resource_provider_) { - return nullptr; - } - - if (!IsValidImageSize()) { - did_fail_to_create_resource_provider_ = true; - if (!Size().IsEmpty() && context_) { - context_->LoseContext(CanvasRenderingContext::kInvalidCanvasSize); - } - return nullptr; - } - - UpdatePreferred2DRasterMode(); - - if (!hibernation_handler_) { - hibernation_handler_ = std::make_unique<CanvasHibernationHandler>(*this); - } - - resource_provider = RecreateCanvasResourceProviderFor2DContext( - CHECK_DEREF(hibernation_handler_.get())); - - UpdateMemoryUsage(); - - if (context_) { - SetNeedsCompositingUpdate(); - } - return resource_provider; } - return CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderImpl(); + if (did_fail_to_create_resource_provider_) { + return nullptr; + } + + if (!IsValidImageSize()) { + did_fail_to_create_resource_provider_ = true; + if (!Size().IsEmpty() && context_) { + context_->LoseContext(CanvasRenderingContext::kInvalidCanvasSize); + } + return nullptr; + } + + UpdatePreferred2DRasterMode(); + + if (!hibernation_handler_) { + hibernation_handler_ = std::make_unique<CanvasHibernationHandler>(*this); + } + + resource_provider = RecreateCanvasResourceProviderForCanvas2D( + CHECK_DEREF(hibernation_handler_.get())); + + UpdateMemoryUsage(); + + if (context_) { + SetNeedsCompositingUpdate(); + } + + return resource_provider; } CanvasResourceProvider* -HTMLCanvasElement::RecreateCanvasResourceProviderFor2DContext( +HTMLCanvasElement::RecreateCanvasResourceProviderForCanvas2D( CanvasHibernationHandler& hibernation_handler) { + CHECK(IsRenderingContext2D()); + // We call GetOrCreateCanvasResourceProviderImpl directly here to prevent a // circular callstack. CanvasResourceProvider* resource_provider =
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 8a75c71..f59e2b2f 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -260,7 +260,8 @@ size_t GetMemoryUsage() const override; bool ShouldAccelerate2dContext() const override; bool LowLatencyEnabled() const override; - CanvasResourceProvider* GetOrCreateCanvasResourceProviderImpl() override; + CanvasResourceProvider* GetOrCreateCanvasResourceProviderForCanvas2D() + override; bool IsPrinting() const override; bool IsHibernating() const override; void SetTransferToGPUTextureWasInvoked() override; @@ -383,7 +384,7 @@ // Recreates the resource provider. // TODO(crbug.com/40280152): Remove parameter once the hibernation handler is // an instance variable of this class. - CanvasResourceProvider* RecreateCanvasResourceProviderFor2DContext( + CanvasResourceProvider* RecreateCanvasResourceProviderForCanvas2D( CanvasHibernationHandler& hibernation_handler); void ColorSchemeMayHaveChanged();
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc index 48db1f880..f26c29e 100644 --- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc +++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -161,7 +161,10 @@ document_cookie_disabled_(false), embedder_force_dark_mode_enabled_( web_view->GetPage()->GetSettings().GetForceDarkModeEnabled()), - auto_dark_overriden_(false) {} + auto_dark_overriden_(false), + embedder_accessibility_font_scale_( + web_view->GetPage()->GetSettings().GetAccessibilityFontScaleFactor()), + accessibility_font_scale_emulation_enabled_(false) {} DevToolsEmulator::~DevToolsEmulator() { // This class is GarbageCollected, so desturctor may run at any time, hence @@ -589,4 +592,28 @@ } } +void DevToolsEmulator::SetAccessibilityFontScaleFactor(double scale) { + embedder_accessibility_font_scale_ = scale; + if (!accessibility_font_scale_emulation_enabled_) { + web_view_->GetPage()->GetSettings().SetAccessibilityFontScaleFactor(scale); + } +} + +void DevToolsEmulator::SetEmulatedAccessibilityFontScaleFactor(double scale) { + if (!accessibility_font_scale_emulation_enabled_) { + accessibility_font_scale_emulation_enabled_ = true; + embedder_accessibility_font_scale_ = + web_view_->GetPage()->GetSettings().GetAccessibilityFontScaleFactor(); + } + web_view_->GetPage()->GetSettings().SetAccessibilityFontScaleFactor(scale); +} + +void DevToolsEmulator::ResetEmulatedAccessibilityFontScaleFactor() { + if (accessibility_font_scale_emulation_enabled_) { + web_view_->GetPage()->GetSettings().SetAccessibilityFontScaleFactor( + embedder_accessibility_font_scale_); + accessibility_font_scale_emulation_enabled_ = false; + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.h b/third_party/blink/renderer/core/inspector/dev_tools_emulator.h index c365bc0..676047a 100644 --- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.h +++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.h
@@ -69,6 +69,10 @@ void SetAutoDarkModeOverride(bool); void ResetAutoDarkModeOverride(); + void SetAccessibilityFontScaleFactor(double scale); + void SetEmulatedAccessibilityFontScaleFactor(double scale); + void ResetEmulatedAccessibilityFontScaleFactor(); + bool HasViewportOverride() const { return !!viewport_override_; } // Notify the DevToolsEmulator about a scroll or scale change of the @@ -160,6 +164,9 @@ bool embedder_force_dark_mode_enabled_; bool auto_dark_overriden_; + + double embedder_accessibility_font_scale_; + bool accessibility_font_scale_emulation_enabled_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc index dd6f535..f237543a 100644 --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -95,6 +95,8 @@ emulated_media_features_(&agent_state_, /*default_value=*/WTF::String()), emulated_vision_deficiency_(&agent_state_, /*default_value=*/WTF::String()), + os_text_scale_emulation_enabled_(&agent_state_, /*default_value=*/false), + emulated_os_text_scale_(&agent_state_, /*default_value=*/1), navigator_platform_override_(&agent_state_, /*default_value=*/WTF::String()), hardware_concurrency_override_(&agent_state_, /*default_value=*/0), @@ -171,11 +173,17 @@ setEmulatedMedia(emulated_media_.Get(), std::move(features)); if (!emulated_vision_deficiency_.Get().IsNull()) setEmulatedVisionDeficiency(emulated_vision_deficiency_.Get()); + if (os_text_scale_emulation_enabled_.Get()) { + setEmulatedOSTextScale(emulated_os_text_scale_.Get()); + } auto status_or_rgba = protocol::DOM::RGBA::ReadFrom( default_background_color_override_rgba_.Get()); if (status_or_rgba.ok()) setDefaultBackgroundColorOverride(std::move(status_or_rgba).value()); - setFocusEmulationEnabled(emulate_focus_.Get()); + if (emulate_focus_.Get()) { + setFocusEmulationEnabled(true); + } + if (emulate_auto_dark_mode_.Get()) setAutoDarkModeOverride(auto_dark_mode_override_.Get()); if (!timezone_id_override_.Get().IsNull()) @@ -242,8 +250,11 @@ std::make_unique<protocol::Array<protocol::Emulation::MediaFeature>>()); if (!emulated_vision_deficiency_.Get().IsNull()) setEmulatedVisionDeficiency(String("none")); + setEmulatedOSTextScale(std::nullopt); setCPUThrottlingRate(1); - setFocusEmulationEnabled(false); + if (emulate_focus_.Get()) { + setFocusEmulationEnabled(false); + } if (emulate_auto_dark_mode_.Get()) { setAutoDarkModeOverride(std::nullopt); } @@ -449,6 +460,27 @@ return response; } +protocol::Response InspectorEmulationAgent::setEmulatedOSTextScale( + std::optional<double> scale) { + protocol::Response response = AssertPage(); + if (!response.IsSuccess()) { + return response; + } + if (scale.has_value()) { + os_text_scale_emulation_enabled_.Set(true); + emulated_os_text_scale_.Set(scale.value()); + GetWebViewImpl() + ->GetDevToolsEmulator() + ->SetEmulatedAccessibilityFontScaleFactor(scale.value()); + } else { + os_text_scale_emulation_enabled_.Set(false); + GetWebViewImpl() + ->GetDevToolsEmulator() + ->ResetEmulatedAccessibilityFontScaleFactor(); + } + return response; +} + protocol::Response InspectorEmulationAgent::setCPUThrottlingRate(double rate) { protocol::Response response = AssertPage(); if (!response.IsSuccess()) @@ -463,9 +495,6 @@ protocol::Response response = AssertPage(); if (!response.IsSuccess()) return response; - if (enabled == emulate_focus_.Get()) { - return response; - } emulate_focus_.Set(enabled); GetWebViewImpl()->GetPage()->GetFocusController().SetFocusEmulationEnabled( enabled);
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h index 49bd6e2..346e0378 100644 --- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.h
@@ -55,6 +55,7 @@ std::unique_ptr<protocol::Array<protocol::Emulation::MediaFeature>> features) override; protocol::Response setEmulatedVisionDeficiency(const String&) override; + protocol::Response setEmulatedOSTextScale(std::optional<double>) override; protocol::Response setCPUThrottlingRate(double) override; protocol::Response setFocusEmulationEnabled(bool) override; protocol::Response setAutoDarkModeOverride(std::optional<bool>) override; @@ -159,6 +160,8 @@ InspectorAgentState::String emulated_media_; InspectorAgentState::StringMap emulated_media_features_; InspectorAgentState::String emulated_vision_deficiency_; + InspectorAgentState::Boolean os_text_scale_emulation_enabled_; + InspectorAgentState::Double emulated_os_text_scale_; InspectorAgentState::String navigator_platform_override_; InspectorAgentState::Integer hardware_concurrency_override_; InspectorAgentState::String user_agent_override_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json index b06549c..7b6e9fbb 100644 --- a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json +++ b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
@@ -98,7 +98,7 @@ { "domain": "Emulation", "include": ["forceViewport", "resetViewport", "resetPageScaleFactor", "setPageScaleFactor", "setScriptExecutionDisabled", "setTouchEmulationEnabled", "setSmallViewportHeightDifferenceOverride", - "setEmulatedMedia", "setEmulatedVisionDeficiency", "setCPUThrottlingRate", "setVirtualTimePolicy", "setTimezoneOverride", "setNavigatorOverrides", "setDefaultBackgroundColorOverride", "setSafeAreaInsetsOverride", "setDeviceMetricsOverride", "clearDeviceMetricsOverride", + "setEmulatedMedia", "setEmulatedVisionDeficiency", "setEmulatedOSTextScale", "setCPUThrottlingRate", "setVirtualTimePolicy", "setTimezoneOverride", "setNavigatorOverrides", "setDefaultBackgroundColorOverride", "setSafeAreaInsetsOverride", "setDeviceMetricsOverride", "clearDeviceMetricsOverride", "setHardwareConcurrencyOverride", "setUserAgentOverride", "setScrollbarsHidden", "setDocumentCookieDisabled", "setFocusEmulationEnabled", "setAutoDarkModeOverride", "setLocaleOverride", "setDisabledImageTypes", "setAutomationOverride"], "include_events": ["virtualTimeBudgetExpired", "virtualTimeAdvanced", "virtualTimePaused"] },
diff --git a/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc index d5e50ad2..1a80efa8 100644 --- a/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/flex/flex_layout_algorithm.cc
@@ -343,6 +343,9 @@ // "last" here refers to last in the block direction. bool is_last_edge_intersection = flex_line_index == flex_lines.size() - 1; + // "last" here refers to last in the inline direction. + bool is_last_item_in_line = + item_index_in_line == flex_line.item_indices.size() - 1; if (item_index_in_line == 0) { // For the first item in each line, the intersection associated with @@ -369,26 +372,37 @@ if (is_first_edge_intersection) { PopulateGapIntersectionsForFirstLine( flex_line, flex_lines.size(), - item_index_in_line == flex_line.item_indices.size() - 1, main_intersection_offset, item_cross_intersections_list); } else if (is_last_edge_intersection) { PopulateGapIntersectionsForLastLine(flex_line, main_intersection_offset, item_cross_intersections_list); } else { - PopulateGapIntersectionsForMiddleItem( - flex_lines, item_index_in_line == flex_line.item_indices.size() - 1, - flex_line_index, main_intersection_offset, - item_cross_intersections_list); + PopulateGapIntersectionsForMiddleItem(flex_lines, flex_line_index, + main_intersection_offset, + item_cross_intersections_list); } cross_axis_gaps_.push_back(std::move(item_cross_intersections_list)); } + + if (is_last_item_in_line && flex_lines.size() > 1 && + !is_last_edge_intersection) { + // If we are the last item in any line except the last, we add the + // intersection of the next main gap with the edge of the container to the + // main axis gap intersections. + LayoutUnit next_main_axis_gap_start = flex_line.LineCrossEnd(); + LayoutUnit next_main_axis_gap_end = + flex_line.LineCrossEnd() + gap_between_lines_; + LayoutUnit cross_intersection_offset = + (next_main_axis_gap_start + next_main_axis_gap_end) / 2; + PopulateNextMainAxisGapIntersectionsForLastItem( + cross_intersection_offset); + } } void PopulateGapIntersectionsForFirstLine( const FlexLine& flex_line, wtf_size_t num_lines, - bool is_last_item_in_line, LayoutUnit main_intersection_offset, Vector<GapIntersection>& item_cross_intersections_list) { // This method assumes that the inline offset of the @@ -418,10 +432,6 @@ AddGapIntersectionToResults(main_intersection_offset, cross_intersection_offset, main_intersections_after_current_line_); - - if (is_last_item_in_line) { - PopulateMainAxisGapIntersectionsForLastItem(cross_intersection_offset); - } } } @@ -481,7 +491,7 @@ main_intersections_before_current_line_.clear(); } - void PopulateMainAxisGapIntersectionsForLastItem( + void PopulateNextMainAxisGapIntersectionsForLastItem( LayoutUnit cross_intersection_offset) { CHECK(container_builder_); // If we are the last item on the line, we add the intersection @@ -502,7 +512,6 @@ void PopulateGapIntersectionsForMiddleItem( const FlexLineVector& flex_lines, - bool is_last_item_in_line, size_t flex_line_index, LayoutUnit main_intersection_offset, Vector<GapIntersection>& item_cross_intersections_list) { @@ -536,10 +545,6 @@ AddGapIntersectionToResults(main_intersection_offset, cross_intersection_offset, item_cross_intersections_list); - - if (is_last_item_in_line) { - PopulateMainAxisGapIntersectionsForLastItem(cross_intersection_offset); - } } void PopulateGapIntersectionsForLastLine(
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc b/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc index 16e2c15..10153a2 100644 --- a/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc +++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc
@@ -362,7 +362,7 @@ // Wait for hover logic to process the event task_runner->AdvanceTimeAndRun( - AnchorElementInteractionTracker::GetHoverDwellTime()); + AnchorElementInteractionTracker::kModerateHoverDwellTime); base::RunLoop().RunUntilIdle(); KURL expected_url = KURL("https://anchor1.com/"); @@ -397,7 +397,7 @@ // Wait for hover logic to process the event task_runner->AdvanceTimeAndRun( - 0.5 * AnchorElementInteractionTracker::GetHoverDwellTime()); + 0.5 * AnchorElementInteractionTracker::kModerateHoverDwellTime); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, hosts_.size()); @@ -430,7 +430,7 @@ mouse_enter_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>()); task_runner->AdvanceTimeAndRun( - 0.5 * AnchorElementInteractionTracker::GetHoverDwellTime()); + 0.5 * AnchorElementInteractionTracker::kModerateHoverDwellTime); WebMouseEvent mouse_leave_event( WebInputEvent::Type::kMouseLeave, coordinates, coordinates, @@ -441,7 +441,7 @@ // Wait for hover logic to process the event task_runner->AdvanceTimeAndRun( - AnchorElementInteractionTracker::GetHoverDwellTime()); + AnchorElementInteractionTracker::kModerateHoverDwellTime); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1u, hosts_.size()); @@ -586,7 +586,7 @@ constexpr gfx::Vector2dF velocity{40, -30}; constexpr base::TimeDelta timestep = base::Milliseconds(20); for (base::TimeDelta t; - t <= AnchorElementInteractionTracker::GetHoverDwellTime(); + t <= AnchorElementInteractionTracker::kModerateHoverDwellTime; t += timestep) { gfx::PointF coordinates = origin + gfx::ScaleVector2d(velocity, t.InSecondsF());
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc index 8442356dc..f54cae8 100644 --- a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc +++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc
@@ -291,14 +291,6 @@ AnchorElementViewportPositionTracker::Observer::Trace(visitor); } -// static -base::TimeDelta AnchorElementInteractionTracker::GetHoverDwellTime() { - static base::FeatureParam<base::TimeDelta> hover_dwell_time{ - &blink::features::kSpeculationRulesPointerHoverHeuristics, - "HoverDwellTime", base::Milliseconds(200)}; - return hover_dwell_time.Get(); -} - void AnchorElementInteractionTracker::OnMouseMoveEvent( const WebMouseEvent& mouse_event) { mouse_motion_estimator_->OnMouseMoveEvent(mouse_event.PositionInScreen()); @@ -367,9 +359,9 @@ .is_mouse = pointer_event.pointerType() == pointer_type_names::kMouse, .anchor_id = AnchorElementId(*anchor), - .timestamp = clock_->NowTicks() + GetHoverDwellTime()}); + .timestamp = clock_->NowTicks() + kModerateHoverDwellTime}); if (!hover_timer_.IsActive()) { - hover_timer_.StartOneShot(GetHoverDwellTime(), FROM_HERE); + hover_timer_.StartOneShot(kModerateHoverDwellTime, FROM_HERE); } } else if (event_type == event_type_names::kPointerout) { // Since the pointer is no longer hovering on the link, there is no need to
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h index 180ddf3..44db3e20 100644 --- a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h +++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h
@@ -83,7 +83,8 @@ explicit AnchorElementInteractionTracker(Document& document); virtual ~AnchorElementInteractionTracker(); - static base::TimeDelta GetHoverDwellTime(); + static constexpr base::TimeDelta kModerateHoverDwellTime{ + base::Milliseconds(200)}; void OnMouseMoveEvent(const WebMouseEvent& mouse_event); void OnPointerEvent(EventTarget& target, const PointerEvent& pointer_event);
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc index 455a851..cab94f3 100644 --- a/third_party/blink/renderer/core/page/focus_controller.cc +++ b/third_party/blink/renderer/core/page/focus_controller.cc
@@ -1325,8 +1325,17 @@ void FocusController::SetFocusedFrame(Frame* frame, bool notify_embedder) { DCHECK(!frame || frame->GetPage() == page_); - if (focused_frame_ == frame || (is_changing_focused_frame_ && frame)) + if (focused_frame_ == frame || (is_changing_focused_frame_ && frame)) { return; + } + + // DevTools starts emulating focus early in the lifecycle. + // blink calls SetFocusedFrame(nullptr) after DevTools has already + // set a focused frame. Returning early to not discard previously + // set emulation state. + if (is_emulating_focus_ && !frame) { + return; + } is_changing_focused_frame_ = true; @@ -1453,6 +1462,12 @@ return false; } + // If DevTools is emulating focus, any document + // is focused irrespective of the tree. + if (is_emulating_focus_) { + return true; + } + if (IsA<HTMLFrameOwnerElement>(focused_frame_->Owner())) { auto* fenced_frame = DynamicTo<HTMLFencedFrameElement>( To<HTMLFrameOwnerElement>(focused_frame_->Owner()));
diff --git a/third_party/blink/renderer/modules/ai/availability.cc b/third_party/blink/renderer/modules/ai/availability.cc index 46b7632..6d63421 100644 --- a/third_party/blink/renderer/modules/ai/availability.cc +++ b/third_party/blink/renderer/modules/ai/availability.cc
@@ -89,6 +89,9 @@ execution_context, AIMetrics::AISessionType::kTranslator, mojom::blink::ModelAvailabilityCheckResult:: kUnavailableUnsupportedLanguage); + case mojom::blink::CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed: + case mojom::blink::CanCreateTranslatorResult:: + kNoExceedsLanguagePackCountLimitation: case mojom::blink::CanCreateTranslatorResult::kNoServiceCrashed: case mojom::blink::CanCreateTranslatorResult::kNoDisallowedByPolicy: case mojom::blink::CanCreateTranslatorResult::
diff --git a/third_party/blink/renderer/modules/ai/on_device_translation/create_translator_client.cc b/third_party/blink/renderer/modules/ai/on_device_translation/create_translator_client.cc index ad43f45b..3b36977 100644 --- a/third_party/blink/renderer/modules/ai/on_device_translation/create_translator_client.cc +++ b/third_party/blink/renderer/modules/ai/on_device_translation/create_translator_client.cc
@@ -21,6 +21,10 @@ const char kExceptionMessageUnableToCreateTranslator[] = "Unable to create translator for the given source and target language."; +const char kLinkToDocument[] = + "See " + "https://developer.chrome.com/docs/ai/translator-api?#supported-languages " + "for more details."; String ConvertCreateTranslatorErrorToDebugString(CreateTranslatorError error) { switch (error) { @@ -32,6 +36,14 @@ return "Failed to initialize the translation library."; case CreateTranslatorError::kFailedToCreateTranslator: return "The translation library failed to create a translator."; + case CreateTranslatorError::kAcceptLanguagesCheckFailed: + return String(base::StrCat( + {"The preferred languages check for Translator API failed. ", + kLinkToDocument})); + case CreateTranslatorError::kExceedsLanguagePackCountLimitation: + return String(base::StrCat( + {"The Translator API language pack count exceeded the limitation. ", + kLinkToDocument})); case CreateTranslatorError::kServiceCrashed: return "The translation service crashed."; case CreateTranslatorError::kDisallowedByPolicy: @@ -58,6 +70,13 @@ NOTREACHED(); case CanCreateTranslatorResult::kNoNotSupportedLanguage: return "The language pair is unsupported."; + case CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed: + equivalent_error = CreateTranslatorError::kAcceptLanguagesCheckFailed; + break; + case CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation: + equivalent_error = + CreateTranslatorError::kExceedsLanguagePackCountLimitation; + break; case CanCreateTranslatorResult::kNoServiceCrashed: equivalent_error = CreateTranslatorError::kServiceCrashed; break; @@ -82,6 +101,8 @@ return true; case CanCreateTranslatorResult::kReadily: case CanCreateTranslatorResult::kNoNotSupportedLanguage: + case CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed: + case CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation: case CanCreateTranslatorResult::kNoServiceCrashed: case CanCreateTranslatorResult::kNoDisallowedByPolicy: case CanCreateTranslatorResult::kNoExceedsServiceCountLimitation: @@ -99,6 +120,8 @@ case CanCreateTranslatorResult::kAfterDownloadTranslatorCreationRequired: return false; case CanCreateTranslatorResult::kNoNotSupportedLanguage: + case CanCreateTranslatorResult::kNoAcceptLanguagesCheckFailed: + case CanCreateTranslatorResult::kNoExceedsLanguagePackCountLimitation: case CanCreateTranslatorResult::kNoServiceCrashed: case CanCreateTranslatorResult::kNoDisallowedByPolicy: case CanCreateTranslatorResult::kNoExceedsServiceCountLimitation: @@ -230,7 +253,8 @@ // they lack the ability to do so. CHECK(window != nullptr || context->IsServiceWorkerGlobalScope()); - if (!context->IsServiceWorkerGlobalScope() && + if (RuntimeEnabledFeatures::TranslationAPIV1Enabled() && + !context->IsServiceWorkerGlobalScope() && RequiresUserActivation(result) && !LocalFrame::ConsumeTransientUserActivation(window->GetFrame())) { GetResolver()->RejectWithDOMException(
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc index e921050..3665d97 100644 --- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc +++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -16,6 +16,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" +#include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "build/build_config.h" #include "cc/paint/skia_paint_canvas.h"
diff --git a/third_party/blink/renderer/modules/mediastream/DEPS b/third_party/blink/renderer/modules/mediastream/DEPS index 5b02fbb..1c7ea94 100644 --- a/third_party/blink/renderer/modules/mediastream/DEPS +++ b/third_party/blink/renderer/modules/mediastream/DEPS
@@ -4,6 +4,7 @@ "+base/strings/utf_string_conversions.h", "+base/strings/stringprintf.h", "+base/containers/flat_map.h", + "+base/memory/singleton.h", # TODO(crbug.com/923394): Remove these dependencies once per-frame # task runners are used in all cases.
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc index 581f153..0145ec2 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
@@ -14,6 +14,7 @@ #include "base/functional/bind.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" +#include "base/memory/singleton.h" #include "base/rand_util.h" #include "base/run_loop.h" #include "base/strings/strcat.h"
diff --git a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h index 44919cd..6a255188 100644 --- a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h +++ b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h
@@ -76,7 +76,8 @@ UTF16RagelIterator operator-(int v) { return *this + -v; } int operator-(const UTF16RagelIterator& other) { - DCHECK_EQ(buffer_, other.buffer_); + DCHECK_EQ(buffer_.data(), other.buffer_.data()); + DCHECK_EQ(buffer_.size(), other.buffer_.size()); return cursor_ - other.cursor_; }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc index 976b28c7..2d0fc34 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
@@ -9,6 +9,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/trace_event/process_memory_dump.h" #include "components/viz/test/test_context_provider.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h"
diff --git a/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc b/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc index fb19ca6d..1977fed4 100644 --- a/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc +++ b/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc
@@ -10,6 +10,7 @@ #include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/strings/string_util.h" +#include "base/strings/to_string.h" #include "base/strings/utf_string_conversions.h" #include "media/base/key_systems.h" #include "media/base/media_permission.h" @@ -61,8 +62,6 @@ case media::CreateCdmStatus::kNotAllowedOnUniqueOrigin: return "EME use is not allowed on unique origins."; #if BUILDFLAG(IS_ANDROID) - case media::CreateCdmStatus::kMediaDrmBridgeCreationFailed: - return "MediaDrmBridge creation failed."; case media::CreateCdmStatus::kMediaCryptoNotAvailable: return "MediaCrypto not available."; case media::CreateCdmStatus::kAndroidMediaDrmIllegalArgument:
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc index 778ce23..653e44a 100644 --- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc +++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -1971,7 +1971,9 @@ void WebMediaPlayerImpl::RestartForHls() { DCHECK(main_task_runner_->BelongsToCurrentThread()); #if BUILDFLAG(ENABLE_HLS_DEMUXER) - observer_->OnHlsManifestDetected(); + if (observer_) { + observer_->OnHlsManifestDetected(); + } SetMemoryReportingState(false); StartPipeline(); #else
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc index f0e0b37..37702c5 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -24,7 +24,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "media/base/media_log.h" #include "media/base/media_switches.h"
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc index 03e004f..b4faf18 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.cc
@@ -12,7 +12,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/task/sequenced_task_runner.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "media/base/media_util.h" #include "media/base/platform_features.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index e246ce8..85d0b2e 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4648,14 +4648,6 @@ status: "stable", }, { - name: "SpeculationRulesPointerDownHeuristics", - base_feature_status: "enabled", - }, - { - name: "SpeculationRulesPointerHoverHeuristics", - base_feature_status: "enabled", - }, - { name: "SpeculationRulesPrefetchWithSubresources", }, { @@ -5045,12 +5037,23 @@ origin_trial_allows_third_party: true, base_feature_status: "enabled", copied_from_base_feature_if: "overridden", + implied_by: ["TranslationAPIV1"], }, { name: "TranslationAPIForWorkers", public: true, }, { + name: "TranslationAPIV1", + status: { + "Win": "experimental", + "Mac": "experimental", + "Linux": "experimental", + "default": "", + }, + copied_from_base_feature_if: "overridden", + }, + { // Ensures symbols are treated as word boundaries during traversal. // See https://crbug.com/40252642 name: "TreatSymbolsAsWordBoundary",
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc index fd4da58..dc1c7fa 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -11,7 +11,7 @@ #include "base/functional/bind.h" #include "base/task/common/scoped_defer_task_posting.h" #include "base/task/single_thread_task_runner.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/renderer/platform/scheduler/common/blink_scheduler_single_thread_task_runner.h" #include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
diff --git a/third_party/blink/renderer/platform/text/layout_locale.cc b/third_party/blink/renderer/platform/text/layout_locale.cc index c37b4f3c..f9a5c69 100644 --- a/third_party/blink/renderer/platform/text/layout_locale.cc +++ b/third_party/blink/renderer/platform/text/layout_locale.cc
@@ -18,6 +18,7 @@ #include "third_party/blink/renderer/platform/text/icu_error.h" #include "third_party/blink/renderer/platform/text/locale_to_script_mapping.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" #include "third_party/blink/renderer/platform/wtf/text/case_folding_hash.h" #include "third_party/blink/renderer/platform/wtf/thread_specific.h" @@ -26,6 +27,32 @@ namespace { +using CaseFoldingHashSet = HashSet<String, CaseFoldingHashTraits<String>>; + +CaseFoldingHashSet CreateMacrolanguageChineseLanguageTags() { + // This list is from the IANA language-subtag-registry: + // https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry + // where "Type: language" and "Macrolanguage: zh". + return CaseFoldingHashSet{"cdo", "cjy", "cmn", "cnp", "cpx", "csp", "czh", + "czo", "gan", "hak", "hnm", "hsn", "luh", "lzh", + "mnp", "nan", "sjc", "wuu", "yue", "zh"}; +} + +CaseFoldingHashSet MacrolanguageChineseLanguageTags() { + DEFINE_THREAD_SAFE_STATIC_LOCAL(CaseFoldingHashSet, tags, + (CreateMacrolanguageChineseLanguageTags())); + return tags; +} + +bool ComputeIsMacrolanguageChinese(const String& value) { + const wtf_size_t separater = value.find('-'); + if (separater == kNotFound) { + return MacrolanguageChineseLanguageTags().Contains(value); + } + const StringView language{value, 0, separater}; + return MacrolanguageChineseLanguageTags().Contains(language.ToString()); +} + struct PerThreadData { HashMap<AtomicString, scoped_refptr<LayoutLocale>, @@ -210,6 +237,12 @@ return locale; } +bool LayoutLocale::IsMacrolanguageChineseSlow() const { + is_macrolanguage_chinese_computed_ = true; + is_macrolanguage_chinese_ = ComputeIsMacrolanguageChinese(string_); + return is_macrolanguage_chinese_; +} + void LayoutLocale::ComputeCaseMapLocale() const { DCHECK(!case_map_computed_); case_map_computed_ = true; @@ -219,12 +252,7 @@ LayoutLocale::LayoutLocale(const AtomicString& locale) : string_(locale), harfbuzz_language_(ToHarfbuzLanguage(locale)), - script_(LocaleToScriptCodeForFontSelection(locale)), - script_for_han_(USCRIPT_COMMON), - has_script_for_han_(false), - hyphenation_computed_(false), - quotes_data_computed_(false), - case_map_computed_(false) {} + script_(LocaleToScriptCodeForFontSelection(locale)) {} // static const LayoutLocale* LayoutLocale::Get(const AtomicString& locale) {
diff --git a/third_party/blink/renderer/platform/text/layout_locale.h b/third_party/blink/renderer/platform/text/layout_locale.h index 4fef38f..dc0d143 100644 --- a/third_party/blink/renderer/platform/text/layout_locale.h +++ b/third_party/blink/renderer/platform/text/layout_locale.h
@@ -64,6 +64,11 @@ static const LayoutLocale* LocaleForHan(const LayoutLocale*); const char* LocaleForHanForSkFontMgr() const; + bool IsMacrolanguageChinese() const { + return is_macrolanguage_chinese_computed_ ? is_macrolanguage_chinese_ + : IsMacrolanguageChineseSlow(); + } + // The normalized locale data to construct |CaseMap| from. const CaseMap::Locale& CaseMapLocale() const { if (case_map_computed_) @@ -89,6 +94,8 @@ private: explicit LayoutLocale(const AtomicString&); + bool IsMacrolanguageChineseSlow() const; + void ComputeScriptForHan() const; void ComputeCaseMapLocale() const; @@ -102,12 +109,14 @@ raw_ptr<const hb_language_impl_t> harfbuzz_language_; UScriptCode script_; - mutable UScriptCode script_for_han_; + mutable UScriptCode script_for_han_ = USCRIPT_COMMON; - mutable unsigned has_script_for_han_ : 1; - mutable unsigned hyphenation_computed_ : 1; - mutable unsigned quotes_data_computed_ : 1; - mutable unsigned case_map_computed_ : 1; + mutable unsigned has_script_for_han_ : 1 = false; + mutable unsigned hyphenation_computed_ : 1 = false; + mutable unsigned quotes_data_computed_ : 1 = false; + mutable unsigned case_map_computed_ : 1 = false; + mutable unsigned is_macrolanguage_chinese_computed_ : 1 = false; + mutable unsigned is_macrolanguage_chinese_ : 1 = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/text/layout_locale_test.cc b/third_party/blink/renderer/platform/text/layout_locale_test.cc index 119877c2..be9c8d718 100644 --- a/third_party/blink/renderer/platform/text/layout_locale_test.cc +++ b/third_party/blink/renderer/platform/text/layout_locale_test.cc
@@ -39,6 +39,7 @@ UScriptCode script; const char* sk_font_mgr = nullptr; std::optional<UScriptCode> script_for_han; + bool is_macrolanguage_chinese = false; } locale_test_data[] = { // Country is not relevant to |SkFontMgr|. {"en-US", USCRIPT_LATIN, "en"}, @@ -65,31 +66,31 @@ USCRIPT_TRADITIONAL_HAN, "zh-Hant", USCRIPT_TRADITIONAL_HAN {"ja-JP", EXPECT_JAPANESE}, {"ko-KR", EXPECT_KOREAN}, - {"zh", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-CN", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-HK", EXPECT_TRADITIONAL_CHINESE}, - {"zh-MO", EXPECT_TRADITIONAL_CHINESE}, - {"zh-SG", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-TW", EXPECT_TRADITIONAL_CHINESE}, + {"zh", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-CN", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-HK", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-MO", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-SG", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-TW", EXPECT_TRADITIONAL_CHINESE, true}, // Encompassed languages within the Chinese macrolanguage. // Both "lang" and "lang-extlang" should work. - {"nan", EXPECT_TRADITIONAL_CHINESE}, - {"wuu", EXPECT_SIMPLIFIED_CHINESE}, - {"yue", EXPECT_TRADITIONAL_CHINESE}, - {"zh-nan", EXPECT_TRADITIONAL_CHINESE}, - {"zh-wuu", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-yue", EXPECT_TRADITIONAL_CHINESE}, + {"nan", EXPECT_TRADITIONAL_CHINESE, true}, + {"wuu", EXPECT_SIMPLIFIED_CHINESE, true}, + {"yue", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-nan", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-wuu", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-yue", EXPECT_TRADITIONAL_CHINESE, true}, // Specified scripts is honored. - {"zh-Hans", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-Hant", EXPECT_TRADITIONAL_CHINESE}, + {"zh-Hans", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-Hant", EXPECT_TRADITIONAL_CHINESE, true}, // Lowercase scripts should be capitalized. // |SkFontMgr_Android| uses case-sensitive match, and `fonts.xml` has // capitalized script names. - {"zh-hans", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-hant", EXPECT_TRADITIONAL_CHINESE}, + {"zh-hans", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-hant", EXPECT_TRADITIONAL_CHINESE, true}, // Script has priority over other subtags. {"en-Hans", EXPECT_SIMPLIFIED_CHINESE}, @@ -98,10 +99,10 @@ {"en-Hant-CN", EXPECT_TRADITIONAL_CHINESE}, {"en-TW-Hans", EXPECT_SIMPLIFIED_CHINESE}, {"en-CN-Hant", EXPECT_TRADITIONAL_CHINESE}, - {"wuu-Hant", EXPECT_TRADITIONAL_CHINESE}, - {"yue-Hans", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-wuu-Hant", EXPECT_TRADITIONAL_CHINESE}, - {"zh-yue-Hans", EXPECT_SIMPLIFIED_CHINESE}, + {"wuu-Hant", EXPECT_TRADITIONAL_CHINESE, true}, + {"yue-Hans", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-wuu-Hant", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-yue-Hans", EXPECT_SIMPLIFIED_CHINESE, true}, // Lang has priority over region. // icu::Locale::getDefault() returns other combinations if, for instance, @@ -110,10 +111,10 @@ {"ja-US", EXPECT_JAPANESE}, {"ko", EXPECT_KOREAN}, {"ko-US", EXPECT_KOREAN}, - {"wuu-TW", EXPECT_SIMPLIFIED_CHINESE}, - {"yue-CN", EXPECT_TRADITIONAL_CHINESE}, - {"zh-wuu-TW", EXPECT_SIMPLIFIED_CHINESE}, - {"zh-yue-CN", EXPECT_TRADITIONAL_CHINESE}, + {"wuu-TW", EXPECT_SIMPLIFIED_CHINESE, true}, + {"yue-CN", EXPECT_TRADITIONAL_CHINESE, true}, + {"zh-wuu-TW", EXPECT_SIMPLIFIED_CHINESE, true}, + {"zh-yue-CN", EXPECT_TRADITIONAL_CHINESE, true}, // Region should not affect script, but it can influence scriptForHan. {"en-CN", USCRIPT_LATIN, "en"}, @@ -154,6 +155,7 @@ } else { EXPECT_EQ(USCRIPT_SIMPLIFIED_HAN, locale->GetScriptForHan()) << test.locale; } + EXPECT_EQ(test.is_macrolanguage_chinese, locale->IsMacrolanguageChinese()); if (test.sk_font_mgr) EXPECT_STREQ(test.sk_font_mgr, locale->LocaleForSkFontMgr()) << test.locale; }
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc index ba28c0c..4f346ea 100644 --- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc +++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -106,11 +106,6 @@ PartitionOptions opts; opts.backup_ref_ptr = brp_setting; opts.memory_tagging = {.enabled = memory_tagging}; - opts.use_small_single_slot_spans = - base::FeatureList::IsEnabled( - base::features::kPartitionAllocUseSmallSingleSlotSpans) - ? partition_alloc::PartitionOptions::kEnabled - : partition_alloc::PartitionOptions::kDisabled; return opts; }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 6b53476..51a4b1d7 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -5217,9 +5217,6 @@ crbug.com/365615740 fast/events/wheel/mouse-wheel-scroll-latching.html [ Failure Pass Timeout ] -# Sheriff 2020-02-28 -crbug.com/40675392 http/tests/devtools/network/network-initiator-chain.js [ Failure Pass ] - crbug.com/1057822 http/tests/misc/synthetic-gesture-initiated-in-cross-origin-frame.html [ Crash Failure Pass ] # Ecosystem-Infra Sheriff 2020-04-15 @@ -9158,3 +9155,7 @@ # Gardener 2025-06-03 crbug.com/422174062 [ Win ] external/wpt/css/css-masking/clip-path/clip-path-inline-009.html [ Failure Pass ] + +# Gardener 2025-06-06 +crbug.com/415666471 [ Linux ] external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Failure Timeout Pass ] +crbug.com/415666471 [ Linux ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Failure Timeout Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index d8c232fa..fd945466 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1866,7 +1866,7 @@ "http/tests/inspector-protocol/service-worker/tentative/static-router" ], "args": ["--enable-features=ServiceWorkerStaticRouterTimingInfo"], - "expires": "Jun 5, 2025", + "expires": "Dec 5, 2025", "owners": ["suzukikeita@chromium.org", "yyanagisawa@chromium.org", "sisidovski@chromium.org"] }, {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025-ref.html new file mode 100644 index 0000000..d4cbf50 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025-ref.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/"> +<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com"> +<style> + body { + margin: 0; + } + + main { + display: flex; + flex-wrap: wrap; + gap: 10px; + } + + .item { + background-color: teal; + height: 50px; + flex-basis: 100%; + } + + .row-gap { + position: absolute; + top: 50px; + left: 0px; + background: gold; + width: 100%; + height: 10px; + } +</style> +<main> + <div class="item"></div> + <div class="item"></div> + <div class="row-gap"></div> +</main>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025.html new file mode 100644 index 0000000..42b46a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-025.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title> + CSS Gap Decorations: flex gaps are painted when there's only one flex line +</title> +<link rel="help" href="https://drafts.csswg.org/css-gaps-1/"> +<link rel="match" href="flex-gap-decorations-025-ref.html"> +<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com"> +<style> + body { + margin: 0; + } + + main { + display: flex; + flex-wrap: wrap; + gap: 10px; + row-rule: 10px solid gold; + } + + .item { + background-color: teal; + height: 50px; + flex-basis: 100%; + } +</style> +<main> + <div class="item"></div> + <div class="item"></div> +</main>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js index dc01aa1..a974ec0 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js
@@ -987,7 +987,8 @@ if (navigator.ml) { equalTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getEqualPrecisionTolerance, test); + buildAndExecuteGraph, getEqualPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js index 704e0c45..21e8b07 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js
@@ -991,7 +991,8 @@ if (navigator.ml) { greaterTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getGreaterPrecisionTolerance, test); + buildAndExecuteGraph, getGreaterPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js index 28a2e89..f9ab2d6 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js
@@ -986,7 +986,8 @@ if (navigator.ml) { greaterOrEqualTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getGreaterOrEqualPrecisionTolerance, test); + buildAndExecuteGraph, getGreaterOrEqualPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js index 0588f3bc..8978435 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js
@@ -998,7 +998,8 @@ if (navigator.ml) { lesserTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getLesserPrecisionTolerance, test); + buildAndExecuteGraph, getLesserPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js index cfcc740..16aa588 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js
@@ -1105,7 +1105,8 @@ if (navigator.ml) { lesserOrEqualTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getLesserOrEqualPrecisionTolerance, test); + buildAndExecuteGraph, getLesserOrEqualPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js index a4d7165..1a03ef54 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js
@@ -414,7 +414,9 @@ if (navigator.ml) { logicalAndTests.forEach((test) => { - webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test); + webnn_conformance_test( + buildAndExecuteGraph, getPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js index 9d1861d..f8949672 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js
@@ -214,7 +214,8 @@ if (navigator.ml) { logicalNotTests.forEach((test) => { webnn_conformance_test( - buildAndExecuteGraph, getLogicalNotPrecisionTolerance, test); + buildAndExecuteGraph, getLogicalNotPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js index f8941b6..83c2619 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js
@@ -414,7 +414,9 @@ if (navigator.ml) { logicalOrTests.forEach((test) => { - webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test); + webnn_conformance_test( + buildAndExecuteGraph, getPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js index 533d52aa..7a9446ea 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js
@@ -414,7 +414,9 @@ if (navigator.ml) { logicalXorTests.forEach((test) => { - webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test); + webnn_conformance_test( + buildAndExecuteGraph, getPrecisionTolerance, test, + /*cast_to_supported_type=*/true); }); } else { test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain-expected.txt b/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain-expected.txt deleted file mode 100644 index 3478cf5..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -Test that computing the initiator graph works for service worker request. - - -http://127.0.0.1:8000/devtools/service-workers/resources/network-fetch-worker.js -Initiators http://127.0.0.1:8000/devtools/service-workers/resources/network-fetch-worker.js -Initiated http://127.0.0.1:8000/devtools/service-workers/resources/network-fetch-worker.js -
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain.js b/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain.js deleted file mode 100644 index 1e0a5c20..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/network/network-initiator-chain.js +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {TestRunner} from 'test_runner'; -import {NetworkTestRunner} from 'network_test_runner'; -import {ApplicationTestRunner} from 'application_test_runner'; - -(async function() { - TestRunner.addResult(`Test that computing the initiator graph works for service worker request.\n`); - await TestRunner.showPanel('network'); - - NetworkTestRunner.recordNetwork(); - let scope = 'http://127.0.0.1:8000/devtools/service-workers/resources/'; - await ApplicationTestRunner.registerServiceWorker('../service-workers/resources/network-fetch-worker.js', scope); - - var requests = NetworkTestRunner.networkRequests(); - requests.forEach((request) => { - TestRunner.addResult('\n' + request.url()); - var graph = - NetworkTestRunner.networkLog().initiatorGraphForRequest(request); - TestRunner.addResult('Initiators ' + Array.from(graph.initiators).map(request => request._url)); - TestRunner.addResult('Initiated ' + Array.from(graph.initiated.keys()).map(request => request._url)); - }); - - TestRunner.completeTest(); -})();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations-expected.txt new file mode 100644 index 0000000..bc96091 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations-expected.txt
@@ -0,0 +1,4 @@ +Tests that page focus emulation persists between navigations +hasFocus(before navigation):true +hasFocus(after navigation):true +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations.js b/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations.js new file mode 100644 index 0000000..8b36700 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/emulation/set-focus-emulation-enabled-persists-navigations.js
@@ -0,0 +1,18 @@ +(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { + const { session } = await testRunner + .startBlank('Tests that page focus emulation persists between navigations'); + + async function logFocus(session, label) { + testRunner.log(`hasFocus(${label}):` + await session.evaluate('document.hasFocus()')); + } + + await session.protocol.Emulation.setFocusEmulationEnabled({enabled: true}); + + await logFocus(session, 'before navigation'); + + await session.navigate('/resources/blank.html'); + + await logFocus(session, 'after navigation'); + + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale-expected.txt b/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale-expected.txt new file mode 100644 index 0000000..5b601fe --- /dev/null +++ b/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale-expected.txt
@@ -0,0 +1,7 @@ +Tests that the OS text scale can be emulated. +Initial preferred-text-scale: 1. +After setting scale to 2, preferred-text-scale is 2. +After setting scale to 2 twice, preferred-text-scale is 2. +After setting scale to 0.85, preferred-text-scale is 0.85. +After stopping emulation, preferred-text-scale is 1. +
diff --git a/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale.js b/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale.js new file mode 100644 index 0000000..705dcc2 --- /dev/null +++ b/third_party/blink/web_tests/inspector-protocol/emulation/set-emulated-os-text-scale.js
@@ -0,0 +1,36 @@ +(async function(/** @type {import('test_runner').TestRunner} */ testRunner) { + let {page, session, dp} = await testRunner.startHTML(` + <div style='font-size: calc(100px * env(preferred-text-scale, 3));'>a</div> + <script> + function getPreferredTextScale() { + let div = document.querySelector('div'); + return parseInt(getComputedStyle(div).fontSize) / 100; + } + </script> + `, 'Tests that the OS text scale can be emulated.'); + + let initial = await session.evaluate("getPreferredTextScale()"); + testRunner.log(`Initial preferred-text-scale: ${initial}.`); + + // Test emulating a scale of 2. + await dp.Emulation.setEmulatedOSTextScale({scale: 2}); + let set_2 = await session.evaluate("getPreferredTextScale()"); + testRunner.log(`After setting scale to 2, preferred-text-scale is ${set_2}.`); + + // Test emulating a scale of 2 when already emulating a scale of 2. + await dp.Emulation.setEmulatedOSTextScale({scale: 2}); + let set_2_again = await session.evaluate("getPreferredTextScale()"); + testRunner.log(`After setting scale to 2 twice, preferred-text-scale is ${set_2_again}.`); + + // Test emulating a scale of 0.85. + await dp.Emulation.setEmulatedOSTextScale({scale: 0.85}); + let set_085 = await session.evaluate("getPreferredTextScale()"); + testRunner.log(`After setting scale to 0.85, preferred-text-scale is ${set_085}.`); + + // Test stopping emulation with no scale. + await dp.Emulation.setEmulatedOSTextScale({}); + let set_none = await session.evaluate("getPreferredTextScale()"); + testRunner.log(`After stopping emulation, preferred-text-scale is ${set_none}.`); + + testRunner.completeTest(); +})
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/equal.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/equal.https.any_cpu-expected.txt index 1395781..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/equal.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/equal.https.any_cpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] equal float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater.https.any_cpu-expected.txt index 9acf726..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater.https.any_cpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greater float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_cpu-expected.txt index ab7740d..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_cpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greaterOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser.https.any_cpu-expected.txt index d3d56a94..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser.https.any_cpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesser float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_cpu-expected.txt index b05c059..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_cpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesserOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_and.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_and.https.any_cpu-expected.txt index 5b4922da..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_and.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_and.https.any_cpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalAnd uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_not.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_not.https.any_cpu-expected.txt deleted file mode 100644 index d22037d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_not.https.any_cpu-expected.txt +++ /dev/null
@@ -1,17 +0,0 @@ -This is a testharness.js-based test. -[FAIL] logicalNot uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D constant tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 2D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 3D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 4D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 5D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_or.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_or.https.any_cpu-expected.txt index d7bb56a..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_or.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_or.https.any_cpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalOr uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_cpu-expected.txt index 46043f26..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_cpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_cpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalXor uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/equal.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/equal.https.any_npu-expected.txt index 1395781..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/equal.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/equal.https.any_npu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] equal float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater.https.any_npu-expected.txt index 9acf726..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater.https.any_npu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greater float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_npu-expected.txt index ab7740d..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_npu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greaterOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser.https.any_npu-expected.txt index d3d56a94..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser.https.any_npu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesser float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_npu-expected.txt index b05c059..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_npu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesserOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_and.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_and.https.any_npu-expected.txt index 5b4922da..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_and.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_and.https.any_npu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalAnd uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_not.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_not.https.any_npu-expected.txt deleted file mode 100644 index d22037d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_not.https.any_npu-expected.txt +++ /dev/null
@@ -1,17 +0,0 @@ -This is a testharness.js-based test. -[FAIL] logicalNot uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D constant tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 2D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 3D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 4D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 5D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_or.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_or.https.any_npu-expected.txt index d7bb56a..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_or.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_or.https.any_npu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalOr uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_xor.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_xor.https.any_npu-expected.txt index 46043f26..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_xor.https.any_npu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/logical_xor.https.any_npu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalXor uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/equal.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/equal.https.any_gpu-expected.txt index 1395781..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/equal.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/equal.https.any_gpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] equal float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] equal float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater.https.any_gpu-expected.txt index 9acf726..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater.https.any_gpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greater float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greater float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_gpu-expected.txt index ab7740d..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/greater_or_equal.https.any_gpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] greaterOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] greaterOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser.https.any_gpu-expected.txt index d3d56a94..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser.https.any_gpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesser float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesser float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_gpu-expected.txt index b05c059..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any_gpu-expected.txt
@@ -1,51 +1,3 @@ This is a testharness.js-based test. -[FAIL] lesserOrEqual float32 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float32 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] lesserOrEqual float16 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_and.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_and.https.any_gpu-expected.txt index 5b4922da..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_and.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_and.https.any_gpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalAnd uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalAnd uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_not.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_not.https.any_gpu-expected.txt deleted file mode 100644 index d22037d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_not.https.any_gpu-expected.txt +++ /dev/null
@@ -1,17 +0,0 @@ -This is a testharness.js-based test. -[FAIL] logicalNot uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D constant tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 1D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 2D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 3D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 4D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalNot uint8 5D tensor - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_or.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_or.https.any_gpu-expected.txt index d7bb56a..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_or.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_or.https.any_gpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalOr uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalOr uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_gpu-expected.txt index 46043f26..d2490db 100644 --- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_gpu-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/logical_xor.https.any_gpu-expected.txt
@@ -1,27 +1,3 @@ This is a testharness.js-based test. -[FAIL] logicalXor uint8 0D scalar - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D constant tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, output 'output' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 1D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 2D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 3D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 4D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 5D tensors - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 0D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 1D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 2D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 3D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." -[FAIL] logicalXor uint8 broadcast 4D to 4D - promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'a' data type uint8 must be one of [float32,float16,int32]." Harness: the test ran to completion.
diff --git a/third_party/catapult b/third_party/catapult index ea769d2..aa341ec 160000 --- a/third_party/catapult +++ b/third_party/catapult
@@ -1 +1 @@ -Subproject commit ea769d2a2a7bedc43ac1baec43fdf7423047184e +Subproject commit aa341ec41f6d475102eee85ddec60d403ef575cd
diff --git a/third_party/crossbench b/third_party/crossbench index 675d2d6..0d4bbb0 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit 675d2d63880904c537f03a76f021c2c13e20e355 +Subproject commit 0d4bbb09c3901288772039f71f071897432d77b8
diff --git a/third_party/dawn b/third_party/dawn index ba5fbf6..4d33621 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit ba5fbf6ca75113fc554651f2cd601ce911f3e6a1 +Subproject commit 4d33621217632e25d8e88e2f0dd2544596d129ac
diff --git a/third_party/depot_tools b/third_party/depot_tools index 749b3f1..d255a8d 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 749b3f1960ffd7575f6e7d5ecf1e90d6b9db673a +Subproject commit d255a8d41e7a2fdc6b50fee69e70014f875d47ef
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 9520a83..d8f5635 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 9520a835b578aa11db9df1cf6651dbe5c3376887 +Subproject commit d8f563509959c9132c81f22536bff9edd4325093
diff --git a/third_party/googletest/src b/third_party/googletest/src index e9092b1..7e2c425 160000 --- a/third_party/googletest/src +++ b/third_party/googletest/src
@@ -1 +1 @@ -Subproject commit e9092b12dc3cf617d47578f13a1f64285cfa5b2f +Subproject commit 7e2c425db2c2e024b2807bfe6d386f4ff068d0d6
diff --git a/third_party/libc++/src b/third_party/libc++/src index 0e24258..cdae0b7 160000 --- a/third_party/libc++/src +++ b/third_party/libc++/src
@@ -1 +1 @@ -Subproject commit 0e242589e53523da3fc2df7ee965f9534550dec5 +Subproject commit cdae0b78c315e58661273c8cd9119b460e68f98b
diff --git a/third_party/skia b/third_party/skia index 07afa62..c408dae 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 07afa62babe959ab4e6759263490db189e2195c2 +Subproject commit c408daec0f9a46d5ed2f698a172ede3fd9f78551
diff --git a/third_party/webrtc b/third_party/webrtc index 2ce86c4..e37b324 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 2ce86c46cefa1c8e62951f54c812b6faf69860ef +Subproject commit e37b3246716888f66e859f17931f2cc7caedbbfd
diff --git a/tools/clang/trace_annotator/TraceAnnotator.cpp b/tools/clang/trace_annotator/TraceAnnotator.cpp index a87cdd1..dbf296b1 100644 --- a/tools/clang/trace_annotator/TraceAnnotator.cpp +++ b/tools/clang/trace_annotator/TraceAnnotator.cpp
@@ -199,7 +199,7 @@ include_added_to.insert(r.getFilePath().str()); // Add also copyright so that |test-expected.cc| passes presubmit. llvm::outs() << "include-user-header:::" << r.getFilePath() - << ":::-1:::-1:::base/trace_event/base_tracing.h" + << ":::-1:::-1:::base/trace_event/trace_event.h" << "\n"; } // Add the actual replacement.
diff --git a/tools/clang/trace_annotator/tests/test-expected.cc b/tools/clang/trace_annotator/tests/test-expected.cc index 70e907d..d0cad0e6b 100644 --- a/tools/clang/trace_annotator/tests/test-expected.cc +++ b/tools/clang/trace_annotator/tests/test-expected.cc
@@ -5,7 +5,7 @@ #include <algorithm> #include <vector> -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" int no_body(int); // No annotation
diff --git a/tools/metrics/histograms/metadata/actor/enums.xml b/tools/metrics/histograms/metadata/actor/enums.xml index 57287df..db39848c 100644 --- a/tools/metrics/histograms/metadata/actor/enums.xml +++ b/tools/metrics/histograms/metadata/actor/enums.xml
@@ -42,6 +42,7 @@ <int value="21" label="CoordinatesOutOfBounds"/> <int value="22" label="ArgumentsInvalid"/> <int value="23" label="TaskPaused"/> + <int value="24" label="kExecutorDestroyed"/> <int value="100" label="NavigateInvalidUrl"/> <int value="200" label="ClickSuppressed"/> <int value="300" label="DragAndReleaseFromOffscreen"/>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml index c4361d9..47d39888 100644 --- a/tools/metrics/histograms/metadata/browser/histograms.xml +++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -1372,6 +1372,18 @@ </summary> </histogram> +<histogram + name="BrowserRenderProcessHost.SpareProcessMaybeTakeAction.NavigationRequest" + enum="SpareProcessMaybeTakeAction" expires_after="2025-12-31"> + <owner>gjc@google.com</owner> + <owner>chrome-loading@google.com</owner> + <summary> + Records what happens when an attempt is made to use a spare + RenderProcessHost during a navigation request. The UMA logs that either the + attempt succeeded or why it failed. + </summary> +</histogram> + <histogram name="BrowserRenderProcessHost.SpareProcessMaybeTakeTime" units="seconds" expires_after="2025-10-26"> <owner>gjc@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/collaboration_service/enums.xml b/tools/metrics/histograms/metadata/collaboration_service/enums.xml index cf8db7d..7f8905f9 100644 --- a/tools/metrics/histograms/metadata/collaboration_service/enums.xml +++ b/tools/metrics/histograms/metadata/collaboration_service/enums.xml
@@ -26,6 +26,28 @@ <enums> +<!-- LINT.IfChange(CollaborationServiceFlowEvent) --> + +<enum name="CollaborationServiceFlowEvent"> + <int value="0" label="Unknown"/> + <int value="1" label="Started"/> + <int value="2" label="Not signed in on a collaboration flow attempt"/> + <int value="3" label="Canceled: due to sign in requirement"/> + <int value="4" label="Signin and sync requirements met"/> + <int value="5" label="Signin not verified when finished"/> + <int value="6" label="Signin verified when finished"/> + <int value="7" label="Signin verified in observer"/> + <int value="8" label="Data sharing service ready when started"/> + <int value="9" label="Data sharing service ready observed"/> + <int value="10" label="Tab group sync service ready"/> + <int value="11" label="All services ready for flow"/> + <int value="12" label="Failure: Device policy disables signin"/> + <int value="13" label="Managed account signed in"/> + <int value="14" label="Account info is not ready upon signin"/> +</enum> + +<!-- LINT.ThenChange(//components/collaboration/internal/metrics.h:CollaborationServiceFlowEvent) --> + <!-- LINT.IfChange(CollaborationServiceJoinEntryPoint) --> <enum name="CollaborationServiceJoinEntryPoint"> @@ -44,7 +66,7 @@ <enum name="CollaborationServiceJoinEvent"> <int value="0" label="Unknown"/> <int value="1" label="Started"/> - <int value="2" label="Canceled - after sign in requirement"/> + <int value="2" label="Canceled - While on join screen"/> <int value="3" label="Canceled - due to sign in requirement"/> <int value="4" label="Not signed in on join attempt"/> <int value="5" label="Accepted - the join invitation"/> @@ -131,8 +153,8 @@ <enum name="CollaborationServiceShareOrManageEvent"> <int value="0" label="Unknown"/> <int value="1" label="Started"/> - <int value="2" label="Canceled - due to sign in requirement"/> - <int value="3" label="Not signed in on share or manage attempt"/> + <int value="2" label="Not signed in on share or manage attempt"/> + <int value="3" label="Canceled - due to sign in requirement"/> <int value="4" label="Share dialog shown"/> <int value="5" label="Manage dialog shown"/> <int value="6" label="Collaboration group created"/>
diff --git a/tools/metrics/histograms/metadata/collaboration_service/histograms.xml b/tools/metrics/histograms/metadata/collaboration_service/histograms.xml index cdc01b7..eaebf89 100644 --- a/tools/metrics/histograms/metadata/collaboration_service/histograms.xml +++ b/tools/metrics/histograms/metadata/collaboration_service/histograms.xml
@@ -22,6 +22,14 @@ <histograms> +<variants name="CollaborationServiceFlow"> + <variant name="JoinFlow" summary="Collaboration join flow"/> + <variant name="LeaveOrDeleteFlow" + summary="Collaboration leave or delete flow"/> + <variant name="ShareOrManageFlow" + summary="Collaboration share or manage flow"/> +</variants> + <variants name="CollaborationServiceStep"> <variant name="AuthenticationInitToSuccess" summary="Authentication initiated to successful completion"/> @@ -111,6 +119,20 @@ </summary> </histogram> +<histogram name="CollaborationService.{CollaborationServiceFlow}.Events" + enum="CollaborationServiceFlowEvent" expires_after="2025-10-11"> + <owner>haileywang@google.com</owner> + <owner>chrome-tab-group-eng@google.com</owner> + <summary> + [ All platforms ] Tracks the type of collaboration flow event that can + happen when going through a collaboration flow. + + Recorded when a collaboration event is triggered by the + CollaborationService. + </summary> + <token key="CollaborationServiceFlow" variants="CollaborationServiceFlow"/> +</histogram> + </histograms> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/extensions/enums.xml b/tools/metrics/histograms/metadata/extensions/enums.xml index 2fcccbd1..90802d52 100644 --- a/tools/metrics/histograms/metadata/extensions/enums.xml +++ b/tools/metrics/histograms/metadata/extensions/enums.xml
@@ -3356,6 +3356,15 @@ <int value="1" label="Chrome Web Store"/> </enum> +<!-- LINT.IfChange(LoadExtensionFlag) --> + +<enum name="LoadExtensionFlag"> + <int value="0" label="LoadExtension"/> + <int value="1" label="DisableExtensionsExcept"/> +</enum> + +<!-- LINT.ThenChange(/chrome/browser/extensions/extension_service.h:LoadExtensionFlag) --> + <enum name="LoadRulesetResult"> <int value="0" label="Load succeeded"/> <int value="1" label="Load failed - Invalid path"/>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index 7cdf3d0..5fdbc30 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -3685,14 +3685,15 @@ </summary> </histogram> -<histogram name="Extensions.LoadingFromCommandLineBlocked" enum="Boolean" +<histogram name="Extensions.LoadingFromCommandLine" enum="LoadExtensionFlag" expires_after="2025-11-30"> <owner>richche@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> - Records when loading extensions via the "--load-extension" command - line switch is blocked. Emitted once per profile start while extensions are - loading. + Recorded when extension are loaded via the "--load-extension" or + "--disable-extensions-except" command line switch. Emitted once + per profile start while extensions are loading with flags present, and the + extension is loaded without being blocked. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/media/enums.xml b/tools/metrics/histograms/metadata/media/enums.xml index e2159b7..32bb904e 100644 --- a/tools/metrics/histograms/metadata/media/enums.xml +++ b/tools/metrics/histograms/metadata/media/enums.xml
@@ -495,7 +495,7 @@ label="Disconnection error. The remote process dropped the callback. e.g. in case of crash."/> <int value="14" label="EME use is not allowed on unique origins."/> - <int value="15" label="Android: MediaDrmBridge creation failed."/> + <int value="15" label="(Obsolete) Android: MediaDrmBridge creation failed."/> <int value="16" label="Android: MediaCrypto not available."/> <int value="17" label="CrOs: Only one instance allowed."/> <int value="18" label="CrOs: Insufficient GPU memory available."/>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 5d11ca1d..ae291bb 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2580,29 +2580,6 @@ </summary> </histogram> -<histogram name="Media.DocumentPictureInPicture.RequestedLargeInitialSize" - enum="BooleanOccurred" expires_after="2026-03-19"> - <owner>steimel@chromium.org</owner> - <owner>media-dev-uma@chromium.org</owner> - <summary> - Recorded when a website opens a document picture-in-picture window. Records - `Occurred` if the website requested a window size larger than the maximum - allowed window size, otherwise records `Did not occur`. - </summary> -</histogram> - -<histogram name="Media.DocumentPictureInPicture.RequestedLargeResize" - enum="BooleanOccurred" expires_after="2026-03-19"> - <owner>steimel@chromium.org</owner> - <owner>media-dev-uma@chromium.org</owner> - <summary> - Recorded when a website resizes a document picture-in-picture window via the - `resizeTo()` or `resizeBy()` APIs. Records `Occurred` if the website - requested a window size larger than the maximum allowed window size, - otherwise records `Did not occur`. - </summary> -</histogram> - <histogram name="Media.DocumentPictureInPicture.RequestedSizeToScreenRatio" units="%" expires_after="2025-11-30"> <owner>steimel@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/enums.xml b/tools/metrics/histograms/metadata/navigation/enums.xml index 670186e..8a1d1be 100644 --- a/tools/metrics/histograms/metadata/navigation/enums.xml +++ b/tools/metrics/histograms/metadata/navigation/enums.xml
@@ -464,7 +464,7 @@ <int value="5" label="WillCommitWithoutUrlLoader"/> </enum> -<!-- LINT.ThenChange(//content/browser/renderer_host/navigation_throttle_runner.h:Event)--> +<!-- LINT.ThenChange(//content/browser/renderer_host/navigation_throttle_registry_impl.h:NavigationThrottleEvent)--> <!-- LINT.IfChange(NavigationTransitionCacheHitOrMissReason) -->
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 6819abb..d407136d 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -7478,6 +7478,38 @@ </summary> </histogram> +<histogram name="Net.TCPSocket.PortReuseTimeWindows.{IPType}.{Result}" + units="ms" expires_after="2025-12-01"> + <owner>arichiv@chromium.org</owner> + <owner>awillia@chromium.org</owner> + <owner>katabolism-finch@google.com</owner> + <summary> + The time between the release of a socket on a particular local address/port + and its future re-use in another connection. The time for the last release + is cleared if the open is successful, and reused without overwriting if not. + + Recorded once for each attempted re-use of an address/port for TCP on + Windows via TCPSocketWin::DoConnectComplete. + + {IPType} + + {Result} + </summary> + <token key="IPType"> + <variant name="LinkLocal" + summary="Link-local IP addresses are used for communication on + sub-network."/> + <variant name="Loopback" + summary="Loopback IP addresses are used for on-device network + testing."/> + <variant name="Other" summary="All other IP addresses."/> + </token> + <token key="Result"> + <variant name="Failure" summary="Socket failed to connect."/> + <variant name="Success" summary="Socket did connect."/> + </token> +</histogram> + <histogram name="Net.TrustTokens.NetErrorForFetchFailure.{TrustTokenOperationType}" enum="NetErrorCodes" expires_after="2023-06-06">
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 442a08e..67156f4 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "full_remote_path": "perfetto-luci-artifacts/v50.1/linux-arm64/trace_processor_shell" }, "win": { - "hash": "51eb61bc5ea08dfee24bdbbef80a60553f9c93ef", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/576110306936083fafbdab5594b96d25d4b4106d/trace_processor_shell.exe" + "hash": "f3146c0f8014bc96968ee4c97457c124efa6023d", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5a1177aedb0839a3a3361ab7aca2db21a253bebe/trace_processor_shell.exe" }, "linux_arm": { "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.cc b/ui/accessibility/platform/ax_platform_node_delegate.cc index 7976964..8771069f 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate.cc +++ b/ui/accessibility/platform/ax_platform_node_delegate.cc
@@ -6,6 +6,7 @@ #include "base/containers/fixed_flat_set.h" #include "base/notreached.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_selection.h"
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index 1e74104a..8cb70fd 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc
@@ -35,7 +35,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/typed_macros.h" #include "build/build_config.h" #include "net/filter/gzip_header.h" #include "skia/ext/image_operations.h"
diff --git a/ui/compositor/compositor_animation_observer.cc b/ui/compositor/compositor_animation_observer.cc index e18d0fb..44fca12 100644 --- a/ui/compositor/compositor_animation_observer.cc +++ b/ui/compositor/compositor_animation_observer.cc
@@ -9,7 +9,6 @@ #include "base/notreached.h" #include "base/time/time.h" #include "base/time/time_override.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/trace_event.h" namespace ui {
diff --git a/ui/compositor/host_begin_frame_observer.cc b/ui/compositor/host_begin_frame_observer.cc index 9dda576..64daee1 100644 --- a/ui/compositor/host_begin_frame_observer.cc +++ b/ui/compositor/host_begin_frame_observer.cc
@@ -9,6 +9,8 @@ #include "base/logging.h" #include "base/task/common/task_annotator.h" #include "base/time/time.h" +#include "base/trace_event/trace_id_helper.h" +#include "base/trace_event/typed_macros.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" namespace ui {
diff --git a/ui/display/manager/util/display_manager_util.h b/ui/display/manager/util/display_manager_util.h index 58e2072..ec4a4e5 100644 --- a/ui/display/manager/util/display_manager_util.h +++ b/ui/display/manager/util/display_manager_util.h
@@ -7,6 +7,7 @@ #include <functional> #include <string> +#include <unordered_map> #include <vector> #include "base/containers/flat_set.h"
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.ts b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.ts index e747f9c7..3923b76 100644 --- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.ts +++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.ts
@@ -290,7 +290,13 @@ return null; // No specific filter selected. } return new RegExp( - '\\.(' + this.fileTypes_[selectedIndex - 1]!.extensions.join('|') + + '\\.(' + + this.fileTypes_[selectedIndex - 1]! + .extensions + // RegExp.escape is available since M136, but Typescript doesn't + // recognize it yet, hence the "as any" below. + .map(ext => (RegExp as any).escape(ext)) + .join('|') + ')$', 'i'); }
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller_unittest.ts b/ui/file_manager/file_manager/foreground/js/dialog_action_controller_unittest.ts new file mode 100644 index 0000000..ac9cc5b --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller_unittest.ts
@@ -0,0 +1,91 @@ +// Copyright 2025 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js'; + +import {MockVolumeManager} from '../../background/js/mock_volume_manager.js'; +import {DialogType} from '../../state/state.js'; + +import {DialogActionController} from './dialog_action_controller.js'; +import {FileFilter} from './directory_contents.js'; +import {FakeFileSelectionHandler} from './fake_file_selection_handler.js'; +import {LaunchParam} from './launch_param.js'; +import {createFakeDirectoryModel} from './mock_directory_model.js'; +import type {NamingController} from './naming_controller.js'; +import {DialogFooter} from './ui/dialog_footer.js'; + +// Mock the same DOM structure as required by DialogFooter constructor. +function constructFooterElement(): HTMLElement { + const footerElement = document.createElement('div'); + + const selectElement = document.createElement('div'); + selectElement.className = 'file-type'; + const options = document.createElement('div'); + options.className = 'options'; + const label = document.createElement('span'); + selectElement.appendChild(label); + selectElement.appendChild(options); + footerElement.appendChild(selectElement); + + const okButton = document.createElement('button'); + okButton.className = 'ok'; + const buttonLabel = document.createElement('span'); + okButton.appendChild(buttonLabel); + footerElement.appendChild(okButton); + + const cancelButton = document.createElement('button'); + cancelButton.className = 'cancel'; + footerElement.appendChild(cancelButton); + + const newFolderButton = document.createElement('button'); + newFolderButton.id = 'new-folder-button'; + footerElement.appendChild(newFolderButton); + + document.body.appendChild(footerElement); + const newFolderCommand = document.createElement('command'); + newFolderCommand.id = 'new-folder'; + document.body.appendChild(newFolderCommand); + + return footerElement; +} + +export function testFilterFilesWithSpecialCharactersExtension() { + const dialogType = DialogType.SELECT_SAVEAS_FILE; + const volumeManager = new MockVolumeManager(); + const fileSelectionHandler = new FakeFileSelectionHandler(); + const fileFilter = new FileFilter(volumeManager); + const footerElement = constructFooterElement(); + + new DialogActionController( + dialogType, + new DialogFooter( + dialogType, footerElement, document.createElement('cr-input')), + createFakeDirectoryModel(), + volumeManager, + fileFilter, + {} as NamingController, + fileSelectionHandler, + new LaunchParam({ + typeList: [ + {extensions: ['*'], description: 'any', selected: false}, + {extensions: ['c++', 'h++'], description: 'custom', selected: true}, + ], + }), + ); + + // The constructor will call onFileTypeFilterChanged_(), which will call + // regexpForCurrentFilter_() and add the regex to the `fileFilter`, that's + // where we can test the regular expression. + // Remove all other filters to make sure we are testing fileType filter. + fileFilter.removeFilter('hidden'); + fileFilter.removeFilter('android_hidden'); + fileFilter.removeFilter('android_download'); + + const entry1 = {name: 'a.c++', isDirectory: false} as any as Entry; + const entry2 = {name: 'b.h++', isDirectory: false} as any as Entry; + const entry3 = {name: 'c.html', isDirectory: false} as any as Entry; + assertTrue(fileFilter.filter(entry1)); + assertTrue(fileFilter.filter(entry2)); + assertFalse(fileFilter.filter(entry3)); +}
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index 28b1fb4..59e5501 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -429,6 +429,7 @@ "file_manager/foreground/js/actions_model_unittest.ts", "file_manager/foreground/js/banner_controller_unittest.ts", "file_manager/foreground/js/banner_util_unittest.ts", + "file_manager/foreground/js/dialog_action_controller_unittest.ts", "file_manager/foreground/js/directory_contents_unittest.ts", "file_manager/foreground/js/directory_model_unittest.ts", "file_manager/foreground/js/empty_folder_controller_unittest.ts",
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc index 6d6a9ba..9c7f4aaf 100644 --- a/ui/gfx/x/connection.cc +++ b/ui/gfx/x/connection.cc
@@ -410,8 +410,7 @@ } events_.pop_front(); } - // Move an event from XCB's internal queue to our queue, if available. - return ReadResponse(/*queued=*/false); + return false; } int Connection::GetFd() {
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc index cba47e8b..c9f3520 100644 --- a/ui/ozone/platform/drm/common/drm_util.cc +++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -22,6 +22,7 @@ #include <optional> #include <string> #include <string_view> +#include <unordered_map> #include <utility> #include <vector>
diff --git a/ui/ozone/platform/drm/gpu/fake_drm_device.h b/ui/ozone/platform/drm/gpu/fake_drm_device.h index 45915cb..c3159ce 100644 --- a/ui/ozone/platform/drm/gpu/fake_drm_device.h +++ b/ui/ozone/platform/drm/gpu/fake_drm_device.h
@@ -19,6 +19,7 @@ #include <optional> #include <set> #include <tuple> +#include <unordered_map> #include <vector> #include "base/containers/flat_map.h"
diff --git a/ui/ozone/platform/wayland/host/zwp_text_input_v3_unittest.cc b/ui/ozone/platform/wayland/host/zwp_text_input_v3_unittest.cc index 93485580..65400a1 100644 --- a/ui/ozone/platform/wayland/host/zwp_text_input_v3_unittest.cc +++ b/ui/ozone/platform/wayland/host/zwp_text_input_v3_unittest.cc
@@ -11,6 +11,7 @@ #include <string_view> #include "base/strings/utf_offset_string_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ime/surrounding_text_tracker.h"
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc index 987a4a5..27a43fc 100644 --- a/ui/views/accessibility/view_ax_platform_node_delegate.cc +++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -17,6 +17,7 @@ #include "base/i18n/rtl.h" #include "base/lazy_instance.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "build/build_config.h"
diff --git a/ui/views/controls/editable_combobox/editable_combobox_unittest.cc b/ui/views/controls/editable_combobox/editable_combobox_unittest.cc index 5be8824..80c58a1 100644 --- a/ui/views/controls/editable_combobox/editable_combobox_unittest.cc +++ b/ui/views/controls/editable_combobox/editable_combobox_unittest.cc
@@ -13,6 +13,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h"
diff --git a/ui/views/examples/animation_example.cc b/ui/views/examples/animation_example.cc index 84097a1d..90936c46 100644 --- a/ui/views/examples/animation_example.cc +++ b/ui/views/examples/animation_example.cc
@@ -8,6 +8,7 @@ #include <memory> #include <utility> +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h"
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 9799a1e..4d5cff80 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -18,7 +18,6 @@ #include "base/observer_list.h" #include "base/strings/utf_string_conversions.h" #include "base/task/current_thread.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "ui/accessibility/platform/ax_platform.h"
diff --git a/ui/views/win/hwnd_util.cc b/ui/views/win/hwnd_util.cc index 3b6e2b7c..0f42fdd 100644 --- a/ui/views/win/hwnd_util.cc +++ b/ui/views/win/hwnd_util.cc
@@ -8,7 +8,7 @@ #include "base/i18n/rtl.h" #include "base/task/current_thread.h" -#include "base/trace_event/base_tracing.h" +#include "base/trace_event/trace_event.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h"
diff --git a/url/android/gurl_java_test_helper.cc b/url/android/gurl_java_test_helper.cc index b710c09..e737d44 100644 --- a/url/android/gurl_java_test_helper.cc +++ b/url/android/gurl_java_test_helper.cc
@@ -4,6 +4,8 @@ #include <stddef.h> +#include <sstream> + #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/test/icu_test_util.h"
diff --git a/url/android/origin_java_test_helper.cc b/url/android/origin_java_test_helper.cc index da9bcfd..7851dffb 100644 --- a/url/android/origin_java_test_helper.cc +++ b/url/android/origin_java_test_helper.cc
@@ -4,6 +4,8 @@ #include <stddef.h> +#include <sstream> + #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "url/gurl.h"
diff --git a/url/gurl.cc b/url/gurl.cc index e8fdf74..278e3a4 100644 --- a/url/gurl.cc +++ b/url/gurl.cc
@@ -21,8 +21,8 @@ #include "base/no_destructor.h" #include "base/notreached.h" #include "base/strings/string_util.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/memory_usage_estimator.h" +#include "base/trace_event/trace_event.h" #include "url/url_canon_stdstring.h" #include "url/url_util.h"
diff --git a/url/origin.cc b/url/origin.cc index ba58f21..1176262f 100644 --- a/url/origin.cc +++ b/url/origin.cc
@@ -27,8 +27,8 @@ #include "base/debug/crash_logging.h" #include "base/pickle.h" #include "base/strings/strcat.h" -#include "base/trace_event/base_tracing.h" #include "base/trace_event/memory_usage_estimator.h" +#include "base/trace_event/trace_event.h" #include "base/unguessable_token.h" #include "url/gurl.h" #include "url/scheme_host_port.h"