diff --git a/.gitmodules b/.gitmodules index 804076fb..e6441a1 100644 --- a/.gitmodules +++ b/.gitmodules
@@ -858,10 +858,6 @@ path = remoting/tools/internal url = https://chrome-internal.googlesource.com/chrome/remoting/tools/internal gclient-condition = checkout_src_internal -[submodule "services/shape_detection/internal"] - path = services/shape_detection/internal - url = https://chrome-internal.googlesource.com/chrome/services/shape_detection - gclient-condition = checkout_src_internal [submodule "signing_keys"] path = signing_keys url = https://chrome-internal.googlesource.com/clank/apptestkey
diff --git a/AUTHORS b/AUTHORS index 9dae142..148d35c1 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -272,6 +272,7 @@ Chanyong Moon <dev.chanyongmoon@gmail.com> Chaobin Zhang <zhchbin@gmail.com> Charles Vaughn <cvaughn@gmail.com> +Chenhao Diao <diaochenhao@gmail.com> Cheng Zhao <zcbenz@gmail.com> Cheng Yu <yuzichengcode@gmail.com> Chenguang Shao <chenguangshao1@gmail.com> @@ -909,6 +910,7 @@ Lisha Guo <lisha.guo@intel.com> Lizhi Fan <lizhi.fan@samsung.com> Lloyd Huang <bzkirto@gmail.com> +Loay Ghreeb <loayahmed655@gmail.com> Loo Rong Jie <loorongjie@gmail.com> Lorenzo Stoakes <lstoakes@gmail.com> Lu Guanqun <guanqun.lu@gmail.com>
diff --git a/DEPS b/DEPS index 55e7235..60ffbb1d 100644 --- a/DEPS +++ b/DEPS
@@ -295,7 +295,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': '81737b465ba8c0c5686ebf867a1adc05eecdc951', + 'src_internal_revision': '26795f31e4ce2586e12dfb1897cbd87573277cff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # 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': '649514930e65cb7a9baa489092431010df5e8b4a', + 'angle_revision': '9e629bbb0f732b071f3c7ca6d13b4692b02f6cef', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -371,7 +371,7 @@ # 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': '1fcf64fb04e2c8477aeda4ad6eaea8ac1ae9422d', + 'crossbench_revision': '76223aed1ca101a8c6ceabf50b2d912424860f74', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -387,7 +387,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': '5d9af4427b5620b138701f9e9a12f70860cdae4d', + 'devtools_frontend_revision': '89f560fc68315d20519c66ed54d61a368308d034', # 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. @@ -411,7 +411,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '168d54a050758eb88e25757111b850bb1e97ed90', + 'dawn_revision': '6a294b931ac942984bdeb350d608c93c0fef8cae', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -515,11 +515,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'llvm_libc_revision': '66ae6e2bd8e09c7a20b8b623b7a0249a5262f87c', + 'llvm_libc_revision': 'e09972e0948f01cace57c08ba82b61fc171c739c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling llvm-libc # and whatever else without interference from each other. - 'compiler_rt_revision': '0ceada7e63a869692256f956cc22869007469c55', + 'compiler_rt_revision': '3b1c4b0e4fee85b10a2272117315d520c607a328', # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. @@ -1448,7 +1448,7 @@ 'packages': [ { 'package': 'chromium/third_party/updater/chromium_win_arm64', - 'version': 'version:2@1476005', + 'version': 'ksRzLnqewvz7P-YMX2e8mxZuDI1hgPtLNCuAXIisXhoC', }, ], }, @@ -1572,7 +1572,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'ceeb89e0f8224ca96ca05598cf0cfc1a7b652963', + '87625a3482c6c67f2ae49c6ed62f44a8ba86a900', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1731,7 +1731,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'dMDoulfjeBxh9IzbcSAvcwijRIqO4KgMa2lhE_dgUWYC', + 'version': 'X7GtTJlh84B4DuULla3Iwb6leLYXIQjpohJ2yqazhdgC', }, ], 'condition': 'checkout_android and non_git_source', @@ -2067,7 +2067,7 @@ 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3f633ff2f98baa7bd2563b710bc4168691eda7bb', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9a172103022289fcd1374c4d12d0192204343f59', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -2926,7 +2926,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4e2ba677d4d655a0b0d69b596f1c076ee0d4b516', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@316ed08fbc9a673e93c8960324cad4801e24a5dd', 'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@21b4e37133868b3a50ef15fc027ecd6d3a52c875', 'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3', 'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@2a611a970fdbc41ac2e3e328802aed9985352dca', @@ -2935,7 +2935,7 @@ 'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@dc6786e527cf8cefd244318f546b3b2ec26e84f4', 'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@d671923090e4dc74c0ebdb10c6e09fa0826e1fe9', 'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@54c9baf20802a13279e23fa4cb0528dd5cf16064', - 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@7cee394fda75d7b33d52b06b9e637abeb23c991c', + 'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@4b207eefa09f304a06c237fcf4913304e0b7d8d1', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21', @@ -2974,7 +2974,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '97733807d3c40aeb165cf2fbe4137f23c92446ea', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '2a8d4a83f751286302ce34573409ad75cc318508', 'src/third_party/webpagereplay': Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'), @@ -4677,7 +4677,7 @@ 'src/components/autofill/core/browser/form_parsing/internal_resources': { 'url': Var('chrome_git') + '/chrome/components/autofill_regex_patterns.git' + '@' + - 'b0d7376c49e618262acef6723c9dbdc7c41d31e8', + '103ef5ee6ebd7611908d3685faf5dc42d79b569d', 'condition': 'checkout_src_internal', }, @@ -4736,7 +4736,7 @@ 'src/components/test/data/autofill/heuristics-json/internal': { 'url': Var('chrome_git') + '/chrome/test/autofill/structured_forms.git' + '@' + - '059ed8f0e91c6377aded5f0b3826ffe6f8717ab0', + 'adc0282015eb4a9fa58b09adb2e1dcd75a522b7f', 'condition': 'checkout_chromium_autofill_test_dependencies', }, @@ -4794,12 +4794,6 @@ 'condition': 'checkout_src_internal', }, - 'src/services/shape_detection/internal': { - 'url': Var('chrome_git') + '/chrome/services/shape_detection.git' + '@' + - '8fd3ed03363d2155b038613ff3e2d094a2ad98a3', - 'condition': 'checkout_src_internal', - }, - 'src/signing_keys': { 'url': Var('chrome_git') + '/clank/apptestkey.git' + '@' + '5138e684915721cbccbb487ec0764ed05650fcd0',
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index dcbce77..a3156b3 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -216,7 +216,7 @@ // Enables or disables Boca OnTask mute ARC audio requests on ChromeOS. BASE_FEATURE(kBocaOnTaskMuteArcAudio, "BocaOnTaskMuteArcAudio", - base::FEATURE_ENABLED_BY_DEFAULT); + base::FEATURE_DISABLED_BY_DEFAULT); // Enables or disables the Boca OnTask pod on ChromeOS. BASE_FEATURE(kBocaOnTaskPod, "BocaOnTaskPod", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java index dc57e4b04..3fca572 100644 --- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java +++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -132,6 +132,57 @@ int COUNT = 4; } + /** + * Count the ChildServiceConnectionDelegate.onServiceConnected callback. + * + * <p>This is to detect the service binding restart. If the counter is more than 1, it means the + * service is restarted (e.g. due to LMK, crash). + * + * <p>onServiceDisconnectedOnLauncherThread() unbinds all service bindings when the child + * process dies to prevent the service from restarting. However there is race and the child + * process can restart. The metrics "Android.ChildProcessConnection.OnServiceConnectedCounts" is + * to understand how much restarts happen in practice. + * + * <p>This is expected to be used for waived service binding which is bound once for the service + * lifetime. retireAndCreateFallbackBindings() unbinds the waived binding, but + * CountOnServiceConnectedDecorator will be recreated at createBindings() in the method. + */ + private static class CountOnServiceConnectedDecorator + implements ChildServiceConnectionDelegate { + private final ChildServiceConnectionDelegate mDelegate; + private final Handler mLauncherHandler; + + private int mCountOnServiceConnected; + + CountOnServiceConnectedDecorator( + ChildServiceConnectionDelegate delegate, Handler launcherHandler) { + mDelegate = delegate; + mLauncherHandler = launcherHandler; + } + + @Override + public void onServiceConnected(final IBinder service) { + mDelegate.onServiceConnected(service); + if (mLauncherHandler.getLooper() == Looper.myLooper()) { + incrementCount(); + return; + } + mLauncherHandler.post(() -> incrementCount()); + } + + @Override + public void onServiceDisconnected() { + mDelegate.onServiceDisconnected(); + } + + private void incrementCount() { + mCountOnServiceConnected += 1; + RecordHistogram.recordCount100Histogram( + "Android.ChildProcessConnection.OnServiceConnectedCounts", + mCountOnServiceConnected); + } + } + private static class ChildProcessMismatchException extends RuntimeException { ChildProcessMismatchException(String msg) { super(msg); @@ -480,7 +531,7 @@ mConnectionFactory.createConnection( mBindIntent, mDefaultBindFlags | Context.BIND_WAIVE_PRIORITY, - mConnectionDelegate, + new CountOnServiceConnectedDecorator(mConnectionDelegate, mLauncherHandler), mInstanceName); }
diff --git a/base/containers/auto_spanification_helper.h b/base/containers/auto_spanification_helper.h index 80595101..155d50d 100644 --- a/base/containers/auto_spanification_helper.h +++ b/base/containers/auto_spanification_helper.h
@@ -7,6 +7,7 @@ #include <array> +#include "base/containers/span.h" #include "base/numerics/checked_math.h" namespace base { @@ -23,6 +24,43 @@ return sizeof(Element) * N; } +// Modifies the input span by removing its first element (if not empty) +// and returns the modified span. +// Used to rewrite pre-increment (++ptr). +// WARNING: This helper is intended to be used only by the auto spanification +// tool. Do not use this helper outside of the tool. Usage should usually be +// replaced with `base::span::(const_)iterator`. +template <typename T> +span<T> PreIncrementSpan(span<T>& span_ref) { + static_assert( + span<T>::extent == dynamic_extent, + "PreIncrementSpan requires a dynamic-extent span (base::span<T>)"); + // An iterator that is at the end is expressed as an empty span and it shall + // not be incremented. + CHECK(!span_ref.empty()); + span_ref = span_ref.template subspan<1u>(); + return span_ref; +} + +// Returns a copy of the input span *before* modification, and then +// modifies the input span by removing its first element (if not empty). +// Used to rewrite post-increment (ptr++). +// WARNING: This helper is intended to be used only by the auto spanification +// tool. Do not use this helper outside of the tool. Usage should usually be +// replaced with `base::span::(const_)iterator`. +template <typename T> +span<T> PostIncrementSpan(span<T>& span_ref) { + static_assert( + span<T>::extent == dynamic_extent, + "PostIncrementSpan requires a dynamic-extent span (base::span<T>)"); + // An iterator that is at the end is expressed as an empty span and it shall + // not be incremented. + CHECK(!span_ref.empty()); + span<T> original_span = span_ref; + span_ref = span_ref.template subspan<1u>(); + return original_span; +} + } // namespace base namespace base::spanification_internal {
diff --git a/base/containers/auto_spanification_helper_unittest.cc b/base/containers/auto_spanification_helper_unittest.cc index 22675f2..c8eb8645 100644 --- a/base/containers/auto_spanification_helper_unittest.cc +++ b/base/containers/auto_spanification_helper_unittest.cc
@@ -9,8 +9,106 @@ #include "base/containers/span.h" #include "base/memory/raw_ptr.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +namespace base { +namespace { + +TEST(AutoSpanificationIncrementTest, PreIncrementSpan) { + std::vector<int> data = {1, 2, 3, 4, 5}; + span<int> s(data); + + span<int> result = PreIncrementSpan(s); + EXPECT_THAT(s, testing::ElementsAre(2, 3, 4, 5)); + + EXPECT_EQ(result.data(), s.data()); + EXPECT_EQ(result.size(), s.size()); +} + +TEST(AutoSpanificationIncrementTest, PreIncrementSingleElementSpan) { + std::vector<int> single_element_data = {42}; + span<int> s(single_element_data); + + span<int> result = PreIncrementSpan(s); + + EXPECT_TRUE(s.empty()); + EXPECT_EQ(s.size(), 0u); + + EXPECT_TRUE(result.empty()); + EXPECT_EQ(result.size(), 0u); +} + +TEST(AutoSpanificationIncrementTest, PreIncrementEmptySpan) { + std::vector<int> empty_data; + span<int> s(empty_data); + + // An iterator that is at the end is expressed as an empty span and it shall + // not be incremented. Expect a CHECK failure when trying to pre-increment an + // empty span. + ASSERT_DEATH_IF_SUPPORTED({ PreIncrementSpan(s); }, ""); +} + +TEST(AutoSpanificationIncrementTest, PreIncrementConstSpan) { + const std::vector<int> data = {1, 2, 3, 4, 5}; + span<const int> s(data); + + span<const int> result = PreIncrementSpan(s); + + EXPECT_THAT(s, testing::ElementsAre(2, 3, 4, 5)); + + EXPECT_EQ(result.data(), s.data()); + EXPECT_EQ(result.size(), s.size()); +} + +TEST(AutoSpanificationIncrementTest, PostIncrementSpan) { + std::vector<int> data = {1, 2, 3, 4, 5}; + span<int> s(data); + + span<int> result = PostIncrementSpan(s); + + EXPECT_THAT(result, testing::ElementsAre(1, 2, 3, 4, 5)); + EXPECT_THAT(s, testing::ElementsAre(2, 3, 4, 5)); +} + +TEST(AutoSpanificationIncrementTest, PostIncrementSingleElementSpan) { + std::vector<int> single_element_data = {42}; + span<int> s(single_element_data); + + span<int> result = PostIncrementSpan(s); + + EXPECT_EQ(result.size(), 1u); + EXPECT_EQ(result[0], 42); + + EXPECT_TRUE(s.empty()); + EXPECT_EQ(s.size(), 0u); +} + +TEST(AutoSpanificationIncrementTest, PostIncrementEmptySpan) { + std::vector<int> empty_data; + span<int> s(empty_data); + + // An iterator that is at the end is expressed as an empty span and it shall + // not be incremented. Expect a CHECK failure when trying to post-increment an + // empty span. + ASSERT_DEATH_IF_SUPPORTED({ PostIncrementSpan(s); }, ""); +} + +TEST(AutoSpanificationIncrementTest, PostIncrementConstSpan) { + const std::vector<int> data = {1, 2, 3, 4, 5}; + span<const int> s(data); + + span<const int> result = PostIncrementSpan(s); + + EXPECT_THAT(result, testing::ElementsAre(1, 2, 3, 4, 5)); + + EXPECT_EQ(s.size(), 4u); + EXPECT_THAT(s, testing::ElementsAre(2, 3, 4, 5)); +} + +} // namespace +} // namespace base + namespace base::internal::spanification { namespace {
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc index a1c1690..0eee119 100644 --- a/base/memory/weak_ptr.cc +++ b/base/memory/weak_ptr.cc
@@ -83,11 +83,14 @@ : flag_(MakeRefCounted<WeakReference::Flag>()) {} WeakReferenceOwner::~WeakReferenceOwner() { - flag_->Invalidate(); + if (flag_) { + flag_->Invalidate(); + } } WeakReference WeakReferenceOwner::GetRef() const { #if DCHECK_IS_ON() + DCHECK(flag_); // If we hold the last reference to the Flag then detach the SequenceChecker. if (!HasRefs()) { flag_->DetachFromSequence(); @@ -98,12 +101,20 @@ } void WeakReferenceOwner::Invalidate() { + DCHECK(flag_); flag_->Invalidate(); flag_ = MakeRefCounted<WeakReference::Flag>(); } +void WeakReferenceOwner::InvalidateAndDoom() { + DCHECK(flag_); + flag_->Invalidate(); + flag_.reset(); +} + void WeakReferenceOwner::BindToCurrentSequence() { #if DCHECK_IS_ON() + DCHECK(flag_); flag_->BindToCurrentSequence(); #endif }
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h index ce64a9b..032f597 100644 --- a/base/memory/weak_ptr.h +++ b/base/memory/weak_ptr.h
@@ -163,6 +163,7 @@ bool HasRefs() const { return !flag_->HasOneRef(); } void Invalidate(); + void InvalidateAndDoom(); void BindToCurrentSequence(); private: @@ -402,18 +403,24 @@ weak_reference_owner_.GetRef(), reinterpret_cast<T*>(ptr_)); } - // Call this method to invalidate all existing weak pointers. + // Invalidates all existing weak pointers. void InvalidateWeakPtrs() { DCHECK(ptr_); weak_reference_owner_.Invalidate(); } - // Call this method to determine if any weak pointers exist. - bool HasWeakPtrs() const { + // Invalidates all existing weak pointers, and makes the factory unusable + // (cannot call GetWeakPtr after this). This is more efficient than + // InvalidateWeakPtrs(). + void InvalidateWeakPtrsAndDoom() { DCHECK(ptr_); - return weak_reference_owner_.HasRefs(); + weak_reference_owner_.InvalidateAndDoom(); + ptr_ = 0; } + // Call this method to determine if any weak pointers exist. + bool HasWeakPtrs() const { return ptr_ && weak_reference_owner_.HasRefs(); } + // Rebind the factory to the current sequence. This allows creating an object // and associated weak pointers on a different thread from the one they are // used on.
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc index 3fd68d84..c4dfba33 100644 --- a/base/memory/weak_ptr_unittest.cc +++ b/base/memory/weak_ptr_unittest.cc
@@ -424,6 +424,22 @@ EXPECT_FALSE(factory.HasWeakPtrs()); } +TEST(WeakPtrTest, InvalidateWeakPtrsAndDoom) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + EXPECT_TRUE(factory.HasWeakPtrs()); + factory.InvalidateWeakPtrsAndDoom(); + EXPECT_EQ(nullptr, ptr.get()); + EXPECT_FALSE(factory.HasWeakPtrs()); + + EXPECT_DCHECK_DEATH({ + // Cannot get a WeakPtr from a doomed factory. + WeakPtr<int> other_ptr = factory.GetWeakPtr(); + }); +} + // Tests that WasInvalidated() is true only for invalidated WeakPtrs (not // nullptr) and doesn't DCHECK (e.g. because of a dereference attempt). TEST(WeakPtrTest, WasInvalidatedByFactoryDestruction) {
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc index de66c5b..e0251b4 100644 --- a/base/nix/xdg_util.cc +++ b/base/nix/xdg_util.cc
@@ -143,6 +143,9 @@ if (value == "LXQt") { return DESKTOP_ENVIRONMENT_LXQT; } + if (value == "COSMIC") { + return DESKTOP_ENVIRONMENT_COSMIC; + } } } @@ -215,6 +218,8 @@ return "UKUI"; case DESKTOP_ENVIRONMENT_LXQT: return "LXQT"; + case DESKTOP_ENVIRONMENT_COSMIC: + return "COSMIC"; } return nullptr; }
diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h index 85b012be..0232fb0 100644 --- a/base/nix/xdg_util.h +++ b/base/nix/xdg_util.h
@@ -41,6 +41,7 @@ DESKTOP_ENVIRONMENT_UNITY = 9, DESKTOP_ENVIRONMENT_XFCE = 10, DESKTOP_ENVIRONMENT_LXQT = 11, + DESKTOP_ENVIRONMENT_COSMIC = 13, }; // Values based on valid types indicated in:
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc index 6474a85..d8d02ca 100644 --- a/base/nix/xdg_util_unittest.cc +++ b/base/nix/xdg_util_unittest.cc
@@ -53,6 +53,7 @@ const char* const kXdgDesktopUnity = "Unity"; const char* const kXdgDesktopUnity7 = "Unity:Unity7"; const char* const kXdgDesktopUnity8 = "Unity:Unity8"; +const char* const kXdgDesktopCosmic = "COSMIC"; const char* const kKDESessionKDE5 = "5"; const char* const kKDESessionKDE6 = "6"; @@ -333,6 +334,15 @@ EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter)); } +TEST(XDGUtilTest, GetXdgDesktopCosmic) { + MockEnvironment getter; + EXPECT_CALL(getter, GetVar(_)).WillRepeatedly(Return(std::nullopt)); + EXPECT_CALL(getter, GetVar(StrEq(kXdgCurrentDesktopEnvVar))) + .WillOnce(Return(kXdgDesktopCosmic)); + + EXPECT_EQ(DESKTOP_ENVIRONMENT_COSMIC, GetDesktopEnvironment(&getter)); +} + TEST(XDGUtilTest, GetXdgSessiontypeUnset) { MockEnvironment getter; EXPECT_CALL(getter, GetVar(_)).WillRepeatedly(Return(std::nullopt));
diff --git a/base/task/sequence_manager/delayed_task_handle_delegate.cc b/base/task/sequence_manager/delayed_task_handle_delegate.cc index cc2e355..a59f75b 100644 --- a/base/task/sequence_manager/delayed_task_handle_delegate.cc +++ b/base/task/sequence_manager/delayed_task_handle_delegate.cc
@@ -4,6 +4,7 @@ #include "base/task/sequence_manager/delayed_task_handle_delegate.h" +#include "base/features.h" #include "base/task/sequence_manager/task_queue_impl.h" namespace base::sequence_manager::internal { @@ -32,7 +33,11 @@ return; } - weak_ptr_factory_.InvalidateWeakPtrs(); + if (features::IsReducePPMsEnabled()) { + weak_ptr_factory_.InvalidateWeakPtrsAndDoom(); + } else { + weak_ptr_factory_.InvalidateWeakPtrs(); + } // If the task is still inside the heap, then it can be removed directly. if (heap_handle_.IsValid()) { @@ -61,7 +66,12 @@ DCHECK(IsValid()); // The task must be removed from the heap before running it. DCHECK(!heap_handle_.IsValid()); - weak_ptr_factory_.InvalidateWeakPtrs(); + + if (features::IsReducePPMsEnabled()) { + weak_ptr_factory_.InvalidateWeakPtrsAndDoom(); + } else { + weak_ptr_factory_.InvalidateWeakPtrs(); + } } } // namespace base::sequence_manager::internal
diff --git a/build/install-build-deps.py b/build/install-build-deps.py index 6b1236a5..412962f 100755 --- a/build/install-build-deps.py +++ b/build/install-build-deps.py
@@ -85,14 +85,16 @@ parser.add_argument( "--nacl", action="store_true", - help="Enable installation of prerequisites for building NaCl", - ) + # Deprecated flag retained as functional for backward compatibility: + # Enable installation of nacl dependencies + help=argparse.SUPPRESS) parser.add_argument( "--no-nacl", action="store_false", dest="nacl", - help="Disable installation of prerequisites for building NaCl", - ) + # Deprecated flag retained as functional for backward compatibility: + # Enable installation of nacl dependencies + help=argparse.SUPPRESS) parser.add_argument( "--backwards-compatible", action="store_true", @@ -202,7 +204,7 @@ def apt_update(options): - if options.lib32 or options.nacl: + if options.lib32 or options.backwards_compatible: subprocess.check_call(["sudo", "dpkg", "--add-architecture", "i386"]) subprocess.check_call(["sudo", "apt-get", "update"]) @@ -327,7 +329,8 @@ packages.append("binutils-mips64el-linux-gnuabi64") # 64-bit systems need a minimum set of 32-bit compat packages for the - # pre-built NaCl binaries. + # pre-built NaCl binaries or Android SDK + # See https://developer.android.com/sdk/installing/index.html?pkg=tools if "ELF 64-bit" in subprocess.check_output(["file", "-L", "/sbin/init"]).decode(): # ARM64 may not support these. @@ -588,6 +591,45 @@ "ttf-kochi-mincho", "ttf-mscorefonts-installer", "xfonts-mathml", + + # for NaCl + "g++-mingw-w64-i686", + "lib32z1-dev", + "libasound2:i386", + "libcap2:i386", + "libelf-dev:i386", + "libfontconfig1:i386", + "libglib2.0-0:i386", + "libgpm2:i386", + "libncurses5:i386", + "libnss3:i386", + "libpango-1.0-0:i386", + "libssl-dev:i386", + "libtinfo-dev", + "libtinfo-dev:i386", + "libtool", + "libudev1:i386", + "libuuid1:i386", + "libxcomposite1:i386", + "libxcursor1:i386", + "libxdamage1:i386", + "libxi6:i386", + "libxrandr2:i386", + "libxss1:i386", + "libxtst6:i386", + "texinfo", + "xvfb", + + # Packages to build NaCl, its toolchains, and its ports. + "ant", + "autoconf", + "bison", + "cmake", + "gawk", + "intltool", + "libtinfo5", + "xutils-dev", + "xsltproc", ] if package_exists("python-is-python2"): @@ -615,6 +657,15 @@ else: packages.append("apache2-bin") + # for NaCl. + # Prefer lib32ncurses5-dev to match libncurses5:i386 if it exists. + # In some Ubuntu releases, lib32ncurses5-dev is a transition package to + # lib32ncurses-dev, so use that as a fallback. + if package_exists("lib32ncurses5-dev"): + packages.append("lib32ncurses5-dev") + else: + packages.append("lib32ncurses-dev") + php_versions = [ ("php8.1-cgi", "libapache2-mod-php8.1"), ("php8.0-cgi", "libapache2-mod-php8.0"), @@ -665,72 +716,6 @@ return packages -def nacl_list(options): - if not options.nacl: - print("Skipping NaCl, NaCl toolchain, NaCl ports dependencies.", - file=sys.stderr) - return [] - - packages = [ - "g++-mingw-w64-i686", - "lib32z1-dev", - "libasound2:i386", - "libcap2:i386", - "libelf-dev:i386", - "libfontconfig1:i386", - "libglib2.0-0:i386", - "libgpm2:i386", - "libncurses5:i386", - "libnss3:i386", - "libpango-1.0-0:i386", - "libssl-dev:i386", - "libtinfo-dev", - "libtinfo-dev:i386", - "libtool", - "libudev1:i386", - "libuuid1:i386", - "libxcomposite1:i386", - "libxcursor1:i386", - "libxdamage1:i386", - "libxi6:i386", - "libxrandr2:i386", - "libxss1:i386", - "libxtst6:i386", - "texinfo", - "xvfb", - # Packages to build NaCl, its toolchains, and its ports. - "ant", - "autoconf", - "bison", - "cmake", - "gawk", - "intltool", - "libtinfo5", - "xutils-dev", - "xsltproc", - ] - - for package in packages: - if not package_exists(package): - print("Skipping NaCl, NaCl toolchain, NaCl ports dependencies because %s " - "is not available" % package, - file=sys.stderr) - return [] - - print("Including NaCl, NaCl toolchain, NaCl ports dependencies.", - file=sys.stderr) - - # Prefer lib32ncurses5-dev to match libncurses5:i386 if it exists. - # In some Ubuntu releases, lib32ncurses5-dev is a transition package to - # lib32ncurses-dev, so use that as a fallback. - if package_exists("lib32ncurses5-dev"): - packages.append("lib32ncurses5-dev") - else: - packages.append("lib32ncurses-dev") - - return packages - - # Packages suffixed with t64 are "transition packages" and should be preferred. def maybe_append_t64(package): name = package.split(":") @@ -781,7 +766,7 @@ def package_list(options): packages = (dev_list() + lib_list() + dbg_list(options) + - lib32_list(options) + arm_list(options) + nacl_list(options) + + lib32_list(options) + arm_list(options) + backwards_compatible_list(options)) packages = [maybe_append_t64(package) for package in set(packages)]
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 22beb28b..b6a7608d 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -186,8 +186,6 @@ "metrics/compositor_timing_history.h", "metrics/custom_metrics_recorder.cc", "metrics/custom_metrics_recorder.h", - "metrics/dropped_frame_counter.cc", - "metrics/dropped_frame_counter.h", "metrics/event_latency_tracing_recorder.cc", "metrics/event_latency_tracing_recorder.h", "metrics/event_latency_tracker.cc", @@ -794,7 +792,6 @@ "metrics/compositor_frame_reporter_unittest.cc", "metrics/compositor_frame_reporting_controller_unittest.cc", "metrics/compositor_timing_history_unittest.cc", - "metrics/dropped_frame_counter_unittest.cc", "metrics/event_metrics_unittest.cc", "metrics/events_metrics_manager_unittest.cc", "metrics/frame_info_unittest.cc",
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc index 9af545d..bfa7e3cd 100644 --- a/cc/layers/picture_layer_impl_perftest.cc +++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -77,7 +77,7 @@ do { std::unique_ptr<TilingSetRasterQueueAll> queue = TilingSetRasterQueueAll::Create( - pending_layer_->picture_layer_tiling_set(), false, true); + pending_layer_->picture_layer_tiling_set(), true); ASSERT_TRUE(queue); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -103,7 +103,7 @@ do { std::unique_ptr<TilingSetRasterQueueAll> queue = TilingSetRasterQueueAll::Create( - pending_layer_->picture_layer_tiling_set(), false, true); + pending_layer_->picture_layer_tiling_set(), true); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired());
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 65faa31..07a6358 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -1504,7 +1504,7 @@ std::unique_ptr<TilingSetRasterQueueAll> queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); for (; !queue->IsEmpty(); queue->Pop()) { const PrioritizedTile& prioritized_tile = queue->Top(); @@ -2933,7 +2933,7 @@ int high_res_now_tiles = 0u; std::unique_ptr<TilingSetRasterQueueAll> queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); @@ -3005,7 +3005,7 @@ unique_tiles.clear(); high_res_tile_count = 0u; queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); @@ -3042,7 +3042,7 @@ } queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), true, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); EXPECT_TRUE(queue->IsEmpty()); } @@ -3907,7 +3907,7 @@ int unoccluded_tile_count = 0; std::unique_ptr<TilingSetRasterQueueAll> queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); @@ -3939,7 +3939,7 @@ unoccluded_tile_count = 0; queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); @@ -3964,7 +3964,7 @@ unoccluded_tile_count = 0; queue = TilingSetRasterQueueAll::Create( - pending_layer()->picture_layer_tiling_set(), false, false); + pending_layer()->picture_layer_tiling_set(), false); EXPECT_TRUE(queue); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top();
diff --git a/cc/layers/tile_display_layer_impl_unittest.cc b/cc/layers/tile_display_layer_impl_unittest.cc index 56ccd06c..44b448c 100644 --- a/cc/layers/tile_display_layer_impl_unittest.cc +++ b/cc/layers/tile_display_layer_impl_unittest.cc
@@ -22,9 +22,8 @@ auto render_pass = viz::CompositorRenderPass::Create(); AppendQuadsData data; - layer.AppendQuads( - AppendQuadsContext{DRAW_MODE_RESOURCELESS_SOFTWARE, {}, false}, - render_pass.get(), &data); + layer.AppendQuads(AppendQuadsContext{DRAW_MODE_SOFTWARE, {}, false}, + render_pass.get(), &data); EXPECT_EQ(render_pass->quad_list.size(), 0u); } @@ -52,9 +51,8 @@ auto render_pass = viz::CompositorRenderPass::Create(); AppendQuadsData data; - raw_layer->AppendQuads( - AppendQuadsContext{DRAW_MODE_RESOURCELESS_SOFTWARE, {}, false}, - render_pass.get(), &data); + raw_layer->AppendQuads(AppendQuadsContext{DRAW_MODE_SOFTWARE, {}, false}, + render_pass.get(), &data); EXPECT_EQ(render_pass->quad_list.size(), 1u); EXPECT_EQ(render_pass->quad_list.front()->rect, kLayerRect); @@ -69,7 +67,8 @@ kLayerColor); } -TEST_F(TileDisplayLayerImplTest, NonEmptyTilingResultsInPictureQuad) { +TEST_F(TileDisplayLayerImplTest, + NonEmptyTilingWithResourceResultsInPictureQuad) { constexpr gfx::Size kLayerBounds(1300, 1900); constexpr gfx::Rect kLayerRect(kLayerBounds); constexpr float kOpacity = 1.0; @@ -103,9 +102,8 @@ auto render_pass = viz::CompositorRenderPass::Create(); AppendQuadsData data; - raw_layer->AppendQuads( - AppendQuadsContext{DRAW_MODE_RESOURCELESS_SOFTWARE, {}, false}, - render_pass.get(), &data); + raw_layer->AppendQuads(AppendQuadsContext{DRAW_MODE_SOFTWARE, {}, false}, + render_pass.get(), &data); EXPECT_EQ(render_pass->quad_list.size(), 1u); EXPECT_EQ(render_pass->quad_list.front()->rect, kLayerRect); @@ -120,6 +118,54 @@ false); } +TEST_F(TileDisplayLayerImplTest, + NonEmptyTilingWithColorResultsInSolidColorQuad) { + constexpr gfx::Size kLayerBounds(1300, 1900); + constexpr gfx::Rect kLayerRect(kLayerBounds); + constexpr float kOpacity = 1.0; + constexpr SkColor4f kTileColor = SkColors::kRed; + + auto layer = std::make_unique<TileDisplayLayerImpl>( + CHECK_DEREF(host_impl()->active_tree()), /*id=*/42); + auto* raw_layer = layer.get(); + host_impl()->active_tree()->AddLayer(std::move(layer)); + + // For the production code to actually append a quad, the layer must have + // non-zero size and not be completely transparent. + raw_layer->SetBounds(kLayerBounds); + raw_layer->draw_properties().visible_layer_rect = kLayerRect; + raw_layer->draw_properties().opacity = kOpacity; + + auto& tiling = raw_layer->GetOrCreateTilingFromScaleKey(1.0); + tiling.SetTileSize(kLayerBounds); + tiling.SetTilingRect(kLayerRect); + + tiling.SetTileContents(TileIndex{0, 0}, kTileColor, /*update_damage=*/true); + + SetupRootProperties(host_impl()->active_tree()->root_layer()); + + auto render_pass = viz::CompositorRenderPass::Create(); + AppendQuadsData data; + raw_layer->AppendQuads(AppendQuadsContext{DRAW_MODE_SOFTWARE, {}, false}, + render_pass.get(), &data); + + EXPECT_EQ(render_pass->quad_list.size(), 1u); + EXPECT_EQ(render_pass->quad_list.front()->rect, kLayerRect); + EXPECT_EQ(render_pass->quad_list.front()->visible_rect, kLayerRect); + EXPECT_EQ(render_pass->quad_list.front()->shared_quad_state->opacity, + kOpacity); + EXPECT_EQ(render_pass->quad_list.front()->material, + viz::DrawQuad::Material::kSolidColor); + EXPECT_EQ( + viz::SolidColorDrawQuad::MaterialCast(render_pass->quad_list.front()) + ->color, + kTileColor); + EXPECT_EQ( + viz::SolidColorDrawQuad::MaterialCast(render_pass->quad_list.front()) + ->force_anti_aliasing_off, + false); +} + class TileDisplayLayerImplWithEdgeAADisabledTest : public TileDisplayLayerImplTest { public: @@ -163,9 +209,8 @@ auto render_pass = viz::CompositorRenderPass::Create(); AppendQuadsData data; - raw_layer->AppendQuads( - AppendQuadsContext{DRAW_MODE_RESOURCELESS_SOFTWARE, {}, false}, - render_pass.get(), &data); + raw_layer->AppendQuads(AppendQuadsContext{DRAW_MODE_SOFTWARE, {}, false}, + render_pass.get(), &data); EXPECT_EQ(render_pass->quad_list.size(), 1u); EXPECT_EQ(viz::TileDrawQuad::MaterialCast(render_pass->quad_list.front())
diff --git a/cc/metrics/begin_main_frame_metrics.h b/cc/metrics/begin_main_frame_metrics.h index 830a578..68427d3f 100644 --- a/cc/metrics/begin_main_frame_metrics.h +++ b/cc/metrics/begin_main_frame_metrics.h
@@ -25,8 +25,8 @@ base::TimeDelta paint; base::TimeDelta composite_commit; base::TimeDelta update_layers; - // True if we should measure smoothness in TotalFrameCounter and - // DroppedFrameCounter. Currently true when first contentful paint is done. + // True if we should measure smoothness in TotalFrameCounter. + // Currently true when first contentful paint is done. bool should_measure_smoothness = false; BeginMainFrameMetrics();
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc index 00a4bba..31cd4da 100644 --- a/cc/metrics/compositor_frame_reporter.cc +++ b/cc/metrics/compositor_frame_reporter.cc
@@ -30,7 +30,6 @@ #include "base/tracing/protos/chrome_track_event.pbzero.h" #include "cc/base/rolling_time_delta_history.h" #include "cc/metrics/custom_metrics_recorder.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_latency_tracing_recorder.h" #include "cc/metrics/event_latency_tracker.h" #include "cc/metrics/event_metrics.h" @@ -515,7 +514,6 @@ smooth_thread_(smooth_thread), layer_tree_host_id_(layer_tree_host_id), global_trackers_(trackers) { - DCHECK(global_trackers_.dropped_frame_counter); DCHECK(global_trackers_.frame_sorter); if (global_trackers_.frame_sorter->first_contentful_paint_received()) { global_trackers_.frame_sorter->AddNewFrame(args); @@ -890,15 +888,6 @@ ReportPaintMetric(); } - if (TestReportType(FrameReportType::kDroppedFrame)) { - global_trackers_.dropped_frame_counter->AddDroppedFrame(); - } else { - if (has_partial_update_) { - global_trackers_.dropped_frame_counter->AddPartialFrame(); - } else { - global_trackers_.dropped_frame_counter->AddGoodFrame(); - } - } global_trackers_.frame_sorter->AddFrameInfoToBuffer(frame_info); if (global_trackers_.frame_sorter->first_contentful_paint_received()) { // Delegates call to DFC->OnEndFrame.
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h index b286c27..78e2ac9 100644 --- a/cc/metrics/compositor_frame_reporter.h +++ b/cc/metrics/compositor_frame_reporter.h
@@ -37,7 +37,6 @@ } namespace cc { -class DroppedFrameCounter; class EventLatencyTracker; class FrameSorter; class LatencyUkmReporter; @@ -45,7 +44,6 @@ struct GlobalMetricsTrackers { // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler // stacks. - RAW_PTR_EXCLUSION DroppedFrameCounter* dropped_frame_counter = nullptr; RAW_PTR_EXCLUSION LatencyUkmReporter* latency_ukm_reporter = nullptr; RAW_PTR_EXCLUSION FrameSequenceTrackerCollection* frame_sequence_trackers = nullptr;
diff --git a/cc/metrics/compositor_frame_reporter_unittest.cc b/cc/metrics/compositor_frame_reporter_unittest.cc index 3c18797..1bcc037 100644 --- a/cc/metrics/compositor_frame_reporter_unittest.cc +++ b/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -16,7 +16,6 @@ #include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "cc/metrics/compositor_frame_reporting_controller.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_metrics.h" #include "components/viz/common/frame_timing_details.h" #include "testing/gmock/include/gmock/gmock.h" @@ -195,8 +194,7 @@ } std::unique_ptr<CompositorFrameReporter> CreatePipelineReporter() { - GlobalMetricsTrackers trackers{&dropped_frame_counter_, - nullptr, + GlobalMetricsTrackers trackers{nullptr, nullptr, nullptr, nullptr, @@ -228,7 +226,6 @@ // and destroyed after that. base::SimpleTestTickClock test_tick_clock_; - DroppedFrameCounter dropped_frame_counter_; FrameSorter frame_sorter_; std::unique_ptr<CompositorFrameReporter> pipeline_reporter_;
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc index 2e159dd..62e686c 100644 --- a/cc/metrics/compositor_frame_reporting_controller.cc +++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -9,7 +9,6 @@ #include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_macros.h" #include "cc/metrics/compositor_frame_reporter.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/frame_sequence_tracker_collection.h" #include "cc/metrics/latency_ukm_reporter.h" #include "cc/metrics/scroll_jank_dropped_frame_tracker.h" @@ -66,10 +65,6 @@ predictor_jank_tracker_->set_scroll_jank_ukm_reporter(nullptr); scroll_jank_dropped_frame_tracker_->set_scroll_jank_ukm_reporter(nullptr); if (global_trackers_.frame_sorter) { - if (global_trackers_.dropped_frame_counter) { - global_trackers_.frame_sorter->RemoveObserver( - global_trackers_.dropped_frame_counter); - } if (global_trackers_.frame_sequence_trackers) { global_trackers_.frame_sorter->RemoveObserver( global_trackers_.frame_sequence_trackers); @@ -854,16 +849,4 @@ } } -void CompositorFrameReportingController::SetDroppedFrameCounter( - DroppedFrameCounter* counter) { - if (global_trackers_.dropped_frame_counter && global_trackers_.frame_sorter) { - global_trackers_.frame_sorter->RemoveObserver( - global_trackers_.dropped_frame_counter); - } - if (global_trackers_.frame_sorter) { - global_trackers_.frame_sorter->AddObserver(counter); - } - global_trackers_.dropped_frame_counter = counter; -} - } // namespace cc
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h index e9e6a0c2..3908918a2 100644 --- a/cc/metrics/compositor_frame_reporting_controller.h +++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -32,7 +32,6 @@ } namespace cc { -class DroppedFrameCounter; class EventLatencyTracker; struct BeginMainFrameMetrics; struct FrameInfo; @@ -107,17 +106,6 @@ global_trackers_.frame_sorter = frame_sorter; } - void SetDroppedFrameCounter(DroppedFrameCounter* counter); - - void ClearDroppedFrameCounter() { - if (global_trackers_.frame_sorter && - global_trackers_.dropped_frame_counter) { - global_trackers_.frame_sorter->RemoveObserver( - global_trackers_.dropped_frame_counter); - } - global_trackers_.dropped_frame_counter = nullptr; - } - void SetFrameSequenceTrackerCollection( FrameSequenceTrackerCollection* frame_sequence_trackers) { if (global_trackers_.frame_sorter) {
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 33cb503..16b0663 100644 --- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -15,7 +15,6 @@ #include "base/test/simple_test_tick_clock.h" #include "base/test/test_trace_processor.h" #include "base/time/time.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_metrics.h" #include "cc/metrics/frame_sequence_metrics.h" #include "cc/metrics/frame_sequence_tracker_collection.h" @@ -118,14 +117,13 @@ class CompositorFrameReportingControllerTest : public testing::Test { public: CompositorFrameReportingControllerTest() - : current_id_(1, 1), tracker_collection_(false, &dropped_counter_) { + : current_id_(1, 1), tracker_collection_(false) { test_tick_clock_.SetNowTicks(base::TimeTicks::Now()); reporting_controller_.set_tick_clock(&test_tick_clock_); args_ = SimulateBeginFrameArgs(current_id_); reporting_controller_.SetFrameSorter(&frame_sorter_); reporting_controller_.SetFrameSequenceTrackerCollection( &tracker_collection_); - reporting_controller_.SetDroppedFrameCounter(&dropped_counter_); } // The following functions simulate the actions that would @@ -345,7 +343,6 @@ viz::FrameTokenGenerator current_token_; FrameSorter frame_sorter_; FrameSequenceTrackerCollection tracker_collection_; - DroppedFrameCounter dropped_counter_; TestCompositorFrameReportingController reporting_controller_; ::base::test::TracingEnvironment tracing_environment_; }; @@ -1458,7 +1455,6 @@ reporting_controller_.ResetReporters(); reporting_controller_.ClearFrameSequenceTrackerCollection(); - reporting_controller_.ClearDroppedFrameCounter(); reporting_controller_.SetFrameSorter(nullptr); } @@ -1520,7 +1516,6 @@ reporting_controller_.ResetReporters(); reporting_controller_.ClearFrameSequenceTrackerCollection(); - reporting_controller_.ClearDroppedFrameCounter(); reporting_controller_.SetFrameSorter(nullptr); } @@ -1549,7 +1544,6 @@ // Stop requesting frames, skip over a few frames, and submit + present // another frame. There should no new dropped frames. frame_sorter_.Reset(/*reset_fcp=*/true); - dropped_counter_.Reset(); reporting_controller_.OnStoppedRequestingBeginFrames(); for (uint32_t i = 0; i < kSkipFrames; ++i) IncrementCurrentId(); @@ -1560,7 +1554,6 @@ reporting_controller_.ResetReporters(); reporting_controller_.ClearFrameSequenceTrackerCollection(); - reporting_controller_.ClearDroppedFrameCounter(); reporting_controller_.SetFrameSorter(nullptr); } @@ -1649,7 +1642,6 @@ tracker_collection_.StartSequence( FrameSequenceTrackerType::kCompositorAnimation); EXPECT_EQ(tracker_collection_.GetSmoothThread(), thread_type_compositor); - dropped_counter_.OnFirstContentfulPaintReceived(); frame_sorter_.OnFirstContentfulPaintReceived(); // Submit and present two compositor frames. @@ -1671,7 +1663,6 @@ EXPECT_EQ(3u + kSkipFrames_1, frame_sorter_.total_frames()); EXPECT_EQ(0u, frame_sorter_.total_partial()); EXPECT_EQ(kSkipFrames_1, frame_sorter_.total_dropped()); - EXPECT_EQ(kSkipFrames_1, dropped_counter_.total_smoothness_dropped()); // Now skip over a few frames which are not affecting smoothness. tracker_collection_.StopSequence( @@ -1685,7 +1676,6 @@ EXPECT_EQ(4u + kSkipFrames_1 + kSkipFrames_2, frame_sorter_.total_frames()); EXPECT_EQ(0u, frame_sorter_.total_partial()); EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2, frame_sorter_.total_dropped()); - EXPECT_EQ(kSkipFrames_1, dropped_counter_.total_smoothness_dropped()); // Now skip over a few frames more frames which are affecting smoothness. tracker_collection_.StartSequence( @@ -1700,8 +1690,6 @@ EXPECT_EQ(0u, frame_sorter_.total_partial()); EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2 + kSkipFrames_3, frame_sorter_.total_dropped()); - EXPECT_EQ(kSkipFrames_1 + kSkipFrames_3, - dropped_counter_.total_smoothness_dropped()); } TEST_F(CompositorFrameReportingControllerTest, @@ -1793,10 +1781,7 @@ FrameSequenceTrackerType::kMainThreadAnimation); EXPECT_EQ(tracker_collection_.GetSmoothThread(), thread_type_main); - dropped_counter_.OnFirstContentfulPaintReceived(); frame_sorter_.OnFirstContentfulPaintReceived(); - dropped_counter_.SetTimeFirstContentfulPaintReceivedForTesting( - args_.frame_time); SimulateBeginMainFrame(); reporting_controller_.OnFinishImplFrame(current_id_); @@ -1831,17 +1816,11 @@ // There are two frames with partial updates EXPECT_EQ(2u, frame_sorter_.total_partial()); - // Which one is accompanied with new main thread update so only one affects - // smoothness - EXPECT_EQ(1u, dropped_counter_.total_smoothness_dropped()); } TEST_F(CompositorFrameReportingControllerTest, NoUpdateCompositorWithJankyMain) { - dropped_counter_.OnFirstContentfulPaintReceived(); frame_sorter_.OnFirstContentfulPaintReceived(); - dropped_counter_.SetTimeFirstContentfulPaintReceivedForTesting( - args_.frame_time); // Start a new frame and take it all the way to start the frame on the main // thread (i.e. 'begin main frame').
diff --git a/cc/metrics/compositor_timing_history_unittest.cc b/cc/metrics/compositor_timing_history_unittest.cc index 6e4f011d..0483a5b 100644 --- a/cc/metrics/compositor_timing_history_unittest.cc +++ b/cc/metrics/compositor_timing_history_unittest.cc
@@ -9,7 +9,6 @@ #include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "cc/base/features.h" -#include "cc/metrics/dropped_frame_counter.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -47,7 +46,6 @@ TestCompositorTimingHistory timing_history_; base::TimeTicks now_; uint64_t sequence_number = 0; - DroppedFrameCounter dropped_counter; viz::BeginFrameArgs GetFakeBeginFrameArg(bool on_critical_path = true) { viz::BeginFrameArgs args = viz::BeginFrameArgs();
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc deleted file mode 100644 index 9a9639ca..0000000 --- a/cc/metrics/dropped_frame_counter.cc +++ /dev/null
@@ -1,420 +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. - -#include "cc/metrics/dropped_frame_counter.h" - -#include <algorithm> -#include <array> -#include <cmath> -#include <iterator> - -#include "base/functional/bind.h" -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_macros.h" -#include "base/trace_event/trace_event.h" -#include "build/chromeos_buildflags.h" -#include "cc/base/features.h" -#include "cc/metrics/custom_metrics_recorder.h" -#include "cc/metrics/frame_sorter.h" -#include "cc/metrics/ukm_smoothness_data.h" - -namespace cc { -namespace { - -const base::TimeDelta kDefaultSlidingWindowInterval = base::Seconds(1); - -// The start ranges of each bucket, up to but not including the start of the -// next bucket. The last bucket contains the remaining values. -constexpr std::array<double, 7> kBucketBounds = {0, 3, 6, 12, 25, 50, 75}; - -} // namespace - -using SlidingWindowHistogram = DroppedFrameCounter::SlidingWindowHistogram; - -void SlidingWindowHistogram::AddPercentDroppedFrame( - double percent_dropped_frame, - size_t count) { - DCHECK_GE(percent_dropped_frame, 0.0); - DCHECK_GE(100.0, percent_dropped_frame); - histogram_bins_[static_cast<int>(std::round(percent_dropped_frame))] += count; - total_count_ += count; -} - -uint32_t SlidingWindowHistogram::GetPercentDroppedFramePercentile( - double percentile) const { - if (total_count_ == 0) - return 0; - DCHECK_GE(percentile, 0.0); - DCHECK_GE(1.0, percentile); - int current_index = 100; // Last bin in historgam - uint32_t skipped_counter = histogram_bins_[current_index]; // Last bin values - double samples_to_skip = ((1 - percentile) * total_count_); - // We expect this method to calculate higher end percentiles such 95 and as a - // result we count from the last bin to find the correct bin. - while (skipped_counter < samples_to_skip && current_index > 0) { - current_index--; - skipped_counter += histogram_bins_[current_index]; - } - return current_index; -} - -double SlidingWindowHistogram::GetPercentDroppedFrameVariance() const { - double sum = 0; - size_t bin_count = sizeof(histogram_bins_) / sizeof(uint32_t); - for (size_t i = 0; i < bin_count; ++i) { - sum += histogram_bins_[i] * i; - } - - // Don't calculate if count is 1 or less. Avoid divide by zero. - if (total_count_ <= 1) - return 0; - - double average = sum / total_count_; - sum = 0; // Sum is reset to be used for variance calculation - - for (size_t i = 0; i < bin_count; ++i) { - sum += histogram_bins_[i] * (i - average) * (i - average); - // histogram_bins_[i] is the number of PDFs which were in the range of - // [i,i+1) so i is used as the actual value which is repeated for - // histogram_bins_[i] times. - } - - return sum / (total_count_ - 1); -} - -std::vector<double> SlidingWindowHistogram::GetPercentDroppedFrameBuckets() - const { - if (total_count_ == 0) - return std::vector<double>(std::size(kBucketBounds), 0); - std::vector<double> buckets(std::size(kBucketBounds)); - for (size_t i = 0; i < std::size(kBucketBounds); ++i) { - buckets[i] = - static_cast<double>(smoothness_buckets_[i]) * 100 / total_count_; - } - return buckets; -} - -void SlidingWindowHistogram::Clear() { - std::fill(std::begin(histogram_bins_), std::end(histogram_bins_), 0); - std::fill(std::begin(smoothness_buckets_), std::end(smoothness_buckets_), 0); - total_count_ = 0; -} - -std::ostream& SlidingWindowHistogram::Dump(std::ostream& stream) const { - for (size_t i = 0; i < std::size(histogram_bins_); ++i) { - stream << i << ": " << histogram_bins_[i] << std::endl; - } - return stream << "Total: " << total_count_; -} - -std::ostream& operator<<( - std::ostream& stream, - const DroppedFrameCounter::SlidingWindowHistogram& histogram) { - return histogram.Dump(stream); -} - -DroppedFrameCounter::DroppedFrameCounter() = default; -DroppedFrameCounter::~DroppedFrameCounter() = default; - -uint32_t DroppedFrameCounter::GetAverageThroughput() const { - size_t good_frames = 0; - for (auto it = End(); it; --it) { - if (**it == kFrameStateComplete || **it == kFrameStatePartial) - ++good_frames; - } - double throughput = 100. * good_frames / ring_buffer_.BufferSize(); - return static_cast<uint32_t>(throughput); -} - -void DroppedFrameCounter::AddGoodFrame() { - ring_buffer_.SaveToBuffer(kFrameStateComplete); - ++total_frames_; -} - -void DroppedFrameCounter::AddPartialFrame() { - ring_buffer_.SaveToBuffer(kFrameStatePartial); - ++total_frames_; - ++total_partial_; -} - -void DroppedFrameCounter::AddDroppedFrame() { - ring_buffer_.SaveToBuffer(kFrameStateDropped); - ++total_frames_; - ++total_dropped_; -} - -// Start with flushing the frames in frame_sorter ignoring the currently -// pending frames, so all callers should call frame_sorter_.Reset(); -// prior to this function. -// TODO(crbug.com/409093076): Remove all uses of this function. -void DroppedFrameCounter::ResetPendingFrames(base::TimeTicks timestamp) { - // Before resetting the pending frames, update the measurements for the - // sliding windows. - if (!latest_sliding_window_start_.is_null()) { - const auto report_until = timestamp - kDefaultSlidingWindowInterval; - // Report the sliding window metrics for frames that have already been - // completed (and some of which may have been dropped). - while (!sliding_window_.empty()) { - const auto& args = sliding_window_.front().first; - if (args.frame_time > report_until) - break; - PopSlidingWindow(); - } - if (sliding_window_.empty()) { - DCHECK_EQ( - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy], - 0u); - DCHECK_EQ(dropped_frame_count_in_window_ - [SmoothnessStrategy::kCompositorFocusedStrategy], - 0u); - } - - // Report no dropped frames for the sliding windows spanning the rest of the - // time. - if (latest_sliding_window_start_ < report_until) { - const auto difference = report_until - latest_sliding_window_start_; - const size_t count = - std::ceil(difference / latest_sliding_window_interval_); - if (count > 0) { - sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy] - .AddPercentDroppedFrame(0., count); - sliding_window_histogram_ - [SmoothnessStrategy::kCompositorFocusedStrategy] - .AddPercentDroppedFrame(0., count); - } - } - } - - dropped_frame_count_in_window_.fill(0); - sliding_window_ = {}; - latest_sliding_window_start_ = {}; - latest_sliding_window_interval_ = {}; -} - -void DroppedFrameCounter::EnableReportForUI() { - report_for_ui_ = true; -} - -void DroppedFrameCounter::OnEndFrame(const viz::BeginFrameArgs& args, - const FrameInfo& frame_info) { - const bool is_dropped = frame_info.IsDroppedAffectingSmoothness(); - if (!args.interval.is_zero()) - total_frames_in_window_ = kDefaultSlidingWindowInterval / args.interval; - - // Don't measure smoothness for frames that start before FCP is received, or - // that have already been reported as dropped. - if (is_dropped && first_contentful_paint_received_ && - args.frame_time >= time_first_contentful_paint_received_) { - ++total_smoothness_dropped_; - - if (!report_for_ui_) { - ReportFrames(); - } - } - - // Report frames on every frame for UI. And this needs to happen after - // `frame_sorter_.AddFrameResult` so that the current ending frame is included - // in the sliding window. - if (report_for_ui_) { - ReportFramesOnEveryFrameForUI(); - } -} - -void DroppedFrameCounter::ReportFrames() { - DCHECK(!report_for_ui_); - - const auto total_frames = total_frames_; - TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame", "total", total_frames, - "smoothness", total_smoothness_dropped_); - if (sliding_window_max_percent_dropped_ != - last_reported_metrics_.max_window) { - UMA_HISTOGRAM_PERCENTAGE( - "Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow", - sliding_window_max_percent_dropped_); - last_reported_metrics_.max_window = sliding_window_max_percent_dropped_; - } - - if (ukm_smoothness_data_ && total_frames > 0) { - UkmSmoothnessData smoothness_data; - smoothness_data.avg_smoothness = - static_cast<double>(total_smoothness_dropped_) * 100 / total_frames; - smoothness_data.median_smoothness = - SlidingWindowMedianPercentDropped(SmoothnessStrategy::kDefaultStrategy); - smoothness_data.compositor_focused_median = - SlidingWindowMedianPercentDropped( - SmoothnessStrategy::kCompositorFocusedStrategy); - ukm_smoothness_data_->Write(smoothness_data); - } -} - -void DroppedFrameCounter::ReportFramesOnEveryFrameForUI() { - DCHECK(report_for_ui_); -} - -void DroppedFrameCounter::SetUkmSmoothnessDestination( - UkmSmoothnessDataShared* smoothness_data) { - ukm_smoothness_data_ = smoothness_data; -} - -// Start with flushing the frames in frame_sorter ignoring the currently -// pending frames, so all callers should call frame_sorter_.Reset(); -// prior to invoking this function. -// TODO(crbug.com/409093076): Remove all uses of this function. -void DroppedFrameCounter::Reset() { - total_frames_ = 0; - total_partial_ = 0; - total_dropped_ = 0; - total_smoothness_dropped_ = 0; - sliding_window_max_percent_dropped_ = 0; - dropped_frame_count_in_window_.fill(0); - first_contentful_paint_received_ = false; - sliding_window_ = {}; - latest_sliding_window_start_ = {}; - sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy].Clear(); - sliding_window_histogram_[SmoothnessStrategy::kCompositorFocusedStrategy] - .Clear(); - ring_buffer_.Clear(); - last_reported_metrics_ = {}; - sliding_window_current_percent_dropped_.reset(); -} - -base::TimeDelta DroppedFrameCounter::ComputeCurrentWindowSize() const { - if (sliding_window_.empty()) - return {}; - return sliding_window_.back().first.frame_time + - sliding_window_.back().first.interval - - sliding_window_.front().first.frame_time; -} - -void DroppedFrameCounter::AddSortedFrame(const viz::BeginFrameArgs& args, - const FrameInfo& frame_info) { - // Entirely disregard the frames with interval larger than the window -- - // these are violating the assumptions in the below code and should - // only occur with external frame control, where dropped frame stats - // are not relevant. - if (args.interval >= kDefaultSlidingWindowInterval) { - return; - } - - sliding_window_.emplace(args, frame_info); - UpdateDroppedFrameCountInWindow(frame_info, 1); - - const bool is_dropped = frame_info.IsDroppedAffectingSmoothness(); - if (!in_dropping_ && is_dropped) { - TRACE_EVENT_BEGIN("cc,benchmark,latency", "DroppedFrameDuration", - perfetto::Track(reinterpret_cast<uint64_t>(this), - perfetto::ThreadTrack::Current()), - args.frame_time); - in_dropping_ = true; - } else if (in_dropping_ && !is_dropped) { - TRACE_EVENT_END("cc,benchmark,latency" /* "DroppedFrameDuration" */, - perfetto::Track(reinterpret_cast<uint64_t>(this), - perfetto::ThreadTrack::Current()), - args.frame_time); - in_dropping_ = false; - } - - OnEndFrame(args, frame_info); - - if (ComputeCurrentWindowSize() < kDefaultSlidingWindowInterval) { - return; - } - - DCHECK_GE( - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy], 0u); - DCHECK_GE( - sliding_window_.size(), - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy]); - - while (ComputeCurrentWindowSize() > kDefaultSlidingWindowInterval) { - PopSlidingWindow(); - } - DCHECK(!sliding_window_.empty()); -} - -void DroppedFrameCounter::PopSlidingWindow() { - const auto removed_args = sliding_window_.front().first; - const auto removed_frame_info = sliding_window_.front().second; - UpdateDroppedFrameCountInWindow(removed_frame_info, -1); - sliding_window_.pop(); - if (sliding_window_.empty()) - return; - - // Don't count the newest element if it is outside the current window. - const auto& newest_args = sliding_window_.back().first; - const auto newest_was_dropped = - sliding_window_.back().second.IsDroppedAffectingSmoothness(); - - uint32_t invalidated_frames = 0; - if (ComputeCurrentWindowSize() > kDefaultSlidingWindowInterval && - newest_was_dropped) { - invalidated_frames++; - } - - // If two consecutive 'completed' frames are far apart from each other (in - // time), then report the 'dropped frame count' for the sliding window(s) in - // between. Note that the window-size still needs to be at least - // kDefaultSlidingWindowInterval. - const auto max_sliding_window_start = - newest_args.frame_time - kDefaultSlidingWindowInterval; - const auto max_difference = newest_args.interval * 1.5; - const auto& remaining_oldest_args = sliding_window_.front().first; - const auto last_timestamp = - std::min(remaining_oldest_args.frame_time, max_sliding_window_start); - const auto difference = last_timestamp - removed_args.frame_time; - const size_t count = difference > max_difference - ? std::ceil(difference / newest_args.interval) - : 1; - - uint32_t dropped = - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] - - invalidated_frames; - const double percent_dropped_frame = - std::min((dropped * 100.0) / total_frames_in_window_, 100.0); - sliding_window_histogram_[SmoothnessStrategy::kDefaultStrategy] - .AddPercentDroppedFrame(percent_dropped_frame, count); - - uint32_t dropped_compositor = - dropped_frame_count_in_window_ - [SmoothnessStrategy::kCompositorFocusedStrategy] - - invalidated_frames; - double percent_dropped_frame_compositor = - std::min((dropped_compositor * 100.0) / total_frames_in_window_, 100.0); - sliding_window_histogram_[SmoothnessStrategy::kCompositorFocusedStrategy] - .AddPercentDroppedFrame(percent_dropped_frame_compositor, count); - - sliding_window_current_percent_dropped_ = percent_dropped_frame; - - latest_sliding_window_start_ = last_timestamp; - latest_sliding_window_interval_ = remaining_oldest_args.interval; -} - -void DroppedFrameCounter::UpdateDroppedFrameCountInWindow( - const FrameInfo& frame_info, - int count) { - if (frame_info.IsDroppedAffectingSmoothness()) { - DCHECK_GE( - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] + - count, - 0u); - dropped_frame_count_in_window_[SmoothnessStrategy::kDefaultStrategy] += - count; - } - if (frame_info.WasSmoothCompositorUpdateDropped()) { - DCHECK_GE(dropped_frame_count_in_window_ - [SmoothnessStrategy::kCompositorFocusedStrategy] + - count, - 0u); - dropped_frame_count_in_window_ - [SmoothnessStrategy::kCompositorFocusedStrategy] += count; - } -} - -void DroppedFrameCounter::OnFirstContentfulPaintReceived() { - DCHECK(!first_contentful_paint_received_); - first_contentful_paint_received_ = true; - time_first_contentful_paint_received_ = base::TimeTicks::Now(); -} - -} // namespace cc
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h deleted file mode 100644 index c5e3ac9b..0000000 --- a/cc/metrics/dropped_frame_counter.h +++ /dev/null
@@ -1,211 +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 CC_METRICS_DROPPED_FRAME_COUNTER_H_ -#define CC_METRICS_DROPPED_FRAME_COUNTER_H_ - -#include <stddef.h> - -#include <array> -#include <map> -#include <optional> -#include <queue> -#include <utility> -#include <vector> - -#include "base/containers/ring_buffer.h" -#include "base/functional/callback_forward.h" -#include "base/memory/raw_ptr.h" -#include "base/time/time.h" -#include "cc/base/features.h" -#include "cc/cc_export.h" -#include "cc/metrics/frame_info.h" -#include "cc/metrics/frame_sorter.h" -#include "cc/metrics/ukm_smoothness_data.h" - -namespace cc { - -// This class maintains a counter for produced/dropped frames, and can be used -// to estimate the recent throughput. -class CC_EXPORT DroppedFrameCounter : public FrameSorterObserver { - public: - enum FrameState { - kFrameStateDropped, - kFrameStatePartial, - kFrameStateComplete - }; - - enum SmoothnessStrategy { - kDefaultStrategy, // All threads and interactions are considered equal. - kScrollFocusedStrategy, // Scroll interactions has the highest priority. - kMainFocusedStrategy, // Reports dropped frames with main thread updates. - kCompositorFocusedStrategy, // Reports dropped frames with compositor - // thread updates. - kStrategyCount - }; - - class CC_EXPORT SlidingWindowHistogram { - public: - void AddPercentDroppedFrame(double percent_dropped_frame, size_t count = 1); - uint32_t GetPercentDroppedFramePercentile(double percentile) const; - double GetPercentDroppedFrameVariance() const; - std::vector<double> GetPercentDroppedFrameBuckets() const; - void Clear(); - std::ostream& Dump(std::ostream& stream) const; - - uint32_t total_count() const { return total_count_; } - - private: - std::array<uint32_t, 101> histogram_bins_ = {0}; - std::array<uint32_t, 7> smoothness_buckets_ = {0}; - uint32_t total_count_ = 0; - }; - - DroppedFrameCounter(); - ~DroppedFrameCounter() override; - - DroppedFrameCounter(const DroppedFrameCounter&) = delete; - DroppedFrameCounter& operator=(const DroppedFrameCounter&) = delete; - - size_t frame_history_size() const { return ring_buffer_.BufferSize(); } - size_t total_frames() const { return total_frames_; } - size_t total_dropped() const { return total_dropped_; } - size_t total_partial() const { return total_partial_; } - size_t total_smoothness_dropped() const { return total_smoothness_dropped_; } - - uint32_t GetAverageThroughput() const; - - typedef base::RingBuffer<FrameState, 180> RingBufferType; - RingBufferType::Iterator Begin() const { return ring_buffer_.Begin(); } - // `End()` points to the last `FrameState`, not past it. - RingBufferType::Iterator End() const { return ring_buffer_.End(); } - - void AddGoodFrame(); - void AddPartialFrame(); - void AddDroppedFrame(); - void ReportFrames(); - void ReportFramesOnEveryFrameForUI(); - - void SetUkmSmoothnessDestination(UkmSmoothnessDataShared* smoothness_data); - void OnFirstContentfulPaintReceived(); - - // Reset is used on navigation, which resets frame statistics as well as - // frame sorter. - void Reset(); - - // ResetPendingFrames is used when we need to keep track of frame statistics, - // but should no longer wait for the pending frames (e.g. connection to - // gpu-process was reset, or the page became invisible, etc.). The pending - // frames are not considered to be dropped. - void ResetPendingFrames(base::TimeTicks timestamp); - - // Enable dropped frame report for ui::Compositor.. - void EnableReportForUI(); - - void SetTimeFirstContentfulPaintReceivedForTesting( - base::TimeTicks time_fcp_received) { - DCHECK(first_contentful_paint_received_); - time_first_contentful_paint_received_ = time_fcp_received; - } - - double sliding_window_max_percent_dropped() const { - return sliding_window_max_percent_dropped_; - } - - std::optional<double> max_percent_dropped_After_1_sec() const { - return sliding_window_max_percent_dropped_After_1_sec_; - } - - std::optional<double> max_percent_dropped_After_2_sec() const { - return sliding_window_max_percent_dropped_After_2_sec_; - } - - std::optional<double> max_percent_dropped_After_5_sec() const { - return sliding_window_max_percent_dropped_After_5_sec_; - } - - uint32_t SlidingWindowMedianPercentDropped( - SmoothnessStrategy strategy) const { - DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy); - return sliding_window_histogram_[strategy].GetPercentDroppedFramePercentile( - 0.5); - } - - double SlidingWindowPercentDroppedVariance( - SmoothnessStrategy strategy) const { - DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy); - return sliding_window_histogram_[strategy].GetPercentDroppedFrameVariance(); - } - - const SlidingWindowHistogram* GetSlidingWindowHistogram( - SmoothnessStrategy strategy) const { - DCHECK_GT(SmoothnessStrategy::kStrategyCount, strategy); - return &sliding_window_histogram_[strategy]; - } - - double sliding_window_current_percent_dropped() const { - return sliding_window_current_percent_dropped_.value_or(0); - } - - bool first_contentful_paint_received() { - return first_contentful_paint_received_; - } - - private: - void AddSortedFrame(const viz::BeginFrameArgs& args, - const FrameInfo& frame_info) override; - virtual void OnEndFrame(const viz::BeginFrameArgs& args, - const FrameInfo& frame_info); - base::TimeDelta ComputeCurrentWindowSize() const; - - void PopSlidingWindow(); - - // Adds count to dropped_frame_count_in_window_ of each strategy. - void UpdateDroppedFrameCountInWindow(const FrameInfo& frame_info, int count); - - std::queue<std::pair<const viz::BeginFrameArgs, FrameInfo>> sliding_window_; - std::array<uint32_t, SmoothnessStrategy::kStrategyCount> - dropped_frame_count_in_window_ = {0}; - double total_frames_in_window_ = 60.0; - std::array<SlidingWindowHistogram, SmoothnessStrategy::kStrategyCount> - sliding_window_histogram_; - - base::TimeTicks latest_sliding_window_start_; - base::TimeDelta latest_sliding_window_interval_; - - RingBufferType ring_buffer_; - size_t total_frames_ = 0; - size_t total_partial_ = 0; - size_t total_dropped_ = 0; - size_t total_smoothness_dropped_ = 0; - bool first_contentful_paint_received_ = false; - double sliding_window_max_percent_dropped_ = 0; - std::optional<double> sliding_window_max_percent_dropped_After_1_sec_; - std::optional<double> sliding_window_max_percent_dropped_After_2_sec_; - std::optional<double> sliding_window_max_percent_dropped_After_5_sec_; - base::TimeTicks time_first_contentful_paint_received_; - raw_ptr<UkmSmoothnessDataShared> ukm_smoothness_data_ = nullptr; - - struct { - double max_window = 0; - double p95_window = 0; - } last_reported_metrics_; - - bool report_for_ui_ = false; - std::optional<double> sliding_window_current_percent_dropped_; - - // Sets to true on a newly dropped frame and stays true as long as the frames - // that follow are dropped. Reset when a frame is presented. It is used to - // generate asynchronous trace events that cover the duration of consecutive - // dropped frames - bool in_dropping_ = false; -}; - -CC_EXPORT std::ostream& operator<<( - std::ostream&, - const DroppedFrameCounter::SlidingWindowHistogram&); - -} // namespace cc - -#endif // CC_METRICS_DROPPED_FRAME_COUNTER_H_
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc deleted file mode 100644 index 36d15bf..0000000 --- a/cc/metrics/dropped_frame_counter_unittest.cc +++ /dev/null
@@ -1,650 +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. - -#include "cc/metrics/dropped_frame_counter.h" - -#include <cstdlib> -#include <memory> -#include <string> -#include <vector> - -#include "base/memory/raw_ptr.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/default_tick_clock.h" -#include "base/time/time.h" -#include "build/chromeos_buildflags.h" -#include "cc/animation/animation_host.h" -#include "cc/base/features.h" -#include "cc/metrics/compositor_frame_reporting_controller.h" -#include "cc/metrics/custom_metrics_recorder.h" -#include "cc/metrics/frame_sorter.h" -#include "cc/test/fake_content_layer_client.h" -#include "cc/test/fake_frame_info.h" -#include "cc/test/fake_picture_layer.h" -#include "cc/test/layer_tree_test.h" - -namespace cc { -namespace { - -using SmoothnessStrategy = DroppedFrameCounter::SmoothnessStrategy; - -FrameInfo CreateStubFrameInfo(bool is_dropped) { - return CreateFakeFrameInfo(is_dropped - ? FrameInfo::FrameFinalState::kDropped - : FrameInfo::FrameFinalState::kPresentedAll); -} - -class TestCustomMetricsRecorder : public CustomMetricRecorder { - public: - TestCustomMetricsRecorder() = default; - ~TestCustomMetricsRecorder() override = default; - - // CustomMetricRecorder: - void ReportPercentDroppedFramesInOneSecondWindow2(double percent) override { - ++report_count_; - last_percent_dropped_frames_ = percent; - } - void ReportEventLatency( - std::vector<EventLatencyTracker::LatencyData> latencies) override {} - - void Reset() { - report_count_ = 0u; - last_percent_dropped_frames_ = 0; - } - - int report_count() const { return report_count_; } - - double last_percent_dropped_frames() const { - return last_percent_dropped_frames_; - } - - private: - int report_count_ = 0u; - double last_percent_dropped_frames_ = 0; -}; - -class DroppedFrameCounterTestBase : public LayerTreeTest { - public: - DroppedFrameCounterTestBase() = default; - ~DroppedFrameCounterTestBase() override = default; - - virtual void SetUpTestConfigAndExpectations() = 0; - - void InitializeSettings(LayerTreeSettings* settings) override { - settings->commit_to_active_tree = false; - } - - void SetupTree() override { - LayerTreeTest::SetupTree(); - - Layer* root_layer = layer_tree_host()->root_layer(); - scroll_layer_ = FakePictureLayer::Create(&client_); - // Set up the layer so it always has something to paint. - scroll_layer_->set_always_update_resources(true); - scroll_layer_->SetBounds({3, 3}); - client_.set_bounds({3, 3}); - root_layer->AddChild(scroll_layer_); - } - - void RunTest(CompositorMode mode) override { - SetUpTestConfigAndExpectations(); - LayerTreeTest::RunTest(mode); - } - - void BeginTest() override { - ASSERT_GT(config_.animation_frames, 0u); - - // Start with requesting main-frames. - PostSetNeedsCommitToMainThread(); - } - - void AfterTest() override { - EXPECT_GE(total_frames_, config_.animation_frames); - // It is possible to drop even more frame than what the test expects (e.g. - // in slower machines, slower builds such as asan/tsan builds, etc.), since - // the test does not strictly control both threads and deadlines. Therefore, - // it is not possible to check for strict equality here. - EXPECT_LE(expect_.min_partial, partial_); - EXPECT_LE(expect_.min_dropped, dropped_); - EXPECT_LE(expect_.min_dropped_smoothness, dropped_smoothness_); - } - - // Compositor thread function overrides: - void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, - const viz::BeginFrameArgs& args, - bool has_damage) override { - if (TestEnded()) - return; - - // Request a re-draw, and set a non-empty damage region (otherwise the - // draw is aborted with 'no damage'). - host_impl->SetNeedsRedraw(); - host_impl->SetViewportDamage(gfx::Rect(0, 0, 10, 20)); - - if (skip_main_thread_next_frame_) { - skip_main_thread_next_frame_ = false; - } else { - // Request update from the main-thread too. - host_impl->SetNeedsCommit(); - } - } - - void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { - // If the main-thread is blocked, then unblock it once the compositor thread - // has already drawn a frame. - base::WaitableEvent* wait = nullptr; - { - base::AutoLock lock(wait_lock_); - wait = wait_; - } - - if (wait) { - // When the main-thread blocks during a frame, skip the main-thread for - // the next frame, so that the main-thread can be in sync with the - // compositor thread again. - skip_main_thread_next_frame_ = true; - wait->Signal(); - } - } - - void DidReceivePresentationTimeOnThread( - LayerTreeHostImpl* host_impl, - uint32_t frame_token, - const gfx::PresentationFeedback& feedback) override { - ++presented_frames_; - if (presented_frames_ < config_.animation_frames) - return; - - auto* dropped_frame_counter = - host_impl->dropped_frame_counter_for_testing(); - DCHECK(dropped_frame_counter); - - total_frames_ = dropped_frame_counter->total_frames(); - partial_ = dropped_frame_counter->total_partial(); - dropped_ = dropped_frame_counter->total_dropped(); - dropped_smoothness_ = dropped_frame_counter->total_smoothness_dropped(); - EndTest(); - } - - // Main-thread function overrides: - void BeginMainFrame(const viz::BeginFrameArgs& args) override { - if (TestEnded()) - return; - - bool should_wait = false; - if (config_.should_drop_main_every > 0) { - should_wait = - args.frame_id.sequence_number % config_.should_drop_main_every == 0; - } - - if (should_wait) { - base::WaitableEvent wait{base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED}; - { - base::AutoLock lock(wait_lock_); - wait_ = &wait; - } - wait.Wait(); - { - base::AutoLock lock(wait_lock_); - wait_ = nullptr; - } - } - - // Make some changes so that the main-thread needs to push updates to the - // compositor thread (i.e. force a commit). - auto const bounds = scroll_layer_->bounds(); - scroll_layer_->SetBounds({bounds.width(), bounds.height() + 1}); - if (config_.should_register_main_thread_animation) { - animation_host()->SetAnimationCounts(1); - animation_host()->SetCurrentFrameHadRaf(true); - animation_host()->SetNextFrameHasPendingRaf(true); - } - } - - protected: - // The test configuration options. This is set before the test starts, and - // remains unchanged after that. So it is safe to read these fields from - // either threads. - struct TestConfig { - uint32_t should_drop_main_every = 0; - uint32_t animation_frames = 0; - bool should_register_main_thread_animation = false; - } config_; - - // The test expectations. This is set before the test starts, and - // remains unchanged after that. So it is safe to read these fields from - // either threads. - struct TestExpectation { - uint32_t min_partial = 0; - uint32_t min_dropped = 0; - uint32_t min_dropped_smoothness = 0; - } expect_; - - private: - // Set up a dummy picture layer so that every begin-main frame requires a - // commit (without the dummy layer, the main-thread never has to paint, which - // causes an early 'no damage' abort of the main-frame. - FakeContentLayerClient client_; - scoped_refptr<FakePictureLayer> scroll_layer_; - - // This field is used only on the compositor thread to track how many frames - // have been processed. - uint32_t presented_frames_ = 0; - - // The |wait_| event is used when the test wants to deliberately force the - // main-thread to block while processing begin-main-frames. - base::Lock wait_lock_; - raw_ptr<base::WaitableEvent> wait_ = nullptr; - - // These fields are populated in the compositor thread when the desired number - // of frames have been processed. These fields are subsequently compared - // against the expectation after the test ends. - uint32_t total_frames_ = 0; - uint32_t partial_ = 0; - uint32_t dropped_ = 0; - uint32_t dropped_smoothness_ = 0; - - bool skip_main_thread_next_frame_ = false; -}; - -class DroppedFrameCounterNoDropTest : public DroppedFrameCounterTestBase { - public: - ~DroppedFrameCounterNoDropTest() override = default; - - void SetUpTestConfigAndExpectations() override { - config_.animation_frames = 28; - config_.should_register_main_thread_animation = false; - - expect_.min_partial = 0; - expect_.min_dropped = 0; - expect_.min_dropped_smoothness = 0; - } -}; - -MULTI_THREAD_TEST_F(DroppedFrameCounterNoDropTest); - -class DroppedFrameCounterMainDropsNoSmoothness - : public DroppedFrameCounterTestBase { - public: - ~DroppedFrameCounterMainDropsNoSmoothness() override = default; - - void SetUpTestConfigAndExpectations() override { - config_.animation_frames = 28; - config_.should_drop_main_every = 5; - config_.should_register_main_thread_animation = false; - - expect_.min_partial = 5; - expect_.min_dropped_smoothness = 0; - } -}; - -// TODO(crbug.com/40144326) Disabled for flakiness. -// MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsNoSmoothness); - -class DroppedFrameCounterMainDropsSmoothnessTest - : public DroppedFrameCounterTestBase { - public: - ~DroppedFrameCounterMainDropsSmoothnessTest() override = default; - - void SetUpTestConfigAndExpectations() override { - config_.animation_frames = 28; - config_.should_drop_main_every = 5; - config_.should_register_main_thread_animation = true; - - expect_.min_partial = 5; - expect_.min_dropped_smoothness = 5; - } -}; - -// TODO(crbug.com/40144326) Disabled for flakiness. -// MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsSmoothnessTest); - -class DroppedFrameCounterTest : public testing::Test { - public: - explicit DroppedFrameCounterTest(SmoothnessStrategy smoothness_strategy = - SmoothnessStrategy::kDefaultStrategy) - : smoothness_strategy_(smoothness_strategy) { - dropped_frame_counter_ = std::make_unique<DroppedFrameCounter>(); - dropped_frame_counter_->OnFirstContentfulPaintReceived(); - frame_sorter_.AddObserver(dropped_frame_counter_.get()); - } - ~DroppedFrameCounterTest() override = default; - - // For each boolean in frame_states produces a frame - void SimulateFrameSequence(std::vector<bool> frame_states, int repeat) { - for (int i = 0; i < repeat; i++) { - for (auto is_dropped : frame_states) { - viz::BeginFrameArgs args_ = SimulateBeginFrameArgs(); - if (dropped_frame_counter_->first_contentful_paint_received()) { - frame_sorter_.AddNewFrame(args_); - frame_sorter_.AddFrameResult(args_, CreateStubFrameInfo(is_dropped)); - } - sequence_number_++; - frame_time_ += interval_; - } - } - } - - // Make a sequence of frame states where the first |dropped_frames| out of - // |total_frames| are dropped. - std::vector<bool> MakeFrameSequence(int dropped_frames, int total_frames) { - std::vector<bool> frame_states(total_frames, false); - for (int i = 0; i < dropped_frames; i++) { - frame_states[i] = true; - } - return frame_states; - } - - std::vector<viz::BeginFrameArgs> SimulatePendingFrame(int repeat) { - std::vector<viz::BeginFrameArgs> args(repeat); - for (int i = 0; i < repeat; i++) { - args[i] = SimulateBeginFrameArgs(); - if (dropped_frame_counter_->first_contentful_paint_received()) { - frame_sorter_.AddNewFrame(args[i]); - } - sequence_number_++; - frame_time_ += interval_; - } - return args; - } - - // Simulate a main and impl thread update on the same frame. - void SimulateForkedFrame(bool main_dropped, bool impl_dropped) { - viz::BeginFrameArgs args_ = SimulateBeginFrameArgs(); - if (dropped_frame_counter_->first_contentful_paint_received()) { - frame_sorter_.AddNewFrame(args_); - frame_sorter_.AddNewFrame(args_); - } - // End the 'main thread' arm of the fork. - auto main_info = CreateStubFrameInfo(main_dropped); - main_info.main_thread_response = FrameInfo::MainThreadResponse::kIncluded; - frame_sorter_.AddFrameResult(args_, main_info); - - // End the 'compositor thread' arm of the fork. - auto impl_info = CreateStubFrameInfo(impl_dropped); - impl_info.main_thread_response = FrameInfo::MainThreadResponse::kMissing; - frame_sorter_.AddFrameResult(args_, impl_info); - - sequence_number_++; - frame_time_ += interval_; - } - - void AdvancetimeByIntervals(int interval_count) { - frame_time_ += interval_ * interval_count; - } - - double PercentDroppedFrameMedian() { - return dropped_frame_counter_->SlidingWindowMedianPercentDropped( - smoothness_strategy_); - } - - double PercentDroppedFrameVariance() { - return dropped_frame_counter_->SlidingWindowPercentDroppedVariance( - smoothness_strategy_); - } - - const DroppedFrameCounter::SlidingWindowHistogram* - GetSlidingWindowHistogram() { - return dropped_frame_counter_->GetSlidingWindowHistogram( - smoothness_strategy_); - } - - double GetTotalFramesInWindow() { return base::Seconds(1) / interval_; } - - void SetInterval(base::TimeDelta interval) { interval_ = interval; } - - base::TimeTicks GetNextFrameTime() const { return frame_time_ + interval_; } - - public: - std::unique_ptr<DroppedFrameCounter> dropped_frame_counter_; - FrameSorter frame_sorter_; - - private: - uint64_t sequence_number_ = 1; - uint64_t source_id_ = 1; - raw_ptr<const base::TickClock> tick_clock_ = - base::DefaultTickClock::GetInstance(); - base::TimeTicks frame_time_ = tick_clock_->NowTicks(); - base::TimeDelta interval_ = base::Microseconds(16667); // 16.667 ms - - SmoothnessStrategy smoothness_strategy_; - - viz::BeginFrameArgs SimulateBeginFrameArgs() { - viz::BeginFrameId current_id_(source_id_, sequence_number_); - viz::BeginFrameArgs args = viz::BeginFrameArgs(); - args.frame_id = current_id_; - args.frame_time = frame_time_; - args.interval = interval_; - return args; - } - base::test::ScopedFeatureList scoped_feature_list_; -}; - -// Test class that supports parameterized tests for each of the different -// SmoothnessStrategy. - -class SmoothnessStrategyDroppedFrameCounterTest - : public DroppedFrameCounterTest, - public testing::WithParamInterface<SmoothnessStrategy> { - public: - SmoothnessStrategyDroppedFrameCounterTest() - : DroppedFrameCounterTest(GetParam()) {} - ~SmoothnessStrategyDroppedFrameCounterTest() override = default; - SmoothnessStrategyDroppedFrameCounterTest( - const SmoothnessStrategyDroppedFrameCounterTest&) = delete; - SmoothnessStrategyDroppedFrameCounterTest& operator=( - const SmoothnessStrategyDroppedFrameCounterTest&) = delete; -}; - -std::vector<SmoothnessStrategy> GetSmoothnessStrategyParams() { - return std::vector<SmoothnessStrategy>{ - SmoothnessStrategy::kDefaultStrategy, - SmoothnessStrategy::kCompositorFocusedStrategy}; -} - -std::string SmoothnessStrategyToString(const SmoothnessStrategy& s) { - if (s == SmoothnessStrategy::kDefaultStrategy) { - return "DefaultStrategy"; - } else if (s == SmoothnessStrategy::kCompositorFocusedStrategy) { - return "CompositorFocusedStrategy"; - } - return "INVALID"; -} - -INSTANTIATE_TEST_SUITE_P(, - SmoothnessStrategyDroppedFrameCounterTest, - ::testing::ValuesIn(GetSmoothnessStrategyParams()), - [](auto& param) { - return SmoothnessStrategyToString(param.param); - }); - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, SimplePattern1) { - // 2 out of every 3 frames are dropped (In total 80 frames out of 120). - SimulateFrameSequence({true, true, true, false, true, false}, 20); - - // The max is the following window: - // 16 * <sequence> + {true, true, true, false - EXPECT_EQ(PercentDroppedFrameMedian(), 65); - EXPECT_LE(PercentDroppedFrameVariance(), 1); -} - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, SimplePattern2) { - // 1 out of every 5 frames are dropped (In total 24 frames out of 120). - SimulateFrameSequence({false, false, false, false, true}, 24); - - // 20th bucket, and as a result 95th percentile is also 20. - EXPECT_EQ(PercentDroppedFrameMedian(), 20); - EXPECT_LE(PercentDroppedFrameVariance(), 1); -} - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, IncompleteWindow) { - // There are only 5 frames submitted, so Max, 95pct, median and variance - // should report zero. - SimulateFrameSequence({false, false, false, false, true}, 1); - EXPECT_EQ(PercentDroppedFrameMedian(), 0); - EXPECT_LE(PercentDroppedFrameVariance(), 1); -} - -TEST_F(DroppedFrameCounterTest, NoCrashForIntervalLargerThanWindow) { - SetInterval(base::Milliseconds(1000)); - SimulateFrameSequence({false, false}, 1); -} - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, Percentile95WithIdleFrames) { - // Test scenario: - // . 4s of 20% dropped frames. - // . 96s of idle time. - // The 96%ile dropped-frame metric should be 0. - - // Set an interval that rounds up nicely with 1 second. - constexpr auto kInterval = base::Milliseconds(10); - constexpr int kFps = base::Seconds(1).IntDiv(kInterval); - static_assert( - kFps % 5 == 0, - "kFps must be a multiple of 5 because this test depends on it."); - SetInterval(kInterval); - - const auto* histogram = GetSlidingWindowHistogram(); - - // First 4 seconds with 20% dropped frames. - SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4); - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u); - - // Then no frames are added for 97s. Note that this 1s more than 96 seconds, - // because the last second remains in the sliding window. - AdvancetimeByIntervals(kFps * 97); - - // A single frame to flush the pipeline. - SimulateFrameSequence({false}, 1); - - EXPECT_EQ(histogram->total_count(), 100u * kFps); - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.96), 0u); - EXPECT_GT(histogram->GetPercentDroppedFramePercentile(0.97), 0u); -} - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, - Percentile95WithIdleFramesWhileHidden) { - // The test scenario is the same as |Percentile95WithIdleFrames| test: - // . 4s of 20% dropped frames. - // . 96s of idle time. - // However, the 96s of idle time happens *after* the page becomes invisible - // (e.g. after a tab-switch). In this case, the idle time *should not* - // contribute to the sliding window. - - // Set an interval that rounds up nicely with 1 second. - constexpr auto kInterval = base::Milliseconds(10); - constexpr int kFps = base::Seconds(1).IntDiv(kInterval); - static_assert( - kFps % 5 == 0, - "kFps must be a multiple of 5 because this test depends on it."); - SetInterval(kInterval); - - const auto* histogram = GetSlidingWindowHistogram(); - - // First 4 seconds with 20% dropped frames. - SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4); - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u); - - // Hide the page (thus resetting the pending frames), then idle for 96s before - // producing a single frame. - dropped_frame_counter_->ResetPendingFrames(GetNextFrameTime()); - AdvancetimeByIntervals(kFps * 97); - - // A single frame to flush the pipeline. - SimulateFrameSequence({false}, 1); - - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u); -} - -TEST_P(SmoothnessStrategyDroppedFrameCounterTest, - Percentile95WithIdleFramesThenHide) { - // The test scenario is the same as |Percentile95WithIdleFramesWhileHidden|: - // . 4s of 20% dropped frames. - // . 96s of idle time. - // However, the 96s of idle time happens *before* the page becomes invisible - // (e.g. after a tab-switch). In this case, the idle time *should* - // contribute to the sliding window. - - // Set an interval that rounds up nicely with 1 second. - constexpr auto kInterval = base::Milliseconds(10); - constexpr int kFps = base::Seconds(1).IntDiv(kInterval); - static_assert( - kFps % 5 == 0, - "kFps must be a multiple of 5 because this test depends on it."); - SetInterval(kInterval); - - const auto* histogram = GetSlidingWindowHistogram(); - - // First 4 seconds with 20% dropped frames. - SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4); - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u); - - // Idle for 96s before hiding the page. - AdvancetimeByIntervals(kFps * 97); - dropped_frame_counter_->ResetPendingFrames(GetNextFrameTime()); - AdvancetimeByIntervals(kFps * 97); - - // A single frame to flush the pipeline. - SimulateFrameSequence({false}, 1); - - EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.96), 0u); - EXPECT_GT(histogram->GetPercentDroppedFramePercentile(0.97), 0u); -} - -TEST_F(DroppedFrameCounterTest, FramesInFlightWhenFcpReceived) { - // Start five frames in flight. - std::vector<viz::BeginFrameArgs> pending_frames = SimulatePendingFrame(5); - - // Set that FCP was received after the third frame starts, but before it ends. - base::TimeTicks time_fcp_sent = - pending_frames[2].frame_time + pending_frames[2].interval / 2; - dropped_frame_counter_->SetTimeFirstContentfulPaintReceivedForTesting( - time_fcp_sent); - - // End each of the frames as dropped. The first three should not count for - // smoothness, only the last two. - for (const auto& frame : pending_frames) { - frame_sorter_.AddFrameResult(frame, CreateStubFrameInfo(true)); - } - EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 2u); -} - -TEST_F(DroppedFrameCounterTest, ForkedCompositorFrameReporter) { - // Run different combinations of main and impl threads dropping, make sure - // only one frame is counted as dropped each time. - SimulateForkedFrame(false, false); - EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 0u); - - SimulateForkedFrame(true, false); - EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 1u); - - SimulateForkedFrame(false, true); - EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 2u); - - SimulateForkedFrame(true, true); - EXPECT_EQ(dropped_frame_counter_->total_smoothness_dropped(), 3u); -} - -class DroppedFrameCounterLegacyMetricsTest : public DroppedFrameCounterTest { - public: - DroppedFrameCounterLegacyMetricsTest(); - ~DroppedFrameCounterLegacyMetricsTest() override = default; - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -DroppedFrameCounterLegacyMetricsTest::DroppedFrameCounterLegacyMetricsTest() { - frame_sorter_.RemoveObserver(dropped_frame_counter_.get()); - dropped_frame_counter_ = std::make_unique<DroppedFrameCounter>(); - frame_sorter_.Reset(/*reset_fcp=*/true); - dropped_frame_counter_->OnFirstContentfulPaintReceived(); - frame_sorter_.OnFirstContentfulPaintReceived(); - frame_sorter_.AddObserver(dropped_frame_counter_.get()); -} - -} // namespace -} // namespace cc
diff --git a/cc/metrics/frame_sequence_tracker_collection.cc b/cc/metrics/frame_sequence_tracker_collection.cc index ddd96ca..4a4b4a0 100644 --- a/cc/metrics/frame_sequence_tracker_collection.cc +++ b/cc/metrics/frame_sequence_tracker_collection.cc
@@ -11,7 +11,6 @@ #include "base/memory/ptr_util.h" #include "base/time/time.h" #include "cc/metrics/compositor_frame_reporting_controller.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/frame_info.h" #include "cc/metrics/frame_sequence_metrics.h" #include "cc/metrics/frame_sequence_tracker.h" @@ -32,10 +31,8 @@ } // namespace FrameSequenceTrackerCollection::FrameSequenceTrackerCollection( - bool is_single_threaded, - DroppedFrameCounter* dropped_frame_counter) - : is_single_threaded_(is_single_threaded), - dropped_frame_counter_(dropped_frame_counter) {} + bool is_single_threaded) + : is_single_threaded_(is_single_threaded) {} FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() { CleanUp(); @@ -222,9 +219,6 @@ auto tracker = std::move(frame_trackers_[key]); active_trackers_.reset(static_cast<size_t>(tracker->type())); - if (dropped_frame_counter_) { - dropped_frame_counter_->ReportFrames(); - } if (tracker->metrics()->GetEffectiveThread() == ThreadType::kCompositor) { DCHECK_GT(compositor_thread_driving_smoothness_, 0u);
diff --git a/cc/metrics/frame_sequence_tracker_collection.h b/cc/metrics/frame_sequence_tracker_collection.h index 29bf960..0dded01 100644 --- a/cc/metrics/frame_sequence_tracker_collection.h +++ b/cc/metrics/frame_sequence_tracker_collection.h
@@ -14,7 +14,6 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "cc/cc_export.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/frame_info.h" #include "cc/metrics/frame_sequence_metrics.h" #include "cc/metrics/frame_sorter.h" @@ -37,8 +36,7 @@ // submitted frames. class CC_EXPORT FrameSequenceTrackerCollection : public FrameSorterObserver { public: - FrameSequenceTrackerCollection(bool is_single_threaded, - DroppedFrameCounter* dropped_frame_counter); + explicit FrameSequenceTrackerCollection(bool is_single_threaded); ~FrameSequenceTrackerCollection() override; FrameSequenceTrackerCollection(const FrameSequenceTrackerCollection&) = @@ -157,7 +155,6 @@ NotifyCustomerTrackerResutlsCallback custom_tracker_results_added_callback_; std::vector<std::unique_ptr<FrameSequenceTracker>> removal_trackers_; - const raw_ptr<DroppedFrameCounter> dropped_frame_counter_ = nullptr; ActiveTrackers active_trackers_; FrameInfo::SmoothEffectDrivingThread scrolling_thread_ = FrameInfo::SmoothEffectDrivingThread::kUnknown;
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc index bc3fa3c..9f942166 100644 --- a/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -42,30 +42,31 @@ } // namespace -// Mock DroppedFrameCounter class in order to test the number of times that +// Mock FrameSorter class in order to test the number of times that // frames get backfilled. This is necessary since `WillBeginImplFrame` creates -// `CompositorFrameReporter`s for backfilled frames which submit to the DFC +// `CompositorFrameReporter`s for backfilled frames which submit to FrameSorter // without a good interim spot to analyze the frame info contents. -class DroppedFrameCounterMock : public DroppedFrameCounter { +class FrameSorterMock : public FrameSorter { public: - MOCK_METHOD2(OnEndFrame, void(const viz::BeginFrameArgs&, const FrameInfo&)); + MOCK_METHOD2(AddFrameResult, + void(const viz::BeginFrameArgs&, const FrameInfo&)); }; -class FrameSequenceTrackerTest : public testing::Test, FrameSorterObserver { +class FrameSequenceTrackerTest : public testing::Test, + public FrameSorterObserver { public: const uint32_t kImplDamage = 0x1; const uint32_t kMainDamage = 0x2; FrameSequenceTrackerTest() - : dfc_mock_(DroppedFrameCounterMock()), - collection_(/*is_single_threaded=*/false, &dfc_mock_), + : sorter_(FrameSorterMock()), + collection_(/*is_single_threaded=*/false), compositor_frame_reporting_controller_( std::make_unique<CompositorFrameReportingController>( /*should_report_histograms=*/true, /*should_report_ukm=*/false, /*layer_tree_host_id=*/1)) { compositor_frame_reporting_controller_->SetFrameSorter(&sorter_); - compositor_frame_reporting_controller_->SetDroppedFrameCounter(&dfc_mock_); sorter_.AddObserver(this); tracker_ = collection_.StartScrollSequence( FrameSequenceTrackerType::kTouchScroll, @@ -327,9 +328,8 @@ } protected: - DroppedFrameCounterMock dfc_mock_; + FrameSorterMock sorter_; FrameSequenceTrackerCollection collection_; - FrameSorter sorter_; // Since CFRC destructor cleans up the FrameSorter's // registered observers (in this case, DFC and FSTC) // it needs to be declared last so that it will be @@ -838,6 +838,12 @@ TEST_F(FrameSequenceTrackerTest, CustomTrackerOutOfOrderFramesMissingV3Data) { CustomTrackerResults results; + + // Override the FrameSorter mock + FrameSorter frame_sorter; + compositor_frame_reporting_controller_->SetFrameSorter(&frame_sorter); + frame_sorter.AddObserver(this); + collection_.set_custom_tracker_results_added_callback( base::BindLambdaForTesting([&](const CustomTrackerResults& reported) { for (const auto& pair : reported) { @@ -855,11 +861,11 @@ // Dispatch 2 frames: frame 0 and frame 1. auto frame0_args = CreateBeginFrameArgs(source, ++sequence); DispatchCompleteFrame(frame0_args, kImplDamage | kMainDamage); - sorter_.AddNewFrame(frame0_args); + frame_sorter.AddNewFrame(frame0_args); auto frame1_args = CreateBeginFrameArgs(source, ++sequence); DispatchCompleteFrame(frame1_args, kImplDamage | kMainDamage); - sorter_.AddNewFrame(frame1_args); + frame_sorter.AddNewFrame(frame1_args); // Frame 1 gets its result before frame 0. FrameInfo frame_info; @@ -867,20 +873,20 @@ frame_info.smooth_thread = FrameInfo::SmoothThread::kSmoothMain; frame_info.scroll_thread = FrameInfo::SmoothEffectDrivingThread::kMain; frame_info.sequence_number = frame1_args.frame_id.sequence_number; - sorter_.AddFrameResult(frame1_args, frame_info); + frame_sorter.AddFrameResult(frame1_args, frame_info); // Stop the tracker. collection_.StopCustomSequence(1); // Frame 0 gets its result after tracker is stopped. FrameSorter flushes all // frames and metrics for both frames should be recorded for v3. - sorter_.AddFrameResult(frame0_args, frame_info); + frame_sorter.AddFrameResult(frame0_args, frame_info); // Frame 2 is dispatched after the tracker is stopped and should be ignored. auto frame2_args = CreateBeginFrameArgs(source, ++sequence); DispatchCompleteFrame(frame2_args, kImplDamage | kMainDamage); - sorter_.AddNewFrame(frame2_args); - sorter_.AddFrameResult(frame2_args, frame_info); + frame_sorter.AddNewFrame(frame2_args); + frame_sorter.AddFrameResult(frame2_args, frame_info); // The upcoming call to ClearAll will destroy tracker_. tracker_ = nullptr; @@ -899,11 +905,10 @@ uint64_t sequence = 0; const uint64_t kNumFramesSkipped = 5; - dfc_mock_.OnFirstContentfulPaintReceived(); sorter_.OnFirstContentfulPaintReceived(); // Expect that kNumFramesSkipped are backfilled with the appropriate smooth // thread set. - EXPECT_CALL(dfc_mock_, OnEndFrame(testing::_, testing::_)) + EXPECT_CALL(sorter_, AddFrameResult(testing::_, testing::_)) .Times(kNumFramesSkipped) .WillRepeatedly([=](const viz::BeginFrameArgs& args, const FrameInfo& frame_info) { @@ -925,7 +930,7 @@ base::TimeTicks::Now() /*+ base::Seconds(5)*/); compositor_frame_reporting_controller_->WillBeginImplFrame(frame5_args); // Clear the expectation before simulating finishing the frame. - testing::Mock::VerifyAndClearExpectations(&dfc_mock_); + testing::Mock::VerifyAndClearExpectations(&sorter_); compositor_frame_reporting_controller_->WillBeginMainFrame(frame5_args); compositor_frame_reporting_controller_->NotifyReadyToCommit(nullptr); compositor_frame_reporting_controller_->WillCommit();
diff --git a/cc/metrics/frame_sorter.h b/cc/metrics/frame_sorter.h index 418d035b..2917d36 100644 --- a/cc/metrics/frame_sorter.h +++ b/cc/metrics/frame_sorter.h
@@ -70,8 +70,8 @@ // The results can be added in any order. However, the frame must have been // added by an earlier call to |AddNewFrame()|. - void AddFrameResult(const viz::BeginFrameArgs& args, - const FrameInfo& frame_info); + virtual void AddFrameResult(const viz::BeginFrameArgs& args, + const FrameInfo& frame_info); // Check if a frame has been previously reported as dropped. bool IsAlreadyReportedDropped(const viz::BeginFrameId& id) const;
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 54e64b9b..d7fdd05 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -31,7 +31,6 @@ #include "base/trace_event/trace_event.h" #include "cc/base/features.h" #include "cc/metrics/begin_main_frame_metrics.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_metrics.h" #include "cc/metrics/frame_sequence_tracker_collection.h" #include "cc/test/fake_compositor_frame_reporting_controller.h" @@ -377,7 +376,7 @@ SchedulerTest() : task_runner_(base::MakeRefCounted<SchedulerTestTaskRunner>()), fake_external_begin_frame_source_(nullptr), - tracker_collection_(false, &dropped_counter) {} + tracker_collection_(false) {} ~SchedulerTest() override { client_->set_scheduler(nullptr); } @@ -417,7 +416,6 @@ reporting_controller->SetFrameSorter(&frame_sorter); reporting_controller->SetFrameSequenceTrackerCollection( &tracker_collection_); - reporting_controller->SetDroppedFrameCounter(&dropped_counter); scheduler_ = std::make_unique<TestScheduler>( task_runner_->GetMockTickClock(), client_.get(), scheduler_settings_, 0, @@ -619,7 +617,6 @@ std::unique_ptr<FakeSchedulerClient> client_; std::unique_ptr<TestScheduler> scheduler_; raw_ptr<FakeCompositorTimingHistory> fake_compositor_timing_history_; - DroppedFrameCounter dropped_counter; FrameSequenceTrackerCollection tracker_collection_; FrameSorter frame_sorter; // Since CFRC destructor cleans up the FrameSorter's
diff --git a/cc/test/fake_proxy.cc b/cc/test/fake_proxy.cc index 60833d2..269feac 100644 --- a/cc/test/fake_proxy.cc +++ b/cc/test/fake_proxy.cc
@@ -49,7 +49,7 @@ return false; } -double FakeProxy::GetPercentDroppedFrames() const { +double FakeProxy::GetAverageThroughput() const { return 0.0; }
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h index 7e66eea..fe09661 100644 --- a/cc/test/fake_proxy.h +++ b/cc/test/fake_proxy.h
@@ -73,7 +73,7 @@ void CompositeImmediatelyForTest(base::TimeTicks frame_begin_time, bool raster, base::OnceClosure callback) override {} - double GetPercentDroppedFrames() const override; + double GetAverageThroughput() const override; void SetPauseRendering(bool pause_rendering) override {} void SetInputResponsePending() override {} bool IsRenderingPaused() const override;
diff --git a/cc/test/fake_tile_manager_client.cc b/cc/test/fake_tile_manager_client.cc index 2ffdc99..324763f 100644 --- a/cc/test/fake_tile_manager_client.cc +++ b/cc/test/fake_tile_manager_client.cc
@@ -19,7 +19,7 @@ } std::unique_ptr<EvictionTilePriorityQueue> -FakeTileManagerClient::BuildEvictionQueue(TreePriority tree_priority) { +FakeTileManagerClient::BuildEvictionQueue() { return nullptr; }
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h index dabd2da..49ce9a8 100644 --- a/cc/test/fake_tile_manager_client.h +++ b/cc/test/fake_tile_manager_client.h
@@ -25,8 +25,7 @@ std::unique_ptr<RasterTilePriorityQueue> BuildRasterQueue( TreePriority tree_priority, RasterTilePriorityQueue::Type type) override; - std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue( - TreePriority tree_priority) override; + std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue() override; std::unique_ptr<TilesWithResourceIterator> CreateTilesWithResourceIterator() override; void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 15de1aa..9b7772d 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -224,12 +224,10 @@ this, reason, scroll_and_viewport_changes_synced); } - void ReadyToCommit(const viz::BeginFrameArgs& commit_args, - bool scroll_and_viewport_changes_synced, + void ReadyToCommit(bool scroll_and_viewport_changes_synced, const BeginMainFrameMetrics* begin_main_frame_metrics, bool commit_timeout) override { - LayerTreeHostImpl::ReadyToCommit(commit_args, - scroll_and_viewport_changes_synced, + LayerTreeHostImpl::ReadyToCommit(scroll_and_viewport_changes_synced, begin_main_frame_metrics, commit_timeout); test_hooks_->ReadyToCommitOnThread(this); }
diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 0164dd8..477160d 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h
@@ -14,7 +14,6 @@ #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/metrics/compositor_timing_history.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/scheduler/scheduler.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/cc/tiles/raster_tile_priority_queue_all.cc b/cc/tiles/raster_tile_priority_queue_all.cc index c4103d3..9f18145f 100644 --- a/cc/tiles/raster_tile_priority_queue_all.cc +++ b/cc/tiles/raster_tile_priority_queue_all.cc
@@ -49,7 +49,6 @@ void CreateTilingSetRasterQueues( const std::vector<raw_ptr<PictureLayerImpl, VectorExperimental>>& layers, - TreePriority tree_priority, std::vector<std::unique_ptr<TilingSetRasterQueueAll>>* queues) { DCHECK(queues->empty()); @@ -62,11 +61,9 @@ if (cc_slimming_enabled && tiling_set->all_tiles_done()) { continue; } - bool prioritize_low_res = tree_priority == SMOOTHNESS_TAKES_PRIORITY; std::unique_ptr<TilingSetRasterQueueAll> tiling_set_queue = TilingSetRasterQueueAll::Create( - tiling_set, prioritize_low_res, - layer->contributes_to_drawn_render_surface()); + tiling_set, layer->contributes_to_drawn_render_surface()); // Queues will only contain non empty tiling sets. if (tiling_set_queue && !tiling_set_queue->IsEmpty()) { queues->push_back(std::move(tiling_set_queue)); @@ -88,8 +85,8 @@ TreePriority tree_priority) { tree_priority_ = tree_priority; - CreateTilingSetRasterQueues(active_layers, tree_priority_, &active_queues_); - CreateTilingSetRasterQueues(pending_layers, tree_priority_, &pending_queues_); + CreateTilingSetRasterQueues(active_layers, &active_queues_); + CreateTilingSetRasterQueues(pending_layers, &pending_queues_); } bool RasterTilePriorityQueueAll::IsEmpty() const {
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc index 1468a56..d29b6c4 100644 --- a/cc/tiles/tile_manager.cc +++ b/cc/tiles/tile_manager.cc
@@ -502,7 +502,7 @@ has_pending_tile_trimming_task_ = false; std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue = - client_->BuildEvictionQueue(global_state_.tree_priority); + client_->BuildEvictionQueue(); bool has_eligible_used_tiles = false; for (; !eviction_priority_queue->IsEmpty(); eviction_priority_queue->Pop()) { const auto& prioritized_tile = eviction_priority_queue->Top(); @@ -811,8 +811,7 @@ MemoryUsage* usage) { while (usage->Exceeds(limit)) { if (!eviction_priority_queue) { - eviction_priority_queue = - client_->BuildEvictionQueue(global_state_.tree_priority); + eviction_priority_queue = client_->BuildEvictionQueue(); } if (eviction_priority_queue->IsEmpty()) break; @@ -833,8 +832,7 @@ MemoryUsage* usage) { while (usage->Exceeds(limit)) { if (!eviction_priority_queue) { - eviction_priority_queue = - client_->BuildEvictionQueue(global_state_.tree_priority); + eviction_priority_queue = client_->BuildEvictionQueue(); } if (eviction_priority_queue->IsEmpty()) break; @@ -2209,7 +2207,7 @@ global_state_.num_resources_limit); std::unique_ptr<EvictionTilePriorityQueue> eviction_priority_queue( - client_->BuildEvictionQueue(global_state_.tree_priority)); + client_->BuildEvictionQueue()); std::set<Tile*> tiles_to_evict; while (!eviction_priority_queue->IsEmpty()) { const PrioritizedTile& tile = eviction_priority_queue->Top();
diff --git a/cc/tiles/tile_manager_client.h b/cc/tiles/tile_manager_client.h index f7945557..48619ce 100644 --- a/cc/tiles/tile_manager_client.h +++ b/cc/tiles/tile_manager_client.h
@@ -54,8 +54,7 @@ // Given an empty eviction tile priority queue, this will build a priority // queue that will return tiles in the order in which they should be evicted. // Note if the queue was previously built, Reset must be called on it. - virtual std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue( - TreePriority tree_priority) = 0; + virtual std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue() = 0; // Returns an iterator over all the tiles that have a resource. virtual std::unique_ptr<TilesWithResourceIterator>
diff --git a/cc/tiles/tile_manager_perftest.cc b/cc/tiles/tile_manager_perftest.cc index c961c6bc..36713e52 100644 --- a/cc/tiles/tile_manager_perftest.cc +++ b/cc/tiles/tile_manager_perftest.cc
@@ -140,13 +140,6 @@ void RunEvictionQueueConstructTest(const std::string& test_name, int layer_count) { - auto priorities = std::to_array<TreePriority>({ - SAME_PRIORITY_FOR_BOTH_TREES, - SMOOTHNESS_TAKES_PRIORITY, - NEW_CONTENT_TAKES_PRIORITY, - }); - int priority_count = 0; - std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 10); for (auto* layer : layers) { layer->UpdateTiles(); @@ -159,8 +152,7 @@ timer_.Reset(); do { std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(priorities[priority_count])); - priority_count = (priority_count + 1) % std::size(priorities); + host_impl()->BuildEvictionQueue()); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -172,13 +164,6 @@ void RunEvictionQueueConstructAndIterateTest(const std::string& test_name, int layer_count, int tile_count) { - auto priorities = std::to_array<TreePriority>({ - SAME_PRIORITY_FOR_BOTH_TREES, - SMOOTHNESS_TAKES_PRIORITY, - NEW_CONTENT_TAKES_PRIORITY, - }); - int priority_count = 0; - std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, tile_count); for (auto* layer : layers) { @@ -193,13 +178,12 @@ do { int count = tile_count; std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(priorities[priority_count])); + host_impl()->BuildEvictionQueue()); while (count--) { ASSERT_FALSE(queue->IsEmpty()); ASSERT_TRUE(queue->Top().tile()); queue->Pop(); } - priority_count = (priority_count + 1) % std::size(priorities); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired());
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index c46677ea..6cd7045b 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -741,7 +741,7 @@ ASSERT_TRUE(pending_layer()->HighResTiling()); std::unique_ptr<EvictionTilePriorityQueue> empty_queue( - host_impl()->BuildEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES)); + host_impl()->BuildEvictionQueue()); EXPECT_TRUE(empty_queue->IsEmpty()); std::set<Tile*> all_tiles; size_t tile_count = 0; @@ -763,7 +763,7 @@ std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(SMOOTHNESS_TAKES_PRIORITY)); + host_impl()->BuildEvictionQueue()); EXPECT_FALSE(queue->IsEmpty()); // Sanity check, all tiles should be visible. @@ -814,7 +814,7 @@ smoothness_tiles.clear(); tile_count = 0; // Here we expect to get increasing combined priority_bin. - queue = host_impl()->BuildEvictionQueue(SMOOTHNESS_TAKES_PRIORITY); + queue = host_impl()->BuildEvictionQueue(); int distance_increasing = 0; int distance_decreasing = 0; while (!queue->IsEmpty()) { @@ -857,7 +857,7 @@ std::set<Tile*> new_content_tiles; last_tile = PrioritizedTile(); // Again, we expect to get increasing combined priority_bin. - queue = host_impl()->BuildEvictionQueue(NEW_CONTENT_TAKES_PRIORITY); + queue = host_impl()->BuildEvictionQueue(); distance_decreasing = 0; distance_increasing = 0; while (!queue->IsEmpty()) { @@ -1013,11 +1013,10 @@ std::vector<Tile*>(all_tiles.begin(), all_tiles.end())); // Verify occlusion is considered by EvictionTilePriorityQueue. - TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY; size_t occluded_count = 0u; PrioritizedTile last_tile; std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(tree_priority)); + host_impl()->BuildEvictionQueue()); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); if (!last_tile.tile()) @@ -1118,11 +1117,10 @@ // Verify that eviction queue returns tiles also from layers without valid // tile priorities and that the tile priority bin of those tiles is (at most) // EVENTUALLY. - TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY; std::set<Tile*> new_content_tiles; size_t tile_count = 0; std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(tree_priority)); + host_impl()->BuildEvictionQueue()); while (!queue->IsEmpty()) { PrioritizedTile prioritized_tile = queue->Top(); Tile* tile = prioritized_tile.tile(); @@ -1220,7 +1218,7 @@ } std::unique_ptr<EvictionTilePriorityQueue> queue( - host_impl()->BuildEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES)); + host_impl()->BuildEvictionQueue()); EXPECT_FALSE(queue->IsEmpty()); tile_count = 0; @@ -1276,7 +1274,7 @@ // marked as ready to draw. for (int i = 0; i < 3; ++i) { std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); EXPECT_TRUE(queue); // There are 3 bins in TilePriority. @@ -1389,7 +1387,7 @@ int eventually_bin_order_correct_count = 0; int eventually_bin_order_incorrect_count = 0; std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); EXPECT_TRUE(queue); for (; !queue->IsEmpty(); queue->Pop()) { if (!last_tile.tile()) @@ -1551,7 +1549,7 @@ intersecting_rect, // Soon rect. intersecting_rect); // Eventually rect. std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); if (features::IsCCSlimmingEnabled()) { EXPECT_FALSE(queue); } else { @@ -1572,7 +1570,7 @@ intersecting_rect, // Soon rect. intersecting_rect); // Eventually rect. std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); EXPECT_TRUE(queue); EXPECT_FALSE(queue->IsEmpty()); } @@ -1584,7 +1582,7 @@ intersecting_rect, // Soon rect. intersecting_rect); // Eventually rect. std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); EXPECT_TRUE(queue); EXPECT_FALSE(queue->IsEmpty()); } @@ -1595,7 +1593,7 @@ non_intersecting_rect, // Soon rect. intersecting_rect); // Eventually rect. std::unique_ptr<TilingSetRasterQueueAll> queue = - TilingSetRasterQueueAll::Create(tiling_set.get(), false, false); + TilingSetRasterQueueAll::Create(tiling_set.get(), false); EXPECT_TRUE(queue); EXPECT_FALSE(queue->IsEmpty()); } @@ -4036,8 +4034,7 @@ host_impl()->active_tree()->SetDeviceViewportRect(viewport); MakeFrame(global_tile_state); - auto eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + auto eviction_queue = host_impl()->BuildEvictionQueue(); bool has_eventually_tiles = false; size_t tiles_count_before = 0; for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { @@ -4054,8 +4051,7 @@ task_runner()->FastForwardBy(TileManager::GetTrimPrepaintTilesDelay()); // Since the policy is still ALLOW_ANYTHING, no changes. - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); size_t tiles_count_after = 0; for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); @@ -4080,8 +4076,7 @@ task_runner()->FastForwardBy(TileManager::GetTrimPrepaintTilesDelay()); tiles_count_after = 0; - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); if (tile.priority().priority_bin == TilePriority::EVENTUALLY) { @@ -4099,8 +4094,7 @@ // All the EVENTUALLY tiles are gone. tiles_count_after = 0; - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); EXPECT_NE(tile.priority().priority_bin, TilePriority::EVENTUALLY); @@ -4124,8 +4118,7 @@ host_impl()->active_tree()->SetDeviceViewportRect(viewport); MakeFrame(global_tile_state); - auto eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + auto eviction_queue = host_impl()->BuildEvictionQueue(); bool has_eventually_tiles = false; size_t tiles_count_before = 0; for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { @@ -4149,8 +4142,7 @@ size_t tiles_count_after = 0; Tile* first_eventually_tile = nullptr; - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); if (tile.priority().priority_bin == TilePriority::EVENTUALLY) { @@ -4175,8 +4167,7 @@ // The tile is there, it's the only remaining EVENTUALLY one. tiles_count_after = 0; bool has_found_tile = false; - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); EXPECT_TRUE(tile.priority().priority_bin != TilePriority::EVENTUALLY || @@ -4193,8 +4184,7 @@ task_runner()->FastForwardBy(TileManager::GetTrimPrepaintTilesDelay()); // The tile is not there anymore. - eviction_queue = host_impl()->BuildEvictionQueue( - host_impl()->global_tile_state().tree_priority); + eviction_queue = host_impl()->BuildEvictionQueue(); for (; !eviction_queue->IsEmpty(); eviction_queue->Pop()) { const auto& tile = eviction_queue->Top(); EXPECT_NE(tile.tile(), first_eventually_tile);
diff --git a/cc/tiles/tiling_set_raster_queue_all.cc b/cc/tiles/tiling_set_raster_queue_all.cc index 1602cae..3dc92543 100644 --- a/cc/tiles/tiling_set_raster_queue_all.cc +++ b/cc/tiles/tiling_set_raster_queue_all.cc
@@ -25,7 +25,6 @@ // static std::unique_ptr<TilingSetRasterQueueAll> TilingSetRasterQueueAll::Create( PictureLayerTilingSet* tiling_set, - bool prioritize_low_res, bool is_drawing_layer) { DCHECK(tiling_set);
diff --git a/cc/tiles/tiling_set_raster_queue_all.h b/cc/tiles/tiling_set_raster_queue_all.h index aac0ef0..9c6c943 100644 --- a/cc/tiles/tiling_set_raster_queue_all.h +++ b/cc/tiles/tiling_set_raster_queue_all.h
@@ -28,7 +28,6 @@ public: static std::unique_ptr<TilingSetRasterQueueAll> Create( PictureLayerTilingSet* tiling_set, - bool prioritize_low_res, bool is_drawing_layer); TilingSetRasterQueueAll(const TilingSetRasterQueueAll&) = delete;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index d02c680..eec4a03 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -2041,9 +2041,9 @@ return result; } -double LayerTreeHost::GetPercentDroppedFrames() const { +double LayerTreeHost::GetAverageThroughput() const { DCHECK(IsMainThread()); - return proxy_->GetPercentDroppedFrames(); + return proxy_->GetAverageThroughput(); } void LayerTreeHost::DropActiveScrollDeltaNextCommit(ElementId scroll_element) {
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 6c04fb4..91ebd9b 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -941,8 +941,8 @@ std::vector<ViewTransitionRequest::ViewTransitionCaptureCallback> TakeViewTransitionCallbacksForTesting(); - // Returns a percentage of dropped frames of the last second. - double GetPercentDroppedFrames() const; + // Returns a percentage of dropped frames as measured by the FrameSorter. + double GetAverageThroughput() const; // TODO(szager): Remove these once threaded compositing is enabled for all // web_tests.
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 66acd867..7255cd42 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -26,7 +26,6 @@ #include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" #include "base/functional/bind.h" -#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr_exclusion.h" @@ -466,8 +465,7 @@ .single_thread_proxy_scheduler, /*should_report_ukm=*/!settings.single_thread_proxy_scheduler, id)), - frame_trackers_(settings.single_thread_proxy_scheduler, - &dropped_frame_counter_), + frame_trackers_(settings.single_thread_proxy_scheduler), lcd_text_metrics_reporter_(LCDTextMetricsReporter::CreateIfNeeded(this)), has_input_resetter_( GetTaskRunner(), @@ -513,8 +511,6 @@ SetDebugState(settings.initial_debug_state); compositor_frame_reporting_controller_->SetFrameSorter(&frame_sorter_); - compositor_frame_reporting_controller_->SetDroppedFrameCounter( - &dropped_frame_counter_); compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection( &frame_trackers_); @@ -523,7 +519,6 @@ compositor_frame_reporting_controller_->set_event_latency_tracker(this); #if BUILDFLAG(IS_CHROMEOS) - dropped_frame_counter_.EnableReportForUI(); frame_sorter_.EnableReportForUI(); frame_trackers_.StartSequence( FrameSequenceTrackerType::kCompositorAnimation); @@ -582,7 +577,6 @@ // CFRC needs to unregister the frame trackers from the frame_sorter observer // set before being cleaned up. compositor_frame_reporting_controller_->ClearFrameSequenceTrackerCollection(); - compositor_frame_reporting_controller_->ClearDroppedFrameCounter(); } InputHandler& LayerTreeHostImpl::GetInputHandler() { @@ -630,17 +624,14 @@ } void LayerTreeHostImpl::ReadyToCommit( - const viz::BeginFrameArgs& commit_args, bool scroll_and_viewport_changes_synced, const BeginMainFrameMetrics* begin_main_frame_metrics, bool commit_timeout) { - if (!is_measuring_smoothness_ && - ((begin_main_frame_metrics && + if (((begin_main_frame_metrics && begin_main_frame_metrics->should_measure_smoothness) || - commit_timeout)) { - is_measuring_smoothness_ = true; + commit_timeout) && + !frame_sorter_.first_contentful_paint_received()) { frame_sorter_.OnFirstContentfulPaintReceived(); - dropped_frame_counter()->OnFirstContentfulPaintReceived(); } // Notify the browser controls manager that we have processed any @@ -1969,7 +1960,7 @@ } std::unique_ptr<EvictionTilePriorityQueue> -LayerTreeHostImpl::BuildEvictionQueue(TreePriority tree_priority) { +LayerTreeHostImpl::BuildEvictionQueue() { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "LayerTreeHostImpl::BuildEvictionQueue"); @@ -3734,7 +3725,6 @@ client_->DidLoseLayerTreeFrameSinkOnImplThread(); lag_tracking_manager_.Clear(); frame_sorter_.Reset(/*reset_fcp=*/false); - dropped_frame_counter_.ResetPendingFrames(base::TimeTicks::Now()); } bool LayerTreeHostImpl::OnlyExpandTopControlsAtPageTop() const { @@ -4036,9 +4026,7 @@ } if (!visible_) { - auto now = base::TimeTicks::Now(); frame_sorter_.Reset(/*reset_fcp=*/false); - dropped_frame_counter_.ResetPendingFrames(now); // When page is invisible, throw away corresponding EventsMetrics since // these metrics will be incorrect due to duration of page being invisible. @@ -5970,14 +5958,10 @@ // The source id has already been associated to the URL. compositor_frame_reporting_controller_->SetSourceId(source_id); frame_sorter_.Reset(/*reset_fcp=*/true); - dropped_frame_counter_.Reset(); - is_measuring_smoothness_ = false; } void LayerTreeHostImpl::SetUkmSmoothnessDestination( base::WritableSharedMemoryMapping ukm_smoothness_data) { - dropped_frame_counter_.SetUkmSmoothnessDestination( - ukm_smoothness_data.GetMemoryAs<UkmSmoothnessDataShared>()); ukm_smoothness_mapping_ = std::move(ukm_smoothness_data); }
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index e06bbfc1..086c5e4f 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -38,7 +38,6 @@ #include "cc/input/scrollbar_animation_controller.h" #include "cc/layers/layer_collections.h" #include "cc/metrics/average_lag_tracking_manager.h" -#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/event_latency_tracker.h" #include "cc/metrics/event_metrics.h" #include "cc/metrics/events_metrics_manager.h" @@ -281,7 +280,6 @@ bool next_bmf, bool scroll_and_viewport_changes_synced); virtual void ReadyToCommit( - const viz::BeginFrameArgs& commit_args, bool scroll_and_viewport_changes_synced, const BeginMainFrameMetrics* begin_main_frame_metrics, bool commit_timeout); @@ -516,8 +514,7 @@ std::unique_ptr<RasterTilePriorityQueue> BuildRasterQueue( TreePriority tree_priority, RasterTilePriorityQueue::Type type) override; - std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue( - TreePriority tree_priority) override; + std::unique_ptr<EvictionTilePriorityQueue> BuildEvictionQueue() override; void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override; std::unique_ptr<TilesWithResourceIterator> CreateTilesWithResourceIterator() override; @@ -693,9 +690,6 @@ std::unique_ptr<CompositorCommitData> ProcessCompositorDeltas( const MutatorHost* main_thread_mutator_host); - DroppedFrameCounter* dropped_frame_counter() { - return &dropped_frame_counter_; - } FrameSorter* frame_sorter() { return &frame_sorter_; } MemoryHistory* memory_history() { return memory_history_.get(); } DebugRectHistory* debug_rect_history() { return debug_rect_history_.get(); } @@ -874,9 +868,6 @@ Viewport& viewport() const { return *viewport_.get(); } - DroppedFrameCounter* dropped_frame_counter_for_testing() { - return &dropped_frame_counter_; - } FrameSorter* frame_sorter_for_testing() { return &frame_sorter_; } // Returns true if the client is currently compositing synchronously. @@ -1158,10 +1149,6 @@ base::WritableSharedMemoryMapping ukm_smoothness_mapping_; base::WritableSharedMemoryMapping ukm_dropped_frames_mapping_; - // `dropped_frame_counter_` holds a pointer `to ukm_smoothness_mapping_` so - // it must be declared last and deleted first; - DroppedFrameCounter dropped_frame_counter_; - std::unique_ptr<MemoryHistory> memory_history_; std::unique_ptr<DebugRectHistory> debug_rect_history_; @@ -1276,8 +1263,8 @@ PresentationTimeCallbackBuffer presentation_time_callbacks_; - // `compositor_frame_reporting_controller_` has a dependency on - // `dropped_frame_counter_` so it must be declared last and deleted first. + // `compositor_frame_reporting_controller_` is an observer of + // `frame_sorter_` so it must be declared last and deleted first. FrameSorter frame_sorter_; std::unique_ptr<CompositorFrameReportingController> compositor_frame_reporting_controller_; @@ -1321,10 +1308,6 @@ bool has_non_fling_input_since_last_frame_ = false; bool has_observed_first_scroll_delay_ = false; - // True if we are measuring smoothness in DroppedFrameCounter. - // Currently true when first contentful paint is done. - bool is_measuring_smoothness_ = false; - // Cache for the results of calls to gfx::ColorSpace::Contains() on sRGB. This // computation is deterministic for a given color space, can be called // multiple times per frame, and incurs a non-trivial cost.
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 7e45112..2f4e0d1 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14446,8 +14446,6 @@ // Test that TotalFrameCounter resets itself under certain conditions TEST_P(LayerTreeHostImplTest, FrameCounterReset) { - DroppedFrameCounter* dropped_frame_counter = - host_impl_->dropped_frame_counter_for_testing(); FrameSorter* frame_sorter = host_impl_->frame_sorter_for_testing(); EXPECT_EQ(frame_sorter->total_frames(), 0u); FrameInfo frame_info; @@ -14467,23 +14465,20 @@ frame_sorter->AddFrameResult( args, CreateFakeFrameInfo(FrameInfo::FrameFinalState::kDropped)); // FCP not received, so the total_smoothness_dropped_ won't increase. - EXPECT_EQ(dropped_frame_counter->total_smoothness_dropped(), 0u); + EXPECT_EQ(frame_sorter->total_dropped(), 0u); BeginMainFrameMetrics begin_frame_metrics; begin_frame_metrics.should_measure_smoothness = true; - host_impl_->ReadyToCommit(args, /*scroll_and_viewport_changes_synced=*/true, + host_impl_->ReadyToCommit(/*scroll_and_viewport_changes_synced=*/true, &begin_frame_metrics, /*commit_timeout=*/false); - dropped_frame_counter->SetTimeFirstContentfulPaintReceivedForTesting( - args.frame_time); frame_sorter->AddNewFrame(args); // Delegates to DFC::AddSortedFrame, which calls DFC::OnEndFrame. frame_sorter->AddFrameResult( args, CreateFakeFrameInfo(FrameInfo::FrameFinalState::kDropped)); - EXPECT_EQ(dropped_frame_counter->total_smoothness_dropped(), 1u); frame_sorter->AddFrameInfoToBuffer(frame_info); host_impl_->SetActiveURL(GURL(), 1u); EXPECT_EQ(frame_sorter->total_frames(), 0u); - EXPECT_EQ(dropped_frame_counter->total_dropped(), 0u); + EXPECT_EQ(frame_sorter->total_dropped(), 0u); } // Test that TotalFrameCounter does not reset itself under certain conditions @@ -14499,7 +14494,7 @@ deadline, interval, viz::BeginFrameArgs::NORMAL); BeginMainFrameMetrics begin_frame_metrics; begin_frame_metrics.should_measure_smoothness = true; - host_impl_->ReadyToCommit(arg1, /*scroll_and_viewport_changes_synced=*/true, + host_impl_->ReadyToCommit(/*scroll_and_viewport_changes_synced=*/true, &begin_frame_metrics, /*commit_timeout=*/false); EXPECT_EQ(frame_sorter->total_frames(), 0u); FrameInfo frame_info; @@ -14514,7 +14509,7 @@ deadline, interval, viz::BeginFrameArgs::NORMAL); // Consecutive BeginFrameMetrics with the same |should_measure_smoothness| // flag should not reset the counter. - host_impl_->ReadyToCommit(arg2, /*scroll_and_viewport_changes_synced=*/true, + host_impl_->ReadyToCommit(/*scroll_and_viewport_changes_synced=*/true, &begin_frame_metrics, /*commit_timeout=*/false); EXPECT_EQ(frame_sorter->total_frames(), 1u); }
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 131f9e7..d40e7e89 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -9708,85 +9708,6 @@ // TODO(crbug.com/40756887): Disabled because test is flaky on Linux and CrOS. // MULTI_THREAD_TEST_F(LayerTreeHostTestIgnoreEventsMetricsForNoUpdate); -class LayerTreeHostUkmSmoothnessMetric : public LayerTreeTest { - public: - LayerTreeHostUkmSmoothnessMetric() = default; - ~LayerTreeHostUkmSmoothnessMetric() override = default; - - void InitializeSettings(LayerTreeSettings* settings) override { - settings->commit_to_active_tree = false; - } - - void SetupTree() override { - LayerTreeTest::SetupTree(); - shmem_region_ = layer_tree_host()->CreateSharedMemoryForSmoothnessUkm(); - shmem_region_dropped_frames_ = - layer_tree_host()->CreateSharedMemoryForDroppedFramesUkm(); - } - - void BeginTest() override { - // Start with requesting main-frames. - PostSetNeedsCommitToMainThread(); - } - - void AfterTest() override { - ASSERT_TRUE(shmem_region_.IsValid()); - auto mapping = shmem_region_.Map(); - auto* smoothness = mapping.GetMemoryAs<UkmSmoothnessDataShared>(); - ASSERT_TRUE(smoothness); - // It is not always possible to guarantee an exact number of dropped frames. - // So validate that there are non-zero dropped frames. - EXPECT_GT(smoothness->data.avg_smoothness, 0); - - ASSERT_TRUE(shmem_region_dropped_frames_.IsValid()); - auto mapping_dropped_frames = shmem_region_dropped_frames_.Map(); - auto* smoothness_dropped_frames = - mapping.GetMemoryAs<UkmDroppedFramesDataShared>(); - ASSERT_TRUE(smoothness_dropped_frames); - // It is not always possible to guarantee an exact number of dropped frames. - // So validate that there are non-zero dropped frames. - EXPECT_GT(smoothness_dropped_frames->data.percent_dropped_frames, 0); - } - - void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, - const viz::BeginFrameArgs& args, - bool has_damage) override { - last_args_ = args; - if (!fcp_sent_) { - host_impl->dropped_frame_counter()->OnFirstContentfulPaintReceived(); - fcp_sent_ = true; - } - host_impl->frame_sorter_for_testing()->AddNewFrame(last_args_); - } - - void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { - if (TestEnded()) - return; - - if (frames_counter_ == 0) { - EndTest(); - return; - } - - // Mark every frame as a dropped frame affecting smoothness. - // Delegates to DFC::AddSortedFrame, which calls DFC::OnEndFrame. - host_impl->frame_sorter_for_testing()->AddFrameResult( - last_args_, CreateFakeImplDroppedFrameInfo()); - host_impl->SetNeedsRedraw(); - --frames_counter_; - } - - private: - const uint32_t kTotalFramesForTest = 5; - uint32_t frames_counter_ = kTotalFramesForTest; - bool fcp_sent_ = false; - viz::BeginFrameArgs last_args_; - base::ReadOnlySharedMemoryRegion shmem_region_; - base::ReadOnlySharedMemoryRegion shmem_region_dropped_frames_; -}; - -MULTI_THREAD_TEST_F(LayerTreeHostUkmSmoothnessMetric); - class LayerTreeHostUkmSmoothnessMemoryOwnership : public LayerTreeTest { public: LayerTreeHostUkmSmoothnessMemoryOwnership() = default; @@ -9809,7 +9730,6 @@ bool has_damage) override { last_args_ = args; if (!fcp_sent_) { - host_impl->dropped_frame_counter()->OnFirstContentfulPaintReceived(); fcp_sent_ = true; } host_impl->SetNeedsCommit();
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index c5861ef1..eeda72c 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -1981,10 +1981,6 @@ return host_impl_->image_animation_controller(); } -DroppedFrameCounter* LayerTreeImpl::dropped_frame_counter() const { - return host_impl_->dropped_frame_counter(); -} - FrameSorter* LayerTreeImpl::frame_sorter() const { return host_impl_->frame_sorter(); }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index f39a762b..9010b93a 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -51,7 +51,6 @@ enum class ActivelyScrollingType; class DebugRectHistory; class ViewTransitionRequest; -class DroppedFrameCounter; class GlobalStateThatImpactsTilePriority; class HeadsUpDisplayLayerImpl; class ImageDecodeCache; @@ -133,7 +132,6 @@ TileManager* tile_manager() const; ImageDecodeCache* image_decode_cache() const; ImageAnimationController* image_animation_controller() const; - DroppedFrameCounter* dropped_frame_counter() const; FrameSorter* frame_sorter() const; MemoryHistory* memory_history() const; DebugRectHistory* debug_rect_history() const;
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h index d537058..e9a4d91 100644 --- a/cc/trees/proxy.h +++ b/cc/trees/proxy.h
@@ -132,9 +132,9 @@ bool raster, base::OnceClosure callback) = 0; - // Returns a percentage of dropped frames of the last second. + // Returns the average throughput as measured by the FrameSorter. // Only implemenented for single threaded proxy. - virtual double GetPercentDroppedFrames() const = 0; + virtual double GetAverageThroughput() const = 0; // Returns true if we have requested to have rendering paused. virtual bool IsRenderingPaused() const = 0;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc index 25156e0..84017d90 100644 --- a/cc/trees/proxy_impl.cc +++ b/cc/trees/proxy_impl.cc
@@ -44,6 +44,7 @@ #include "cc/trees/swap_promise.h" #include "cc/trees/task_runner_provider.h" #include "cc/trees/trace_utils.h" +#include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/frame_sinks/delay_based_time_source.h" #include "components/viz/common/frame_timing_details.h" #include "components/viz/common/gpu/raster_context_provider.h" @@ -353,7 +354,6 @@ std::unique_ptr<CommitState> commit_state, const ThreadUnsafeCommitState* unsafe_state, base::TimeTicks main_thread_start_time, - const viz::BeginFrameArgs& commit_args, bool scroll_and_viewport_changes_synced, CommitTimestamps* commit_timestamps, bool commit_timeout) { @@ -395,7 +395,7 @@ scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time); auto& begin_main_frame_metrics = commit_state->begin_main_frame_metrics; - host_impl_->ReadyToCommit(commit_args, scroll_and_viewport_changes_synced, + host_impl_->ReadyToCommit(scroll_and_viewport_changes_synced, begin_main_frame_metrics.get(), commit_timeout); int source_frame_number = commit_state->source_frame_number;
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h index 7aa5610a..131df3c 100644 --- a/cc/trees/proxy_impl.h +++ b/cc/trees/proxy_impl.h
@@ -94,7 +94,6 @@ std::unique_ptr<CommitState> commit_state, const ThreadUnsafeCommitState* unsafe_state, base::TimeTicks main_thread_start_time, - const viz::BeginFrameArgs& commit_args, bool scroll_and_viewport_changes_synced, CommitTimestamps* commit_timestamps, bool commit_timeout = false);
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc index 2a984b3a..a0d057e 100644 --- a/cc/trees/proxy_main.cc +++ b/cc/trees/proxy_main.cc
@@ -469,13 +469,13 @@ main_thread_blocked.emplace(task_runner_provider_); ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce( - &ProxyImpl::NotifyReadyToCommitOnImpl, - base::Unretained(proxy_impl_.get()), completion_event, - std::move(commit_state), &unsafe_state, begin_main_frame_start_time, - frame_args, scroll_and_viewport_changes_synced, - blocking ? &commit_timestamps : nullptr, commit_timeout)); + FROM_HERE, base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl, + base::Unretained(proxy_impl_.get()), + completion_event, std::move(commit_state), + &unsafe_state, begin_main_frame_start_time, + scroll_and_viewport_changes_synced, + (blocking ? &commit_timestamps : nullptr), + commit_timeout)); if (blocking) layer_tree_host_->WaitForProtectedSequenceCompletion(); } @@ -960,7 +960,7 @@ SetNeedsCommit(); } -double ProxyMain::GetPercentDroppedFrames() const { +double ProxyMain::GetAverageThroughput() const { NOTIMPLEMENTED(); return 0.0; }
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h index ed13d3e..1fc6401f 100644 --- a/cc/trees/proxy_main.h +++ b/cc/trees/proxy_main.h
@@ -141,7 +141,7 @@ void CompositeImmediatelyForTest(base::TimeTicks frame_begin_time, bool raster, base::OnceClosure callback) override; - double GetPercentDroppedFrames() const override; + double GetAverageThroughput() const override; bool IsRenderingPaused() const override; void NotifyNewLocalSurfaceIdExpectedWhilePaused() override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 92bfce75..ba264aa1 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -821,7 +821,7 @@ layer_tree_host_->RecordStartOfFrameMetrics(); DoBeginMainFrame(begin_frame_args); commit_requested_ = false; - DoPainting(begin_frame_args); + DoPainting(); layer_tree_host_->RecordEndOfFrameMetrics(frame_begin_time, /* trackers */ 0u); DoCommit(begin_frame_args); @@ -1008,10 +1008,9 @@ host_impl_->SetRenderFrameObserver(std::move(observer)); } -double SingleThreadProxy::GetPercentDroppedFrames() const { +double SingleThreadProxy::GetAverageThroughput() const { DebugScopedSetImplThread impl(task_runner_provider_); - return host_impl_->dropped_frame_counter() - ->sliding_window_current_percent_dropped(); + return host_impl_->frame_sorter()->GetAverageThroughput(); } void SingleThreadProxy::UpdateBrowserControlsState( @@ -1154,7 +1153,7 @@ return; } - DoPainting(begin_frame_args); + DoPainting(); layer_tree_host_->RecordEndOfFrameMetrics(frame_start_time, /* trackers */ 0u); } @@ -1193,14 +1192,13 @@ did_apply_compositor_deltas_ = false; } -void SingleThreadProxy::DoPainting(const viz::BeginFrameArgs& commit_args) { +void SingleThreadProxy::DoPainting() { layer_tree_host_->UpdateLayers(); update_layers_requested_ = false; std::unique_ptr<BeginMainFrameMetrics> begin_main_frame_metrics = layer_tree_host_->TakeBeginMainFrameMetrics(); - host_impl_->ReadyToCommit(commit_args, - /*scroll_and_viewport_changes_synced=*/true, + host_impl_->ReadyToCommit(/*scroll_and_viewport_changes_synced=*/true, begin_main_frame_metrics.get(), /*commit_timeout=*/false);
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 7aaa669..601c08f 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -94,7 +94,7 @@ void CompositeImmediatelyForTest(base::TimeTicks frame_begin_time, bool raster, base::OnceClosure callback) override; - double GetPercentDroppedFrames() const override; + double GetAverageThroughput() const override; void UpdateBrowserControlsState( BrowserControlsState constraints, @@ -202,7 +202,7 @@ void BeginMainFrame(const viz::BeginFrameArgs& begin_frame_args); void BeginMainFrameAbortedOnImplThread(CommitEarlyOutReason reason); void DoBeginMainFrame(const viz::BeginFrameArgs& begin_frame_args); - void DoPainting(const viz::BeginFrameArgs& commit_args); + void DoPainting(); void DoCommit(const viz::BeginFrameArgs& commit_args); void DoPostCommit(); DrawResult DoComposite(LayerTreeHostImpl::FrameData* frame);
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 5329e1f7..86007c8 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -26,7 +26,6 @@ import("//extensions/buildflags/buildflags.gni") import("//media/media_options.gni") import("//ppapi/buildflags/buildflags.gni") -import("//services/shape_detection/features.gni") import("//third_party/angle/gni/angle.gni") import("//third_party/blink/public/public_features.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -1724,9 +1723,6 @@ if (build_with_internal_optimization_guide) { deps += [ ":optimization_guide_symbols" ] } - if (build_with_internal_shape_detection) { - deps += [ ":shape_detection_symbols" ] - } if (!use_static_angle) { deps += [ ":angle_egl_symbols", @@ -1825,21 +1821,6 @@ deps = [ "//components/optimization_guide/internal:optimization_guide_internal" ] } } - if (build_with_internal_shape_detection) { - extract_symbols("shape_detection_symbols") { - binary = "$root_out_dir/libshape_detection_internal.so" - if (current_cpu == "x86") { - # GYP used "ia32" so keep that naming for back-compat. - symbol_file = "$root_out_dir/shape_detection_internal.breakpad.ia32" - } else { - symbol_file = - "$root_out_dir/shape_detection_internal.breakpad.$current_cpu" - } - - deps = - [ "//services/shape_detection/internal:shape_detection_internal" ] - } - } } # Copies some scripts and resources that are used for desktop integration.
diff --git a/chrome/VERSION b/chrome/VERSION index 105f431..4cb20bf5 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=139 MINOR=0 -BUILD=7250 +BUILD=7251 PATCH=0
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java index d6a9c28..02fa447 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java
@@ -22,7 +22,6 @@ import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.selectTabWithDescription; import static org.chromium.chrome.browser.keyboard_accessory.ManualFillingTestHelper.whenDisplayed; -import android.os.Build; import android.widget.TextView; import androidx.test.filters.MediumTest; @@ -35,7 +34,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Features; import org.chromium.chrome.browser.ChromeWindow; @@ -130,12 +128,7 @@ @Test @MediumTest - @DisabledTest(message = "https://crbug.com/418234086") - @DisableIf.Build( - sdk_is_less_than = Build.VERSION_CODES.TIRAMISU, - sdk_is_greater_than = Build.VERSION_CODES.P, - supported_abis_includes = "x86_64", - message = "crbug.com/40190628") + @DisabledTest(message = "https://crbug.com/418234086,https://crbug.com/40190628") public void testFillsSuggestionOnClick() throws TimeoutException { loadTestPage(FakeKeyboard::new); mHelper.clickNodeAndShowKeyboard("NAME_FIRST", 1);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java index a244878..fda6bb9 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchRenderTest.java
@@ -8,8 +8,6 @@ import static org.chromium.ui.base.DeviceFormFactor.PHONE; -import android.os.Build; - import androidx.test.filters.MediumTest; import org.junit.After; @@ -25,7 +23,6 @@ import org.chromium.base.test.params.ParameterAnnotations; import org.chromium.base.test.params.ParameterizedRunner; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features; import org.chromium.base.test.util.Restriction; @@ -64,10 +61,6 @@ ChromeFeatureList.GRID_TAB_SWITCHER_UPDATE, ChromeFeatureList.ANDROID_THEME_MODULE }) -// Disable in Pie because search box does not get focus automatically. -@DisableIf.Build( - sdk_is_greater_than = Build.VERSION_CODES.O_MR1, - sdk_is_less_than = Build.VERSION_CODES.Q) public class TabSwitcherSearchRenderTest { private static final int SERVER_PORT = 13245;
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java index c443ca48..06799d90 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherSearchTest.java
@@ -12,8 +12,6 @@ import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking; import static org.chromium.ui.base.DeviceFormFactor.PHONE; -import android.os.Build; - import androidx.test.filters.LargeTest; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -29,7 +27,6 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.RequiresRestart; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -59,10 +56,6 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) @Batch(Batch.PER_CLASS) -// Disable in Pie because search box does not get focus automatically. -@DisableIf.Build( - sdk_is_greater_than = Build.VERSION_CODES.O_MR1, - sdk_is_less_than = Build.VERSION_CODES.Q) public class TabSwitcherSearchTest { private static final int SERVER_PORT = 13245; private static final String URL_PREFIX = "127.0.0.1:" + SERVER_PORT;
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 a6b52cdb..82eb851e 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
@@ -24,8 +24,10 @@ 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.base.WindowAndroid; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.ui.modaldialog.ModalDialogManagerHolder; import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; @@ -39,6 +41,8 @@ /** Dialog for selecting a media source for media capture. */ public class MediaCapturePickerDialog implements AllTabObserver.Observer { + // This web contents is the one that is receiving the shared content. + private final WebContents mWebContents; private final ModalDialogManager mModalDialogManager; private final String mAppName; private final View mDialogView; @@ -114,32 +118,39 @@ int DEFAULT = 0; } + private static @Nullable Context maybeGetContext(WebContents webContents) { + final WindowAndroid window = webContents.getTopLevelNativeWindow(); + if (window == null) return null; + return window.getContext().get(); + } + /** * Shows the media capture picker dialog. * - * @param modalDialogManager Manager for managing the modal dialog. + * @param webContents The {@link WebContents} to show the dialog on behalf of. * @param appName Name of the app that wants to share content. * @param requestAudio True if audio sharing is also requested. * @param delegate Invoked with a WebContents if a tab is selected, or {@code null} if the * dialog is dismissed. */ public static void showDialog( - Context context, - ModalDialogManager modalDialogManager, - String appName, - boolean requestAudio, - Delegate delegate) { - new MediaCapturePickerDialog(context, modalDialogManager, appName, requestAudio, delegate) - .show(); + WebContents webContents, String appName, boolean requestAudio, Delegate delegate) { + final Context context = maybeGetContext(webContents); + if (context == null) { + delegate.onCancel(); + return; + } + new MediaCapturePickerDialog(context, webContents, appName, requestAudio, delegate).show(); } private MediaCapturePickerDialog( Context context, - ModalDialogManager modalDialogManager, + WebContents webContents, String appName, boolean requestAudio, Delegate delegate) { - mModalDialogManager = modalDialogManager; + mWebContents = webContents; + mModalDialogManager = ((ModalDialogManagerHolder) context).getModalDialogManager(); mAppName = appName; mDelegate = delegate; @@ -198,7 +209,7 @@ fragment.startAndroidCapturePrompt( (action, result) -> { if (action != CaptureAction.CAPTURE_CANCELLED) { - ScreenCapture.onPick(result); + ScreenCapture.onPick(mWebContents, result); } switch (action) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialogBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialogBridge.java index a78499b..2d2cdfe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialogBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialogBridge.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.media; -import android.app.Activity; - import androidx.annotation.NonNull; import org.jni_zero.CalledByNative; @@ -13,8 +11,6 @@ import org.jni_zero.NativeMethods; import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.WindowAndroid; -import org.chromium.ui.modaldialog.ModalDialogManagerHolder; /** Glue for the media capture picker dialog UI code and communication with the native backend. */ public class MediaCapturePickerDialogBridge implements MediaCapturePickerDialog.Delegate { @@ -42,22 +38,17 @@ /** * Shows the media capture picker dialog. * - * @param windowAndroid Window to show the dialog on. + * @param webContents The {@link WebContents} to show the dialog on behalf of. * @param appName Name of the app that wants to share content. * @param requestAudio True if audio sharing is also requested. */ @CalledByNative public void showDialog( - WindowAndroid windowAndroid, + WebContents webContents, @JniType("std::u16string") String appName, boolean requestAudio) { - Activity activity = windowAndroid.getActivity().get(); MediaCapturePickerDialog.showDialog( - activity, - ((ModalDialogManagerHolder) activity).getModalDialogManager(), - appName, - requestAudio, - this); + webContents, appName, requestAudio, /* delegate= */ this); } @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java index a2db93e..1f558c4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewBridge.java
@@ -88,7 +88,7 @@ @JniType("std::vector") List<LoyaltyCard> affiliatedLoyaltyCards, @JniType("std::vector") List<LoyaltyCard> allLoyaltyCards, boolean firstTimeUsage) { - mComponent.showLoyaltyCards(allLoyaltyCards, affiliatedLoyaltyCards, firstTimeUsage); + mComponent.showLoyaltyCards(affiliatedLoyaltyCards, allLoyaltyCards, firstTimeUsage); } @CalledByNative
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java index 8620769..8808d59 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchCriticalTest.java
@@ -6,8 +6,6 @@ import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; -import android.os.Build.VERSION_CODES; - import androidx.test.filters.SmallTest; import org.hamcrest.MatcherAssert; @@ -24,7 +22,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Features.EnableFeatures; @@ -140,7 +137,7 @@ @SmallTest @Feature({"ContextualSearch"}) // Previously disabled: crbug.com/765403 - @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.P, message = "crbug.com/377363763") + @DisabledTest(message = "crbug.com/377363763") public void testSearchTermResolutionError() throws Exception { simulateSlowResolveSearch("states"); assertSearchTermRequested();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 38351b5..7e463c88 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -624,11 +624,7 @@ expectedCaptionStart, barControl.getCaptionText().subSequence(0, expectedCaptionStart.length())); // TODO(donnd): figure out why we get ~0.65 on Oreo rather than 1. https://crbug.com/818515. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - Assert.assertEquals(1.f, imageControl.getCustomImageVisibilityPercentage(), 0); - } else { - Assert.assertTrue(0.5f < imageControl.getCustomImageVisibilityPercentage()); - } + Assert.assertTrue(0.5f < imageControl.getCustomImageVisibilityPercentage()); CompositorAnimationHandler.setTestingMode(false); } @@ -684,7 +680,7 @@ @SmallTest @Feature({"ContextualSearch"}) // TODO(donnd): reenable - recent fixes as of 3/31/2023 - @DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.O, message = "crbug.com/1075895") + @DisabledTest(message = "crbug.com/1075895") // Previously disabled: https://crbug.com/1127796 public void testQuickActionUrl() throws Exception { final String testUrl = mTestServer.getURL("/chrome/test/data/android/google.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java index 84bc0fa..3232e94 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java
@@ -9,7 +9,6 @@ import android.app.DownloadManager; import android.content.Context; import android.content.Intent; -import android.os.Build.VERSION_CODES; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.MediumTest; @@ -29,7 +28,7 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisableIf; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.download.DownloadManagerBridge.DownloadQueryResult; @@ -312,10 +311,9 @@ */ @Test @MediumTest - @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.P) // https://crbug.com/338971643 + @DisabledTest(message = "https://crbug.com/338971643") @Feature({"Download"}) public void testQueryDownloadResult() { - Context context = getTestContext(); DownloadManager manager = (DownloadManager) getTestContext().getSystemService(Context.DOWNLOAD_SERVICE); long downloadId1 = @@ -346,7 +344,7 @@ */ @Test @MediumTest - @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.P) // https://crbug.com/338971643 + @DisabledTest(message = "https://crbug.com/338971643") @Feature({"Download"}) public void testClearPendingOMADownloads() { Context context = getTestContext();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ManifestHWATest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ManifestHWATest.java index 499c6d85..aa19b9f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ManifestHWATest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/hardware_acceleration/ManifestHWATest.java
@@ -25,7 +25,6 @@ @RunWith(BaseJUnit4ClassRunner.class) @Batch(Batch.UNIT_TESTS) @DisableIf.Build( - sdk_is_greater_than = Build.VERSION_CODES.P, sdk_is_less_than = Build.VERSION_CODES.TIRAMISU, supported_abis_includes = "x86_64", message = "vr tests do not apply to emulator")
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java index dcc630d..4592b99 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
@@ -6,7 +6,6 @@ import android.app.Activity; import android.net.Uri; -import android.os.Build; import android.os.Environment; import androidx.test.core.app.ApplicationProvider; @@ -28,7 +27,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; @@ -293,10 +291,6 @@ @Test @MediumTest @CommandLineFlags.Add({"enable-features=OfflinePagesSharing"}) - @DisableIf.Build( - message = "https://crbug.com/1001506", - sdk_is_greater_than = Build.VERSION_CODES.N, - sdk_is_less_than = Build.VERSION_CODES.P) public void testShareTemporaryOfflinePage() throws Exception { loadOfflinePage(SUGGESTED_ARTICLES_ID); final Semaphore semaphore = new Semaphore(0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java index fefaf26..6dae1b46 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java
@@ -10,7 +10,6 @@ import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForSecondChromeTabbedActivity; import android.app.Activity; -import android.os.Build; import android.text.TextUtils; import android.view.ViewGroup; import android.widget.ImageView; @@ -32,7 +31,6 @@ import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.CriteriaNotSatisfiedException; -import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.ChromeTabbedActivity2; @@ -240,7 +238,7 @@ @Test @MediumTest - @DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.P, message = "crbug.com/1195129") + @DisabledTest(message = "crbug.com/1195129") public void testSwitchToTabSuggestion() throws InterruptedException { mTestServer = EmbeddedTestServer.createAndStartHTTPSServer( @@ -314,7 +312,7 @@ @Test @MediumTest - @DisableIf.Build(sdk_is_greater_than = Build.VERSION_CODES.P, message = "crbug.com/1195129") + @DisabledTest(message = "crbug.com/1195129") public void testNoSwitchToIncognitoTabFromNormalModel() throws InterruptedException { mTestServer = EmbeddedTestServer.createAndStartHTTPSServer(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java index df319aa..3c87db0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java
@@ -12,7 +12,6 @@ import android.content.Context; import android.content.Intent; import android.media.AudioManager; -import android.os.Build; import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.MediumTest; @@ -32,7 +31,6 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.ChromeTabbedActivity2; @@ -72,7 +70,6 @@ "ignore-certificate-errors", MediaSwitches.AUTOPLAY_NO_GESTURE_REQUIRED_POLICY }) -@MinAndroidSdkLevel(Build.VERSION_CODES.Q) public class TabSuspensionTest { private static final String STARTING_FQDN = "example.com"; private static final String DIFFERENT_FQDN = "www.google.com"; @@ -215,9 +212,7 @@ @Test @MediumTest - @DisableIf.Build( - sdk_is_greater_than = Build.VERSION_CODES.P, - message = "https://crbug.com/1036556") + @DisabledTest(message = "https://crbug.com/1036556") public void testMediaSuspension() throws TimeoutException { mActivityTestRule.loadUrl( mTestServer.getURLWithHostName(STARTING_FQDN, MEDIA_FILE_TEST_PATH));
diff --git a/chrome/browser/actor/BUILD.gn b/chrome/browser/actor/BUILD.gn index ebca02f..16d0928 100644 --- a/chrome/browser/actor/BUILD.gn +++ b/chrome/browser/actor/BUILD.gn
@@ -22,6 +22,7 @@ "execution_engine.h", "tools/observation_delay_controller.h", "tools/tool_controller.h", + "tools/tool_request.h", ] public_deps = [ ":types", @@ -54,22 +55,45 @@ "execution_engine.cc", "site_policy.cc", "site_policy.h", + "tools/click_tool_request.cc", + "tools/click_tool_request.h", + "tools/drag_and_release_tool_request.cc", + "tools/drag_and_release_tool_request.h", "tools/history_tool.cc", "tools/history_tool.h", + "tools/history_tool_request.cc", + "tools/history_tool_request.h", + "tools/move_mouse_tool_request.cc", + "tools/move_mouse_tool_request.h", "tools/navigate_tool.cc", "tools/navigate_tool.h", + "tools/navigate_tool_request.cc", + "tools/navigate_tool_request.h", "tools/observation_delay_controller.cc", "tools/page_tool.cc", "tools/page_tool.h", + "tools/page_tool_request.cc", + "tools/page_tool_request.h", + "tools/scroll_tool_request.cc", + "tools/scroll_tool_request.h", + "tools/select_tool_request.cc", + "tools/select_tool_request.h", "tools/tab_management_tool.cc", "tools/tab_management_tool.h", + "tools/tab_management_tool_request.cc", + "tools/tab_management_tool_request.h", "tools/tool.cc", "tools/tool.h", "tools/tool_callbacks.cc", "tools/tool_callbacks.h", "tools/tool_controller.cc", + "tools/tool_request.cc", + "tools/type_tool_request.cc", + "tools/type_tool_request.h", "tools/wait_tool.cc", "tools/wait_tool.h", + "tools/wait_tool_request.cc", + "tools/wait_tool_request.h", ] public_deps = [ "//chrome/browser:browser_public_dependencies" ]
diff --git a/chrome/browser/actor/browser_action_util.cc b/chrome/browser/actor/browser_action_util.cc index fec656e4..01430dc4 100644 --- a/chrome/browser/actor/browser_action_util.cc +++ b/chrome/browser/actor/browser_action_util.cc
@@ -4,200 +4,479 @@ #include "chrome/browser/actor/browser_action_util.h" +#include <optional> + +#include "chrome/browser/actor/tools/click_tool_request.h" +#include "chrome/browser/actor/tools/drag_and_release_tool_request.h" +#include "chrome/browser/actor/tools/history_tool_request.h" +#include "chrome/browser/actor/tools/move_mouse_tool_request.h" +#include "chrome/browser/actor/tools/navigate_tool_request.h" +#include "chrome/browser/actor/tools/scroll_tool_request.h" +#include "chrome/browser/actor/tools/select_tool_request.h" +#include "chrome/browser/actor/tools/tab_management_tool_request.h" +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/browser/actor/tools/type_tool_request.h" +#include "chrome/browser/actor/tools/wait_tool_request.h" #include "chrome/common/actor/actor_logging.h" #include "components/optimization_guide/content/browser/page_content_proto_provider.h" #include "components/optimization_guide/proto/features/actions_data.pb.h" -#include "components/optimization_guide/proto/features/common_quality_data.pb.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" -#include "ui/gfx/geometry/point_f.h" +#include "ui/base/window_open_disposition.h" namespace actor { -using ::content::RenderFrameHost; -using ::content::RenderWidgetHost; -using ::content::WebContents; +// Alias the namespace to make the long enums a bit more readable in +// implementations. +namespace apc = ::optimization_guide::proto; + +using apc::Action; +using apc::ActionTarget; +using apc::ActivateTabAction; +using apc::ClickAction; +using apc::CloseTabAction; +using apc::CreateTabAction; +using apc::DragAndReleaseAction; +using apc::HistoryBackAction; +using apc::HistoryForwardAction; +using apc::MoveMouseAction; +using apc::NavigateAction; +using apc::ScrollAction; +using apc::SelectAction; +using apc::TypeAction; +using apc::WaitAction; using ::optimization_guide::DocumentIdentifierUserData; -using ::optimization_guide::proto::Action; -using ::optimization_guide::proto::ActionTarget; -using ::optimization_guide::proto::DocumentIdentifier; +using ::tabs::TabHandle; +using ::tabs::TabInterface; namespace { -bool IsTargetingTab(const Action& action) { - switch (action.action_case()) { - case Action::ActionCase::kClick: - case Action::ActionCase::kType: - case Action::ActionCase::kScroll: - case Action::ActionCase::kMoveMouse: - case Action::ActionCase::kDragAndRelease: - case Action::ActionCase::kSelect: - // These actions target neither tabs nor frames. - case Action::ActionCase::kCreateTab: - case Action::ActionCase::kCloseTab: - case Action::ActionCase::kActivateTab: - case Action::ActionCase::kCreateWindow: - case Action::ActionCase::kCloseWindow: - case Action::ActionCase::kActivateWindow: - case Action::ActionCase::kYieldToUser: - return false; - case Action::ActionCase::kNavigate: - case Action::ActionCase::kBack: - case Action::ActionCase::kForward: - case Action::ActionCase::kWait: - return true; - case Action::ActionCase::ACTION_NOT_SET: - NOTREACHED(); +struct PageScopedParams { + std::string document_identifier; + TabHandle tab_handle; +}; + +template <class T> +TabHandle GetTabHandle(const T& action, TabInterface* deprecated_fallback_tab) { + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); } + return tab_handle; } -// Finds the local root of a given RenderFrameHost. The local root is the -// highest ancestor in the frame tree that shares the same RenderWidgetHost. -RenderFrameHost* GetLocalRoot(RenderFrameHost* rfh) { - RenderFrameHost* local_root = rfh; - while (local_root && local_root->GetParent()) { - if (local_root->GetRenderWidgetHost() != - local_root->GetParent()->GetRenderWidgetHost()) { - break; - } - local_root = local_root->GetParent(); +template <class T> +PageScopedParams GetPageScopedParams(const T& action, + TabInterface* deprecated_fallback_tab) { + std::string document_identifier; + if (action.has_target()) { + document_identifier = + action.target().document_identifier().serialized_token(); } - return local_root; + + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } + return {document_identifier, tab_handle}; +} + +// DragAndRelease is unusual in that it has no target, it has a from_target and +// to_target. Specialize and use the from_target as the document-scoping target. +template <> +PageScopedParams GetPageScopedParams<DragAndReleaseAction>( + const DragAndReleaseAction& action, + TabInterface* deprecated_fallback_tab) { + std::string document_identifier; + if (action.has_from_target()) { + document_identifier = + action.from_target().document_identifier().serialized_token(); + } + + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } + return {document_identifier, tab_handle}; +} + +PageToolRequest::Target ToPageToolTarget( + const optimization_guide::proto::ActionTarget& target) { + if (target.has_coordinate()) { + return PageToolRequest::Target( + gfx::Point(target.coordinate().x(), target.coordinate().y())); + } else { + return PageToolRequest::Target(target.content_node_id()); + } +} +std::unique_ptr<ToolRequest> CreateClickRequest( + const ClickAction& action, + TabInterface* deprecated_fallback_tab) { + using ClickCount = ClickToolRequest::ClickCount; + using ClickType = ClickToolRequest::ClickType; + + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + + if (!action.has_target() || !action.has_click_count() || + !action.has_click_type() || page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + ClickCount count; + switch (action.click_count()) { + case apc::ClickAction_ClickCount_SINGLE: + count = ClickCount::kSingle; + break; + case apc::ClickAction_ClickCount_DOUBLE: + count = ClickCount::kDouble; + break; + case apc::ClickAction_ClickCount_UNKNOWN_CLICK_COUNT: + case apc:: + ClickAction_ClickCount_ClickAction_ClickCount_INT_MIN_SENTINEL_DO_NOT_USE_: + case apc:: + ClickAction_ClickCount_ClickAction_ClickCount_INT_MAX_SENTINEL_DO_NOT_USE_: + // TODO(crbug.com/412700289): Revert once this is set. + count = ClickCount::kSingle; + break; + } + + ClickType type; + switch (action.click_type()) { + case apc::ClickAction_ClickType_LEFT: + type = ClickType::kLeft; + break; + case apc::ClickAction_ClickType_RIGHT: + type = ClickType::kRight; + break; + case apc:: + ClickAction_ClickType_ClickAction_ClickType_INT_MIN_SENTINEL_DO_NOT_USE_: + case apc:: + ClickAction_ClickType_ClickAction_ClickType_INT_MAX_SENTINEL_DO_NOT_USE_: + case apc::ClickAction_ClickType_UNKNOWN_CLICK_TYPE: + // TODO(crbug.com/412700289): Revert once this is set. + type = ClickType::kLeft; + break; + } + + return std::make_unique<ClickToolRequest>( + page.tab_handle, page.document_identifier, + ToPageToolTarget(action.target()), type, count); +} + +std::unique_ptr<ToolRequest> CreateTypeRequest( + const TypeAction& action, + TabInterface* deprecated_fallback_tab) { + using TypeMode = TypeToolRequest::Mode; + + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + + if (!action.has_target() || !action.has_text() || !action.has_mode() || + !action.has_follow_by_enter() || page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + TypeMode mode; + switch (action.mode()) { + case apc::TypeAction_TypeMode_DELETE_EXISTING: + mode = TypeMode::kReplace; + break; + case apc::TypeAction_TypeMode_PREPEND: + mode = TypeMode::kPrepend; + break; + case apc::TypeAction_TypeMode_APPEND: + mode = TypeMode::kAppend; + break; + case apc::TypeAction_TypeMode_UNKNOWN_TYPE_MODE: + case apc:: + TypeAction_TypeMode_TypeAction_TypeMode_INT_MIN_SENTINEL_DO_NOT_USE_: + case apc:: + TypeAction_TypeMode_TypeAction_TypeMode_INT_MAX_SENTINEL_DO_NOT_USE_: + // TODO(crbug.com/412700289): Revert once this is set. + mode = TypeMode::kReplace; + break; + } + return std::make_unique<TypeToolRequest>( + page.tab_handle, page.document_identifier, + ToPageToolTarget(action.target()), action.text(), + action.follow_by_enter(), mode); +} + +std::unique_ptr<ToolRequest> CreateScrollRequest( + const ScrollAction& action, + TabInterface* deprecated_fallback_tab) { + using Direction = ScrollToolRequest::Direction; + + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + + if (!action.has_direction() || !action.has_distance() || + page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + PageToolRequest::Target page_target; + + if (action.has_target()) { + page_target = ToPageToolTarget(action.target()); + } else { + // Scroll action may omit a target which means "target the viewport". + // TODO(bokan): This can be removed once the scroll action provides the main + // document's id in these cases. + page_target = std::nullopt; + if (page.document_identifier.empty()) { + TabInterface* tab = page.tab_handle.Get(); + if (!tab) { + return nullptr; + } + page.document_identifier = + DocumentIdentifierUserData::GetOrCreateForCurrentDocument( + tab->GetContents()->GetPrimaryMainFrame()) + ->serialized_token(); + } + } + + Direction direction; + switch (action.direction()) { + case apc::ScrollAction_ScrollDirection_LEFT: + direction = Direction::kLeft; + break; + case apc::ScrollAction_ScrollDirection_RIGHT: + direction = Direction::kRight; + break; + case apc::ScrollAction_ScrollDirection_UP: + direction = Direction::kUp; + break; + case apc::ScrollAction_ScrollDirection_DOWN: + direction = Direction::kDown; + break; + case apc::ScrollAction_ScrollDirection_UNKNOWN_SCROLL_DIRECTION: + case apc:: + ScrollAction_ScrollDirection_ScrollAction_ScrollDirection_INT_MIN_SENTINEL_DO_NOT_USE_: + case apc:: + ScrollAction_ScrollDirection_ScrollAction_ScrollDirection_INT_MAX_SENTINEL_DO_NOT_USE_: + // TODO(crbug.com/412700289): Revert once this is set. + direction = Direction::kDown; + break; + } + + return std::make_unique<ScrollToolRequest>( + page.tab_handle, page.document_identifier, page_target, direction, + action.distance()); +} + +std::unique_ptr<ToolRequest> CreateMoveMouseRequest( + const MoveMouseAction& action, + TabInterface* deprecated_fallback_tab) { + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + if (!action.has_target() || page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + return std::make_unique<MoveMouseToolRequest>( + page.tab_handle, page.document_identifier, + ToPageToolTarget(action.target())); +} + +std::unique_ptr<ToolRequest> CreateDragAndReleaseRequest( + const DragAndReleaseAction& action, + TabInterface* deprecated_fallback_tab) { + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + + if (!action.has_from_target() || !action.has_to_target() || + page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + return std::make_unique<DragAndReleaseToolRequest>( + page.tab_handle, page.document_identifier, + ToPageToolTarget(action.from_target()), + ToPageToolTarget(action.to_target())); +} + +std::unique_ptr<ToolRequest> CreateSelectRequest( + const SelectAction& action, + TabInterface* deprecated_fallback_tab) { + PageScopedParams page = GetPageScopedParams(action, deprecated_fallback_tab); + if (!action.has_value() || !action.has_target() || + page.tab_handle == TabHandle::Null()) { + return nullptr; + } + + return std::make_unique<SelectToolRequest>( + page.tab_handle, page.document_identifier, + ToPageToolTarget(action.target()), action.value()); +} + +std::unique_ptr<ToolRequest> CreateNavigateRequest( + const NavigateAction& action, + TabInterface* deprecated_fallback_tab) { + TabHandle tab_handle = GetTabHandle(action, deprecated_fallback_tab); + if (!action.has_url() || tab_handle == TabHandle::Null()) { + return nullptr; + } + + return std::make_unique<NavigateToolRequest>(tab_handle, GURL(action.url())); +} + +std::unique_ptr<ToolRequest> CreateCreateTabRequest( + const CreateTabAction& action) { + if (!action.has_window_id()) { + return nullptr; + } + + int32_t window_id = action.window_id(); + + // TODO(bokan): Is the foreground bit always set? If not, should this return + // an error or default to what? For now we default to foreground. + WindowOpenDisposition disposition = + !action.has_foreground() || action.foreground() + ? WindowOpenDisposition::NEW_FOREGROUND_TAB + : WindowOpenDisposition::NEW_BACKGROUND_TAB; + + return std::make_unique<CreateTabToolRequest>(window_id, disposition); +} + +std::unique_ptr<ToolRequest> CreateActivateTabRequest( + const ActivateTabAction& action, + TabInterface* deprecated_fallback_tab) { + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = tabs::TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } else { + return nullptr; + } + + return std::make_unique<ActivateTabToolRequest>(tab_handle); +} + +std::unique_ptr<ToolRequest> CreateCloseTabRequest( + const CloseTabAction& action, + TabInterface* deprecated_fallback_tab) { + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = tabs::TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } else { + return nullptr; + } + + return std::make_unique<CloseTabToolRequest>(tab_handle); +} + +std::unique_ptr<ToolRequest> CreateBackRequest( + const HistoryBackAction& action, + TabInterface* deprecated_fallback_tab) { + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = tabs::TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } else { + return nullptr; + } + + return std::make_unique<HistoryToolRequest>( + tab_handle, HistoryToolRequest::Direction::kBack); +} + +std::unique_ptr<ToolRequest> CreateForwardRequest( + const HistoryForwardAction& action, + TabInterface* deprecated_fallback_tab) { + tabs::TabHandle tab_handle; + if (action.has_tab_id()) { + tab_handle = tabs::TabHandle(action.tab_id()); + } else if (deprecated_fallback_tab) { + tab_handle = deprecated_fallback_tab->GetHandle(); + } else { + return nullptr; + } + + return std::make_unique<HistoryToolRequest>( + tab_handle, HistoryToolRequest::Direction::kForward); +} + +std::unique_ptr<ToolRequest> CreateWaitRequest(const WaitAction& action) { + constexpr base::TimeDelta kWaitTime = base::Seconds(3); + return std::make_unique<WaitToolRequest>(kWaitTime); } } // namespace -const ActionTarget* ExtractTarget(const Action& action) { +std::unique_ptr<ToolRequest> CreateToolRequest( + const optimization_guide::proto::Action& action, + TabInterface* deprecated_fallback_tab) { switch (action.action_case()) { - case Action::ActionCase::kClick: - if (!action.click().has_target()) { - return nullptr; - } - return &action.click().target(); - case Action::ActionCase::kType: - if (!action.type().has_target()) { - return nullptr; - } - return &action.type().target(); - case Action::ActionCase::kScroll: - if (!action.scroll().has_target()) { - return nullptr; - } - return &action.scroll().target(); - case Action::ActionCase::kMoveMouse: - if (!action.move_mouse().has_target()) { - return nullptr; - } - return &action.move_mouse().target(); - case Action::ActionCase::kDragAndRelease: - if (!action.drag_and_release().has_from_target()) { - return nullptr; - } - return &action.drag_and_release().from_target(); - case Action::ActionCase::kSelect: - if (!action.select().has_target()) { - return nullptr; - } - return &action.select().target(); - case Action::ActionCase::kNavigate: - case Action::ActionCase::kBack: - case Action::ActionCase::kForward: - case Action::ActionCase::kWait: - case Action::ActionCase::kCreateTab: - case Action::ActionCase::kCloseTab: - case Action::ActionCase::kActivateTab: - case Action::ActionCase::kCreateWindow: - case Action::ActionCase::kCloseWindow: - case Action::ActionCase::kActivateWindow: - case Action::ActionCase::kYieldToUser: - case Action::ActionCase::ACTION_NOT_SET: - return nullptr; - } -} - -RenderFrameHost* GetRenderFrameForDocumentIdentifier( - content::WebContents& web_contents, - std::string_view target_document_token) { - RenderFrameHost* render_frame = nullptr; - web_contents.ForEachRenderFrameHostWithAction([&target_document_token, - &render_frame]( - RenderFrameHost* rfh) { - // Skip inactive frame and its children. - if (!rfh->IsActive()) { - return RenderFrameHost::FrameIterationAction::kSkipChildren; + case optimization_guide::proto::Action::kClick: { + const ClickAction& click_action = action.click(); + return CreateClickRequest(click_action, deprecated_fallback_tab); } - auto* user_data = DocumentIdentifierUserData::GetForCurrentDocument(rfh); - if (user_data && user_data->serialized_token() == target_document_token) { - render_frame = rfh; - return RenderFrameHost::FrameIterationAction::kStop; + case optimization_guide::proto::Action::kType: { + const TypeAction& type_action = action.type(); + return CreateTypeRequest(type_action, deprecated_fallback_tab); } - return RenderFrameHost::FrameIterationAction::kContinue; - }); - return render_frame; -} - -RenderFrameHost* GetRootFrameForWidget(content::WebContents& web_contents, - RenderWidgetHost* rwh) { - RenderFrameHost* root_frame = nullptr; - web_contents.ForEachRenderFrameHostWithAction([rwh, &root_frame]( - RenderFrameHost* rfh) { - if (!rfh->IsActive()) { - return RenderFrameHost::FrameIterationAction::kSkipChildren; + case optimization_guide::proto::Action::kScroll: { + const ScrollAction& scroll_action = action.scroll(); + return CreateScrollRequest(scroll_action, deprecated_fallback_tab); } - // A frame is a local root if it has no parent or if its parent belongs - // to a different widget. We are looking for the local root frame - // associated with the target widget. - if (rfh->GetRenderWidgetHost() == rwh && - (!rfh->GetParent() || rfh->GetParent()->GetRenderWidgetHost() != rwh)) { - root_frame = rfh; - return RenderFrameHost::FrameIterationAction::kStop; + case optimization_guide::proto::Action::kMoveMouse: { + const MoveMouseAction& move_mouse_action = action.move_mouse(); + return CreateMoveMouseRequest(move_mouse_action, deprecated_fallback_tab); } - return RenderFrameHost::FrameIterationAction::kContinue; - }); - return root_frame; -} - -RenderFrameHost* FindTargetLocalRootFrame(WebContents& web_contents, - const Action& action) { - // If the action targets the tab as a whole, the target is the primary main - // frame. - if (IsTargetingTab(action)) { - return web_contents.GetPrimaryMainFrame(); + case optimization_guide::proto::Action::kDragAndRelease: { + const DragAndReleaseAction& drag_action = action.drag_and_release(); + return CreateDragAndReleaseRequest(drag_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kSelect: { + const SelectAction& select_action = action.select(); + return CreateSelectRequest(select_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kNavigate: { + const NavigateAction& navigate_action = action.navigate(); + return CreateNavigateRequest(navigate_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kBack: { + const HistoryBackAction& back_action = action.back(); + return CreateBackRequest(back_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kForward: { + const HistoryForwardAction& forward_action = action.forward(); + return CreateForwardRequest(forward_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kWait: { + const WaitAction& wait_action = action.wait(); + return CreateWaitRequest(wait_action); + } + case optimization_guide::proto::Action::kCreateTab: { + const CreateTabAction& create_tab_action = action.create_tab(); + return CreateCreateTabRequest(create_tab_action); + } + case optimization_guide::proto::Action::kCloseTab: { + const CloseTabAction& close_tab_action = action.close_tab(); + return CreateCloseTabRequest(close_tab_action, deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kActivateTab: { + const ActivateTabAction& activate_tab_action = action.activate_tab(); + return CreateActivateTabRequest(activate_tab_action, + deprecated_fallback_tab); + } + case optimization_guide::proto::Action::kCreateWindow: + case optimization_guide::proto::Action::kCloseWindow: + case optimization_guide::proto::Action::kActivateWindow: + case optimization_guide::proto::Action::kYieldToUser: + NOTIMPLEMENTED(); + break; + case optimization_guide::proto::Action::ACTION_NOT_SET: + ACTOR_LOG() << "Action Type Not Set!"; + break; } - const ActionTarget* target = ExtractTarget(action); - if (!target) { - // A scroll action may not have a target, which indicates scrolling the main - // frame. - if (action.action_case() == Action::kScroll) { - return web_contents.GetPrimaryMainFrame(); - } - ACTOR_LOG() << "Page-level BrowserAction did not specify an ActionTarget."; - return nullptr; - } - - if (target->has_content_node_id()) { - const std::string& serialized_token = - target->document_identifier().serialized_token(); - - RenderFrameHost* target_frame = - GetRenderFrameForDocumentIdentifier(web_contents, serialized_token); - // After finding the target frame, walk up to its local root. - return GetLocalRoot(target_frame); - } - - if (target->has_coordinate()) { - const gfx::PointF target_point = - gfx::PointF(target->coordinate().x(), target->coordinate().y()); - RenderWidgetHost* target_rwh = web_contents.FindWidgetAtPoint(target_point); - if (!target_rwh) { - return nullptr; - } - return GetRootFrameForWidget(web_contents, target_rwh); - } - - ACTOR_LOG() << "Page-level BrowserAction ActionTarget is invalid."; return nullptr; }
diff --git a/chrome/browser/actor/browser_action_util.h b/chrome/browser/actor/browser_action_util.h index ada981d..6f9eee7 100644 --- a/chrome/browser/actor/browser_action_util.h +++ b/chrome/browser/actor/browser_action_util.h
@@ -5,50 +5,35 @@ #ifndef CHROME_BROWSER_ACTOR_BROWSER_ACTION_UTIL_H_ #define CHROME_BROWSER_ACTOR_BROWSER_ACTION_UTIL_H_ -#include <string_view> +#include <memory> -namespace content { -class RenderFrameHost; -class RenderWidgetHost; -class WebContents; -} // namespace content +// Conversion function for turning optimization_guide::proto::* types into +// ToolRequests usable by the actor framework. +// TODO(bokan): Rename to actor_proto_conversion.h|cc namespace optimization_guide::proto { class Action; -class ActionTarget; -class DocumentIdentifier; } // namespace optimization_guide::proto +namespace tabs { +class TabInterface; +} + namespace actor { +class ToolRequest; -// Helper to pick out the ActionTarget from the specific type of action in the -// Action proto. Returns nullptr actions which don't contain this -// field (tab-targeting actions). -const optimization_guide::proto::ActionTarget* ExtractTarget( - const optimization_guide::proto::Action& action); - -// Iterates through the frame tree to find the active RenderFrameHost associated -// with a given DocumentIdentifier. -content::RenderFrameHost* GetRenderFrameForDocumentIdentifier( - content::WebContents& web_contents, - const std::string_view target_document_token); - -// Iterates through the frame tree to find the local root RenderFrameHost -// associated with a given RenderWidgetHost. A local root is a frame that is -// the highest in its frame subtree to be associated with the widget. -content::RenderFrameHost* GetRootFrameForWidget( - content::WebContents& web_contents, - content::RenderWidgetHost* rwh); - -// Finds local root frame in the given WebContents that's requested by the -// given action. For a tab-targeting action, this returns the current primary -// main frame. For frame-targeting actions, this returns a nullptr if the -// frame is no longer active or has a new document since the action was -// generated. Otherwise it returns the local root RenderFrameHost that contains -// the target node or coordinate. -content::RenderFrameHost* FindTargetLocalRootFrame( - content::WebContents& web_contents, - const optimization_guide::proto::Action& action); +// Build a ToolRequest from the provided optimization_guide Action proto. If the +// action proto doesn't provide a tab_id, and the fallback_tab parameter is +// provided (non-null), the fallback_tab will be used as the acting tab. +// However, this parameter will eventually be phased out and clients will be +// expected to always provide a tab id on each Action. Returns nullptr if the +// action is invalid. +// TODO(https://crbug.com/411462297): The client should eventually always +// provide a tab id for actions where one is needed. Remove this parameter when +// that's done. +std::unique_ptr<ToolRequest> CreateToolRequest( + const optimization_guide::proto::Action& action, + tabs::TabInterface* deprecated_fallback_tab); } // namespace actor
diff --git a/chrome/browser/actor/execution_engine.cc b/chrome/browser/actor/execution_engine.cc index deadb22..8a28152 100644 --- a/chrome/browser/actor/execution_engine.cc +++ b/chrome/browser/actor/execution_engine.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/actor/browser_action_util.h" #include "chrome/browser/actor/site_policy.h" #include "chrome/browser/actor/tools/tool_controller.h" +#include "chrome/browser/actor/tools/tool_request.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" @@ -27,9 +28,7 @@ #include "chrome/common/actor/action_result.h" #include "chrome/common/chrome_features.h" #include "components/optimization_guide/content/browser/page_content_proto_provider.h" -#include "components/optimization_guide/content/browser/page_content_proto_util.h" #include "components/optimization_guide/proto/features/actions_data.pb.h" -#include "components/optimization_guide/proto/features/common_quality_data.pb.h" #include "components/tabs/public/tab_interface.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" @@ -83,36 +82,6 @@ } } -// Whether the action requires a frame. -bool ActionRequiresFrame(const Action& action) { - switch (action.action_case()) { - case Action::kClick: - case Action::kType: - case Action::kScroll: - case Action::kMoveMouse: - case Action::kDragAndRelease: - case Action::kSelect: - return true; - // TODO(crbug.com/411462297): These requests do not require frames. For now - // we return `true` to preserve existing behavior. - case Action::kBack: - case Action::kForward: - case Action::kNavigate: - case Action::kWait: - return true; - - case Action::kCreateTab: - case Action::kCloseTab: - case Action::kActivateTab: - case Action::kCreateWindow: - case Action::kCloseWindow: - case Action::kActivateWindow: - case Action::kYieldToUser: - case Action::ACTION_NOT_SET: - return false; - } -} - tabs::TabHandle GetTabHandleFromAction( const optimization_guide::proto::Action& action) { switch (action.action_case()) { @@ -183,51 +152,6 @@ FROM_HERE, base::BindOnce(std::move(callback), std::move(result))); } -// Perform validation based on APC and document identifier for coordinate based -// target to compare the candidate frame with the target frame identified in -// last observation. -bool ValidateTargetFrameCandidate( - const ActionTarget* target, - RenderFrameHost* candidate_frame, - WebContents& web_contents, - AnnotatedPageContent* last_observed_page_content) { - std::string target_document_token; - // The document identifier in the action itself takes highest precedence. - if (target->has_document_identifier()) { - target_document_token = target->document_identifier().serialized_token(); - } else if (last_observed_page_content) { - // Otherwise, fall back to APC hit testing. - // TODO(crbug.com/426021822): FindNodeAtPoint does not handle corner cases - // like clip paths. Need more checks to ensure we don't drop actions - // unnecessarily. - std::optional<optimization_guide::TargetNodeInfo> target_node_info = - optimization_guide::FindNodeAtPoint(*last_observed_page_content, - target->coordinate()); - if (target_node_info) { - target_document_token = - target_node_info->document_identifier.serialized_token(); - } else { - return false; - } - } else { - // An error if document identifier isn't set on target and no cached APC - // available - return false; - } - - RenderFrameHost* apc_target_frame = - GetRenderFrameForDocumentIdentifier(web_contents, target_document_token); - - // Only return the candidate if its RenderWidgetHost matches the target - // and it's also a local root frame(i.e. has no parent or parent has - // a different RenderWidgetHost) - if (apc_target_frame && apc_target_frame->GetRenderWidgetHost() == - candidate_frame->GetRenderWidgetHost()) { - return true; - } - return false; -} - } // namespace ExecutionEngine::ExecutionEngine(Profile* profile) @@ -258,6 +182,7 @@ void ExecutionEngine::SetOwner(ActorTask* task) { task_ = task; + tool_controller_ = std::make_unique<ToolController>(task_->id(), *journal_); } // static @@ -433,50 +358,23 @@ void ExecutionEngine::ExecuteNextAction() { CHECK(actions_v1_ || actions_v2_); + CHECK(tool_controller_); const Action& action = GetNextAction(); ++action_index_; - tabs::TabInterface* tab = GetTab(action); - - if (ActionRequiresTab(action) && !tab) { + // TODO(bokan): ExecutionEngine shouldn't know about the Action proto, it + // should operate in terms of ToolRequest. + std::unique_ptr<ToolRequest> tool_request = CreateToolRequest(action, tab_); + if (!tool_request) { journal_->Log(GURL::EmptyGURL(), task_->id(), "Act Failed", - "The tab is no longer present"); - CompleteActions(MakeResult(mojom::ActionResultCode::kTabWentAway, - "The tab is no longer present.")); + "Failed to convert ActionInformation proto to ToolRequest"); + CompleteActions(MakeResult(mojom::ActionResultCode::kArgumentsInvalid)); return; } - RenderFrameHost* target_frame_candidate = nullptr; - if (ActionRequiresFrame(action)) { - target_frame_candidate = - FindTargetLocalRootFrame(*tab->GetContents(), action); - if (!target_frame_candidate) { - journal_->Log(LastCommittedURLOfCurrentTask(), task_->id(), "Act Failed", - "The target frame is no longer present in the tab."); - CompleteActions( - MakeResult(mojom::ActionResultCode::kFrameWentAway, - "The target frame is no longer present in the tab.")); - return; - } - - const ActionTarget* target = ExtractTarget(action); - - // Perform validation for coordinate based target only. - if (target && target->has_coordinate() && - !ValidateTargetFrameCandidate(target, target_frame_candidate, - *tab->GetContents(), - last_observed_page_content_.get())) { - journal_->Log(LastCommittedURLOfCurrentTask(), task_->id(), "Act Failed", - "The target frame has changed."); - CompleteActions(MakeResult( - mojom::ActionResultCode::kFrameLocationChangedSinceObservation, - "The target frame has changed.")); - return; - } - } - tool_controller_.Invoke( - action, *journal_, task_->id(), tab, target_frame_candidate, + tool_controller_->Invoke( + std::move(tool_request), last_observed_page_content_.get(), base::BindOnce(&ExecutionEngine::FinishOneAction, GetWeakPtr())); }
diff --git a/chrome/browser/actor/execution_engine.h b/chrome/browser/actor/execution_engine.h index 6cebd1a..3f11edc 100644 --- a/chrome/browser/actor/execution_engine.h +++ b/chrome/browser/actor/execution_engine.h
@@ -170,7 +170,9 @@ // Owns `this`. raw_ptr<ActorTask> task_; - ToolController tool_controller_; + // Created when task_ is set. Handles execution details for an individual tool + // request. + std::unique_ptr<ToolController> tool_controller_; // A sequence of actions that the model has requested. When it is finished // being processed it is reset.
diff --git a/chrome/browser/actor/tools/click_tool_request.cc b/chrome/browser/actor/tools/click_tool_request.cc new file mode 100644 index 0000000..15a6bcd --- /dev/null +++ b/chrome/browser/actor/tools/click_tool_request.cc
@@ -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. + +#include "chrome/browser/actor/tools/click_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +ClickToolRequest::ClickToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + ClickType type, + ClickCount count) + : PageToolRequest(tab_handle, document_identifier, target), + click_type_(type), + click_count_(count) {} + +ClickToolRequest::~ClickToolRequest() = default; + +std::string ClickToolRequest::JournalEvent() const { + return "Click"; +} + +mojom::ToolActionPtr ClickToolRequest::ToMojoToolAction() const { + auto click = mojom::ClickAction::New(); + + click->target = PageToolRequest::ToMojoToolTarget(GetTarget()); + + switch (click_type_) { + case ClickType::kLeft: + click->type = actor::mojom::ClickAction::Type::kLeft; + break; + case ClickType::kRight: + click->type = actor::mojom::ClickAction::Type::kRight; + break; + } + + switch (click_count_) { + case ClickCount::kSingle: + click->count = actor::mojom::ClickAction::Count::kSingle; + break; + case ClickCount::kDouble: + click->count = actor::mojom::ClickAction::Count::kDouble; + break; + } + + return mojom::ToolAction::NewClick(std::move(click)); +} + +std::unique_ptr<PageToolRequest> ClickToolRequest::Clone() const { + return std::make_unique<ClickToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/click_tool_request.h b/chrome/browser/actor/tools/click_tool_request.h new file mode 100644 index 0000000..cff83f3 --- /dev/null +++ b/chrome/browser/actor/tools/click_tool_request.h
@@ -0,0 +1,42 @@ +// 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_ACTOR_TOOLS_CLICK_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_CLICK_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +class ClickToolRequest : public PageToolRequest { + public: + enum class ClickType { kLeft, kRight }; + enum class ClickCount { kSingle, kDouble }; + + ClickToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + ClickType type, + ClickCount count); + ~ClickToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; + + private: + ClickType click_type_; + ClickCount click_count_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_CLICK_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/drag_and_release_tool_request.cc b/chrome/browser/actor/tools/drag_and_release_tool_request.cc new file mode 100644 index 0000000..4ce8671 --- /dev/null +++ b/chrome/browser/actor/tools/drag_and_release_tool_request.cc
@@ -0,0 +1,41 @@ +// 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/actor/tools/drag_and_release_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +DragAndReleaseToolRequest::DragAndReleaseToolRequest( + TabHandle tab_handle, + std::string_view document_identifier, + const Target& from_target, + const Target& to_target) + : PageToolRequest(tab_handle, document_identifier, from_target), + from_target_(from_target), + to_target_(to_target) {} + +DragAndReleaseToolRequest::~DragAndReleaseToolRequest() = default; + +std::string DragAndReleaseToolRequest::JournalEvent() const { + return "DragAndRelease"; +} + +mojom::ToolActionPtr DragAndReleaseToolRequest::ToMojoToolAction() const { + auto drag = mojom::DragAndReleaseAction::New(); + + drag->from_target = PageToolRequest::ToMojoToolTarget(from_target_); + drag->to_target = PageToolRequest::ToMojoToolTarget(to_target_); + + return mojom::ToolAction::NewDragAndRelease(std::move(drag)); +} + +std::unique_ptr<PageToolRequest> DragAndReleaseToolRequest::Clone() const { + return std::make_unique<DragAndReleaseToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/drag_and_release_tool_request.h b/chrome/browser/actor/tools/drag_and_release_tool_request.h new file mode 100644 index 0000000..31d331c --- /dev/null +++ b/chrome/browser/actor/tools/drag_and_release_tool_request.h
@@ -0,0 +1,41 @@ +// 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_ACTOR_TOOLS_DRAG_AND_RELEASE_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_DRAG_AND_RELEASE_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +// Simulates a mouse press, move, release sequence. As this is a PageTool, the +// sequence can only span a local subtree (i.e. cannot drag and drop between +// OOPIFs or RenderWidgetHosts). +class DragAndReleaseToolRequest : public PageToolRequest { + public: + DragAndReleaseToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& from_target, + const Target& to_target); + ~DragAndReleaseToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; + + private: + Target from_target_; + Target to_target_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_DRAG_AND_RELEASE_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/history_tool.cc b/chrome/browser/actor/tools/history_tool.cc index 2c0b9ef..e5098739 100644 --- a/chrome/browser/actor/tools/history_tool.cc +++ b/chrome/browser/actor/tools/history_tool.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/actor/tools/history_tool.h" #include "base/time/time.h" +#include "chrome/browser/actor/tools/observation_delay_controller.h" #include "chrome/browser/actor/tools/tool_callbacks.h" #include "chrome/common/actor.mojom.h" #include "chrome/common/actor/action_result.h" @@ -29,8 +30,11 @@ using ::content::NavigationController; using ::content::NavigationHandle; using ::content::WebContents; +using ::tabs::TabHandle; +using ::tabs::TabInterface; -HistoryTool::HistoryTool(WebContents& web_contents, Direction direction) +HistoryTool::HistoryTool(WebContents& web_contents, + HistoryToolRequest::Direction direction) : WebContentsObserver(&web_contents), direction_(direction) {} HistoryTool::~HistoryTool() = default; @@ -39,9 +43,11 @@ NavigationController& controller = web_contents()->GetController(); mojom::ActionResultPtr result; - if (direction_ == kBack && !controller.CanGoBack()) { + if (direction_ == HistoryToolRequest::Direction::kBack && + !controller.CanGoBack()) { result = MakeResult(mojom::ActionResultCode::kHistoryNoBackEntries); - } else if (direction_ == kForward && !controller.CanGoForward()) { + } else if (direction_ == HistoryToolRequest::Direction::kForward && + !controller.CanGoForward()) { result = MakeResult(mojom::ActionResultCode::kHistoryNoForwardEntries); } else { result = MakeOkResult(); @@ -69,10 +75,10 @@ // is manually dismissed by the user but we may want to provide automatic // resolution here. - if (direction_ == kBack) { + if (direction_ == HistoryToolRequest::Direction::kBack) { pending_navigations_ = web_contents()->GetController().GoBack(); } else { - CHECK_EQ(direction_, kForward); + CHECK_EQ(direction_, HistoryToolRequest::Direction::kForward); pending_navigations_ = web_contents()->GetController().GoForward(); } @@ -93,7 +99,14 @@ } std::string HistoryTool::JournalEvent() const { - return direction_ == kBack ? "Back" : "Forward"; + return direction_ == HistoryToolRequest::Direction::kBack ? "Back" + : "Forward"; +} + +std::unique_ptr<ObservationDelayController> HistoryTool::GetObservationDelayer() + const { + return std::make_unique<ObservationDelayController>( + *web_contents()->GetPrimaryMainFrame()); } void HistoryTool::DidStartNavigation(NavigationHandle* navigation_handle) {
diff --git a/chrome/browser/actor/tools/history_tool.h b/chrome/browser/actor/tools/history_tool.h index 1a03fc5..6262ee5 100644 --- a/chrome/browser/actor/tools/history_tool.h +++ b/chrome/browser/actor/tools/history_tool.h
@@ -5,12 +5,16 @@ #ifndef CHROME_BROWSER_ACTOR_TOOLS_HISTORY_TOOL_H_ #define CHROME_BROWSER_ACTOR_TOOLS_HISTORY_TOOL_H_ +#include <memory> #include <optional> #include <vector> #include "base/memory/weak_ptr.h" +#include "chrome/browser/actor/tools/history_tool_request.h" #include "chrome/browser/actor/tools/tool.h" +#include "chrome/browser/actor/tools/tool_request.h" #include "chrome/common/actor.mojom-forward.h" +#include "components/tabs/public/tab_interface.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/web_contents_observer.h" #include "third_party/abseil-cpp/absl/container/flat_hash_set.h" @@ -25,12 +29,8 @@ // Performs a history navigation in a WebContents. class HistoryTool : public Tool, content::WebContentsObserver { public: - enum Direction { - kBack, - kForward, - }; - - HistoryTool(content::WebContents& web_contents, Direction direction); + HistoryTool(content::WebContents& web_contents, + HistoryToolRequest::Direction direction); ~HistoryTool() override; // actor::Tool @@ -38,6 +38,8 @@ void Invoke(InvokeCallback callback) override; std::string DebugString() const override; std::string JournalEvent() const override; + std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const override; // content::WebContentsObserver void DidStartNavigation( @@ -53,7 +55,7 @@ bool IsInvokeInProgress() const; // Whether the navigation is backwards or forwards in session history. - Direction direction_; + HistoryToolRequest::Direction direction_; // This class tracks all navigation handles created as a result of the history // traversal in `pending_navigations_`. However, these navigations may or may
diff --git a/chrome/browser/actor/tools/history_tool_request.cc b/chrome/browser/actor/tools/history_tool_request.cc new file mode 100644 index 0000000..ded0730 --- /dev/null +++ b/chrome/browser/actor/tools/history_tool_request.cc
@@ -0,0 +1,38 @@ +// 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/actor/tools/history_tool_request.h" + +#include "chrome/browser/actor/tools/history_tool.h" +#include "chrome/common/actor.mojom.h" +#include "chrome/common/actor/action_result.h" + +namespace actor { + +using ::tabs::TabHandle; +using ::tabs::TabInterface; + +HistoryToolRequest::HistoryToolRequest(tabs::TabHandle tab, Direction direction) + : TabToolRequest(tab), direction_(direction) {} +HistoryToolRequest::~HistoryToolRequest() = default; + +ToolRequest::CreateToolResult HistoryToolRequest::CreateTool( + AggregatedJournal& journal) const { + TabInterface* tab = GetTabHandle().Get(); + + if (!tab) { + return {/*tool=*/nullptr, MakeResult(mojom::ActionResultCode::kTabWentAway, + "The tab is no longer present.")}; + } + + CHECK(tab->GetContents()); + return {std::make_unique<HistoryTool>(*tab->GetContents(), direction_), + MakeOkResult()}; +} + +std::string HistoryToolRequest::JournalEvent() const { + return "History"; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/history_tool_request.h b/chrome/browser/actor/tools/history_tool_request.h new file mode 100644 index 0000000..16f9c17 --- /dev/null +++ b/chrome/browser/actor/tools/history_tool_request.h
@@ -0,0 +1,38 @@ +// 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_ACTOR_TOOLS_HISTORY_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_HISTORY_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/common/actor.mojom-forward.h" +#include "url/gurl.h" + +namespace actor { + +// Invokes a history back or forward traversal in a specified tab. +class HistoryToolRequest : public TabToolRequest { + public: + enum class Direction { + kBack, + kForward, + }; + + HistoryToolRequest(tabs::TabHandle handle, Direction direction); + ~HistoryToolRequest() override; + + // ToolRequest + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; + + // Whether the navigation is backwards or forwards in session history. + Direction direction_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_HISTORY_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/move_mouse_tool_request.cc b/chrome/browser/actor/tools/move_mouse_tool_request.cc new file mode 100644 index 0000000..41a1a3a --- /dev/null +++ b/chrome/browser/actor/tools/move_mouse_tool_request.cc
@@ -0,0 +1,36 @@ +// 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/actor/tools/move_mouse_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +MoveMouseToolRequest::MoveMouseToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target) + : PageToolRequest(tab_handle, document_identifier, target) {} + +MoveMouseToolRequest::~MoveMouseToolRequest() = default; + +std::string MoveMouseToolRequest::JournalEvent() const { + return "MoveMouse"; +} + +mojom::ToolActionPtr MoveMouseToolRequest::ToMojoToolAction() const { + auto move_mouse = mojom::MouseMoveAction::New(); + + move_mouse->target = PageToolRequest::ToMojoToolTarget(GetTarget()); + + return mojom::ToolAction::NewMouseMove(std::move(move_mouse)); +} + +std::unique_ptr<PageToolRequest> MoveMouseToolRequest::Clone() const { + return std::make_unique<MoveMouseToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/move_mouse_tool_request.h b/chrome/browser/actor/tools/move_mouse_tool_request.h new file mode 100644 index 0000000..fbd1a2d --- /dev/null +++ b/chrome/browser/actor/tools/move_mouse_tool_request.h
@@ -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. + +#ifndef CHROME_BROWSER_ACTOR_TOOLS_MOVE_MOUSE_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_MOVE_MOUSE_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +// Injects a mouse move event at the given target. +class MoveMouseToolRequest : public PageToolRequest { + public: + MoveMouseToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target); + ~MoveMouseToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_MOVE_MOUSE_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/navigate_tool.cc b/chrome/browser/actor/tools/navigate_tool.cc index a0b0f963..07edfea 100644 --- a/chrome/browser/actor/tools/navigate_tool.cc +++ b/chrome/browser/actor/tools/navigate_tool.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/actor/tools/navigate_tool.h" +#include "chrome/browser/actor/tools/observation_delay_controller.h" #include "chrome/browser/actor/tools/tool_callbacks.h" #include "chrome/common/actor.mojom.h" #include "chrome/common/actor/action_result.h" @@ -62,6 +63,12 @@ return "Navigate"; } +std::unique_ptr<ObservationDelayController> +NavigateTool::GetObservationDelayer() const { + return std::make_unique<ObservationDelayController>( + *web_contents()->GetPrimaryMainFrame()); +} + void NavigateTool::DidFinishNavigation(NavigationHandle* navigation_handle) { // TODO(crbug.com/411748801): We should probably handle the case where the // page navigates before it's done loading. Common with client-side redirects.
diff --git a/chrome/browser/actor/tools/navigate_tool.h b/chrome/browser/actor/tools/navigate_tool.h index 38c3cba..8a5f771 100644 --- a/chrome/browser/actor/tools/navigate_tool.h +++ b/chrome/browser/actor/tools/navigate_tool.h
@@ -30,6 +30,8 @@ void Invoke(InvokeCallback callback) override; std::string DebugString() const override; std::string JournalEvent() const override; + std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const override; // content::WebContentsObserver void DidFinishNavigation(
diff --git a/chrome/browser/actor/tools/navigate_tool_request.cc b/chrome/browser/actor/tools/navigate_tool_request.cc new file mode 100644 index 0000000..518db2b --- /dev/null +++ b/chrome/browser/actor/tools/navigate_tool_request.cc
@@ -0,0 +1,37 @@ +// 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/actor/tools/navigate_tool_request.h" + +#include "chrome/browser/actor/tools/navigate_tool.h" +#include "chrome/common/actor.mojom.h" +#include "chrome/common/actor/action_result.h" + +namespace actor { + +using ::tabs::TabHandle; +using ::tabs::TabInterface; + +NavigateToolRequest::NavigateToolRequest(TabHandle tab_handle, GURL url) + : TabToolRequest(tab_handle), url_(url) {} + +NavigateToolRequest::~NavigateToolRequest() = default; + +ToolRequest::CreateToolResult NavigateToolRequest::CreateTool( + AggregatedJournal& journal) const { + TabInterface* tab = GetTabHandle().Get(); + if (!tab) { + return {/*tool=*/nullptr, MakeResult(mojom::ActionResultCode::kTabWentAway, + "The tab is no longer present.")}; + } + + return {std::make_unique<NavigateTool>(*tab->GetContents(), url_), + MakeOkResult()}; +} + +std::string NavigateToolRequest::JournalEvent() const { + return "Navigate"; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/navigate_tool_request.h b/chrome/browser/actor/tools/navigate_tool_request.h new file mode 100644 index 0000000..642c737 --- /dev/null +++ b/chrome/browser/actor/tools/navigate_tool_request.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. + +#ifndef CHROME_BROWSER_ACTOR_TOOLS_NAVIGATE_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_NAVIGATE_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/common/actor.mojom-forward.h" +#include "url/gurl.h" + +namespace actor { + +// Navigates a specified tab to a specified URL. +class NavigateToolRequest : public TabToolRequest { + public: + NavigateToolRequest(tabs::TabHandle tab_handle, GURL url); + ~NavigateToolRequest() override; + + // ToolRequest + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; + + private: + GURL url_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_NAVIGATE_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/page_tool.cc b/chrome/browser/actor/tools/page_tool.cc index 84c6b9ea..bf703e56 100644 --- a/chrome/browser/actor/tools/page_tool.cc +++ b/chrome/browser/actor/tools/page_tool.cc
@@ -8,9 +8,16 @@ #include "base/task/sequenced_task_runner.h" #include "chrome/browser/actor/aggregated_journal.h" #include "chrome/browser/actor/execution_engine.h" +#include "chrome/browser/actor/tools/observation_delay_controller.h" +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/common/actor.mojom-forward.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 "components/optimization_guide/content/browser/page_content_proto_provider.h" +#include "components/optimization_guide/content/browser/page_content_proto_util.h" +#include "components/optimization_guide/proto/features/common_quality_data.pb.h" +#include "components/tabs/public/tab_interface.h" #include "content/public/browser/global_routing_id.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -20,173 +27,159 @@ #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "ui/gfx/geometry/point.h" -namespace { +namespace actor { using ::content::GlobalRenderFrameHostId; using ::content::RenderFrameHost; +using ::content::RenderWidgetHost; using ::content::WebContents; using ::content::WebContentsObserver; -using ::optimization_guide::proto::Action; -using ::optimization_guide::proto::ActionTarget; -using ::optimization_guide::proto::ClickAction_ClickCount; -using ::optimization_guide::proto::ClickAction_ClickType; -using ::optimization_guide::proto::ScrollAction_ScrollDirection; -using ::optimization_guide::proto::TypeAction_TypeMode; +using ::optimization_guide::DocumentIdentifierUserData; +using optimization_guide::proto::ActionTarget; +using optimization_guide::proto::AnnotatedPageContent; +using ::tabs::TabHandle; +using ::tabs::TabInterface; -void SetMojoTarget(const ActionTarget& target, - actor::mojom::ToolTargetPtr& out_mojo_target) { - if (target.has_coordinate()) { - out_mojo_target = actor::mojom::ToolTarget::NewCoordinate( - gfx::Point(target.coordinate().x(), target.coordinate().y())); - } else { - // A ContentNodeId of 0 indicates the viewport. The mojo message indicates - // viewport by omitting a target. - if (target.content_node_id() > 0) { - out_mojo_target = - actor::mojom::ToolTarget::NewDomNodeId(target.content_node_id()); +namespace { + +// Finds the local root of a given RenderFrameHost. The local root is the +// highest ancestor in the frame tree that shares the same RenderWidgetHost. +RenderFrameHost* GetLocalRoot(RenderFrameHost* rfh) { + RenderFrameHost* local_root = rfh; + while (local_root && local_root->GetParent()) { + if (local_root->GetRenderWidgetHost() != + local_root->GetParent()->GetRenderWidgetHost()) { + break; } + local_root = local_root->GetParent(); } + return local_root; } -// Set mojom for click action based on proto. Returns false if the proto does -// not contain correct/sufficient information, true otherwise. -bool SetClickToolArgs(actor::mojom::ClickActionPtr& click, - const Action& action) { - SetMojoTarget(action.click().target(), click->target); - - switch (action.click().click_type()) { - case ClickAction_ClickType::ClickAction_ClickType_LEFT: - click->type = actor::mojom::ClickAction::Type::kLeft; - break; - case ClickAction_ClickType::ClickAction_ClickType_RIGHT: - click->type = actor::mojom::ClickAction::Type::kRight; - break; - case ClickAction_ClickType::ClickAction_ClickType_UNKNOWN_CLICK_TYPE: - case ClickAction_ClickType:: - ClickAction_ClickType_ClickAction_ClickType_INT_MAX_SENTINEL_DO_NOT_USE_: - case ClickAction_ClickType:: - ClickAction_ClickType_ClickAction_ClickType_INT_MIN_SENTINEL_DO_NOT_USE_: - // TODO(issuetracker.google.com/412700289): Revert once this is set. - click->type = actor::mojom::ClickAction::Type::kLeft; - break; - // return false; - } - - switch (action.click().click_count()) { - case ClickAction_ClickCount::ClickAction_ClickCount_SINGLE: - click->count = actor::mojom::ClickAction::Count::kSingle; - break; - case ClickAction_ClickCount::ClickAction_ClickCount_DOUBLE: - click->count = actor::mojom::ClickAction::Count::kDouble; - break; - case ClickAction_ClickCount::ClickAction_ClickCount_UNKNOWN_CLICK_COUNT: - case ClickAction_ClickCount:: - ClickAction_ClickCount_ClickAction_ClickCount_INT_MIN_SENTINEL_DO_NOT_USE_: - case ClickAction_ClickCount:: - ClickAction_ClickCount_ClickAction_ClickCount_INT_MAX_SENTINEL_DO_NOT_USE_: - // TODO(issuetracker.google.com/412700289): Revert once this is set. - click->count = actor::mojom::ClickAction::Count::kSingle; - break; - // return false; - } - return true; +RenderFrameHost* GetRenderFrameForDocumentIdentifier( + content::WebContents& web_contents, + std::string_view target_document_token) { + RenderFrameHost* render_frame = nullptr; + web_contents.ForEachRenderFrameHostWithAction([&target_document_token, + &render_frame]( + RenderFrameHost* rfh) { + // Skip inactive frame and its children. + if (!rfh->IsActive()) { + return RenderFrameHost::FrameIterationAction::kSkipChildren; + } + auto* user_data = DocumentIdentifierUserData::GetForCurrentDocument(rfh); + if (user_data && user_data->serialized_token() == target_document_token) { + render_frame = rfh; + return RenderFrameHost::FrameIterationAction::kStop; + } + return RenderFrameHost::FrameIterationAction::kContinue; + }); + return render_frame; } -// Set mojom for mouse move action based on proto. -void SetMouseMoveToolArgs(actor::mojom::MouseMoveActionPtr& move, - const Action& action) { - SetMojoTarget(action.move_mouse().target(), move->target); +RenderFrameHost* GetRootFrameForWidget(content::WebContents& web_contents, + RenderWidgetHost* rwh) { + RenderFrameHost* root_frame = nullptr; + web_contents.ForEachRenderFrameHostWithAction([rwh, &root_frame]( + RenderFrameHost* rfh) { + if (!rfh->IsActive()) { + return RenderFrameHost::FrameIterationAction::kSkipChildren; + } + // A frame is a local root if it has no parent or if its parent belongs + // to a different widget. We are looking for the local root frame + // associated with the target widget. + if (rfh->GetRenderWidgetHost() == rwh && + (!rfh->GetParent() || rfh->GetParent()->GetRenderWidgetHost() != rwh)) { + root_frame = rfh; + return RenderFrameHost::FrameIterationAction::kStop; + } + return RenderFrameHost::FrameIterationAction::kContinue; + }); + return root_frame; } -// Set mojom for type action based on proto. -// Returns false if the proto does not contain correct/sufficient information, -// true otherwise. -bool SetTypeToolArgs(actor::mojom::TypeActionPtr& type_action, - const Action& action) { - SetMojoTarget(action.type().target(), type_action->target); - - type_action->text = action.type().text(); - type_action->follow_by_enter = action.type().follow_by_enter(); - - // Map proto enum to mojom enum - switch (action.type().mode()) { - case TypeAction_TypeMode::TypeAction_TypeMode_DELETE_EXISTING: - type_action->mode = actor::mojom::TypeAction::Mode::kDeleteExisting; - break; - case TypeAction_TypeMode::TypeAction_TypeMode_PREPEND: - type_action->mode = actor::mojom::TypeAction::Mode::kPrepend; - break; - case TypeAction_TypeMode::TypeAction_TypeMode_APPEND: - type_action->mode = actor::mojom::TypeAction::Mode::kAppend; - break; - case TypeAction_TypeMode::TypeAction_TypeMode_UNKNOWN_TYPE_MODE: - case TypeAction_TypeMode:: - TypeAction_TypeMode_TypeAction_TypeMode_INT_MIN_SENTINEL_DO_NOT_USE_: - case TypeAction_TypeMode:: - TypeAction_TypeMode_TypeAction_TypeMode_INT_MAX_SENTINEL_DO_NOT_USE_: - // TODO(issuetracker.google.com/412700289): Revert once this is set. - type_action->mode = actor::mojom::TypeAction::Mode::kDeleteExisting; - break; - // DLOG(ERROR) << "TypeAction proto type mode not supported" - // << action.type().mode(); - // return false; +RenderFrameHost* FindTargetLocalRootFrame( + TabHandle tab_handle, + std::optional<std::string> document_identifier, + PageToolRequest::Target target) { + TabInterface* tab = tab_handle.Get(); + if (!tab) { + return nullptr; } - return true; -} + WebContents& contents = *tab->GetContents(); -bool SetScrollToolArgs(actor::mojom::ScrollActionPtr& scroll, - const Action& action) { - if (action.scroll().has_target()) { - SetMojoTarget(action.scroll().target(), scroll->target); + if (std::holds_alternative<PageToolRequest::CoordinateTarget>(target)) { + auto coordinate = std::get<PageToolRequest::CoordinateTarget>(target); + + RenderWidgetHost* target_rwh = + contents.FindWidgetAtPoint(gfx::PointF(coordinate)); + if (!target_rwh) { + return nullptr; + } + return GetRootFrameForWidget(contents, target_rwh); } - switch (action.scroll().direction()) { - case ScrollAction_ScrollDirection::ScrollAction_ScrollDirection_LEFT: - scroll->direction = actor::mojom::ScrollAction::ScrollDirection::kLeft; - break; - case ScrollAction_ScrollDirection::ScrollAction_ScrollDirection_RIGHT: - scroll->direction = actor::mojom::ScrollAction::ScrollDirection::kRight; - break; - case ScrollAction_ScrollDirection::ScrollAction_ScrollDirection_UP: - scroll->direction = actor::mojom::ScrollAction::ScrollDirection::kUp; - break; - case ScrollAction_ScrollDirection::ScrollAction_ScrollDirection_DOWN: - scroll->direction = actor::mojom::ScrollAction::ScrollDirection::kDown; - break; - case ScrollAction_ScrollDirection:: - ScrollAction_ScrollDirection_UNKNOWN_SCROLL_DIRECTION: - case ScrollAction_ScrollDirection:: - ScrollAction_ScrollDirection_ScrollAction_ScrollDirection_INT_MIN_SENTINEL_DO_NOT_USE_: - case ScrollAction_ScrollDirection:: - ScrollAction_ScrollDirection_ScrollAction_ScrollDirection_INT_MAX_SENTINEL_DO_NOT_USE_: - // TODO(issuetracker.google.com/412700289): Revert once this is set. - scroll->direction = actor::mojom::ScrollAction::ScrollDirection::kDown; - break; - // return false; + + CHECK(std::holds_alternative<PageToolRequest::NodeTarget>(target)); + + CHECK(document_identifier.has_value()); + const std::string& serialized_token = document_identifier.value(); + + RenderFrameHost* target_frame = GetRenderFrameForDocumentIdentifier( + *tab->GetContents(), serialized_token); + + // After finding the target frame, walk up to its local root. + return GetLocalRoot(target_frame); +} + +// Perform validation based on APC and document identifier for coordinate based +// target to compare the candidate frame with the target frame identified in +// last observation. +bool ValidateTargetFrameCandidate( + const PageToolRequest::Target& target, + RenderFrameHost* candidate_frame, + WebContents& web_contents, + const AnnotatedPageContent* last_observed_page_content) { + // Frame validation is performed only when targeting using coordinates. + CHECK(std::holds_alternative<PageToolRequest::CoordinateTarget>(target)); + + if (!last_observed_page_content) { + // TODO(bokan): We can't perform a TOCTOU check If there's no last + // observation. Consider what to do in this case. + return true; } - scroll->distance = action.scroll().distance(); - return true; -} -void SetSelectToolArgs(actor::mojom::SelectActionPtr& select, - const Action& action) { - SetMojoTarget(action.select().target(), select->target); - select->value = action.select().value(); -} + // TODO(bokan): This helper should take a gfx::Point. + auto coordinate = std::get<PageToolRequest::CoordinateTarget>(target); + optimization_guide::proto::Coordinate apc_coordinate; + apc_coordinate.set_x(coordinate.x()); + apc_coordinate.set_y(coordinate.y()); -void SetDragAndReleaseToolArgs( - actor::mojom::DragAndReleaseActionPtr& drag_and_release, - Action action) { - SetMojoTarget(action.drag_and_release().from_target(), - drag_and_release->from_target); - SetMojoTarget(action.drag_and_release().to_target(), - drag_and_release->to_target); + // TODO(crbug.com/426021822): FindNodeAtPoint does not handle corner cases + // like clip paths. Need more checks to ensure we don't drop actions + // unnecessarily. + std::optional<optimization_guide::TargetNodeInfo> target_node_info = + optimization_guide::FindNodeAtPoint(*last_observed_page_content, + apc_coordinate); + if (!target_node_info) { + return false; + } + + RenderFrameHost* apc_target_frame = GetRenderFrameForDocumentIdentifier( + web_contents, target_node_info->document_identifier.serialized_token()); + + // Only return the candidate if its RenderWidgetHost matches the target + // and it's also a local root frame(i.e. has no parent or parent has + // a different RenderWidgetHost) + if (apc_target_frame && apc_target_frame->GetRenderWidgetHost() == + candidate_frame->GetRenderWidgetHost()) { + return true; + } + return false; } } // namespace -namespace actor { - // Observer to track if the a given RenderFrameHost is changed. class RenderFrameChangeObserver : public WebContentsObserver { public: @@ -212,11 +205,17 @@ base::OnceClosure callback_; }; -PageTool::PageTool(AggregatedJournal& journal, - RenderFrameHost& frame, - const Action& action) - : render_frame_host_(frame.GetWeakDocumentPtr()), action_(action) { - journal.EnsureJournalBound(frame); +PageTool::PageTool(const PageToolRequest& request, AggregatedJournal& journal) + : request_(request.Clone()) { + // TODO(crbug.com/411462297): We shouldn't assume we have a frame until TOCTOU + // checks are done - a frame should only be resolved at that time. Same for + // tab. + RenderFrameHost* frame = FindTargetLocalRootFrame( + request.GetTabHandle(), request.DocumentIdentifier(), + request.GetTarget()); + if (frame) { + journal.EnsureJournalBound(*frame); + } } PageTool::~PageTool() = default; @@ -227,77 +226,46 @@ FROM_HERE, base::BindOnce(std::move(callback), MakeOkResult())); } +mojom::ActionResultPtr PageTool::TimeOfUseValidation( + const AnnotatedPageContent* last_observation) const { + RenderFrameHost* frame = FindTargetLocalRootFrame( + request_->GetTabHandle(), request_->DocumentIdentifier(), + request_->GetTarget()); + if (!frame) { + return MakeResult(mojom::ActionResultCode::kFrameWentAway); + } + + TabInterface* tab = request_->GetTabHandle().Get(); + // If the frame still exists the tab must as well. + CHECK(tab); + + // Perform validation for coordinate based target only. + if (std::holds_alternative<PageToolRequest::CoordinateTarget>( + request_->GetTarget())) { + if (!ValidateTargetFrameCandidate(request_->GetTarget(), frame, + *tab->GetContents(), last_observation)) { + return MakeResult( + mojom::ActionResultCode::kFrameLocationChangedSinceObservation); + } + } + + return MakeOkResult(); +} + void PageTool::Invoke(InvokeCallback callback) { invoke_callback_ = std::move(callback); - RenderFrameHost* frame = render_frame_host_.AsRenderFrameHostIfValid(); - if (!frame) { - PostFinishInvoke(mojom::ActionResultCode::kFrameWentAway); - return; - } + + // Frame was validated in TimeOfUseValidation. + RenderFrameHost* frame = FindTargetLocalRootFrame( + request_->GetTabHandle(), request_->DocumentIdentifier(), + request_->GetTarget()); + CHECK(frame); auto request = actor::mojom::ToolInvocation::New(); + request->action = request_->ToMojoToolAction(); - switch (action_.action_case()) { - case Action::ActionCase::kClick: { - auto click = mojom::ClickAction::New(); - if (!SetClickToolArgs(click, action_)) { - PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); - return; - } - request->action = mojom::ToolAction::NewClick(std::move(click)); - break; - } - case Action::ActionCase::kType: { - auto type = mojom::TypeAction::New(); - if (!SetTypeToolArgs(type, action_)) { - PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); - return; - } - request->action = mojom::ToolAction::NewType(std::move(type)); - break; - } - case Action::ActionCase::kScroll: { - auto scroll = mojom::ScrollAction::New(); - if (!SetScrollToolArgs(scroll, action_)) { - PostFinishInvoke(mojom::ActionResultCode::kArgumentsInvalid); - return; - } - request->action = mojom::ToolAction::NewScroll(std::move(scroll)); - break; - } - case Action::ActionCase::kMoveMouse: { - auto mouse_move = mojom::MouseMoveAction::New(); - SetMouseMoveToolArgs(mouse_move, action_); - request->action = mojom::ToolAction::NewMouseMove(std::move(mouse_move)); - break; - } - case Action::ActionCase::kDragAndRelease: { - auto drag_and_release = mojom::DragAndReleaseAction::New(); - SetDragAndReleaseToolArgs(drag_and_release, action_); - request->action = - mojom::ToolAction::NewDragAndRelease(std::move(drag_and_release)); - break; - } - case Action::ActionCase::kSelect: { - auto select = mojom::SelectAction::New(); - SetSelectToolArgs(select, action_); - request->action = mojom::ToolAction::NewSelect(std::move(select)); - break; - } - case Action::ActionCase::kNavigate: - case Action::ActionCase::kBack: - case Action::ActionCase::kForward: - case Action::ActionCase::kWait: - case Action::kCreateTab: - case Action::kCloseTab: - case Action::kActivateTab: - case Action::kCreateWindow: - case Action::kCloseWindow: - case Action::kActivateWindow: - case Action::kYieldToUser: - case Action::ActionCase::ACTION_NOT_SET: - NOTREACHED(); - } + // ToolRequest params are checked for validity at creation. + CHECK(request->action); frame->GetRemoteAssociatedInterfaces()->GetInterface(&chrome_render_frame_); @@ -339,40 +307,23 @@ return absl::StrFormat("PageTool:%s", JournalEvent().c_str()); } +GURL PageTool::JournalURL() const { + return request_->GetURLForJournal(); +} + std::string PageTool::JournalEvent() const { - switch (action_.action_case()) { - case Action::ActionCase::kClick: { - return "Click"; - } - case Action::ActionCase::kType: { - return "Type"; - } - case Action::ActionCase::kScroll: { - return "Scroll"; - } - case Action::ActionCase::kMoveMouse: { - return "MoveMouse"; - } - case Action::ActionCase::kDragAndRelease: { - return "DragAndRelease"; - } - case Action::ActionCase::kSelect: { - return "Select"; - } - case Action::ActionCase::kNavigate: - case Action::ActionCase::kBack: - case Action::ActionCase::kForward: - case Action::ActionCase::kWait: - case Action::kCreateTab: - case Action::kCloseTab: - case Action::kActivateTab: - case Action::kCreateWindow: - case Action::kCloseWindow: - case Action::kActivateWindow: - case Action::kYieldToUser: - case Action::ActionCase::ACTION_NOT_SET: - NOTREACHED(); - } + return request_->JournalEvent(); +} + +std::unique_ptr<ObservationDelayController> PageTool::GetObservationDelayer() + const { + RenderFrameHost* frame = FindTargetLocalRootFrame( + request_->GetTabHandle(), request_->DocumentIdentifier(), + request_->GetTarget()); + // It's the caller's responsibility to ensure a frame is still live if calling + // this method. + CHECK(frame); + return std::make_unique<ObservationDelayController>(*frame); } void PageTool::FinishInvoke(mojom::ActionResultPtr result) {
diff --git a/chrome/browser/actor/tools/page_tool.h b/chrome/browser/actor/tools/page_tool.h index 490b3099..6032223 100644 --- a/chrome/browser/actor/tools/page_tool.h +++ b/chrome/browser/actor/tools/page_tool.h
@@ -9,19 +9,17 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/actor/tools/tool.h" +#include "chrome/browser/actor/tools/tool_request.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 { -class RenderFrameHost; -} - namespace actor { class AggregatedJournal; +class PageToolRequest; class RenderFrameChangeObserver; // A page tool is any tool implemented in the renderer by ToolExecutor. This @@ -29,16 +27,20 @@ // of the request to the renderer. class PageTool : public Tool { public: - PageTool(AggregatedJournal& journal, - content::RenderFrameHost& frame, - const optimization_guide::proto::Action& action); + PageTool(const PageToolRequest& params, AggregatedJournal& journal); ~PageTool() override; // actor::Tool void Validate(ValidateCallback callback) override; + mojom::ActionResultPtr TimeOfUseValidation( + const optimization_guide::proto::AnnotatedPageContent* last_observation) + const override; void Invoke(InvokeCallback callback) override; std::string DebugString() const override; + GURL JournalURL() const override; std::string JournalEvent() const override; + std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const override; private: void FinishInvoke(mojom::ActionResultPtr result); @@ -46,9 +48,8 @@ void PostFinishInvoke(mojom::ActionResultCode result_code); InvokeCallback invoke_callback_; - content::WeakDocumentPtr render_frame_host_; + std::unique_ptr<PageToolRequest> request_; std::unique_ptr<RenderFrameChangeObserver> frame_change_observer_; - optimization_guide::proto::Action action_; mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> chrome_render_frame_; base::WeakPtrFactory<PageTool> weak_ptr_factory_{this};
diff --git a/chrome/browser/actor/tools/page_tool_request.cc b/chrome/browser/actor/tools/page_tool_request.cc new file mode 100644 index 0000000..00cf5fd --- /dev/null +++ b/chrome/browser/actor/tools/page_tool_request.cc
@@ -0,0 +1,64 @@ +// 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/actor/tools/page_tool_request.h" + +#include "chrome/browser/actor/tools/page_tool.h" +#include "chrome/common/actor.mojom.h" +#include "chrome/common/actor/action_result.h" +#include "chrome/common/actor/actor_constants.h" +#include "components/optimization_guide/content/browser/page_content_proto_provider.h" +#include "components/tabs/public/tab_interface.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" + +namespace actor { + +using content::RenderFrameHost; +using content::WebContents; +using optimization_guide::DocumentIdentifierUserData; +using tabs::TabHandle; + +// static +mojom::ToolTargetPtr PageToolRequest::ToMojoToolTarget(const Target& target) { + if (std::holds_alternative<CoordinateTarget>(target)) { + return actor::mojom::ToolTarget::NewCoordinate( + std::get<CoordinateTarget>(target)); + } + + NodeTarget node_id = std::get<NodeTarget>(target); + return actor::mojom::ToolTarget::NewDomNodeId( + node_id.value_or(kRootElementDomNodeId)); +} + +PageToolRequest::PageToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target) + : TabToolRequest(tab_handle), + document_identifier_(document_identifier), + target_(target) {} + +PageToolRequest::~PageToolRequest() = default; + +PageToolRequest::PageToolRequest(const PageToolRequest& other) = default; + +ToolRequest::CreateToolResult PageToolRequest::CreateTool( + AggregatedJournal& journal) const { + if (!GetTabHandle().Get()) { + return {/*tool=*/nullptr, MakeResult(mojom::ActionResultCode::kTabWentAway, + "The tab is no longer present.")}; + } + + return {std::make_unique<PageTool>(*this, journal), MakeOkResult()}; +} + +const std::optional<std::string>& PageToolRequest::DocumentIdentifier() const { + return document_identifier_; +} + +const PageToolRequest::Target& PageToolRequest::GetTarget() const { + return target_; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/page_tool_request.h b/chrome/browser/actor/tools/page_tool_request.h new file mode 100644 index 0000000..56c048c --- /dev/null +++ b/chrome/browser/actor/tools/page_tool_request.h
@@ -0,0 +1,73 @@ +// 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_ACTOR_TOOLS_PAGE_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_PAGE_TOOL_REQUEST_H_ + +#include <memory> +#include <string> +#include <string_view> + +#include "chrome/browser/actor/tools/tool_request.h" +#include "components/tabs/public/tab_interface.h" +#include "content/public/browser/weak_document_ptr.h" +#include "url/gurl.h" + +namespace actor { + +class AggregatedJournal; + +// Tool requests targeting a specific, existing document should inherit from +// this subclass. Being page-scoped implies also being tab-scoped since a page +// exists inside a tab. +class PageToolRequest : public TabToolRequest { + public: + // Page tool requests must specify a target within the document. This must be + // one of: + // * A coordinate, relative to the local root origin + // * A specific node, specified by DOMNodeId. If not set, targets the root + // element / viewport. + using NodeTarget = std::optional<int>; + using CoordinateTarget = gfx::Point; + using Target = std::variant<NodeTarget, CoordinateTarget>; + + // A document identifier is optional if a CoordinateTarget. It is required + // when using a NodeTarget. + // TODO(crbug.com/411462297): Put document identifier into the Target type. + PageToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target); + ~PageToolRequest() override; + PageToolRequest(const PageToolRequest& other); + + // Converts this request into the ToolAction mojo message which can be + // executed in the renderer. + virtual mojom::ToolActionPtr ToMojoToolAction() const = 0; + + virtual std::unique_ptr<PageToolRequest> Clone() const = 0; + + // ToolRequest + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + + // The provided document identifier in which this request should act. nullopt + // if using coordinates in which case the target document must be hit tested + // from coordinates. + const std::optional<std::string>& DocumentIdentifier() const; + + // Returns what in the page the tool should act upon. + const Target& GetTarget() const; + + protected: + // Helper usable by child classes when implementing ToMojoToolAction. + // Constructs an actor::mojom::ToolTarget from a PageToolRequest::Target. + static mojom::ToolTargetPtr ToMojoToolTarget(const Target& target); + + private: + std::optional<std::string> document_identifier_; + Target target_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_PAGE_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/scroll_tool_request.cc b/chrome/browser/actor/tools/scroll_tool_request.cc new file mode 100644 index 0000000..4ce3de6c --- /dev/null +++ b/chrome/browser/actor/tools/scroll_tool_request.cc
@@ -0,0 +1,56 @@ +// 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/actor/tools/scroll_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +ScrollToolRequest::ScrollToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + Direction direction, + float distance) + : PageToolRequest(tab_handle, document_identifier, target), + direction_(direction), + distance_(distance) {} + +ScrollToolRequest::~ScrollToolRequest() = default; + +std::string ScrollToolRequest::JournalEvent() const { + return "Scroll"; +} + +mojom::ToolActionPtr ScrollToolRequest::ToMojoToolAction() const { + auto scroll = mojom::ScrollAction::New(); + + scroll->target = PageToolRequest::ToMojoToolTarget(GetTarget()); + switch (direction_) { + case Direction::kLeft: + scroll->direction = mojom::ScrollAction::ScrollDirection::kLeft; + break; + case Direction::kRight: + scroll->direction = mojom::ScrollAction::ScrollDirection::kRight; + break; + case Direction::kUp: + scroll->direction = mojom::ScrollAction::ScrollDirection::kUp; + break; + case Direction::kDown: + scroll->direction = mojom::ScrollAction::ScrollDirection::kDown; + break; + } + + scroll->distance = distance_; + + return mojom::ToolAction::NewScroll(std::move(scroll)); +} + +std::unique_ptr<PageToolRequest> ScrollToolRequest::Clone() const { + return std::make_unique<ScrollToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/scroll_tool_request.h b/chrome/browser/actor/tools/scroll_tool_request.h new file mode 100644 index 0000000..a9bc006b --- /dev/null +++ b/chrome/browser/actor/tools/scroll_tool_request.h
@@ -0,0 +1,45 @@ +// 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_ACTOR_TOOLS_SCROLL_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_SCROLL_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +// Scrolls an element or viewport in the page a given distance. +class ScrollToolRequest : public PageToolRequest { + public: + enum class Direction { kLeft, kRight, kUp, kDown }; + + // Programmatically scrolls the scroller specified by target a given distance. + // If Target is a nullopt ContentNodeId, the root viewport is scrolled. + // Distance is specified in physical pixels. + ScrollToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + Direction direction, + float distance); + ~ScrollToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; + + private: + Direction direction_; + float distance_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_SCROLL_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/select_tool_request.cc b/chrome/browser/actor/tools/select_tool_request.cc new file mode 100644 index 0000000..5848584b --- /dev/null +++ b/chrome/browser/actor/tools/select_tool_request.cc
@@ -0,0 +1,38 @@ +// 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/actor/tools/select_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +SelectToolRequest::SelectToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + std::string_view value) + : PageToolRequest(tab_handle, document_identifier, target), value_(value) {} + +SelectToolRequest::~SelectToolRequest() = default; + +std::string SelectToolRequest::JournalEvent() const { + return "Select"; +} + +mojom::ToolActionPtr SelectToolRequest::ToMojoToolAction() const { + auto select = mojom::SelectAction::New(); + + select->target = PageToolRequest::ToMojoToolTarget(GetTarget()); + select->value = value_; + + return mojom::ToolAction::NewSelect(std::move(select)); +} + +std::unique_ptr<PageToolRequest> SelectToolRequest::Clone() const { + return std::make_unique<SelectToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/select_tool_request.h b/chrome/browser/actor/tools/select_tool_request.h new file mode 100644 index 0000000..28f1401 --- /dev/null +++ b/chrome/browser/actor/tools/select_tool_request.h
@@ -0,0 +1,41 @@ +// 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_ACTOR_TOOLS_SELECT_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_SELECT_TOOL_REQUEST_H_ + +#include <memory> +#include <string> +#include <string_view> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +// Chooses an option in a <select> box on the page based on the value attribute +// of the <option> children. +class SelectToolRequest : public PageToolRequest { + public: + SelectToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + std::string_view value); + ~SelectToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; + + private: + // The <option> whose value attribute matches this parameter will be selected. + std::string value_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_SELECT_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/tab_management_tool.cc b/chrome/browser/actor/tools/tab_management_tool.cc index c0ae0ef9..eb88a19 100644 --- a/chrome/browser/actor/tools/tab_management_tool.cc +++ b/chrome/browser/actor/tools/tab_management_tool.cc
@@ -4,12 +4,14 @@ #include "chrome/browser/actor/tools/tab_management_tool.h" +#include "chrome/browser/actor/tools/observation_delay_controller.h" #include "chrome/browser/actor/tools/tool_callbacks.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" #include "chrome/common/actor.mojom.h" #include "chrome/common/actor/action_result.h" #include "components/sessions/core/session_id.h" +#include "components/tabs/public/tab_interface.h" #include "content/public/browser/web_contents.h" #include "third_party/abseil-cpp/absl/strings/str_format.h" #include "ui/base/window_open_disposition.h" @@ -18,10 +20,16 @@ namespace actor { -TabManagementTool::TabManagementTool( - int32_t window_id, - const optimization_guide::proto::CreateTabAction& action) - : window_id_(window_id), action_(action) {} +using ::tabs::TabHandle; + +TabManagementTool::TabManagementTool(int32_t window_id, + WindowOpenDisposition create_disposition) + : action_(Action::kCreate), + create_disposition_(create_disposition), + window_id_(window_id) {} + +TabManagementTool::TabManagementTool(Action action, TabHandle tab_handle) + : action_(action), target_tab_(tab_handle) {} TabManagementTool::~TabManagementTool() = default; @@ -30,25 +38,35 @@ } void TabManagementTool::Invoke(InvokeCallback callback) { - BrowserWindowInterface* browser_window_interface = - BrowserWindowInterface::FromSessionID( - SessionID::FromSerializedValue(window_id_)); - if (!browser_window_interface) { - PostResponseTask(std::move(callback), - MakeResult(mojom::ActionResultCode::kWindowWentAway)); - return; + // TODO(crbug.com/411462297): Only the create action is hooked up and + // implemented. + switch (action_) { + case kCreate: { + CHECK(window_id_.has_value()); + CHECK(create_disposition_.has_value()); + BrowserWindowInterface* browser_window_interface = + BrowserWindowInterface::FromSessionID( + SessionID::FromSerializedValue(window_id_.value())); + if (!browser_window_interface) { + PostResponseTask(std::move(callback), + MakeResult(mojom::ActionResultCode::kWindowWentAway)); + return; + } + + // Open a blank tab. + browser_window_interface->OpenGURL(GURL(url::kAboutBlankURL), + create_disposition_.value()); + break; + } + case kActivate: + case kClose: + CHECK(target_tab_.has_value()); + NOTIMPLEMENTED() << "ActivateTab and CloseTab not yet implemented"; + PostResponseTask(std::move(callback), + MakeResult(mojom::ActionResultCode::kError)); + return; } - // TODO(bokan): Is the foreground bit always set? If not, should this return - // an error or default to what? For now we default to foreground. - WindowOpenDisposition disposition = - (!action_.has_foreground() || action_.foreground()) - ? WindowOpenDisposition::NEW_FOREGROUND_TAB - : WindowOpenDisposition::NEW_BACKGROUND_TAB; - - // Open a blank tab. - browser_window_interface->OpenGURL(GURL(url::kAboutBlankURL), disposition); - PostResponseTask(std::move(callback), MakeOkResult()); } @@ -57,13 +75,19 @@ } std::string TabManagementTool::JournalEvent() const { - return "CreateTab"; + switch (action_) { + case kCreate: + return "CreateTab"; + case kActivate: + return "ActivateTab"; + case kClose: + return "CloseTab"; + } } -bool TabManagementTool::RequiresFrame() const { - // This is to avoid the kFrameWentAway check in - // ToolController::ValidationComplete. - return false; +std::unique_ptr<ObservationDelayController> +TabManagementTool::GetObservationDelayer() const { + return nullptr; } } // namespace actor
diff --git a/chrome/browser/actor/tools/tab_management_tool.h b/chrome/browser/actor/tools/tab_management_tool.h index a0c0bd5..0fd1725 100644 --- a/chrome/browser/actor/tools/tab_management_tool.h +++ b/chrome/browser/actor/tools/tab_management_tool.h
@@ -7,17 +7,26 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/actor/tools/tool.h" -#include "components/optimization_guide/proto/features/actions_data.pb.h" +#include "chrome/browser/actor/tools/tool_request.h" +#include "ui/base/window_open_disposition.h" namespace actor { +class ObservationDelayController; + // A tool to manage the tabs in a browser window, e.g. create, close, // activate, etc. // TODO(crbug.com/411462297): Implement actions other than create. class TabManagementTool : public Tool { public: - TabManagementTool(int32_t window_id, - const optimization_guide::proto::CreateTabAction& action); + enum Action { kCreate, kActivate, kClose }; + + // Public for std::make_unique, use For* static methods above. + // Create constructor + TabManagementTool(int32_t window, WindowOpenDisposition create_disposition); + // Activate|Close constructor. + TabManagementTool(Action action, tabs::TabHandle target_tab); + ~TabManagementTool() override; // actor::Tool: @@ -25,11 +34,20 @@ void Invoke(InvokeCallback callback) override; std::string DebugString() const override; std::string JournalEvent() const override; - bool RequiresFrame() const override; + std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const override; private: - int32_t window_id_; - const optimization_guide::proto::CreateTabAction action_; + Action action_; + + // Used for activate or close action. + std::optional<tabs::TabHandle> target_tab_; + + // If creating a tab, whether to create in the foreground. + std::optional<WindowOpenDisposition> create_disposition_; + + // If creating a tab, the window in which to create the tab. + std::optional<int32_t> window_id_; base::WeakPtrFactory<TabManagementTool> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/actor/tools/tab_management_tool_request.cc b/chrome/browser/actor/tools/tab_management_tool_request.cc new file mode 100644 index 0000000..7174618a --- /dev/null +++ b/chrome/browser/actor/tools/tab_management_tool_request.cc
@@ -0,0 +1,74 @@ +// 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/actor/tools/tab_management_tool_request.h" + +#include <memory> + +#include "chrome/browser/actor/tools/tab_management_tool.h" +#include "chrome/common/actor/action_result.h" + +namespace actor { + +using tabs::TabInterface; + +CreateTabToolRequest::CreateTabToolRequest(int32_t window_id, + WindowOpenDisposition disposition) + : window_id_(window_id), disposition_(disposition) {} + +CreateTabToolRequest::~CreateTabToolRequest() = default; + +ToolRequest::CreateToolResult CreateTabToolRequest::CreateTool( + AggregatedJournal& journal) const { + return {std::make_unique<TabManagementTool>(window_id_, disposition_), + MakeOkResult()}; +} + +std::string CreateTabToolRequest::JournalEvent() const { + return "CreateTab"; +} + +ActivateTabToolRequest::ActivateTabToolRequest(tabs::TabHandle tab_handle) + : TabToolRequest(tab_handle) {} + +ActivateTabToolRequest::~ActivateTabToolRequest() = default; + +ToolRequest::CreateToolResult ActivateTabToolRequest::CreateTool( + AggregatedJournal& journal) const { + TabInterface* tab = GetTabHandle().Get(); + if (!tab) { + return {/*tool=*/nullptr, MakeResult(mojom::ActionResultCode::kTabWentAway, + "The tab is no longer present.")}; + } + return {std::make_unique<TabManagementTool>(TabManagementTool::kActivate, + GetTabHandle()), + MakeOkResult()}; +} + +std::string ActivateTabToolRequest::JournalEvent() const { + return "ActivateTab"; +} + +CloseTabToolRequest::CloseTabToolRequest(tabs::TabHandle tab_handle) + : TabToolRequest(tab_handle) {} + +CloseTabToolRequest::~CloseTabToolRequest() = default; + +ToolRequest::CreateToolResult CloseTabToolRequest::CreateTool( + AggregatedJournal& journal) const { + TabInterface* tab = GetTabHandle().Get(); + if (!tab) { + return {/*tool=*/nullptr, MakeResult(mojom::ActionResultCode::kTabWentAway, + "The tab is no longer present.")}; + } + return {std::make_unique<TabManagementTool>(TabManagementTool::kClose, + GetTabHandle()), + MakeOkResult()}; +} + +std::string CloseTabToolRequest::JournalEvent() const { + return "CloseTab"; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/tab_management_tool_request.h b/chrome/browser/actor/tools/tab_management_tool_request.h new file mode 100644 index 0000000..355970c --- /dev/null +++ b/chrome/browser/actor/tools/tab_management_tool_request.h
@@ -0,0 +1,51 @@ +// 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_ACTOR_TOOLS_TAB_MANAGEMENT_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_TAB_MANAGEMENT_TOOL_REQUEST_H_ + +#include <string> + +#include "chrome/browser/actor/tools/tool_request.h" +#include "ui/base/window_open_disposition.h" + +namespace actor { + +// Creates a new blank tab in the specified window. +class CreateTabToolRequest : public ToolRequest { + public: + enum class Disposition { kForeground, kBackground }; + + CreateTabToolRequest(int32_t window_id, WindowOpenDisposition disposition); + ~CreateTabToolRequest() override; + + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; + + private: + int32_t window_id_; + WindowOpenDisposition disposition_; +}; + +// Brings the specified tab to the foreground. +class ActivateTabToolRequest : public TabToolRequest { + public: + explicit ActivateTabToolRequest(tabs::TabHandle tab); + ~ActivateTabToolRequest() override; + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; +}; + +// Closes the specified tab to the foreground. +class CloseTabToolRequest : public TabToolRequest { + public: + explicit CloseTabToolRequest(tabs::TabHandle tab); + ~CloseTabToolRequest() override; + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_TAB_MANAGEMENT_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/tool.cc b/chrome/browser/actor/tools/tool.cc index 75c24c7..ea9dcf9 100644 --- a/chrome/browser/actor/tools/tool.cc +++ b/chrome/browser/actor/tools/tool.cc
@@ -4,19 +4,19 @@ #include "chrome/browser/actor/tools/tool.h" -#include <memory> - -#include "chrome/browser/actor/tools/observation_delay_controller.h" +#include "chrome/common/actor/action_result.h" namespace actor { -std::unique_ptr<ObservationDelayController> Tool::GetObservationDelayer( - content::RenderFrameHost& target_frame) const { - return std::make_unique<ObservationDelayController>(target_frame); +mojom::ActionResultPtr Tool::TimeOfUseValidation( + const optimization_guide::proto::AnnotatedPageContent* last_observation) + const { + // TODO(crbug.com/411462297): This should be made pure-virtual. + return MakeOkResult(); } -bool Tool::RequiresFrame() const { - return true; +GURL Tool::JournalURL() const { + return GURL::EmptyGURL(); } } // namespace actor
diff --git a/chrome/browser/actor/tools/tool.h b/chrome/browser/actor/tools/tool.h index 57fab05..b0a5107 100644 --- a/chrome/browser/actor/tools/tool.h +++ b/chrome/browser/actor/tools/tool.h
@@ -9,11 +9,13 @@ #include <string> #include "base/functional/callback_forward.h" -#include "chrome/common/actor.mojom-forward.h" +#include "chrome/browser/actor/aggregated_journal.h" +#include "chrome/common/actor.mojom.h" +#include "url/gurl.h" -namespace content { -class RenderFrameHost; -} // namespace content +namespace optimization_guide::proto { +class AnnotatedPageContent; +} // namespace optimization_guide::proto namespace actor { @@ -37,6 +39,16 @@ // the tool will be destroyed. virtual void Validate(ValidateCallback callback) = 0; + // Perform any synchronous time-of-use checks just before invoking the tool. + // These are typically TOCTOU (time-of-check/time-of-use) validations that the + // live state of the page/browser still matches what the client can see as of + // the last observation snapshot. This is a synchronous check so there are no + // further opportunities for changes to the live browser state before invoking + // the tool. + virtual mojom::ActionResultPtr TimeOfUseValidation( + const optimization_guide::proto::AnnotatedPageContent* last_observation) + const; + // Perform the action of the tool. The given callback must be invoked when the // tool has finished its actions. virtual void Invoke(InvokeCallback callback) = 0; @@ -45,22 +57,19 @@ // debugging purposes. virtual std::string DebugString() const = 0; + // Provides the URL to be recorded in journal entries for this tool. This can + // be an empty URL for tool not associated with a tab/frame or if the + // tab/frame is no longer available. + virtual GURL JournalURL() const; + // Provides a journal event name. virtual std::string JournalEvent() const = 0; // Returns an optional delay object that can be used to delay completion of - // the tool until some external conditions are met. By default, this returns - // an object that watches for loading navigations and waits until load is - // completed and a new frame presented. - virtual std::unique_ptr<ObservationDelayController> GetObservationDelayer( - content::RenderFrameHost& target_frame) const; - - // Whether or not the tool requires a frame to operate on. Note, this also - // includes "tab-scoped" tools which are considered to operate on the "main - // frame" in the tab. - // TODO(crbug.com/411462297): Temporary until we have a better mechanism for - // non-frame-scoped tools. - virtual bool RequiresFrame() const; + // the tool until some external conditions are met, typically waiting on a + // loading navigation to settle. + virtual std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const = 0; }; } // namespace actor
diff --git a/chrome/browser/actor/tools/tool_controller.cc b/chrome/browser/actor/tools/tool_controller.cc index 534dd51c..bfa2618b 100644 --- a/chrome/browser/actor/tools/tool_controller.cc +++ b/chrome/browser/actor/tools/tool_controller.cc
@@ -5,142 +5,67 @@ #include "chrome/browser/actor/tools/tool_controller.h" #include <memory> +#include <string> #include "base/feature_list.h" #include "base/functional/callback.h" #include "base/memory/safe_ref.h" -#include "base/notimplemented.h" #include "chrome/browser/actor/aggregated_journal.h" -#include "chrome/browser/actor/execution_engine.h" -#include "chrome/browser/actor/tools/history_tool.h" -#include "chrome/browser/actor/tools/navigate_tool.h" -#include "chrome/browser/actor/tools/page_tool.h" -#include "chrome/browser/actor/tools/tab_management_tool.h" #include "chrome/browser/actor/tools/tool.h" #include "chrome/browser/actor/tools/tool_callbacks.h" -#include "chrome/browser/actor/tools/wait_tool.h" -#include "chrome/common/actor.mojom.h" +#include "chrome/browser/actor/tools/tool_request.h" #include "chrome/common/actor/action_result.h" #include "chrome/common/chrome_features.h" -#include "components/optimization_guide/proto/features/actions_data.pb.h" -#include "content/public/browser/weak_document_ptr.h" -#include "content/public/browser/web_contents.h" #include "url/gurl.h" -using content::RenderFrameHost; -using content::WebContents; -using optimization_guide::proto::Action; -using tabs::TabInterface; - namespace actor { -namespace { -const GURL& GetURL(TabInterface* tab, RenderFrameHost* target_frame) { - if (target_frame) { - return target_frame->GetLastCommittedURL(); - } else if (tab) { - return tab->GetContents()->GetLastCommittedURL(); - } - return GURL::EmptyGURL(); -} - -} // namespace +using ::optimization_guide::proto::AnnotatedPageContent; ToolController::ActiveState::ActiveState( std::unique_ptr<Tool> tool, ResultCallback completion_callback, - content::WeakDocumentPtr weak_document_ptr, - std::unique_ptr<AggregatedJournal::PendingAsyncEntry> journal_entry) + std::unique_ptr<AggregatedJournal::PendingAsyncEntry> journal_entry, + const optimization_guide::proto::AnnotatedPageContent* last_observation) : tool(std::move(tool)), completion_callback(std::move(completion_callback)), - weak_document_ptr(weak_document_ptr), - journal_entry(std::move(journal_entry)) { + journal_entry(std::move(journal_entry)), + last_observation(last_observation) { CHECK(this->tool); CHECK(!this->completion_callback.is_null()); } ToolController::ActiveState::~ActiveState() = default; -ToolController::ToolController() { +ToolController::ToolController(TaskId task_id, AggregatedJournal& journal) + : task_id_(task_id), journal_(journal.GetSafeRef()) { CHECK(base::FeatureList::IsEnabled(features::kGlicActor)); } ToolController::~ToolController() = default; -std::unique_ptr<Tool> ToolController::CreateTool(AggregatedJournal& journal, - TaskId task_id, - TabInterface* tab, - RenderFrameHost* frame, - const Action& action) { - switch (action.action_case()) { - case Action::kClick: - case Action::kType: - case Action::kScroll: - case Action::kMoveMouse: - case Action::kDragAndRelease: - case Action::kSelect: { - CHECK(frame); - // PageTools are all implemented in the renderer so share the PageTool - // implementation to shuttle them there. - return std::make_unique<PageTool>(journal, *frame, action); - } - case Action::kNavigate: { - GURL url(action.navigate().url()); - return std::make_unique<NavigateTool>(*tab->GetContents(), url); - } - case Action::kBack: { - return std::make_unique<HistoryTool>(*tab->GetContents(), - HistoryTool::kBack); - } - case Action::kForward: { - return std::make_unique<HistoryTool>(*tab->GetContents(), - HistoryTool::kForward); - } - case Action::kWait: { - return std::make_unique<WaitTool>(); - } - case Action::kCreateTab: { - // Extract the window ID from the action. - int32_t window_id = action.create_tab().window_id(); - return std::make_unique<TabManagementTool>(window_id, - action.create_tab()); - } - case Action::kCloseTab: - case Action::kActivateTab: - case Action::kCreateWindow: - case Action::kCloseWindow: - case Action::kActivateWindow: - case Action::kYieldToUser: - case Action::ACTION_NOT_SET: - NOTREACHED(); - } -} - -void ToolController::Invoke(const Action& action, - AggregatedJournal& journal, - TaskId task_id, - tabs::TabInterface* tab, - content::RenderFrameHost* target_frame, +void ToolController::Invoke(std::unique_ptr<ToolRequest> request, + const AnnotatedPageContent* last_observation, ResultCallback result_callback) { - std::unique_ptr<Tool> created_tool = - CreateTool(journal, task_id, tab, target_frame, action); + CHECK(request); + ToolRequest::CreateToolResult create_result = request->CreateTool(*journal_); - if (!created_tool) { - // Tool not found. + if (!IsOk(*create_result.result)) { + CHECK(!create_result.tool); + journal_->Log(request->GetURLForJournal(), task_id_, + "ToolController Invoke Failed", + create_result.result->message); PostResponseTask(std::move(result_callback), - MakeResult(mojom::ActionResultCode::kToolUnknown)); + std::move(create_result.result)); return; } - auto journal_event = journal.CreatePendingAsyncEntry( - GetURL(tab, target_frame), task_id, created_tool->JournalEvent(), - created_tool->DebugString()); + std::unique_ptr<Tool>& tool = create_result.tool; + CHECK(tool); - content::WeakDocumentPtr document_ptr; - if (target_frame) { - document_ptr = target_frame->GetWeakDocumentPtr(); - } - active_state_.emplace(std::move(created_tool), std::move(result_callback), - document_ptr, std::move(journal_event)); + auto journal_event = journal_->CreatePendingAsyncEntry( + tool->JournalURL(), task_id_, tool->JournalEvent(), tool->DebugString()); + active_state_.emplace(std::move(tool), std::move(result_callback), + std::move(journal_event), last_observation); active_state_->tool->Validate(base::BindOnce( &ToolController::ValidationComplete, weak_ptr_factory_.GetWeakPtr())); @@ -154,18 +79,17 @@ return; } + mojom::ActionResultPtr toctou_result = + active_state_->tool->TimeOfUseValidation(active_state_->last_observation); + if (!IsOk(*toctou_result)) { + CompleteToolRequest(std::move(toctou_result)); + return; + } + // TODO(crbug.com/389739308): Ensure the acting tab remains valid (i.e. alive // and focused), return error otherwise. - if (active_state_->tool->RequiresFrame()) { - RenderFrameHost* target_frame = - active_state_->weak_document_ptr.AsRenderFrameHostIfValid(); - if (!target_frame) { - CompleteToolRequest(MakeResult(mojom::ActionResultCode::kFrameWentAway)); - return; - } - observation_delayer_ = - active_state_->tool->GetObservationDelayer(*target_frame); - } + + observation_delayer_ = active_state_->tool->GetObservationDelayer(); active_state_->tool->Invoke(base::BindOnce( &ToolController::DidFinishToolInvoke, weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/actor/tools/tool_controller.h b/chrome/browser/actor/tools/tool_controller.h index 514ce97..5b0811dc 100644 --- a/chrome/browser/actor/tools/tool_controller.h +++ b/chrome/browser/actor/tools/tool_controller.h
@@ -8,29 +8,21 @@ #include <memory> #include "base/functional/callback.h" +#include "base/memory/raw_ref.h" +#include "base/memory/safe_ref.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/actor/aggregated_journal.h" #include "chrome/browser/actor/task_id.h" #include "chrome/browser/actor/tools/observation_delay_controller.h" #include "chrome/common/actor.mojom-forward.h" +#include "components/optimization_guide/proto/features/common_quality_data.pb.h" #include "content/public/browser/weak_document_ptr.h" -namespace tabs { -class TabInterface; -} // namespace tabs - -namespace content { -class RenderFrameHost; -} // namespace content - -namespace optimization_guide::proto { -class Action; -} // namespace optimization_guide::proto - namespace actor { class AggregatedJournal; class Tool; +class ToolRequest; // Entry point into actor tool usage. ToolController is a profile-scoped, // ExecutionEngine-owned object. This class routes a tool use request to the @@ -39,18 +31,16 @@ class ToolController { public: using ResultCallback = base::OnceCallback<void(mojom::ActionResultPtr)>; - ToolController(); + ToolController(TaskId task_id, AggregatedJournal& journal); ~ToolController(); ToolController(const ToolController&) = delete; ToolController& operator=(const ToolController&) = delete; - // Invokes a tool action. Both `tab` and `target_frame` can be null. - void Invoke(const optimization_guide::proto::Action& action, - AggregatedJournal& journal, - TaskId task_id, - tabs::TabInterface* tab, - content::RenderFrameHost* target_frame, - ResultCallback result_callback); + // Invokes a tool action. + void Invoke( + std::unique_ptr<ToolRequest> request, + const optimization_guide::proto::AnnotatedPageContent* last_observation, + ResultCallback result_callback); private: // Called when the tool itself finishes its invocation. @@ -60,13 +50,6 @@ // the initiator. Must only be called when a tool invocation is in-progress. void CompleteToolRequest(mojom::ActionResultPtr result); - std::unique_ptr<Tool> CreateTool( - AggregatedJournal& journal, - TaskId task_id, - tabs::TabInterface* tab, - content::RenderFrameHost* frame, - const optimization_guide::proto::Action& action); - void ValidationComplete(mojom::ActionResultPtr result); // This state is non-null whenever a tool invocation is in progress. @@ -74,8 +57,9 @@ ActiveState( std::unique_ptr<Tool> tool, ResultCallback completion_callback, - content::WeakDocumentPtr weak_document_ptr, - std::unique_ptr<AggregatedJournal::PendingAsyncEntry> journal_entry); + std::unique_ptr<AggregatedJournal::PendingAsyncEntry> journal_entry, + const optimization_guide::proto::AnnotatedPageContent* + last_observation); ~ActiveState(); ActiveState(const ActiveState&) = delete; ActiveState& operator=(const ActiveState&) = delete; @@ -84,8 +68,9 @@ // active_state_ is set. std::unique_ptr<Tool> tool; ResultCallback completion_callback; - content::WeakDocumentPtr weak_document_ptr; std::unique_ptr<AggregatedJournal::PendingAsyncEntry> journal_entry; + raw_ptr<const optimization_guide::proto::AnnotatedPageContent> + last_observation; }; std::optional<ActiveState> active_state_; @@ -93,6 +78,10 @@ // completion_callback until the page is ready for observation. std::unique_ptr<ObservationDelayController> observation_delayer_; + TaskId task_id_; + + base::SafeRef<AggregatedJournal> journal_; + base::WeakPtrFactory<ToolController> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/actor/tools/tool_request.cc b/chrome/browser/actor/tools/tool_request.cc new file mode 100644 index 0000000..431e9f3c --- /dev/null +++ b/chrome/browser/actor/tools/tool_request.cc
@@ -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. + +#include "chrome/browser/actor/tools/tool_request.h" + +#include "chrome/browser/actor/tools/tool.h" +#include "components/tabs/public/tab_interface.h" +#include "content/public/browser/web_contents.h" + +namespace actor { + +using ::content::WebContents; +using ::tabs::TabHandle; +using ::tabs::TabInterface; + +ToolRequest::CreateToolResult::CreateToolResult(std::unique_ptr<Tool> tool, + mojom::ActionResultPtr result) + : tool(std::move(tool)), result(std::move(result)) {} +ToolRequest::CreateToolResult::~CreateToolResult() = default; + +ToolRequest::ToolRequest() = default; +ToolRequest::~ToolRequest() = default; + +GURL ToolRequest::GetURLForJournal() const { + return GURL::EmptyGURL(); +} + +TabToolRequest::TabToolRequest(const tabs::TabInterface::Handle tab_handle) + : tab_handle_(tab_handle) { + // The given handle need not be valid - the handle is validated at time of + // dereferencing when instantiating a tool. However, it must be a non-null + // value. + CHECK_NE(tab_handle.raw_value(), TabHandle::Null().raw_value()); +} +TabToolRequest::~TabToolRequest() = default; + +GURL TabToolRequest::GetURLForJournal() const { + if (TabInterface* tab = tab_handle_.Get()) { + return tab->GetContents()->GetLastCommittedURL(); + } + return ToolRequest::GetURLForJournal(); +} + +tabs::TabInterface::Handle TabToolRequest::GetTabHandle() const { + return tab_handle_; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/tool_request.h b/chrome/browser/actor/tools/tool_request.h new file mode 100644 index 0000000..37f3f592 --- /dev/null +++ b/chrome/browser/actor/tools/tool_request.h
@@ -0,0 +1,73 @@ +// 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_ACTOR_TOOLS_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_TOOL_REQUEST_H_ + +#include <memory> +#include <string_view> +#include <variant> + +#include "base/types/expected.h" +#include "chrome/browser/actor/task_id.h" +#include "chrome/common/actor.mojom.h" +#include "components/tabs/public/tab_interface.h" +#include "ui/gfx/geometry/point.h" +#include "url/gurl.h" + +namespace actor { + +class AggregatedJournal; +class Tool; + +// Base class for all tool requests. For tools scoped to a tab (e.g. History +// traversal, Navigate) derive from TabToolRequest. For tools operating in a web +// contents, implemented in the renderer, derive from PageToolRequest. Tools not +// scoped to either can derive directly from this class. +class ToolRequest { + public: + ToolRequest(); + virtual ~ToolRequest(); + + // Returns the URL to record in the journal when recording entries for this + // request. This may be empty for requests that aren't tied to a frame/tab or + // if the scoped object no longer exists. + virtual GURL GetURLForJournal() const; + + // Returns the name to use for the journal when recording entries for this + // request. + virtual std::string JournalEvent() const = 0; + + struct CreateToolResult { + CreateToolResult(std::unique_ptr<Tool> tool, mojom::ActionResultPtr result); + ~CreateToolResult(); + std::unique_ptr<Tool> tool; + mojom::ActionResultPtr result; + }; + + // Instantiates the tool requested by this object. + virtual CreateToolResult CreateTool(AggregatedJournal& journal) const = 0; +}; + +// Tool requests targeting a specific, existing tab should inherit from this +// subclass. +class TabToolRequest : public ToolRequest { + public: + explicit TabToolRequest(const tabs::TabInterface::Handle tab_handle); + ~TabToolRequest() override; + + // ToolRequest + GURL GetURLForJournal() const override; + + // Returns a handle to the tab being targeted by this request. This handle + // should never be null but it may be for a tab that is no longer available. + tabs::TabInterface::Handle GetTabHandle() const; + + private: + tabs::TabInterface::Handle tab_handle_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/type_tool_request.cc b/chrome/browser/actor/tools/type_tool_request.cc new file mode 100644 index 0000000..d82e47954 --- /dev/null +++ b/chrome/browser/actor/tools/type_tool_request.cc
@@ -0,0 +1,57 @@ +// 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/actor/tools/type_tool_request.h" + +#include "chrome/common/actor.mojom.h" + +namespace actor { + +using ::tabs::TabHandle; + +TypeToolRequest::TypeToolRequest(TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + std::string_view text, + bool follow_by_enter, + Mode mode) + : PageToolRequest(tab_handle, document_identifier, target), + text(text), + follow_by_enter(follow_by_enter), + mode(mode) {} + +TypeToolRequest::~TypeToolRequest() = default; + +std::string TypeToolRequest::JournalEvent() const { + return "Type"; +} + +mojom::ToolActionPtr TypeToolRequest::ToMojoToolAction() const { + auto type = mojom::TypeAction::New(); + + type->target = PageToolRequest::ToMojoToolTarget(GetTarget()); + + type->text = text; + type->follow_by_enter = follow_by_enter; + + switch (mode) { + case Mode::kReplace: + type->mode = mojom::TypeAction::Mode::kDeleteExisting; + break; + case Mode::kPrepend: + type->mode = mojom::TypeAction::Mode::kPrepend; + break; + case Mode::kAppend: + type->mode = mojom::TypeAction::Mode::kAppend; + break; + } + + return mojom::ToolAction::NewType(std::move(type)); +} + +std::unique_ptr<PageToolRequest> TypeToolRequest::Clone() const { + return std::make_unique<TypeToolRequest>(*this); +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/type_tool_request.h b/chrome/browser/actor/tools/type_tool_request.h new file mode 100644 index 0000000..d47aa8b --- /dev/null +++ b/chrome/browser/actor/tools/type_tool_request.h
@@ -0,0 +1,56 @@ +// 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_ACTOR_TOOLS_TYPE_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_TYPE_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "chrome/browser/actor/tools/page_tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +class TypeToolRequest : public PageToolRequest { + public: + enum class Mode { + // Replace all existing text in the editing context. + kReplace, + + // Insert text before any existing text in the editing context. + kPrepend, + + // Insert text after any existing text in the editing context. + kAppend + }; + + TypeToolRequest(tabs::TabHandle tab_handle, + std::string_view document_identifier, + const Target& target, + std::string_view text, + bool follow_by_enter, + Mode mode); + ~TypeToolRequest() override; + + // ToolRequest + std::string JournalEvent() const override; + + // PageToolRequest + mojom::ToolActionPtr ToMojoToolAction() const override; + std::unique_ptr<PageToolRequest> Clone() const override; + + // Text to type. + std::string text; + + // Whether to inject an enter/return key after typing. + bool follow_by_enter; + + // Behavior with respect to existing text. + Mode mode; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_TYPE_TOOL_REQUEST_H_
diff --git a/chrome/browser/actor/tools/wait_tool.cc b/chrome/browser/actor/tools/wait_tool.cc index 07dd27f..4b3f481 100644 --- a/chrome/browser/actor/tools/wait_tool.cc +++ b/chrome/browser/actor/tools/wait_tool.cc
@@ -14,15 +14,10 @@ namespace actor { -namespace { - -constexpr base::TimeDelta kWaitTime = base::Seconds(3); - -} // namespace - bool WaitTool::no_delay_for_testing_ = false; -WaitTool::WaitTool() = default; +WaitTool::WaitTool(base::TimeDelta wait_duration) + : wait_duration_(wait_duration) {} WaitTool::~WaitTool() = default; @@ -35,7 +30,7 @@ FROM_HERE, base::BindOnce(&WaitTool::OnDelayFinished, weak_ptr_factory_.GetWeakPtr(), std::move(callback)), - no_delay_for_testing_ ? base::TimeDelta() : kWaitTime); + no_delay_for_testing_ ? base::TimeDelta() : wait_duration_); } std::string WaitTool::DebugString() const { @@ -46,8 +41,8 @@ return "Wait"; } -std::unique_ptr<ObservationDelayController> WaitTool::GetObservationDelayer( - content::RenderFrameHost&) const { +std::unique_ptr<ObservationDelayController> WaitTool::GetObservationDelayer() + const { // Wait tool shouldn't delay observation aside from its own built-in delay. return nullptr; }
diff --git a/chrome/browser/actor/tools/wait_tool.h b/chrome/browser/actor/tools/wait_tool.h index 4e86116e..33b30fc 100644 --- a/chrome/browser/actor/tools/wait_tool.h +++ b/chrome/browser/actor/tools/wait_tool.h
@@ -7,13 +7,15 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/actor/tools/tool.h" +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/browser/actor/tools/wait_tool_request.h" namespace actor { // Waits for a page to settle before continuing with other tools. class WaitTool : public Tool { public: - WaitTool(); + explicit WaitTool(base::TimeDelta wait_duration); ~WaitTool() override; // actor::Tool @@ -21,16 +23,20 @@ void Invoke(InvokeCallback callback) override; std::string DebugString() const override; std::string JournalEvent() const override; - std::unique_ptr<ObservationDelayController> GetObservationDelayer( - content::RenderFrameHost& target_frame) const override; + std::unique_ptr<ObservationDelayController> GetObservationDelayer() + const override; static void SetNoDelayForTesting(); private: void OnDelayFinished(InvokeCallback callback); + // TODO(bokan): This could be removed in place of tests setting the wait + // duration explicitly. static bool no_delay_for_testing_; + base::TimeDelta wait_duration_; + base::WeakPtrFactory<WaitTool> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/actor/tools/wait_tool_request.cc b/chrome/browser/actor/tools/wait_tool_request.cc new file mode 100644 index 0000000..da6ceb3 --- /dev/null +++ b/chrome/browser/actor/tools/wait_tool_request.cc
@@ -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. + +#include "chrome/browser/actor/tools/wait_tool_request.h" + +#include "chrome/browser/actor/tools/wait_tool.h" +#include "chrome/common/actor/action_result.h" + +namespace actor { + +WaitToolRequest::WaitToolRequest(base::TimeDelta wait_duration) + : wait_duration_(wait_duration) {} + +WaitToolRequest::~WaitToolRequest() = default; + +ToolRequest::CreateToolResult WaitToolRequest::CreateTool( + AggregatedJournal& journal) const { + return {std::make_unique<WaitTool>(wait_duration_), MakeOkResult()}; +} + +std::string WaitToolRequest::JournalEvent() const { + return "Wait"; +} + +} // namespace actor
diff --git a/chrome/browser/actor/tools/wait_tool_request.h b/chrome/browser/actor/tools/wait_tool_request.h new file mode 100644 index 0000000..ea24cbc6d --- /dev/null +++ b/chrome/browser/actor/tools/wait_tool_request.h
@@ -0,0 +1,32 @@ +// 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_ACTOR_TOOLS_WAIT_TOOL_REQUEST_H_ +#define CHROME_BROWSER_ACTOR_TOOLS_WAIT_TOOL_REQUEST_H_ + +#include <memory> +#include <string> + +#include "base/time/time.h" +#include "chrome/browser/actor/tools/tool_request.h" +#include "chrome/common/actor.mojom-forward.h" + +namespace actor { + +class WaitToolRequest : public ToolRequest { + public: + explicit WaitToolRequest(base::TimeDelta wait_duration); + ~WaitToolRequest() override; + + // ToolRequest + CreateToolResult CreateTool(AggregatedJournal& journal) const override; + std::string JournalEvent() const override; + + private: + base::TimeDelta wait_duration_; +}; + +} // namespace actor + +#endif // CHROME_BROWSER_ACTOR_TOOLS_WAIT_TOOL_REQUEST_H_
diff --git a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc index ca7351d..a9afb5c 100644 --- a/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/ash/extensions/autotest_private/autotest_private_api.cc
@@ -1008,7 +1008,7 @@ DCHECK_EQ(windows.size(), 1u); auto* root_window = windows[0].get(); throughput_.push_back( - 100 - root_window->GetHost()->compositor()->GetPercentDroppedFrames()); + root_window->GetHost()->compositor()->GetAverageThroughput()); } aura::WindowTracker root_window_tracker_; @@ -6077,7 +6077,7 @@ auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); const uint32_t smoothness = - 100 - root_window->GetHost()->compositor()->GetPercentDroppedFrames(); + root_window->GetHost()->compositor()->GetAverageThroughput(); return RespondNow( ArgumentList(api::autotest_private::GetDisplaySmoothness::Results::Create( smoothness)));
diff --git a/chrome/browser/autofill/android/android_autofill_availability_status.h b/chrome/browser/autofill/android/android_autofill_availability_status.h index 482a98a..b6b76efd 100644 --- a/chrome/browser/autofill/android/android_autofill_availability_status.h +++ b/chrome/browser/autofill/android/android_autofill_availability_status.h
@@ -22,7 +22,7 @@ kNotAllowedByPolicy = 1, // The Android version doesn't provide a compatible Autofill framework. - kAndroidVersionTooOld = 2, + // Deprecated: kAndroidVersionTooOld = 2, // The Autofill Manager is not available or even provided by the OEM. kAndroidAutofillManagerNotAvailable = 3,
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillClientProviderUtils.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillClientProviderUtils.java index e814e48..16606d5 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillClientProviderUtils.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillClientProviderUtils.java
@@ -9,7 +9,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences.Editor; -import android.os.Build; import android.view.autofill.AutofillManager; import org.jni_zero.CalledByNative; @@ -96,9 +95,6 @@ if (!prefs.getBoolean(Pref.AUTOFILL_THIRD_PARTY_PASSWORD_MANAGERS_ALLOWED)) { return AndroidAutofillAvailabilityStatus.NOT_ALLOWED_BY_POLICY; } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - return AndroidAutofillAvailabilityStatus.ANDROID_VERSION_TOO_OLD; - } AutofillManager manager = ContextUtils.getApplicationContext().getSystemService(AutofillManager.class); if (manager == null) {
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java index ae43532..2bcc4de 100644 --- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java +++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsMediator.java
@@ -138,7 +138,6 @@ case AndroidAutofillAvailabilityStatus.SETTING_TURNED_OFF: // Pref may be changed! case AndroidAutofillAvailabilityStatus.AVAILABLE: return false; - case AndroidAutofillAvailabilityStatus.ANDROID_VERSION_TOO_OLD: case AndroidAutofillAvailabilityStatus.ANDROID_AUTOFILL_MANAGER_NOT_AVAILABLE: case AndroidAutofillAvailabilityStatus.ANDROID_AUTOFILL_NOT_SUPPORTED: case AndroidAutofillAvailabilityStatus.UNKNOWN_ANDROID_AUTOFILL_SERVICE:
diff --git a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsTest.java b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsTest.java index 593d272..b817d905 100644 --- a/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsTest.java +++ b/chrome/browser/autofill/android/junit/src/org/chromium/chrome/browser/autofill/options/AutofillOptionsTest.java
@@ -17,8 +17,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.ANDROID_AUTOFILL_MANAGER_NOT_AVAILABLE; import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.ANDROID_AUTOFILL_SERVICE_IS_GOOGLE; -import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.ANDROID_VERSION_TOO_OLD; import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.AVAILABLE; import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.NOT_ALLOWED_BY_POLICY; import static org.chromium.chrome.browser.autofill.AndroidAutofillAvailabilityStatus.UNKNOWN_ANDROID_AUTOFILL_SERVICE; @@ -217,7 +217,7 @@ @Test @SmallTest public void overrideForAwgDoesntAllowOtherChecksToBeSkipped() { - setAutofillAvailabilityToUseForTesting(ANDROID_VERSION_TOO_OLD); + setAutofillAvailabilityToUseForTesting(ANDROID_AUTOFILL_MANAGER_NOT_AVAILABLE); addFeatureOverrideToSkipChecks(ONLY_SKIP_AWG_CHECK_PARAM_VALUE); doReturn(false).when(mPrefs).getBoolean(Pref.AUTOFILL_USING_VIRTUAL_VIEW_STRUCTURE);
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java index b220911..e446e9f 100644 --- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java +++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowMediator.java
@@ -8,7 +8,6 @@ import android.content.Context; import android.graphics.drawable.Drawable; -import android.os.Build; import android.text.SpannableString; import android.text.Spanned; import android.text.style.ForegroundColorSpan; @@ -346,9 +345,7 @@ setPriceTrackingToggleVisualsOnly(true); // Make sure the notification channel is initialized when the user tracks the product. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mPriceDropNotificationManager.createNotificationChannel(); - } + mPriceDropNotificationManager.createNotificationChannel(); } @Override
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java index ed811d0..368db4b 100644 --- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java +++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtils.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.bookmarks; import android.content.res.Resources; -import android.os.Build; import com.google.common.primitives.UnsignedLongs; @@ -195,9 +194,7 @@ // Make sure the notification channel is initialized when the user tracks a product. // TODO(crbug.com/40245507): Add a SubscriptionsObserver in the PriceDropNotificationManager // and initialize the channel there. - if (enabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - priceDropNotificationManager.createNotificationChannel(); - } + priceDropNotificationManager.createNotificationChannel(); PriceTrackingUtils.setPriceTrackingStateForBookmark( profile, bookmarkId.getId(), enabled, wrapperCallback); }
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc index 6e5384c..8f9813d 100644 --- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc +++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.cc
@@ -327,7 +327,7 @@ EXTENSION_FUNCTION_VALIDATE(params); int64_t request_id = params->request_id; - bool result = ForwardMountResult(request_id, mutable_args()); + bool result = ForwardMountResult(request_id, GetMutableArgs()); if (!result) Respond(Error(kInterfaceUnavailable)); return RespondLater(); @@ -365,7 +365,7 @@ EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kUnmountSuccess); if (!result) Respond(Error(kInterfaceUnavailable)); @@ -379,7 +379,7 @@ EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kGetEntryMetadataSuccess); if (!result) return RespondNow(Error(kInterfaceUnavailable)); @@ -392,7 +392,7 @@ std::optional<Params> params(Params::Create(args())); EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kGetActionsSuccess); if (!result) return RespondNow(Error(kInterfaceUnavailable)); @@ -406,7 +406,7 @@ std::optional<Params> params(Params::Create(args())); EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kReadDirectorySuccess); if (!result) return RespondNow(Error(kInterfaceUnavailable)); @@ -422,7 +422,7 @@ std::optional<Params> params(Params::Create(args())); EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kReadFileSuccess); if (!result) return RespondNow(Error(kInterfaceUnavailable)); @@ -438,7 +438,7 @@ std::optional<Params> params(Params::Create(args())); EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOpenFileFinishedSuccessullyResult(std::move(params), - mutable_args()); + GetMutableArgs()); if (!result) { return RespondNow(Error(kInterfaceUnavailable)); } @@ -468,7 +468,7 @@ ->crosapi_ash() ->file_system_provider_service_ash() ->OpenFileFinishedSuccessfullyWithProfile( - std::move(file_system_id), request_id, std::move(mutable_args()), + std::move(file_system_id), request_id, std::move(GetMutableArgs()), std::move(callback), profile); return true; } @@ -480,7 +480,7 @@ EXTENSION_FUNCTION_VALIDATE(params); bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kGenericSuccess); if (!result) return RespondNow(Error(kInterfaceUnavailable)); @@ -499,7 +499,7 @@ } bool result = ForwardOperationResult( - params, mutable_args(), + params, GetMutableArgs(), crosapi::mojom::FSPOperationResponse::kGenericFailure); if (!result) return RespondNow(Error(kInterfaceUnavailable));
diff --git a/chrome/browser/device_reauth/android/device_authenticator_android.cc b/chrome/browser/device_reauth/android/device_authenticator_android.cc index fcb0310e..36091d70 100644 --- a/chrome/browser/device_reauth/android/device_authenticator_android.cc +++ b/chrome/browser/device_reauth/android/device_authenticator_android.cc
@@ -146,7 +146,6 @@ case device_reauth::BiometricsAvailability::kHwUnavailable: case device_reauth::BiometricsAvailability::kNotEnrolled: case device_reauth::BiometricsAvailability::kSecurityUpdateRequired: - case device_reauth::BiometricsAvailability::kAndroidVersionNotSupported: case device_reauth::BiometricsAvailability::kOtherError: break; }
diff --git a/chrome/browser/device_reauth/android/device_authenticator_bridge.h b/chrome/browser/device_reauth/android/device_authenticator_bridge.h index 2a5a396..07f3a6a6 100644 --- a/chrome/browser/device_reauth/android/device_authenticator_bridge.h +++ b/chrome/browser/device_reauth/android/device_authenticator_bridge.h
@@ -38,7 +38,7 @@ kHwUnavailable = 4, kNotEnrolled = 5, kSecurityUpdateRequired = 6, - kAndroidVersionNotSupported = 7, + // Deprecated: kAndroidVersionNotSupported = 7, kRequired = 8, kRequiredButHasError = 9,
diff --git a/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/DeviceAuthenticatorControllerImpl.java b/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/DeviceAuthenticatorControllerImpl.java index ab4d4e9..eccef5f2 100644 --- a/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/DeviceAuthenticatorControllerImpl.java +++ b/chrome/browser/device_reauth/android/java/src/org/chromium/chrome/browser/device_reauth/DeviceAuthenticatorControllerImpl.java
@@ -15,11 +15,8 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; -import android.os.Build; import android.os.CancellationSignal; -import androidx.annotation.RequiresApi; - import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; import org.chromium.build.annotations.NullMarked; @@ -31,29 +28,23 @@ class DeviceAuthenticatorControllerImpl implements DeviceAuthenticatorController { private final Context mContext; private final Delegate mDelegate; - private @Nullable BiometricPrompt mBiometricPrompt; + private final @Nullable BiometricPrompt mBiometricPrompt; protected @Nullable CancellationSignal mCancellationSignal; public DeviceAuthenticatorControllerImpl(Context context, Delegate delegate) { mContext = context; mDelegate = delegate; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { - BiometricPrompt.Builder promptBuilder = - new BiometricPrompt.Builder(mContext) - .setTitle( - mContext.getString( - R.string.password_filling_reauth_prompt_title)); - promptBuilder.setDeviceCredentialAllowed(true); - promptBuilder.setConfirmationRequired(false); - mBiometricPrompt = promptBuilder.build(); - } + BiometricPrompt.Builder promptBuilder = + new BiometricPrompt.Builder(mContext) + .setTitle( + mContext.getString(R.string.password_filling_reauth_prompt_title)); + promptBuilder.setDeviceCredentialAllowed(true); + promptBuilder.setConfirmationRequired(false); + mBiometricPrompt = promptBuilder.build(); } @Override public @BiometricsAvailability int canAuthenticateWithBiometric() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - return BiometricsAvailability.ANDROID_VERSION_NOT_SUPPORTED; - } BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class); if (biometricManager == null) return BiometricsAvailability.OTHER_ERROR; @@ -82,15 +73,10 @@ @Override public boolean canAuthenticateWithBiometricOrScreenLock() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - return false; - } - @BiometricsAvailability int availability = canAuthenticateWithBiometric(); return (availability == BiometricsAvailability.AVAILABLE) || hasScreenLockSetUp(); } - @RequiresApi(Build.VERSION_CODES.P) @Override public void authenticate() { if (mBiometricPrompt == null) {
diff --git a/chrome/browser/download/android/download_manager_bridge.cc b/chrome/browser/download/android/download_manager_bridge.cc index fcf6904..7bdccd4 100644 --- a/chrome/browser/download/android/download_manager_bridge.cc +++ b/chrome/browser/download/android/download_manager_bridge.cc
@@ -39,23 +39,12 @@ download::DownloadItem* download, AddCompletedDownloadCallback callback) { JNIEnv* env = base::android::AttachCurrentThread(); - std::string file_name = download->GetFileNameToReportUser().value(); - std::string mime_type = download->GetMimeType(); - std::string file_path = download->GetTargetFilePath().value(); - int64_t file_size = download->GetReceivedBytes(); - ScopedJavaLocalRef<jobject> joriginal_url = - url::GURLAndroid::FromNativeGURL(env, download->GetOriginalUrl()); - ScopedJavaLocalRef<jobject> jreferer = - url::GURLAndroid::FromNativeGURL(env, download->GetReferrerUrl()); - std::string download_guid = download->GetGuid(); // Make copy on the heap so we can pass the pointer through JNI. intptr_t callback_id = reinterpret_cast<intptr_t>( new AddCompletedDownloadCallback(std::move(callback))); - Java_DownloadManagerBridge_addCompletedDownload( - env, file_name, file_name, mime_type, file_path, file_size, joriginal_url, - jreferer, download_guid, callback_id); + Java_DownloadManagerBridge_addCompletedDownload(env, callback_id); } void DownloadManagerBridge::RemoveCompletedDownload(
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java index 7ad36d1..b59b4126 100644 --- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java +++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/DownloadManagerBridge.java
@@ -9,9 +9,6 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; -import android.os.Build; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.os.Environment; import android.text.TextUtils; @@ -20,7 +17,6 @@ import org.jni_zero.NativeMethods; import org.chromium.base.Callback; -import org.chromium.base.ContentUriUtils; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; @@ -30,7 +26,6 @@ import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; import org.chromium.components.browser_ui.util.DownloadUtils; -import org.chromium.url.GURL; import java.io.File; import java.util.concurrent.RejectedExecutionException; @@ -85,41 +80,6 @@ } /** - * Adds a download to the Android DownloadManager. - * @see android.app.DownloadManager#addCompletedDownload(String, String, boolean, String, - * String, long, boolean) - */ - public static long addCompletedDownload( - String fileName, - String description, - String mimeType, - String filePath, - long fileSizeBytes, - GURL originalUrl, - GURL referer, - String downloadGuid) { - assert !ThreadUtils.runningOnUiThread(); - assert VERSION.SDK_INT < VERSION_CODES.Q - : "addCompletedDownload is deprecated in Q, may cause crash."; - long downloadId = getDownloadIdForDownloadGuid(downloadGuid); - if (downloadId != DownloadUtils.INVALID_SYSTEM_DOWNLOAD_ID) return downloadId; - - downloadId = - DownloadUtils.addCompletedDownload( - fileName, - description, - mimeType, - filePath, - fileSizeBytes, - originalUrl, - referer); - if (downloadId != DownloadUtils.INVALID_SYSTEM_DOWNLOAD_ID) { - addDownloadIdMapping(downloadId, downloadGuid); - } - return downloadId; - } - - /** * Removes a download from Android DownloadManager. * * @param downloadGuid The GUID of the download. @@ -242,25 +202,11 @@ } /** - * Inserts a new download ID mapping into the SharedPreferences - * - * @param downloadId system download ID from Android DownloadManager. - * @param downloadGuid Download GUID. - */ - private static void addDownloadIdMapping(long downloadId, String downloadGuid) { - synchronized (sLock) { - SharedPreferences sharedPrefs = getSharedPreferences(); - SharedPreferences.Editor editor = sharedPrefs.edit(); - editor.putLong(downloadGuid, downloadId); - editor.apply(); - } - } - - /** * Removes a download Id mapping from the SharedPreferences given the download GUID. + * * @param downloadGuid Download GUID. * @return the Android DownloadManager's download ID that is removed, or - * INVALID_SYSTEM_DOWNLOAD_ID if it is not found. + * INVALID_SYSTEM_DOWNLOAD_ID if it is not found. */ private static long removeDownloadIdMapping(String downloadGuid) { long downloadId = DownloadUtils.INVALID_SYSTEM_DOWNLOAD_ID; @@ -296,38 +242,12 @@ * to the android's DownloadManager if the download is not a content URI. */ @CalledByNative - private static void addCompletedDownload( - @JniType("std::string") String fileName, - @JniType("std::string") String description, - @JniType("std::string") String originalMimeType, - @JniType("std::string") String filePath, - long fileSizeBytes, - GURL originalUrl, - GURL referrer, - @JniType("std::string") String downloadGuid, - long callbackId) { - final String mimeType = - MimeUtils.remapGenericMimeType(originalMimeType, originalUrl.getSpec(), fileName); + private static void addCompletedDownload(long callbackId) { AsyncTask<Long> task = new AsyncTask<>() { @Override protected Long doInBackground() { - long downloadId = DownloadConstants.INVALID_DOWNLOAD_ID; - // On Android Q-, add the completed download to Android download manager. - if (!ContentUriUtils.isContentUri(filePath) - && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - downloadId = - addCompletedDownload( - fileName, - description, - mimeType, - filePath, - fileSizeBytes, - originalUrl, - referrer, - downloadGuid); - } - return downloadId; + return DownloadConstants.INVALID_DOWNLOAD_ID; } @Override
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chrome/browser/extensions/api/content_settings/content_settings_api.cc index 3b1daaa..249c3fe8 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_api.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -80,7 +80,8 @@ ExtensionFunction::ResponseAction ContentSettingsContentSettingClearFunction::Run() { ContentSettingsType content_type; - EXTENSION_FUNCTION_VALIDATE(RemoveContentType(mutable_args(), &content_type)); + EXTENSION_FUNCTION_VALIDATE( + RemoveContentType(GetMutableArgs(), &content_type)); std::optional<Clear::Params> params = Clear::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params); @@ -117,7 +118,8 @@ ExtensionFunction::ResponseAction ContentSettingsContentSettingGetFunction::Run() { ContentSettingsType content_type; - EXTENSION_FUNCTION_VALIDATE(RemoveContentType(mutable_args(), &content_type)); + EXTENSION_FUNCTION_VALIDATE( + RemoveContentType(GetMutableArgs(), &content_type)); std::optional<Get::Params> params = Get::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params); @@ -189,7 +191,8 @@ ExtensionFunction::ResponseAction ContentSettingsContentSettingSetFunction::Run() { ContentSettingsType content_type; - EXTENSION_FUNCTION_VALIDATE(RemoveContentType(mutable_args(), &content_type)); + EXTENSION_FUNCTION_VALIDATE( + RemoveContentType(GetMutableArgs(), &content_type)); std::optional<Set::Params> params = Set::Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params);
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc index 828882c..ae52c23c 100644 --- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc +++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
@@ -46,7 +46,7 @@ DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(source_process_id(), request_id_, this); - mutable_args().erase(args().begin()); + GetMutableArgs().erase(args().begin()); std::optional<api::desktop_capture::ChooseDesktopMedia::Params> params = api::desktop_capture::ChooseDesktopMedia::Params::Create(args());
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc index 998e868b..d802758 100644 --- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc +++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -130,7 +130,7 @@ return true; } - base::Value& first_arg = mutable_args()[0]; + const base::Value& first_arg = args()[0]; switch (first_arg.type()) { case base::Value::Type::INTEGER: @@ -141,7 +141,7 @@ // Found the details argument. details_ = &first_arg.GetDict(); // Still need to check for the tabId within details. - if (base::Value* tab_id_value = details_->Find("tabId")) { + if (const base::Value* tab_id_value = details_->Find("tabId")) { switch (tab_id_value->type()) { case base::Value::Type::NONE: // OK; tabId is optional, leave it default. @@ -212,7 +212,7 @@ // setIcon can take a variant argument: either a dictionary of canvas // ImageData, or an icon index. - base::Value::Dict* canvas_set = details_->FindDict("imageData"); + const base::Value::Dict* canvas_set = details_->FindDict("imageData"); if (canvas_set) { gfx::ImageSkia icon; @@ -257,7 +257,7 @@ ExtensionFunction::ResponseAction ExtensionActionSetPopupFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); - std::string* popup_string = details_->FindString("popup"); + const std::string* popup_string = details_->FindString("popup"); EXTENSION_FUNCTION_VALIDATE(popup_string); GURL popup_url; @@ -280,7 +280,7 @@ ExtensionActionSetBadgeTextFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); - std::string* badge_text = details_->FindString("text"); + const std::string* badge_text = details_->FindString("text"); if (badge_text) { extension_action_->SetBadgeText(tab_id_, *badge_text); } else { @@ -294,7 +294,7 @@ ExtensionFunction::ResponseAction ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); - base::Value* color_value = details_->Find("color"); + const base::Value* color_value = details_->Find("color"); EXTENSION_FUNCTION_VALIDATE(color_value); SkColor color = 0; if (!ParseColor(*color_value, color)) { @@ -308,7 +308,7 @@ ExtensionFunction::ResponseAction ActionSetBadgeTextColorFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); - base::Value* color_value = details_->Find("color"); + const base::Value* color_value = details_->Find("color"); EXTENSION_FUNCTION_VALIDATE(color_value); SkColor color = 0; if (!ParseColor(*color_value, color)) {
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chrome/browser/extensions/api/extension_action/extension_action_api.h index eb7f3fad..de62a845 100644 --- a/chrome/browser/extensions/api/extension_action/extension_action_api.h +++ b/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -50,7 +50,7 @@ // All the extension action APIs take a single argument called details that // is a dictionary. - raw_ptr<base::Value::Dict> details_; + raw_ptr<const base::Value::Dict> details_; // The tab id the extension action function should apply to, if any, or // kDefaultTabId if none was specified.
diff --git a/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc b/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc index aadb317..5d075d1 100644 --- a/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc +++ b/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
@@ -41,7 +41,7 @@ DesktopCaptureRequestsRegistry::GetInstance()->AddRequest(source_process_id(), request_id_, this); - mutable_args().erase(args().begin()); + GetMutableArgs().erase(args().begin()); std::optional<Params> params = Params::Create(args()); EXTENSION_FUNCTION_VALIDATE(params);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java index 32161d2..394406f 100644 --- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java +++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettingsTest.java
@@ -121,7 +121,6 @@ @Test @SmallTest @DisableIf.Build( - sdk_is_greater_than = Build.VERSION_CODES.P, sdk_is_less_than = Build.VERSION_CODES.S, message = "Flaky in Q and R, crbug.com/40190787") public void testToggleOfferToTranslate() {
diff --git a/chrome/browser/media/android/media_capture_picker_dialog_bridge.cc b/chrome/browser/media/android/media_capture_picker_dialog_bridge.cc index d28edc8..1219125 100644 --- a/chrome/browser/media/android/media_capture_picker_dialog_bridge.cc +++ b/chrome/browser/media/android/media_capture_picker_dialog_bridge.cc
@@ -10,7 +10,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" -#include "ui/android/window_android.h" // Must come after all headers that specialize FromJniType() / ToJniType(). #include "chrome/android/chrome_jni_headers/MediaCapturePickerDialogBridge_jni.h" @@ -39,16 +38,8 @@ CHECK(callback_.is_null()); callback_ = std::move(callback); JNIEnv* env = base::android::AttachCurrentThread(); - ui::WindowAndroid* window_android = web_contents->GetTopLevelNativeWindow(); - if (!window_android) { - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback_), content::DesktopMediaID())); - return; - } - Java_MediaCapturePickerDialogBridge_showDialog( - env, java_object_, window_android->GetJavaObject(), app_name, + env, java_object_, web_contents->GetJavaWebContents(), app_name, request_audio); }
diff --git a/chrome/browser/page_load_metrics/integration_tests/smoothness_metric_browsertest.cc b/chrome/browser/page_load_metrics/integration_tests/smoothness_metric_browsertest.cc index 0eb9f73..f1b92ba 100644 --- a/chrome/browser/page_load_metrics/integration_tests/smoothness_metric_browsertest.cc +++ b/chrome/browser/page_load_metrics/integration_tests/smoothness_metric_browsertest.cc
@@ -77,14 +77,8 @@ web_contents()->ClosePage(); ui_test_utils::WaitForBrowserToClose(browser()); - int64_t fsm_pdf_value, avg_value; - // Ensure that the smoothness UKM is reported. - ASSERT_TRUE(ExtractUKMSmoothnessMetric( - ukm_recorder(), - Graphics_Smoothness_NormalizedPercentDroppedFrames::kEntryName, - Graphics_Smoothness_NormalizedPercentDroppedFrames::kAverageName, - &avg_value)); - // FrameSequenceMetric export should also show a value. + int64_t fsm_pdf_value; + // FrameSequenceMetric export should show a value. ASSERT_TRUE(ExtractUKMSmoothnessMetric( ukm_recorder(), Graphics_Smoothness_FrameSequence::kEntryName, Graphics_Smoothness_FrameSequence::kPercentDroppedFramesName, @@ -93,5 +87,4 @@ // Some of the frames should be dropped. It is not possible to measure the // exact number of dropped frames, so validate that it is non-zero. EXPECT_NE(fsm_pdf_value, 0); - EXPECT_NE(avg_value, 0); }
diff --git a/chrome/browser/printing/printer_manager_dialog_linux.cc b/chrome/browser/printing/printer_manager_dialog_linux.cc index 47454d2..7e4ead49 100644 --- a/chrome/browser/printing/printer_manager_dialog_linux.cc +++ b/chrome/browser/printing/printer_manager_dialog_linux.cc
@@ -83,6 +83,7 @@ case base::nix::DESKTOP_ENVIRONMENT_PANTHEON: case base::nix::DESKTOP_ENVIRONMENT_UNITY: case base::nix::DESKTOP_ENVIRONMENT_XFCE: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: opened = OpenPrinterConfigDialog(kSystemConfigPrinterCommand); break; case base::nix::DESKTOP_ENVIRONMENT_DEEPIN:
diff --git a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java index b91ace5..6e4d484c 100644 --- a/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java +++ b/chrome/browser/quick_delete/android/java/src/org/chromium/chrome/browser/quick_delete/QuickDeleteController.java
@@ -7,7 +7,6 @@ import static org.chromium.build.NullUtil.assumeNonNull; import android.content.Context; -import android.os.Build; import android.os.VibrationEffect; import android.os.Vibrator; import android.view.LayoutInflater; @@ -233,12 +232,7 @@ private void triggerHapticFeedback() { Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); final long duration = 50; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - v.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE)); - } else { - // Deprecated in API 26. - v.vibrate(duration); - } + v.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE)); } /** A method to show the quick delete snack-bar. */
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/TapToSeekSelectionManager.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/TapToSeekSelectionManager.java index 8a35f5e..70367eb 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/TapToSeekSelectionManager.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/TapToSeekSelectionManager.java
@@ -5,7 +5,6 @@ import static org.chromium.build.NullUtil.assumeNonNull; -import android.os.Build; import android.view.textclassifier.TextClassifier; import androidx.annotation.VisibleForTesting; @@ -29,11 +28,6 @@ */ @NullMarked public class TapToSeekSelectionManager implements SelectionClient.SurroundingTextCallback { - // Whether Smart Select is allowed to be enabled in Chrome. Set to true for Android O+. This - // check is also mirrored in {@link SelectionClientManager} when making the Smart Selection - // Client - private static final boolean IS_SMART_SELECTION_ENABLED_IN_CHROME = - Build.VERSION.SDK_INT > Build.VERSION_CODES.O; // Tab that Tap to Seek is hooked into. Can be null if not hooked into any tab. private @Nullable Tab mObservingTab; private final ReadAloudController mReadAloudController; @@ -51,9 +45,7 @@ ReadAloudController readAloudController, ObservableSupplier<@Nullable Tab> activePlaybackTab) { mReadAloudController = readAloudController; - if (IS_SMART_SELECTION_ENABLED_IN_CHROME) { - activePlaybackTab.addObserver(this::onActivePlaybackTabUpdated); - } + activePlaybackTab.addObserver(this::onActivePlaybackTabUpdated); } @Override @@ -88,7 +80,7 @@ } private void addHooks(@Nullable WebContents webContents) { - if (IS_SMART_SELECTION_ENABLED_IN_CHROME && webContents != null) { + if (webContents != null) { mSelectionClient = new TapToSeekSelectionClient( assumeNonNull(
diff --git a/chrome/browser/resources/web_app_internals/web_app_internals.ts b/chrome/browser/resources/web_app_internals/web_app_internals.ts index 7021609..a75260e5 100644 --- a/chrome/browser/resources/web_app_internals/web_app_internals.ts +++ b/chrome/browser/resources/web_app_internals/web_app_internals.ts
@@ -235,6 +235,13 @@ const installButton = getRequiredElement<HTMLButtonElement>( 'iwa-update-manifest-dialog-install'); + const closeButton = + getRequiredElement<HTMLButtonElement>('iwa-update-manifest-dialog-close'); + + closeButton.addEventListener('click', () => { + iwaDevUpdateManifestDialog.close(); + }, {once: true}); + const installEventListener = async () => { installButton.removeEventListener('click', installEventListener);
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 ba9436c..d708974 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn +++ b/chrome/browser/touch_to_fill/autofill/android/internal/BUILD.gn
@@ -46,6 +46,7 @@ android_resources("java_resources") { sources = [ + "java/res/layout/touch_to_fill_all_loyalty_cards_item.xml", "java/res/layout/touch_to_fill_credit_card_sheet_item.xml", "java/res/layout/touch_to_fill_iban_sheet_item.xml", "java/res/layout/touch_to_fill_loyalty_card_sheet_item.xml",
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_all_loyalty_cards_item.xml b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_all_loyalty_cards_item.xml new file mode 100644 index 0000000..0498b3f --- /dev/null +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/res/layout/touch_to_fill_all_loyalty_cards_item.xml
@@ -0,0 +1,41 @@ +<?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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:descendantFocusability="blocksDescendants" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="2dp" + android:layout_marginHorizontal="8dp" + android:background="@color/baseline_neutral_90" + android:gravity="center_vertical" + android:orientation="horizontal" + android:padding="16dp"> + + <TextView + android:id="@+id/all_loyalty_cards_item_title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:layout_weight="1" + android:maxLines="1" + android:text="@string/autofill_bottom_sheet_all_your_loyalty_cards" + android:textAppearance="@style/TextAppearance.TextLarge.Primary" + android:ellipsize="middle" /> + + <ImageView + android:id="@+id/loyalty_card_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:contentDescription="@string/autofill_bottom_sheet_expand_all_loyalty_cards_description" + app:tint="@color/default_icon_color_secondary_tint_list" + app:srcCompat="@drawable/ic_expand_more_horizontal_black_24dp" /> + +</LinearLayout>
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 29348f3..e713c3f 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
@@ -49,6 +49,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.IBAN_NICKNAME; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.IBAN_VALUE; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.ON_IBAN_CLICK_ACTION; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.ALL_LOYALTY_CARDS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FILL_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FOOTER; @@ -914,6 +915,8 @@ is(LOYALTY_CARD_1.getLoyaltyCardNumber())); assertThat(loyaltyCardModel.get(MERCHANT_NAME), is(LOYALTY_CARD_1.getMerchantName())); + assertThat(getModelsOfType(itemList, ALL_LOYALTY_CARDS).size(), is(0)); + assertThat(getModelsOfType(itemList, FILL_BUTTON).size(), is(1)); assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(1)); PropertyModel walletSettingButtonModel = @@ -949,7 +952,9 @@ HistogramWatcher.newSingleRecordWatcher( TOUCH_TO_FILL_NUMBER_OF_LOYALTY_CARDS_SHOWN, 1); mCoordinator.showLoyaltyCards( - List.of(LOYALTY_CARD_1), List.of(LOYALTY_CARD_1), /* firstTimeUsage= */ false); + List.of(LOYALTY_CARD_1), + List.of(LOYALTY_CARD_1, LOYALTY_CARD_2), + /* firstTimeUsage= */ false); histogramWatcher.assertExpected(); ModelList itemList = mTouchToFillPaymentMethodModel.get(SHEET_ITEMS); @@ -967,6 +972,7 @@ is(LOYALTY_CARD_1.getLoyaltyCardNumber())); assertThat(loyaltyCardModel.get(MERCHANT_NAME), is(LOYALTY_CARD_1.getMerchantName())); + assertThat(getModelsOfType(itemList, ALL_LOYALTY_CARDS).size(), is(1)); assertThat(getModelsOfType(itemList, FILL_BUTTON).size(), is(1)); assertThat(getModelsOfType(itemList, WALLET_SETTINGS_BUTTON).size(), is(0)); assertThat(getModelsOfType(itemList, FOOTER).size(), is(1)); @@ -1004,6 +1010,7 @@ is(LOYALTY_CARD_2.getLoyaltyCardNumber())); assertThat(loyaltyCardModel2.get(MERCHANT_NAME), is(LOYALTY_CARD_2.getMerchantName())); + assertThat(getModelsOfType(itemList, ALL_LOYALTY_CARDS).size(), is(1)); 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 9e3b91e..7f9d7bc9 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
@@ -7,6 +7,7 @@ import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getCardIcon; import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getValuableIcon; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.DISMISS_HANDLER; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.ALL_LOYALTY_CARDS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FILL_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FOOTER; @@ -132,6 +133,10 @@ TouchToFillPaymentMethodViewBinder::createLoyaltyCardItemView, TouchToFillPaymentMethodViewBinder::bindLoyaltyCardItemView); adapter.registerType( + ALL_LOYALTY_CARDS, + TouchToFillPaymentMethodViewBinder::createAllLoyaltyCardsItemView, + TouchToFillPaymentMethodViewBinder::bindAllLoyaltyCardsItemView); + adapter.registerType( HEADER, TouchToFillPaymentMethodViewBinder::createHeaderItemView, TouchToFillPaymentMethodViewBinder::bindHeaderView);
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 6f038ac..7af1b923 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
@@ -27,6 +27,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.IBAN_VALUE; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.NON_TRANSFORMING_IBAN_KEYS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.ON_IBAN_CLICK_ACTION; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.ALL_LOYALTY_CARDS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FILL_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FOOTER; @@ -60,6 +61,7 @@ import org.chromium.chrome.browser.touch_to_fill.common.FillableItemCollectionInfo; import org.chromium.chrome.browser.touch_to_fill.common.TouchToFillResourceProvider; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodComponent.Delegate; +import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.AllLoyaltyCardsItemProperties; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ButtonProperties; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.FooterProperties; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.HeaderProperties; @@ -189,7 +191,7 @@ private PropertyModel mModel; private List<AutofillSuggestion> mSuggestions; private List<Iban> mIbans; - private List<LoyaltyCard> mLoyaltyCards; + private List<LoyaltyCard> mAffiliatedLoyaltyCards; private BottomSheetFocusHelper mBottomSheetFocusHelper; private InputProtector mInputProtector = new InputProtector(); @@ -212,7 +214,7 @@ assert suggestions != null; mSuggestions = suggestions; mIbans = null; - mLoyaltyCards = null; + mAffiliatedLoyaltyCards = null; ModelList sheetItems = mModel.get(SHEET_ITEMS); sheetItems.clear(); @@ -262,7 +264,7 @@ assert ibans != null; mIbans = ibans; mSuggestions = null; - mLoyaltyCards = null; + mAffiliatedLoyaltyCards = null; ModelList sheetItems = mModel.get(SHEET_ITEMS); sheetItems.clear(); @@ -301,7 +303,7 @@ mInputProtector.markShowTime(); assert allLoyaltyCards != null && affiliatedLoyaltyCards != null; - mLoyaltyCards = allLoyaltyCards; + mAffiliatedLoyaltyCards = affiliatedLoyaltyCards; mSuggestions = null; mIbans = null; // TODO: crbug.com/420957826 - Display affiliated loyalty cards. @@ -309,12 +311,17 @@ ModelList sheetItems = mModel.get(SHEET_ITEMS); sheetItems.clear(); - for (LoyaltyCard loyaltyCard : mLoyaltyCards) { + for (LoyaltyCard loyaltyCard : mAffiliatedLoyaltyCards) { final PropertyModel model = createLoyaltyCardModel(loyaltyCard, valuableImageFunction); sheetItems.add(new ListItem(LOYALTY_CARD, model)); } - if (mLoyaltyCards.size() == 1) { + if (!firstTimeUsage) { + assert !allLoyaltyCards.isEmpty(); + sheetItems.add(new ListItem(ALL_LOYALTY_CARDS, createAllLoyaltyCardsItemModel())); + } + + if (mAffiliatedLoyaltyCards.size() == 1) { // Use the LOYALTY_CARD model as the property model for the fill button too. assert sheetItems.get(0).type == LOYALTY_CARD; sheetItems.add( @@ -322,7 +329,9 @@ FILL_BUTTON, createFillButtonModel( R.string.autofill_loyalty_card_autofill_button, - () -> this.onSelectedLoyaltyCard(mLoyaltyCards.get(0))))); + () -> + this.onSelectedLoyaltyCard( + mAffiliatedLoyaltyCards.get(0))))); } if (firstTimeUsage) { @@ -336,7 +345,7 @@ mModel.set(VISIBLE, true); RecordHistogram.recordCount100Histogram( - TOUCH_TO_FILL_NUMBER_OF_LOYALTY_CARDS_SHOWN, mLoyaltyCards.size()); + TOUCH_TO_FILL_NUMBER_OF_LOYALTY_CARDS_SHOWN, mAffiliatedLoyaltyCards.size()); } void hideSheet() { @@ -364,7 +373,7 @@ TouchToFillIbanOutcome.DISMISS, TouchToFillIbanOutcome.MAX_VALUE); } else { - assert mLoyaltyCards != null; + assert mAffiliatedLoyaltyCards != null; recordTouchToFillLoyaltyCardOutcomeHistogram(TouchToFillLoyaltyCardOutcome.DISMISS); } } @@ -387,13 +396,13 @@ } public void showGoogleWalletSettings() { - assert mLoyaltyCards != null; + assert mAffiliatedLoyaltyCards != null; recordTouchToFillLoyaltyCardOutcomeHistogram(TouchToFillLoyaltyCardOutcome.WALLET_SETTINGS); mDelegate.showGoogleWalletSettings(); } public void showManageLoyaltyCards() { - assert mLoyaltyCards != null; + assert mAffiliatedLoyaltyCards != null; mDelegate.openPassesManagementUi(); recordTouchToFillLoyaltyCardOutcomeHistogram( TouchToFillLoyaltyCardOutcome.MANAGE_LOYALTY_CARDS); @@ -414,7 +423,7 @@ TOUCH_TO_FILL_CREDIT_CARD_INDEX_SELECTED, mSuggestions.indexOf(suggestion)); } - public void onSelectedIban(Iban iban) { + private void onSelectedIban(Iban iban) { if (!mInputProtector.shouldInputBeProcessed()) return; if (iban.getRecordType() == IbanRecordType.LOCAL_IBAN) { mDelegate.localIbanSuggestionSelected(iban.getGuid()); @@ -426,12 +435,17 @@ TOUCH_TO_FILL_IBAN_INDEX_SELECTED, mIbans.indexOf(iban)); } - public void onSelectedLoyaltyCard(LoyaltyCard loyaltyCard) { + private void onSelectedLoyaltyCard(LoyaltyCard loyaltyCard) { if (!mInputProtector.shouldInputBeProcessed()) return; mDelegate.loyaltyCardSuggestionSelected(loyaltyCard.getLoyaltyCardNumber()); recordTouchToFillLoyaltyCardOutcomeHistogram(TouchToFillLoyaltyCardOutcome.LOYALTY_CARD); RecordHistogram.recordCount100Histogram( - TOUCH_TO_FILL_LOYALTY_CARD_INDEX_SELECTED, mLoyaltyCards.indexOf(loyaltyCard)); + TOUCH_TO_FILL_LOYALTY_CARD_INDEX_SELECTED, + mAffiliatedLoyaltyCards.indexOf(loyaltyCard)); + } + + private void showAllLoyaltyCards() { + // TODO: crbug.com/420957826 - Implement all loyalty cards screen. } private PropertyModel createCardSuggestionModel( @@ -496,6 +510,12 @@ return loyaltyCardModelBuilder.build(); } + private PropertyModel createAllLoyaltyCardsItemModel() { + return new PropertyModel.Builder(AllLoyaltyCardsItemProperties.ALL_KEYS) + .with(AllLoyaltyCardsItemProperties.ON_CLICK_ACTION, this::showAllLoyaltyCards) + .build(); + } + private PropertyModel createFillButtonModel(@StringRes int titleId, Runnable onClickAction) { return new PropertyModel.Builder(ButtonProperties.ALL_KEYS) .with(TEXT_ID, titleId)
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 6f3b900..c69a7e3 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
@@ -43,18 +43,21 @@ // A section containing the loyalty card data. int LOYALTY_CARD = 3; + // An item which displays all user's loyalty cards upon click. + int ALL_LOYALTY_CARDS = 4; + // A "Continue" button, which is shown when there is only one payment // method available. - int FILL_BUTTON = 4; + int FILL_BUTTON = 5; // A button that redirects the user to the Wallet settings in Chrome. - int WALLET_SETTINGS_BUTTON = 5; + int WALLET_SETTINGS_BUTTON = 6; // A footer section containing additional actions. - int FOOTER = 6; + int FOOTER = 7; // A section with a terms label is present when card benefits are available. - int TERMS_LABEL = 7; + int TERMS_LABEL = 8; } /** Metadata associated with a card's image. */ @@ -151,6 +154,16 @@ private LoyaltyCardProperties() {} } + /** Properties for the "All your loyalty cards" item in the TouchToFill sheet for payments. */ + static class AllLoyaltyCardsItemProperties { + static final PropertyModel.ReadableObjectPropertyKey<Runnable> ON_CLICK_ACTION = + new PropertyModel.ReadableObjectPropertyKey<>("all_loyalty_cards_on_click_action"); + + static final PropertyKey[] ALL_KEYS = {ON_CLICK_ACTION}; + + private AllLoyaltyCardsItemProperties() {} + } + /** * Properties defined here reflect the visible state of the terms message in the TouchToFill * sheet for payments.
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 cc97044..21b698e 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
@@ -50,6 +50,7 @@ case ItemType.CREDIT_CARD: case ItemType.IBAN: case ItemType.LOYALTY_CARD: + case ItemType.ALL_LOYALTY_CARDS: return false; } assert false : "Undefined whether to skip setting background for item of type: " + type;
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 0c7249b0..ba35740 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
@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.autofill.AutofillUiUtils; import org.chromium.chrome.browser.touch_to_fill.common.FillableItemCollectionInfo; +import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.AllLoyaltyCardsItemProperties; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -256,6 +257,24 @@ } } + static View createAllLoyaltyCardsItemView(ViewGroup parent) { + View view = + LayoutInflater.from(parent.getContext()) + .inflate(R.layout.touch_to_fill_all_loyalty_cards_item, parent, false); + AutofillUiUtils.setFilterTouchForSecurity(view); + return view; + } + + static void bindAllLoyaltyCardsItemView( + PropertyModel model, View view, PropertyKey propertyKey) { + if (propertyKey == AllLoyaltyCardsItemProperties.ON_CLICK_ACTION) { + view.setOnClickListener( + unusedView -> model.get(AllLoyaltyCardsItemProperties.ON_CLICK_ACTION).run()); + } else { + assert false : "Unhandled update to property: " + propertyKey; + } + } + /** * Factory used to create a new header inside the ListView inside the {@link * TouchToFillPaymentMethodView}.
diff --git a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java index 6050d8a7..09e6df2 100644 --- a/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java +++ b/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodViewTest.java
@@ -44,6 +44,7 @@ import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.IBAN_VALUE; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.NON_TRANSFORMING_IBAN_KEYS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.IbanProperties.ON_IBAN_CLICK_ACTION; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.ALL_LOYALTY_CARDS; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FILL_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.HEADER; @@ -65,6 +66,7 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.IdRes; import androidx.annotation.StringRes; import androidx.recyclerview.widget.RecyclerView; import androidx.test.filters.MediumTest; @@ -95,6 +97,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.touch_to_fill.common.FillableItemCollectionInfo; import org.chromium.chrome.browser.touch_to_fill.common.TouchToFillResourceProvider; +import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.AllLoyaltyCardsItemProperties; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ButtonProperties; import org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.HeaderProperties; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -368,10 +371,7 @@ .findViewById(R.id.touch_to_fill_sheet_title); assertThat( title.getText().toString(), - is( - mActivityTestRule - .getActivity() - .getString(R.string.autofill_loyalty_card_bottom_sheet_title))); + is(getString(R.string.autofill_loyalty_card_bottom_sheet_title))); } @Test @@ -595,12 +595,7 @@ }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); waitForEvent(actionCallback).run(); } @@ -636,19 +631,9 @@ .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); onView(withText(NICKNAMED_VISA_SUGGESTION.getLabel())) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED)); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED)); } @@ -756,10 +741,7 @@ assertContentDescriptionEquals(secondLineLabel, /* position= */ 1, /* total= */ 1); TextView benefitsTermsLabel = getCreditCardBenefitsTermsLabel(); String expectedBenefitsTermsLabel = - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_bottom_sheet_benefits_terms_label); + getString(R.string.autofill_payment_method_bottom_sheet_benefits_terms_label); assertThat(benefitsTermsLabel.getText(), is(expectedBenefitsTermsLabel)); } @@ -822,10 +804,7 @@ assertContentDescriptionEquals(secondLineLabel, /* position= */ 1, /* total= */ 1); TextView benefitsTermsLabel = getCreditCardBenefitsTermsLabel(); String expectedBenefitsTermsLabel = - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_bottom_sheet_benefits_terms_label); + getString(R.string.autofill_payment_method_bottom_sheet_benefits_terms_label); assertThat(benefitsTermsLabel.getText(), is(expectedBenefitsTermsLabel)); } @@ -929,12 +908,7 @@ }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); waitForEvent(actionCallback).run(); } @@ -969,19 +943,9 @@ .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); onView(withText(LOCAL_IBAN.getLabel())) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED)); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); - onView( - withText( - mActivityTestRule - .getActivity() - .getString( - R.string.autofill_payment_method_continue_button))) + onView(withText(getString(R.string.autofill_payment_method_continue_button))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED)); } @@ -1083,11 +1047,36 @@ }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); - onView( - withText( - mActivityTestRule - .getActivity() - .getString(R.string.autofill_loyalty_card_autofill_button))) + onView(withText(getString(R.string.autofill_loyalty_card_autofill_button))) + .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); + waitForEvent(actionCallback).run(); + } + + @Test + @MediumTest + public void testAllLoyaltyCardsItem() { + Runnable actionCallback = mock(Runnable.class); + runOnUiThreadBlocking( + () -> { + mTouchToFillPaymentMethodModel + .get(SHEET_ITEMS) + .add( + new ListItem( + ALL_LOYALTY_CARDS, + createAllLoyaltyCardsItemModel(actionCallback))); + mTouchToFillPaymentMethodModel.set(VISIBLE, true); + }); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + + TextView allLoyaltyCardsItemTitle = + mTouchToFillPaymentMethodView + .getContentView() + .findViewById(R.id.all_loyalty_cards_item_title); + assertThat( + allLoyaltyCardsItemTitle.getText().toString(), + is(getString(R.string.autofill_bottom_sheet_all_your_loyalty_cards))); + + onView(withText(getString(R.string.autofill_bottom_sheet_all_your_loyalty_cards))) .perform(createClickActionWithFlags(MotionEvent.FLAG_WINDOW_IS_OBSCURED)); waitForEvent(actionCallback).run(); } @@ -1122,6 +1111,10 @@ return mBottomSheetController.getSheetState(); } + private String getString(@IdRes int id) { + return mActivityTestRule.getActivity().getString(id); + } + private static PropertyModel createHeaderModel() { return new PropertyModel.Builder(HeaderProperties.ALL_KEYS) .with(IMAGE_DRAWABLE_ID, R.drawable.ic_globe_24dp) @@ -1167,12 +1160,17 @@ private static PropertyModel createLoyaltyCardModel( LoyaltyCard loyaltyCard, Runnable runnable) { - PropertyModel.Builder loyaltyCardModelBuilder = - new PropertyModel.Builder(NON_TRANSFORMING_LOYALTY_CARD_KEYS) - .with(LOYALTY_CARD_NUMBER, loyaltyCard.getLoyaltyCardNumber()) - .with(MERCHANT_NAME, loyaltyCard.getMerchantName()) - .with(ON_LOYALTY_CARD_CLICK_ACTION, runnable); - return loyaltyCardModelBuilder.build(); + return new PropertyModel.Builder(NON_TRANSFORMING_LOYALTY_CARD_KEYS) + .with(LOYALTY_CARD_NUMBER, loyaltyCard.getLoyaltyCardNumber()) + .with(MERCHANT_NAME, loyaltyCard.getMerchantName()) + .with(ON_LOYALTY_CARD_CLICK_ACTION, runnable) + .build(); + } + + private static PropertyModel createAllLoyaltyCardsItemModel(Runnable runnable) { + return new PropertyModel.Builder(AllLoyaltyCardsItemProperties.ALL_KEYS) + .with(AllLoyaltyCardsItemProperties.ON_CLICK_ACTION, runnable) + .build(); } private static PropertyModel createFillButtonModel(Runnable actionCallback) {
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc index 40894456..b4a951a 100644 --- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc +++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -245,7 +245,8 @@ // expiration delay to a large value by default (in case it was zeroed in a // previous test). TranslateService::InitializeForTesting( - network::mojom::ConnectionType::CONNECTION_WIFI); + network::mojom::ConnectionType::CONNECTION_WIFI, + /*wait_for_eula=*/false); translate::TranslateDownloadManager* download_manager = translate::TranslateDownloadManager::GetInstance(); download_manager->ClearTranslateScriptForTesting();
diff --git a/chrome/browser/translate/translate_service.cc b/chrome/browser/translate/translate_service.cc index 368d763..0f1d12b 100644 --- a/chrome/browser/translate/translate_service.cc +++ b/chrome/browser/translate/translate_service.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/translate/translate_service.h" +#include "base/check_is_test.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/metrics/field_trial.h" @@ -34,6 +35,10 @@ namespace { // The singleton instance of TranslateService. TranslateService* g_translate_service = nullptr; + +// Controls whether EULA is checked for resource requests. +// May be false only in test. +bool g_wait_for_eula = true; } // namespace TranslateService::TranslateService() @@ -41,7 +46,11 @@ g_browser_process->local_state(), switches::kDisableBackgroundNetworking, base::BindOnce(&content::GetNetworkConnectionTracker)) { - resource_request_allowed_notifier_.Init(this, true /* leaky */); + if (!g_wait_for_eula) { + CHECK_IS_TEST(); + } + resource_request_allowed_notifier_.Init(this, true /* leaky */, + g_wait_for_eula); } TranslateService::~TranslateService() = default; @@ -75,8 +84,10 @@ } // static -void TranslateService::InitializeForTesting( - network::mojom::ConnectionType type) { +void TranslateService::InitializeForTesting(network::mojom::ConnectionType type, + bool wait_for_eula) { + g_wait_for_eula = wait_for_eula; + translate::TranslateDownloadManager::GetInstance()->ResetForTesting(); TranslateService::Initialize(); translate::TranslateManager::SetIgnoreMissingKeyForTesting(true); @@ -89,6 +100,7 @@ // static void TranslateService::ShutdownForTesting() { TranslateService::Shutdown(); + g_wait_for_eula = true; } void TranslateService::OnResourceRequestsAllowed() {
diff --git a/chrome/browser/translate/translate_service.h b/chrome/browser/translate/translate_service.h index bde60e5..fe837f1 100644 --- a/chrome/browser/translate/translate_service.h +++ b/chrome/browser/translate/translate_service.h
@@ -27,7 +27,10 @@ // Initializes the TranslateService in a way that it can be initialized // multiple times in a unit test suite (once for each test). Should be paired // with ShutdownForTesting at the end of the test. - static void InitializeForTesting(network::mojom::ConnectionType type); + // If `wait_for_eula` is false, EULA acceptance state is ignored for resource + // requests. + static void InitializeForTesting(network::mojom::ConnectionType type, + bool wait_for_eula = true); // Shuts down the TranslateService at the end of a test in a way that the next // test can initialize and use the service.
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java index c535659..685d176 100644 --- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java +++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java
@@ -16,7 +16,6 @@ import android.app.role.RoleManager; import android.content.pm.ActivityInfo; import android.content.pm.ResolveInfo; -import android.os.Build; import org.junit.After; import org.junit.Assert; @@ -88,10 +87,8 @@ MessagesFactory.attachMessageDispatcher(mWindowAndroid, mMockMessageDispatcher); SearchEngineChoiceService.setInstanceForTests(mMockSearchEngineChoiceService); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - mShadowRoleManager = shadowOf(mActivity.getSystemService(RoleManager.class)); - mShadowRoleManager.addAvailableRole(RoleManager.ROLE_BROWSER); - } + mShadowRoleManager = shadowOf(mActivity.getSystemService(RoleManager.class)); + mShadowRoleManager.addAvailableRole(RoleManager.ROLE_BROWSER); mUtils = new DefaultBrowserPromoUtils(mCounter, mProvider); setDepsMockWithDefaultValues();
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/NightModeUtils.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/NightModeUtils.java index 0666d1ee..a7992d1 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/NightModeUtils.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/NightModeUtils.java
@@ -9,7 +9,6 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; -import android.os.Build; import android.view.ContextThemeWrapper; import androidx.annotation.StyleRes; @@ -58,16 +57,7 @@ // Rebase the theme against the new configuration, so the attributes get resolved to the // correct colors based on the night mode setting. See https://crbug.com/1280540. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - activity.getTheme().rebase(); - } else { - // Theme#rebase() is only available on APIs 29+ and the support library of the method - // isn't guaranteed to succeed on older versions. So, we manually re-apply all the - // cached styles. - for (Integer themeResId : themeResIds) { - activity.getTheme().applyStyle(themeResId, true); - } - } + activity.getTheme().rebase(); } /** @@ -122,7 +112,7 @@ public static @ThemeType int getThemeSetting() { int userSetting = ChromeSharedPreferences.getInstance().readInt(UI_THEME_SETTING, -1); if (userSetting == -1) { - return isNightModeDefaultToLight() ? ThemeType.LIGHT : ThemeType.SYSTEM_DEFAULT; + return ThemeType.SYSTEM_DEFAULT; } else { return userSetting; } @@ -151,11 +141,4 @@ sNightModeSupportedForTest = nightModeSupported; ResettersForTesting.register(() -> sNightModeSupportedForTest = null); } - - /** - * @return Whether or not to default to the light theme. - */ - public static boolean isNightModeDefaultToLight() { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q; - } }
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/RadioButtonGroupThemePreference.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/RadioButtonGroupThemePreference.java index 8744c389..28e7fb4 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/RadioButtonGroupThemePreference.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/RadioButtonGroupThemePreference.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.night_mode.settings; import android.content.Context; -import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.CheckBox; @@ -96,11 +95,9 @@ mButtons.set( ThemeType.SYSTEM_DEFAULT, (RadioButtonWithDescription) holder.findViewById(R.id.system_default)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - mButtons.get(ThemeType.SYSTEM_DEFAULT) - .setDescriptionText( - getContext().getString(R.string.themes_system_default_summary_api_29)); - } + mButtons.get(ThemeType.SYSTEM_DEFAULT) + .setDescriptionText( + getContext().getString(R.string.themes_system_default_summary_api_29)); mButtons.set(ThemeType.LIGHT, (RadioButtonWithDescription) holder.findViewById(R.id.light)); mButtons.set(ThemeType.DARK, (RadioButtonWithDescription) holder.findViewById(R.id.dark));
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragment.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragment.java index b38ea15..963049c 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragment.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragment.java
@@ -6,7 +6,6 @@ import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.UI_THEME_SETTING; -import android.os.Build; import android.os.Bundle; import org.chromium.base.shared_preferences.SharedPreferencesManager; @@ -24,7 +23,6 @@ import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment; import org.chromium.components.browser_ui.settings.CustomDividerFragment; import org.chromium.components.browser_ui.settings.SettingsUtils; -import org.chromium.ui.UiUtils; /** Fragment to manage the theme user settings. */ @NullMarked @@ -89,20 +87,6 @@ } @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // On O_MR1, the flag View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR in this fragment is not - // updated to the attribute android:windowLightNavigationBar set in preference theme, so - // we set the flag explicitly to workaround the issue. See https://crbug.com/942551. - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) { - UiUtils.setNavigationBarIconColor( - getActivity().getWindow().getDecorView(), - getResources().getBoolean(R.bool.window_light_navigation_bar)); - } - } - - @Override public boolean hasDivider() { return false; }
diff --git a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java index 9651670db..8d321dcb 100644 --- a/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java +++ b/chrome/browser/ui/android/night_mode/java/src/org/chromium/chrome/browser/night_mode/settings/ThemeSettingsFragmentTest.java
@@ -11,7 +11,6 @@ import static org.chromium.chrome.browser.flags.ChromeFeatureList.DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING; import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.UI_THEME_SETTING; -import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; @@ -100,13 +99,7 @@ launchThemeSettings(ThemeSettingsEntry.SETTINGS); ThreadUtils.runOnUiThreadBlocking( () -> { - int expectedDefaultTheme = ThemeType.LIGHT; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - Assert.assertFalse( - "Q should not default to light.", - NightModeUtils.isNightModeDefaultToLight()); - expectedDefaultTheme = ThemeType.SYSTEM_DEFAULT; - } + int expectedDefaultTheme = ThemeType.SYSTEM_DEFAULT; Assert.assertEquals( "Incorrect default theme setting.", @@ -151,13 +144,7 @@ launchThemeSettings(ThemeSettingsEntry.SETTINGS); ThreadUtils.runOnUiThreadBlocking( () -> { - int expectedDefaultTheme = ThemeType.LIGHT; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - Assert.assertFalse( - "Q should not default to light.", - NightModeUtils.isNightModeDefaultToLight()); - expectedDefaultTheme = ThemeType.SYSTEM_DEFAULT; - } + int expectedDefaultTheme = ThemeType.SYSTEM_DEFAULT; LinearLayout checkboxContainer = mPreference.getCheckboxContainerForTesting(); RadioButtonWithDescriptionLayout group = mPreference.getGroupForTesting();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java index 548d89e..dbde738 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -445,17 +445,15 @@ // See crbug.com/410642190 super.onTextChanged(text, start, lengthBefore, lengthAfter); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - // Due to crbug.com/1103555, Autofill had to be disabled on the UrlBar to work around - // an issue on Android Q+. With Autofill disabled, the Autofill compat mode no longer - // learns of changes to the UrlBar, which prevents it from cancelling the session if - // the domain changes. We restore this behavior by mimicking the relevant part of - // TextView.notifyListeningManagersAfterTextChanged(). - // https://cs.android.com/android/platform/superproject/+/5d123b67756dffcfdebdb936ab2de2b29c799321:frameworks/base/core/java/android/widget/TextView.java;l=10618;drc=master;bpv=0 - final AutofillManager afm = getContext().getSystemService(AutofillManager.class); - if (afm != null) { - afm.notifyValueChanged(this); - } + // Due to crbug.com/1103555, Autofill had to be disabled on the UrlBar to work around + // an issue on Android Q+. With Autofill disabled, the Autofill compat mode no longer + // learns of changes to the UrlBar, which prevents it from cancelling the session if + // the domain changes. We restore this behavior by mimicking the relevant part of + // TextView.notifyListeningManagersAfterTextChanged(). + // https://cs.android.com/android/platform/superproject/+/5d123b67756dffcfdebdb936ab2de2b29c799321:frameworks/base/core/java/android/widget/TextView.java;l=10618;drc=master;bpv=0 + final AutofillManager afm = getContext().getSystemService(AutofillManager.class); + if (afm != null) { + afm.notifyValueChanged(this); } limitDisplayableLength();
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarApi26.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarApi26.java index 1a36102..c5339940 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarApi26.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarApi26.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.omnibox; import android.content.Context; -import android.os.Build; import android.util.AttributeSet; import android.view.ViewStructure; @@ -38,10 +37,6 @@ // https://crbug.com/1103555: Prevent augmented autofill service from taking over the // session by disabling both standard and augmented autofill on versions of Android // where both are supported. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - return AUTOFILL_TYPE_NONE; - } else { - return super.getAutofillType(); - } + return AUTOFILL_TYPE_NONE; } }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java index b48d670f..5eb4f64 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java
@@ -10,8 +10,6 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Build.VERSION; import android.os.Handler; import android.transition.ChangeBounds; import android.transition.Fade; @@ -325,8 +323,7 @@ // Set hover state tooltip text for optional toolbar buttons(e.g. share, voice search, new // tab and profile). if (buttonSpec.getHoverTooltipTextId() != ButtonSpec.INVALID_TOOLTIP_TEXT_ID - && mButton != null - && VERSION.SDK_INT >= Build.VERSION_CODES.O) { + && mButton != null) { TooltipCompat.setTooltipText( mButton, getContext().getString(buttonSpec.getHoverTooltipTextId())); } else {
diff --git a/chrome/browser/ui/autofill/autofill_client_provider.cc b/chrome/browser/ui/autofill/autofill_client_provider.cc index 8e6581e..5e6e3a2b 100644 --- a/chrome/browser/ui/autofill/autofill_client_provider.cc +++ b/chrome/browser/ui/autofill/autofill_client_provider.cc
@@ -92,7 +92,6 @@ availability = AndroidAutofillAvailabilityStatus::kAvailable; } ABSL_FALLTHROUGH_INTENDED; // No skip-awg-check but skip-all may apply. - case AndroidAutofillAvailabilityStatus::kAndroidVersionTooOld: case AndroidAutofillAvailabilityStatus::kAndroidAutofillManagerNotAvailable: case AndroidAutofillAvailabilityStatus::kAndroidAutofillNotSupported: case AndroidAutofillAvailabilityStatus::kUnknownAndroidAutofillService:
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc index b36eb03..8c8ca11 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
@@ -297,6 +297,7 @@ #endif browser_frame_ = nullptr; browser_view_ = nullptr; + DesktopWindowTreeHostLinux::ClientDestroyedWidget(); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc index 766aa916..8b9a1aa 100644 --- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc +++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -546,6 +546,7 @@ browser_window_property_manager_.reset(); browser_frame_ = nullptr; browser_view_ = nullptr; + DesktopWindowTreeHostWin::ClientDestroyedWidget(); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc index 4b208868..ce504264 100644 --- a/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc +++ b/chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc
@@ -183,6 +183,7 @@ case base::nix::DESKTOP_ENVIRONMENT_UNITY: case base::nix::DESKTOP_ENVIRONMENT_XFCE: case base::nix::DESKTOP_ENVIRONMENT_LXQT: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: return false; } NOTREACHED();
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc index edac099..5e15a858 100644 --- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
@@ -8,6 +8,7 @@ #include <optional> #include "base/callback_list.h" +#include "base/check_is_test.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/functional/bind.h" @@ -124,6 +125,7 @@ bool IsBrowserForSystemWebApp(const Browser* browser) { #if BUILDFLAG(IS_CHROMEOS) + CHECK(browser); const auto* const app_controller = browser->app_controller(); if (app_controller && app_controller->system_app()) { return true; @@ -210,7 +212,10 @@ // Register for memory usage enabled pref change events. Exclude // tracking them for system web apps (e.g. ChromeOS terminal app). - if (!IsBrowserForSystemWebApp(tab_strip_->GetBrowser())) { + Browser* browser = tab_strip_->GetBrowser(); + if (!browser) { + CHECK_IS_TEST(); + } else if (!IsBrowserForSystemWebApp(browser)) { OnHovercardMemoryUsageEnabledChanged(); pref_change_registrar_.Add( prefs::kHoverCardMemoryUsageEnabled,
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.cc b/chrome/browser/ui/web_applications/navigation_capturing_process.cc index 5c22c94..0d41110 100644 --- a/chrome/browser/ui/web_applications/navigation_capturing_process.cc +++ b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
@@ -656,12 +656,6 @@ return CancelInitialNavigation( NavigationCapturingInitialResult::kNavigationCanceled); } - // App popups and picture-in-picture are handled in the switch statement in - // `GetBrowserAndTabForDisposition()`. - if (disposition_ == WindowOpenDisposition::NEW_POPUP || - disposition_ == WindowOpenDisposition::NEW_PICTURE_IN_PICTURE) { - return CapturingDisabled(); - } const webapps::AppId& iwa_id = *first_navigation_app_id_; @@ -669,19 +663,34 @@ bool iwa_browser = params.browser && web_app::AppBrowserController::IsForWebApp(params.browser, iwa_id); - if (iwa_browser) { - if (disposition_ == WindowOpenDisposition::CURRENT_TAB) { - return CapturingDisabled(); - } - // If the browser window does not yet have any tabs, and we are - // attempting to add the first tab to it, allow for it to be reused. - bool navigating_new_tab = - disposition_ == WindowOpenDisposition::NEW_FOREGROUND_TAB || - disposition_ == WindowOpenDisposition::NEW_BACKGROUND_TAB; - if (navigating_new_tab && params.browser->tab_strip_model()->empty()) { - return CapturingDisabled(); + bool capturing_disabled = [&]() { + switch (disposition_) { + case WindowOpenDisposition::NEW_POPUP: + case WindowOpenDisposition::NEW_PICTURE_IN_PICTURE: + // App popups and picture-in-picture are handled in the switch statement + // in `GetBrowserAndTabForDisposition()`. + return true; + case WindowOpenDisposition::NEW_FOREGROUND_TAB: + case WindowOpenDisposition::NEW_BACKGROUND_TAB: + // If the browser window does not yet have any tabs, and we are + // attempting to add the first tab to it, allow for it to be reused. + return iwa_browser && params.browser->tab_strip_model()->empty(); + case WindowOpenDisposition::CURRENT_TAB: + return iwa_browser; + case WindowOpenDisposition::NEW_WINDOW: + case WindowOpenDisposition::UNKNOWN: + case WindowOpenDisposition::SINGLETON_TAB: + case WindowOpenDisposition::SAVE_TO_DISK: + case WindowOpenDisposition::OFF_THE_RECORD: + case WindowOpenDisposition::IGNORE_ACTION: + case WindowOpenDisposition::SWITCH_TO_TAB: + return false; } + }(); + + if (capturing_disabled) { + return CapturingDisabled(); } Browser* host_window = CreateWebAppWindowFromNavigationParams(
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index d3e21d9..7e923d2e 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -584,6 +584,10 @@ return app_name; } + if (provider_->ui_manager().GetNumWindowsForApp(app_id()) == 1) { + return app_name; + } + return base::StrCat({app_name, u" - ", raw_title}); }
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 68e68408..aad1b0c 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -2158,7 +2158,9 @@ EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); NavigateViaLinkClickToURLAndWait( app_browser, https_server()->GetURL("app.site.test", "/simple.html")); - EXPECT_EQ(u"A Web App - OK", app_browser->GetWindowTitleForCurrentTab(false)); + // The page title is "OK" but the app title should be used instead + // for a single window instance of an app. + EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); } // Ensure that web app windows display the app title instead of the page @@ -2178,9 +2180,9 @@ app_browser->tab_strip_model()->GetActiveWebContents(); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); - // When we are within scope, show the page title. - EXPECT_EQ(u"A Web App - Google", - app_browser->GetWindowTitleForCurrentTab(false)); + // When we are within scope, show the app title for a single instance of an + // app. + EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); NavigateViaLinkClickToURLAndWait( app_browser, https_server()->GetURL("app.site.test", "/simple.html")); @@ -2210,6 +2212,44 @@ EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); } +// Ensure that when a single PWA window is open, only the app name is shown +// in the title. +// When a second window is opened, it includes the page title as a suffix. +// Navigating in the first window updates its title to include the page +// title as a suffix. +IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, MultipleAppWindowTitleTest) { + BrowserWaiter browser_waiter(nullptr); + const GURL app_url = + https_server()->GetURL("/banners/manifest_test_page.html"); + NavigateViaLinkClickToURLAndWait(browser(), app_url); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + const webapps::AppId app_id = test::InstallForWebContents( + browser()->profile(), web_contents, + webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON); + + Browser* app_browser = browser_waiter.AwaitAdded(FROM_HERE); + EXPECT_EQ(u"Manifest test app", app_browser->GetWindowTitleForCurrentTab( + /*include_app_name=*/false)); + + Browser* const second_browser = LaunchWebAppBrowserAndWait(app_id); + content::WebContents* const second_web_contents = + second_browser->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::WaitForLoadStop(second_web_contents)); + ASSERT_TRUE(AppBrowserController::IsForWebApp(second_browser, app_id)); + + EXPECT_EQ( + u"Manifest test app - Web app banner test page", + second_browser->GetWindowTitleForCurrentTab(/*include_app_name=*/false)); + + // The first browser window should update title after navigation. + NavigateViaLinkClickToURLAndWait(app_browser, app_url); + EXPECT_EQ( + u"Manifest test app - Web app banner test page", + app_browser->GetWindowTitleForCurrentTab(/*include_app_name=*/false)); +} + // WebApps should have origin text. IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, OriginTextRemoved) { const GURL app_url = GetInstallableAppURL();
diff --git a/chrome/browser/ui/webui/settings/settings_utils_linux.cc b/chrome/browser/ui/webui/settings/settings_utils_linux.cc index a416e01..e8ec30c 100644 --- a/chrome/browser/ui/webui/settings/settings_utils_linux.cc +++ b/chrome/browser/ui/webui/settings/settings_utils_linux.cc
@@ -49,6 +49,8 @@ const char* const kDeepinProxyConfigCommand[] = {"dde-control-center", "-m", "network"}; +const char* const kCosmicProxyConfigCommand[] = {"cosmic-settings", "network"}; + // The URL for Linux proxy configuration help when not running under a // supported desktop environment. constexpr char kLinuxProxyConfigUrl[] = "chrome://linux-proxy-config"; @@ -149,6 +151,10 @@ launched = StartProxyConfigUtil(kKDE6ProxyConfigCommand); break; + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: + launched = StartProxyConfigUtil(kCosmicProxyConfigCommand); + break; + case base::nix::DESKTOP_ENVIRONMENT_XFCE: case base::nix::DESKTOP_ENVIRONMENT_LXQT: case base::nix::DESKTOP_ENVIRONMENT_OTHER:
diff --git a/chrome/browser/ui/webui/whats_new/whats_new_storage_service_impl_unittest.cc b/chrome/browser/ui/webui/whats_new/whats_new_storage_service_impl_unittest.cc index 722befa6..c30c720 100644 --- a/chrome/browser/ui/webui/whats_new/whats_new_storage_service_impl_unittest.cc +++ b/chrome/browser/ui/webui/whats_new/whats_new_storage_service_impl_unittest.cc
@@ -4,9 +4,11 @@ #include "chrome/browser/ui/webui/whats_new/whats_new_storage_service_impl.h" +#include "chrome/browser/global_features.h" #include "chrome/common/chrome_version.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" +#include "components/user_education/webui/whats_new_registry.h" #include "testing/gtest/include/gtest/gtest.h" class WhatsNewStorageServiceTest : public testing::Test { @@ -17,17 +19,25 @@ void SetUp() override { testing::Test::SetUp(); - storage_service_ = - std::make_unique<whats_new::WhatsNewStorageServiceImpl>(); + + // WhatsNewStorageServiceImpl is created and initialized in + // GlobalFeatures::CreateWhatsNewRegistry() in the same way as the + // production. + storage_service_ = TestingBrowserProcess::GetGlobal() + ->GetFeatures() + ->whats_new_registry() + ->GetMutableStorageServiceForTesting(); + // Resets it here to satisfy the precondition. + storage_service_->Reset(); } void TearDown() override { - storage_service_.reset(); + storage_service_ = nullptr; testing::Test::TearDown(); } protected: - std::unique_ptr<whats_new::WhatsNewStorageService> storage_service_; + raw_ptr<whats_new::WhatsNewStorageService> storage_service_; ScopedTestingLocalState local_state_; };
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc index 030de51..5137b73f 100644 --- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc +++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -4675,7 +4675,7 @@ // Check update takes effect on live web app window. app_window_update.Run(); AppBrowserController* app_controller = app_browser->app_controller(); - EXPECT_EQ(app_controller->GetTitle(), u"New name - Web app banner test page"); + EXPECT_EQ(app_controller->GetTitle(), u"New name"); EXPECT_EQ(app_controller->GetThemeColor(), SK_ColorGREEN); // Force the app icon to load again and check that it's the new one.
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index 0cf1957..30874fa 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1750269586-2541c10ab89657ed3256b53b3de94658682995c1-dd570630dd79aeff1c3fb36a63d96f1ffd6181cb.profdata +chrome-android32-main-1750398892-0c6509bb8a78b91ba7face94e542ca7ad6910a9b-f77793b2afb14e49cb5be2c29b1269741be81695.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index c2e2bfc5..e12e17a 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1750357489-177384a0ab01db513be8fc3baa999ad2f53aacf4-f06918e3c7a545f7b681d02a7590c3973be54cc9.profdata +chrome-android64-main-1750405413-29933facb59d6f55a29bb1b07fe237032aa14329-558ed507cbc466d97a9139a5f77581d4e5f55d0d.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt index ea85cb2..47255ec 100644 --- a/chrome/build/android-desktop-x64.pgo.txt +++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@ -chrome-android-desktop-x64-main-1750318566-189f587f0bb5c58b601f136f0560aac9109aeda6-8af14c9bdc88f1a0975c23e63c0834d75b06c770.profdata +chrome-android-desktop-x64-main-1750399281-0d6a4fab094e091b031248ed5e363c178368e522-8d1dfcf686439ae4b28eaf59cfed8925b167369d.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 630a6112..eb9fcf6 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1750334220-384f3305931f50ac93bab045eb3391c976ede5c9-12dc10e4b46d562de2a591ed14c26ad65506775b.profdata +chrome-linux-main-1750398892-570f6f17b0026a29e46be76ac316669e7d58d453-f77793b2afb14e49cb5be2c29b1269741be81695.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index a439f7d..7450f3a 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1750363175-8b4ba7735d137dc6ea78ef20fa63c4f54e6b04d5-913bcb67a2810d40c6e41dbdfd265980c84344af.profdata +chrome-mac-arm-main-1750405413-9c19d675cd73804cd1a53e96f05cd2a4d28d47d9-558ed507cbc466d97a9139a5f77581d4e5f55d0d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index f446300..27d5b6d 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1750334220-5e66a37f9ea1a1bbeee19c78bb57ec8685768d6f-12dc10e4b46d562de2a591ed14c26ad65506775b.profdata +chrome-mac-main-1750398892-2796e3beec873d3e688f7837ba67be39cb5a0926-f77793b2afb14e49cb5be2c29b1269741be81695.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index ea397f8..8669eb0 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1750334220-7f06cb7efbfdb140ecf56ae1cab346e18943aff6-12dc10e4b46d562de2a591ed14c26ad65506775b.profdata +chrome-win-arm64-main-1750377569-cd7e02dc5a39229b108c336f8aa3f4706412566c-819d9c41f166fd60a26d8034d3cfb31468b15635.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index aadc8c9d..5cb85f6 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1750323273-a3ecc05df4b51f2bae00cbd691a02256f9a4fc30-da89cfc19ad7b608b6f9741a598b97dbb3dfc2f5.profdata +chrome-win32-main-1750366781-864436dd8343f85f2c935d83e08087703e381749-19d14ae4a957ef0f158e3b37cc7f3c76e839ce5d.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index b15fd5e2..fbccebc2 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1750312787-7a08c10602284f11ad063d6a444da3dc21d6c582-b8253859060147acedd34cb5515d4d9c96d56aac.profdata +chrome-win64-main-1750366781-3028e378b10524f70cd39d9457a3bfb780e0f099-19d14ae4a957ef0f158e3b37cc7f3c76e839ce5d.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 97829cfe..03c5ca7 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -361,6 +361,7 @@ sources += [ "actor/action_result.cc", "actor/action_result.h", + "actor/actor_constants.h", "actor/actor_logging.h", "read_anything/read_anything_util.cc", "read_anything/read_anything_util.h",
diff --git a/chrome/common/actor.mojom b/chrome/common/actor.mojom index cceaa513..81dbf0a 100644 --- a/chrome/common/actor.mojom +++ b/chrome/common/actor.mojom
@@ -88,7 +88,7 @@ // This target is the element to scroll. A null target implies scrolling the // page's viewport. If the scroll action returns failure, it means the target // isn't scrollable. - ToolTarget? target; + ToolTarget target; ScrollDirection direction; // Scroll distance in physical pixels, and it should always be positive. float distance;
diff --git a/chrome/common/actor/actor_constants.h b/chrome/common/actor/actor_constants.h new file mode 100644 index 0000000..28893d1 --- /dev/null +++ b/chrome/common/actor/actor_constants.h
@@ -0,0 +1,16 @@ +// 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_COMMON_ACTOR_ACTOR_CONSTANTS_H_ +#define CHROME_COMMON_ACTOR_ACTOR_CONSTANTS_H_ + +namespace actor { + +// 0 is not a valid DOMNodeId so it is used to indicate targeting the +// root/viewport. +inline constexpr int kRootElementDomNodeId = 0; + +} // namespace actor + +#endif // CHROME_COMMON_ACTOR_ACTOR_CONSTANTS_H_
diff --git a/chrome/renderer/actor/scroll_tool.cc b/chrome/renderer/actor/scroll_tool.cc index 90e4f135..b0c831e6 100644 --- a/chrome/renderer/actor/scroll_tool.cc +++ b/chrome/renderer/actor/scroll_tool.cc
@@ -10,6 +10,7 @@ #include "base/strings/to_string.h" #include "base/time/time.h" #include "chrome/common/actor/action_result.h" +#include "chrome/common/actor/actor_constants.h" #include "chrome/common/actor/actor_logging.h" #include "chrome/renderer/actor/tool_utils.h" #include "content/public/renderer/render_frame.h" @@ -87,25 +88,22 @@ mojom::ActionResultCode::kArgumentsInvalid, "Negative Distance")); } + if (action_->target->is_coordinate()) { + NOTIMPLEMENTED() << "Coordinate-based target not yet supported."; + return base::unexpected(MakeErrorResult()); + } WebElement scrolling_element; - if (!action_->target) { + int32_t dom_node_id = action_->target->get_dom_node_id(); + if (dom_node_id == kRootElementDomNodeId) { scrolling_element = web_frame->GetDocument().ScrollingElement(); - if (scrolling_element.IsNull()) { return base::unexpected( MakeResult(mojom::ActionResultCode::kScrollNoScrollingElement)); } } else { - if (action_->target->is_coordinate()) { - NOTIMPLEMENTED() << "Coordinate-based target not yet supported."; - return base::unexpected(MakeErrorResult()); - } - - int32_t dom_node_id = action_->target->get_dom_node_id(); scrolling_element = GetNodeFromId(frame_.get(), dom_node_id).DynamicTo<WebElement>(); - if (scrolling_element.IsNull()) { return base::unexpected( MakeResult(mojom::ActionResultCode::kInvalidDomNodeId));
diff --git a/chrome/test/base/scoped_testing_local_state.cc b/chrome/test/base/scoped_testing_local_state.cc index 9731da0..71154a4 100644 --- a/chrome/test/base/scoped_testing_local_state.cc +++ b/chrome/test/base/scoped_testing_local_state.cc
@@ -4,20 +4,14 @@ #include "chrome/test/base/scoped_testing_local_state.h" -#include "chrome/browser/prefs/browser_prefs.h" #include "chrome/test/base/testing_browser_process.h" -#include "testing/gtest/include/gtest/gtest.h" ScopedTestingLocalState::ScopedTestingLocalState( TestingBrowserProcess* browser_process) - : browser_process_(browser_process) { - CHECK(browser_process_); - RegisterLocalState(local_state_.registry()); - EXPECT_FALSE(browser_process_->local_state()); - browser_process_->SetLocalState(&local_state_); -} + : browser_process_(browser_process) {} -ScopedTestingLocalState::~ScopedTestingLocalState() { - EXPECT_EQ(&local_state_, browser_process_->local_state()); - browser_process_->SetLocalState(nullptr); +ScopedTestingLocalState::~ScopedTestingLocalState() = default; + +TestingPrefServiceSimple* ScopedTestingLocalState::Get() { + return browser_process_->GetTestingLocalState(); }
diff --git a/chrome/test/base/scoped_testing_local_state.h b/chrome/test/base/scoped_testing_local_state.h index 9764ffc..12f5c34 100644 --- a/chrome/test/base/scoped_testing_local_state.h +++ b/chrome/test/base/scoped_testing_local_state.h
@@ -10,6 +10,11 @@ class TestingBrowserProcess; +// DEPRECATED: This class no longer have any effect. TestingBrowserProcess has +// its own testing local state, so unit tests can just use it without setting up +// one. +// TODO(crbug.com/422039036): Remove this class and existing usage. +// // Helper class to temporarily set up a |local_state| in the global // TestingBrowserProcess (for most unit tests it's NULL). class ScopedTestingLocalState { @@ -19,13 +24,10 @@ ScopedTestingLocalState& operator=(const ScopedTestingLocalState&) = delete; ~ScopedTestingLocalState(); - TestingPrefServiceSimple* Get() { - return &local_state_; - } + TestingPrefServiceSimple* Get(); private: raw_ptr<TestingBrowserProcess> browser_process_; - TestingPrefServiceSimple local_state_; }; #endif // CHROME_TEST_BASE_SCOPED_TESTING_LOCAL_STATE_H_
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index 9f895493..693321f 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/notifications/system_notification_helper.h" #include "chrome/browser/permissions/chrome_permissions_client.h" #include "chrome/browser/policy/chrome_browser_policy_connector.h" +#include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h" @@ -42,6 +43,7 @@ #include "components/permissions/permissions_client.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/prefs/pref_service.h" +#include "components/prefs/testing_pref_service.h" #include "components/subresource_filter/content/shared/browser/ruleset_service.h" #include "content/public/browser/network_service_instance.h" #include "extensions/buildflags/buildflags.h" @@ -144,8 +146,11 @@ } TestingBrowserProcess::TestingBrowserProcess() - : platform_part_(std::make_unique<TestingBrowserProcessPlatformPart>()), + : testing_local_state_(std::make_unique<TestingPrefServiceSimple>()), + platform_part_(std::make_unique<TestingBrowserProcessPlatformPart>()), os_crypt_async_(os_crypt_async::GetTestOSCryptAsyncForTesting()) { + RegisterLocalState(testing_local_state_->registry()); + // Observe TaskEnvironment to get a chance to teardown components before // ThreadPool is destroyed. // In production, BrowserProcess is destroyed while ThreadPool is still @@ -159,14 +164,19 @@ // Tear down components for tests that do not have TaskEnvironment. MaybeStartTearDown(); - EXPECT_FALSE(local_state_); #if BUILDFLAG(ENABLE_EXTENSIONS) extensions::ExtensionsBrowserClient::Set(nullptr); extensions::AppWindowClient::Set(nullptr); #endif - if (test_network_connection_tracker_) + if (test_network_connection_tracker_) { content::SetNetworkConnectionTrackerForTesting(nullptr); + } + + // Destroy objects in the same way as BrowserProcessImpl does. + serial_policy_allowed_ports_.reset(); + testing_local_state_.reset(); + browser_policy_connector_.reset(); // Destructors for some objects owned by TestingBrowserProcess will use // g_browser_process if it is not null, so it must be null before proceeding. @@ -278,7 +288,7 @@ // NotificationUIManager can contain references to elements in the current // ProfileManager. So when we change the ProfileManager (typically during test // shutdown) make sure to reset any objects that might maintain references to - // it. See SetLocalState() for a description of a similar situation. + // it. notification_ui_manager_.reset(); #endif profile_manager_ = std::move(profile_manager); @@ -290,7 +300,7 @@ } PrefService* TestingBrowserProcess::local_state() { - return local_state_; + return testing_local_state_.get(); } signin::ActivePrimaryAccountsMetricsRecorder* @@ -309,9 +319,6 @@ policy::ChromeBrowserPolicyConnector* TestingBrowserProcess::browser_policy_connector() { if (!browser_policy_connector_) { - EXPECT_FALSE(created_browser_policy_connector_); - created_browser_policy_connector_ = true; - #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC) // Make sure that the machine policy directory does not exist so that // machine-wide policies do not affect tests. @@ -511,13 +518,11 @@ network_time::NetworkTimeTracker* TestingBrowserProcess::network_time_tracker() { if (!network_time_tracker_) { - if (!local_state_) - return nullptr; - + CHECK(local_state()); network_time_tracker_ = std::make_unique<network_time::NetworkTimeTracker>( std::unique_ptr<base::Clock>(new base::DefaultClock()), std::unique_ptr<base::TickClock>(new base::DefaultTickClock()), - local_state_, nullptr, std::nullopt); + local_state(), nullptr, std::nullopt); } return network_time_tracker_.get(); } @@ -618,34 +623,16 @@ system_notification_helper_ = std::move(system_notification_helper); } -void TestingBrowserProcess::SetLocalState(PrefService* local_state) { - if (!local_state) { - // The local_state_ PrefService is owned outside of TestingBrowserProcess, - // but some of the members of TestingBrowserProcess hold references to it - // (for example, via PrefNotifier members). But given our test - // infrastructure which tears down individual tests before freeing the - // TestingBrowserProcess, there's not a good way to make local_state outlive - // these dependencies. As a workaround, whenever local_state_ is cleared - // (assumedly as part of exiting the test and freeing TestingBrowserProcess) - // any components owned by TestingBrowserProcess that depend on local_state - // are also freed. - network_time_tracker_.reset(); -#if BUILDFLAG(ENABLE_CHROME_NOTIFICATIONS) - notification_ui_manager_.reset(); -#endif - serial_policy_allowed_ports_.reset(); - ShutdownBrowserPolicyConnector(); - created_browser_policy_connector_ = false; - } - local_state_ = local_state; -} - void TestingBrowserProcess::MaybeStartTearDown() { if (is_torn_down_) { return; } is_torn_down_ = true; + network_time_tracker_.reset(); +#if BUILDFLAG(ENABLE_CHROME_NOTIFICATIONS) + notification_ui_manager_.reset(); +#endif ShutdownBrowserPolicyConnector(); } @@ -664,7 +651,6 @@ #endif browser_policy_connector_->Shutdown(); } - browser_policy_connector_.reset(); } TestingBrowserProcessPlatformPart* @@ -719,6 +705,10 @@ } #endif +TestingPrefServiceSimple* TestingBrowserProcess::GetTestingLocalState() { + return testing_local_state_.get(); +} + /////////////////////////////////////////////////////////////////////////////// TestingBrowserProcessInitializer::TestingBrowserProcessInitializer() {
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 07e8e1e..8985217 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -36,6 +36,7 @@ class NotificationPlatformBridge; class NotificationUIManager; class PrefService; +class TestingPrefServiceSimple; class SystemNotificationHelper; namespace extensions { @@ -177,9 +178,6 @@ // TaskEnvironment::DestructionObserver: void WillDestroyCurrentTaskEnvironment() override; - // Set the local state for tests. Consumer is responsible for cleaning it up - // afterwards (using ScopedTestingLocalState, for example). - void SetLocalState(PrefService* local_state); void SetMetricsService(metrics::MetricsService* metrics_service); void SetProfileManager(std::unique_ptr<ProfileManager> profile_manager); void SetSafeBrowsingService(safe_browsing::SafeBrowsingService* sb_service); @@ -210,6 +208,9 @@ std::unique_ptr<UsbSystemTrayIcon> usb_system_tray_icon); #endif + // Same as local_state() but provides TestingPrefServiceSimple interface. + TestingPrefServiceSimple* GetTestingLocalState(); + private: // See CreateInstance() and DestoryInstance() above. TestingBrowserProcess(); @@ -230,13 +231,14 @@ std::unique_ptr<policy::ChromeBrowserPolicyConnector> browser_policy_connector_; - bool created_browser_policy_connector_ = false; std::unique_ptr<network::TestNetworkQualityTracker> test_network_quality_tracker_; raw_ptr<metrics::MetricsService> metrics_service_ = nullptr; raw_ptr<variations::VariationsService> variations_service_ = nullptr; std::unique_ptr<ProfileManager> profile_manager_; + std::unique_ptr<TestingPrefServiceSimple> testing_local_state_; + #if BUILDFLAG(ENABLE_CHROME_NOTIFICATIONS) std::unique_ptr<NotificationUIManager> notification_ui_manager_; #endif @@ -269,7 +271,6 @@ std::unique_ptr<network_time::NetworkTimeTracker> network_time_tracker_; // The following objects are not owned by TestingBrowserProcess: - raw_ptr<PrefService> local_state_ = nullptr; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; std::unique_ptr<TestingBrowserProcessPlatformPart> platform_part_; @@ -311,7 +312,6 @@ // ...stuff... // private: // TestingBrowserProcessInitializer initializer_; -// LocalState local_state_; // Needs a BrowserProcess to initialize. // }; class TestingBrowserProcessInitializer { public:
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index b23c736..ed26639 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -16323.0.0-1069691 \ No newline at end of file +16324.0.0-1069713 \ No newline at end of file
diff --git a/chromeos/ash/services/recording/recording_service.cc b/chromeos/ash/services/recording/recording_service.cc index d897246..6f825ef9 100644 --- a/chromeos/ash/services/recording/recording_service.cc +++ b/chromeos/ash/services/recording/recording_service.cc
@@ -389,7 +389,8 @@ info->visible_rect); scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( info->pixel_format, info->coded_size, visible_rect, visible_rect.size(), - mapping, info->timestamp); + reinterpret_cast<const uint8_t*>(mapping.memory()), mapping.size(), + info->timestamp); if (!frame) { DLOG(ERROR) << "Failed to create a VideoFrame."; return;
diff --git a/clank b/clank index ceeb89e..87625a3 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit ceeb89e0f8224ca96ca05598cf0cfc1a7b652963 +Subproject commit 87625a3482c6c67f2ae49c6ed62f44a8ba86a900
diff --git a/components/autofill/core/browser/form_parsing/internal_resources b/components/autofill/core/browser/form_parsing/internal_resources index b0d7376..103ef5e 160000 --- a/components/autofill/core/browser/form_parsing/internal_resources +++ b/components/autofill/core/browser/form_parsing/internal_resources
@@ -1 +1 @@ -Subproject commit b0d7376c49e618262acef6723c9dbdc7c41d31e8 +Subproject commit 103ef5ee6ebd7611908d3685faf5dc42d79b569d
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index 108f59f5..b5781b8 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -1255,6 +1255,12 @@ <message name="IDS_AUTOFILL_BOTTOM_SHEET_MANAGE_PAYMENT_METHODS" desc="An option in the autofill bottom sheet that triggers navigation to the payment settings." formatter_data="android_java"> Manage payment methods </message> + <message name="IDS_AUTOFILL_BOTTOM_SHEET_ALL_YOUR_LOYALTY_CARDS" desc="An option in the autofill bottom sheet that shows all loyalty cards of a user." formatter_data="android_java"> + All your loyalty cards + </message> + <message name="IDS_AUTOFILL_BOTTOM_SHEET_EXPAND_ALL_LOYALTY_CARDS_DESCRIPTION" desc="Accessibility string for the icon that allows entering the screen with all loyalty cards of a user." formatter_data="android_java"> + Change to all loyalty cards under this menu item. + </message> <message name="IDS_AUTOFILL_BOTTOM_SHEET_MANAGE_LOYALTY_CARDS" desc="An option in the autofill bottom sheet that triggers navigation to the loyalty cards management UI in Google Wallet." formatter_data="android_java"> Manage loyalty cards </message>
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_ALL_YOUR_LOYALTY_CARDS.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_ALL_YOUR_LOYALTY_CARDS.png.sha1 new file mode 100644 index 0000000..bb5ff45 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_ALL_YOUR_LOYALTY_CARDS.png.sha1
@@ -0,0 +1 @@ +cdd7298b45b7d29538ee7a6eb32001715b1289e5 \ No newline at end of file
diff --git a/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_EXPAND_ALL_LOYALTY_CARDS_DESCRIPTION.png.sha1 b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_EXPAND_ALL_LOYALTY_CARDS_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..d397937 --- /dev/null +++ b/components/autofill_payments_strings_grdp/IDS_AUTOFILL_BOTTOM_SHEET_EXPAND_ALL_LOYALTY_CARDS_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +b76735e955dc00cb226322e907171847022bcbd8 \ No newline at end of file
diff --git a/components/capture_mode/camera_video_frame_handler.cc b/components/capture_mode/camera_video_frame_handler.cc index 94845a2..3bf22eb 100644 --- a/components/capture_mode/camera_video_frame_handler.cc +++ b/components/capture_mode/camera_video_frame_handler.cc
@@ -175,8 +175,8 @@ auto& frame_info = buffer->frame_info; auto frame = media::VideoFrame::WrapExternalData( frame_info->pixel_format, frame_info->coded_size, - frame_info->visible_rect, frame_info->visible_rect.size(), mapping, - frame_info->timestamp); + frame_info->visible_rect, frame_info->visible_rect.size(), + mapping.GetMemoryAs<uint8_t>(), mapping.size(), frame_info->timestamp); if (frame) { frame->AddDestructionObserver(base::DoNothingWithBoundArgs(mapping_));
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc index 98e16bae3..a849f01 100644 --- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc +++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -658,9 +658,8 @@ media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_I420, test_image->visible_size, gfx::Rect(test_image->visible_size), test_image->visible_size, - in_shm_->mapping.GetMemoryAsSpan<uint8_t>().first( - test_image->image_data.size()), - base::TimeDelta()); + static_cast<uint8_t*>(in_shm_->mapping.memory()), + test_image->image_data.size(), base::TimeDelta()); LOG_ASSERT(input_frame_.get()); input_frame_->BackWithSharedMemory(&in_shm_->region);
diff --git a/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc b/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc index c994a33..eaca32b 100644 --- a/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc +++ b/components/chromeos_camera/mojo_jpeg_encode_accelerator_service.cc
@@ -262,12 +262,15 @@ return; } + const uint8_t* input_shm_memory = + input_mapping.GetMemoryAsSpan<uint8_t>().data(); scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_I420, // format coded_size, // coded_size gfx::Rect(coded_size), // visible_rect coded_size, // natural_size - input_mapping, // data + input_shm_memory, // data + input_buffer_size, // data_size base::TimeDelta()); // timestamp if (!frame.get()) { LOG(ERROR) << "Could not create VideoFrame for buffer id " << task_id;
diff --git a/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc b/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc index 9269556..b174a4c 100644 --- a/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc +++ b/components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.cc
@@ -238,12 +238,14 @@ return; } + uint8_t* shm_memory = mapping.GetMemoryAsSpan<uint8_t>().data(); scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_I420, // format coded_size, // coded_size gfx::Rect(coded_size), // visible_rect coded_size, // natural_size - mapping, // data + shm_memory, // data + output_buffer_size, // data_size base::TimeDelta()); // timestamp if (!frame.get()) { LOG(ERROR) << "Could not create VideoFrame for input buffer id "
diff --git a/components/gwp_asan/client/extreme_lightweight_detector_quarantine.h b/components/gwp_asan/client/extreme_lightweight_detector_quarantine.h index ea522f0..060e562 100644 --- a/components/gwp_asan/client/extreme_lightweight_detector_quarantine.h +++ b/components/gwp_asan/client/extreme_lightweight_detector_quarantine.h
@@ -42,11 +42,11 @@ #include <vector> #include "base/compiler_specific.h" -#include "base/component_export.h" #include "base/memory/raw_ref.h" #include "base/rand_util.h" #include "base/thread_annotations.h" #include "base/trace_event/malloc_dump_provider.h" +#include "components/gwp_asan/client/export.h" #include "partition_alloc/internal_allocator_forward.h" #include "partition_alloc/partition_alloc_forward.h" #include "partition_alloc/partition_lock.h" @@ -63,7 +63,7 @@ class ExtremeLightweightDetectorQuarantineBranch; -class COMPONENT_EXPORT(GWP_ASAN) ExtremeLightweightDetectorQuarantineRoot { +class GWP_ASAN_EXPORT ExtremeLightweightDetectorQuarantineRoot { public: explicit ExtremeLightweightDetectorQuarantineRoot( partition_alloc::PartitionRoot& allocator_root) @@ -100,7 +100,7 @@ friend class ExtremeLightweightDetectorQuarantineBranch; }; -class COMPONENT_EXPORT(GWP_ASAN) ExtremeLightweightDetectorQuarantineBranch { +class GWP_ASAN_EXPORT ExtremeLightweightDetectorQuarantineBranch { public: using Root = ExtremeLightweightDetectorQuarantineRoot;
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index 1be7e486..8b5980f 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -203,6 +203,8 @@ return metrics::SystemProfileProto::OS::XFCE; case base::nix::DesktopEnvironment::DESKTOP_ENVIRONMENT_LXQT: return metrics::SystemProfileProto::OS::LXQT; + case base::nix::DesktopEnvironment::DESKTOP_ENVIRONMENT_COSMIC: + return metrics::SystemProfileProto::OS::COSMIC; } NOTREACHED();
diff --git a/components/mirroring/service/video_capture_client.cc b/components/mirroring/service/video_capture_client.cc index 7be99d2..5c21e7d 100644 --- a/components/mirroring/service/video_capture_client.cc +++ b/components/mirroring/service/video_capture_client.cc
@@ -235,7 +235,8 @@ frame = media::VideoFrame::WrapExternalData( buffer->info->pixel_format, buffer->info->coded_size, buffer->info->visible_rect, buffer->info->visible_rect.size(), - mapping, buffer->info->timestamp); + mapping.GetMemoryAs<uint8_t>(), frame_allocation_size, + buffer->info->timestamp); } buffer_finished_callback = base::BindPostTaskToCurrentDefault(base::BindOnce( @@ -253,7 +254,8 @@ frame = media::VideoFrame::WrapExternalData( buffer->info->pixel_format, buffer->info->coded_size, buffer->info->visible_rect, buffer->info->visible_rect.size(), - mapping, buffer->info->timestamp); + mapping.GetMemoryAs<uint8_t>(), frame_allocation_size, + buffer->info->timestamp); if (frame) { frame->BackWithOwnedSharedMemory(std::move(shm_region), std::move(mapping));
diff --git a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc index 4eb26590..0e22f80 100644 --- a/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc +++ b/components/os_crypt/async/browser/freedesktop_secret_key_provider.cc
@@ -330,6 +330,7 @@ case base::nix::DESKTOP_ENVIRONMENT_UNITY: case base::nix::DESKTOP_ENVIRONMENT_XFCE: case base::nix::DESKTOP_ENVIRONMENT_LXQT: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: InitializeFreedesktopSecretService(); break; }
diff --git a/components/os_crypt/sync/key_storage_util_linux.cc b/components/os_crypt/sync/key_storage_util_linux.cc index bec399d7..66680df 100644 --- a/components/os_crypt/sync/key_storage_util_linux.cc +++ b/components/os_crypt/sync/key_storage_util_linux.cc
@@ -59,6 +59,7 @@ case base::nix::DESKTOP_ENVIRONMENT_UKUI: case base::nix::DESKTOP_ENVIRONMENT_UNITY: case base::nix::DESKTOP_ENVIRONMENT_XFCE: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: return SelectedLinuxBackend::GNOME_LIBSECRET; // KDE3 didn't use DBus, which our KWallet store uses. case base::nix::DESKTOP_ENVIRONMENT_KDE3:
diff --git a/components/test/data/autofill/heuristics-json/internal b/components/test/data/autofill/heuristics-json/internal index 059ed8f..adc0282 160000 --- a/components/test/data/autofill/heuristics-json/internal +++ b/components/test/data/autofill/heuristics-json/internal
@@ -1 +1 @@ -Subproject commit 059ed8f0e91c6377aded5f0b3826ffe6f8717ab0 +Subproject commit adc0282015eb4a9fa58b09adb2e1dcd75a522b7f
diff --git a/components/user_education/webui/whats_new_registry.h b/components/user_education/webui/whats_new_registry.h index 843ea8c..87d86834 100644 --- a/components/user_education/webui/whats_new_registry.h +++ b/components/user_education/webui/whats_new_registry.h
@@ -214,6 +214,10 @@ return editions_; } + WhatsNewStorageService* GetMutableStorageServiceForTesting() { + return storage_service_.get(); + } + private: std::unique_ptr<WhatsNewStorageService> storage_service_; std::map<std::string, WhatsNewModule> modules_;
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index e05b4da2..15758d49 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -440,13 +440,16 @@ const gfx::Rect& rect, const gfx::Rect& visible_rect, const gfx::Rect& foreground_rect) { - auto memory = base::AlignedUninit<uint8_t>( - rect.size().GetArea() * 2, media::VideoFrame::kFrameAddressAlignment); + std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( + static_cast<unsigned char*>( + base::AlignedAlloc(rect.size().GetArea() * 2, + media::VideoFrame::kFrameAddressAlignment))); const gfx::Rect video_visible_rect = gfx::Rect(rect.width(), rect.height()); scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_Y16, rect.size(), video_visible_rect, - visible_rect.size(), memory, base::TimeDelta()); + visible_rect.size(), memory.get(), rect.size().GetArea() * 2, + base::TimeDelta()); DCHECK_EQ(video_frame->rows(0) % 2, 0); DCHECK_EQ(video_frame->stride(0) % 2, 0ul);
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc index 2a4e1f9f..d46a6153 100644 --- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc +++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -273,7 +273,8 @@ ASSERT_LE(required_bytes_to_hold_planes, mapping.size()); frame = media::VideoFrame::WrapExternalData( info->pixel_format, info->coded_size, info->visible_rect, - info->visible_rect.size(), mapping, info->timestamp); + info->visible_rect.size(), mapping.GetMemoryAs<const uint8_t>(), + mapping.size(), info->timestamp); ASSERT_TRUE(frame); frame->AddDestructionObserver( base::BindOnce([](base::ReadOnlySharedMemoryMapping mapping) {},
diff --git a/components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.cc b/components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.cc index bd9c3e1..5217379 100644 --- a/components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.cc +++ b/components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.cc
@@ -113,9 +113,10 @@ // and 2) the mapped memory remains valid until the // WritableSharedMemoryMapping goes out-of-scope (when the OnceClosure is // destroyed). - scoped_refptr<VideoFrame> frame = - VideoFrame::WrapExternalData(format, size, gfx::Rect(size), size, - pooled_buffer.mapping, base::TimeDelta()); + scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalData( + format, size, gfx::Rect(size), size, + static_cast<uint8_t*>(pooled_buffer.mapping.memory()), + pooled_buffer.mapping.size(), base::TimeDelta()); CHECK(frame); // Sanity-check the assumption being made for SetMarkedBuffer(): CHECK_EQ(frame->data(0), pooled_buffer.mapping.memory());
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java index b3dbd48..6031954 100644 --- a/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java +++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/AuthenticatorImpl.java
@@ -12,7 +12,6 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.util.Pair; @@ -248,9 +247,7 @@ } private boolean couldSupportConditionalMediation() { - return GmsCoreUtils.isWebauthnSupported() - && isChrome(mWebContents) - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + return GmsCoreUtils.isWebauthnSupported() && isChrome(mWebContents); } private boolean couldSupportUvpaa() {
diff --git a/components/webauthn/android/junit/src/org/chromium/components/webauthn/Fido2CredentialRequestRobolectricTest.java b/components/webauthn/android/junit/src/org/chromium/components/webauthn/Fido2CredentialRequestRobolectricTest.java index a416462..4c50629 100644 --- a/components/webauthn/android/junit/src/org/chromium/components/webauthn/Fido2CredentialRequestRobolectricTest.java +++ b/components/webauthn/android/junit/src/org/chromium/components/webauthn/Fido2CredentialRequestRobolectricTest.java
@@ -48,7 +48,6 @@ import org.chromium.base.Callback; import org.chromium.base.FeatureOverrides; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.blink.mojom.AuthenticatorStatus; import org.chromium.blink.mojom.Mediation; import org.chromium.blink.mojom.PublicKeyCredentialCreationOptions; @@ -78,7 +77,6 @@ shadows = { ShadowCredentialManager.class, }) -@MinAndroidSdkLevel(Build.VERSION_CODES.P) public class Fido2CredentialRequestRobolectricTest { private static final String TEST_CHANNEL_EXTRA = "stable"; private static final Boolean TEST_INCOGNITO_EXTRA = true;
diff --git a/components/webauthn/android/junit/src/org/chromium/components/webauthn/IdentityCredentialsHelperRobolectricTest.java b/components/webauthn/android/junit/src/org/chromium/components/webauthn/IdentityCredentialsHelperRobolectricTest.java index ad93aa9..c436369 100644 --- a/components/webauthn/android/junit/src/org/chromium/components/webauthn/IdentityCredentialsHelperRobolectricTest.java +++ b/components/webauthn/android/junit/src/org/chromium/components/webauthn/IdentityCredentialsHelperRobolectricTest.java
@@ -9,7 +9,6 @@ import static org.mockito.Mockito.when; import android.content.Context; -import android.os.Build; import android.os.Bundle; import androidx.test.filters.SmallTest; @@ -23,12 +22,10 @@ import org.mockito.MockitoAnnotations; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.blink.mojom.PublicKeyCredentialCreationOptions; import org.chromium.content_public.browser.RenderFrameHost; @RunWith(BaseRobolectricTestRunner.class) -@MinAndroidSdkLevel(Build.VERSION_CODES.P) public class IdentityCredentialsHelperRobolectricTest { private static final String ORIGIN_STRING = "https://subdomain.coolwebsitekayserispor.com"; private static final byte[] CLIENT_DATA_HASH = new byte[] {1, 2, 3};
diff --git a/components/webauthn/android/junit/src/org/chromium/components/webauthn/cred_man/CredManHelperRobolectricTest.java b/components/webauthn/android/junit/src/org/chromium/components/webauthn/cred_man/CredManHelperRobolectricTest.java index 452b0d5..c6a514d1 100644 --- a/components/webauthn/android/junit/src/org/chromium/components/webauthn/cred_man/CredManHelperRobolectricTest.java +++ b/components/webauthn/android/junit/src/org/chromium/components/webauthn/cred_man/CredManHelperRobolectricTest.java
@@ -26,7 +26,6 @@ import android.credentials.GetCredentialRequest; import android.credentials.GetCredentialResponse; import android.credentials.PrepareGetCredentialResponse; -import android.os.Build; import android.os.Bundle; import androidx.test.filters.SmallTest; @@ -45,7 +44,6 @@ import org.chromium.base.Callback; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.blink.mojom.AuthenticatorStatus; import org.chromium.blink.mojom.Mediation; import org.chromium.blink.mojom.PublicKeyCredentialCreationOptions; @@ -86,7 +84,6 @@ ShadowPrepareGetCredentialResponse.class, ShadowWebContentsStatics.class }) -@MinAndroidSdkLevel(Build.VERSION_CODES.P) public class CredManHelperRobolectricTest { private CredManHelper mCredManHelper; private Fido2ApiTestHelper.AuthenticatorCallback mCallback;
diff --git a/content/browser/devtools/devtools_video_consumer.cc b/content/browser/devtools/devtools_video_consumer.cc index 3e4467a..cb1e5f4 100644 --- a/content/browser/devtools/devtools_video_consumer.cc +++ b/content/browser/devtools/devtools_video_consumer.cc
@@ -178,7 +178,7 @@ // portion of the frame that contains content is used. scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( info->pixel_format, info->coded_size, content_rect, content_rect.size(), - mapping_memory, info->timestamp); + mapping_memory.data(), mapping_memory.size(), info->timestamp); if (!frame) { DLOG(ERROR) << "Unable to create VideoFrame wrapper around the shmem."; return;
diff --git a/content/browser/media/capture/fake_video_capture_stack.cc b/content/browser/media/capture/fake_video_capture_stack.cc index feeca83..97d9cef 100644 --- a/content/browser/media/capture/fake_video_capture_stack.cc +++ b/content/browser/media/capture/fake_video_capture_stack.cc
@@ -148,7 +148,8 @@ auto video_frame = media::VideoFrame::WrapExternalData( frame.frame_info->pixel_format, frame.frame_info->coded_size, frame.frame_info->visible_rect, frame.frame_info->visible_rect.size(), - mapping, frame.frame_info->timestamp); + mapping.GetMemoryAs<const uint8_t>(), mapping.size(), + frame.frame_info->timestamp); CHECK(video_frame); video_frame->set_metadata(frame.frame_info->metadata);
diff --git a/content/browser/service_host/utility_process_sandbox_browsertest.cc b/content/browser/service_host/utility_process_sandbox_browsertest.cc index ccdf187..0eb83fd0 100644 --- a/content/browser/service_host/utility_process_sandbox_browsertest.cc +++ b/content/browser/service_host/utility_process_sandbox_browsertest.cc
@@ -129,7 +129,6 @@ case Sandbox::kIme: case Sandbox::kTts: case Sandbox::kNearby: - case Sandbox::kShapeDetection: #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case Sandbox::kLibassistant: #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
diff --git a/content/browser/service_host/utility_sandbox_delegate.cc b/content/browser/service_host/utility_sandbox_delegate.cc index fe8ef22..5ff3c5d 100644 --- a/content/browser/service_host/utility_sandbox_delegate.cc +++ b/content/browser/service_host/utility_sandbox_delegate.cc
@@ -86,7 +86,6 @@ sandbox_type_ == sandbox::mojom::Sandbox::kIme || sandbox_type_ == sandbox::mojom::Sandbox::kTts || sandbox_type_ == sandbox::mojom::Sandbox::kNearby || - sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection || #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant || #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) @@ -154,7 +153,6 @@ sandbox_type_ == sandbox::mojom::Sandbox::kIme || sandbox_type_ == sandbox::mojom::Sandbox::kTts || sandbox_type_ == sandbox::mojom::Sandbox::kNearby || - sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection || #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant || #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
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 f42bcc4..44bbdb5 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 static org.chromium.build.NullUtil.assumeNonNull; + import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -25,9 +27,10 @@ import org.jni_zero.JNINamespace; import org.jni_zero.NativeMethods; -import org.chromium.base.ContextUtils; import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.Nullable; +import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.WindowAndroid; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicReference; @@ -38,10 +41,20 @@ public class ScreenCapture { private static final String TAG = "ScreenCapture"; + private static class PickState { + final WebContents mWebContents; + final ActivityResult mActivityResult; + + PickState(WebContents webContents, ActivityResult activityResult) { + mWebContents = webContents; + mActivityResult = activityResult; + } + } + // 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); + // requires this state to begin the session. + private static final AtomicReference<PickState> sNextPickState = new AtomicReference<>(null); // Starting a MediaProjection session requires a foreground service to be running. This class // does not handle how that is achieved, but `sLatch` provides a way for this class to wait @@ -55,6 +68,7 @@ private final HandlerThread mBackgroundThread = new HandlerThread("ScreenCapture"); private @Nullable Handler mBackgroundHandler; + private @Nullable WebContents mWebContents; private @Nullable MediaProjection mMediaProjection; // While capture is running these references should only be modified on the background thread. @@ -79,11 +93,19 @@ * * <p>The {@link ActivityResult} is consumed by a subsequent call to {@link #startCapture()}. * - * @param nextResult The {@link ActivityResult} from the MediaProjection API. + * @param webContents The {@link WebContents} initiating the capture. + * @param activityResult The {@link ActivityResult} from the MediaProjection API. */ - public static void onPick(ActivityResult nextResult) { - var oldResult = sNextResult.getAndSet(nextResult); - assert oldResult == null; + public static void onPick(WebContents webContents, ActivityResult activityResult) { + final PickState oldPickState = + sNextPickState.getAndSet(new PickState(webContents, activityResult)); + assert oldPickState == null; + } + + private @Nullable Context maybeGetContext() { + final WindowAndroid window = assumeNonNull(mWebContents).getTopLevelNativeWindow(); + if (window == null) return null; + return window.getContext().get(); } @CalledByNative @@ -93,24 +115,28 @@ @CalledByNative boolean startCapture() { - var nextResult = sNextResult.getAndSet(null); - assert nextResult != null; - assert nextResult.getData() != null; + final PickState pickState = sNextPickState.getAndSet(null); + assert pickState != null; + mWebContents = pickState.mWebContents; + + final ActivityResult activityResult = pickState.mActivityResult; + assert activityResult.getData() != null; // We need to wait for the foreground service to start before trying to use the // MediaProjection API. It's okay to block here since we are on the desktop capturer thread. sLatch.block(); - // TODO(crbug.com/352187279): Use the specific activity context for the captured target - // here. - final Context context = ContextUtils.getApplicationContext(); + // TODO(crbug.com/352187279): Update the context if the WebContents is reparented. + final Context context = maybeGetContext(); + if (context == null) return false; var manager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE); if (manager == null) return false; mMediaProjection = - manager.getMediaProjection(nextResult.getResultCode(), nextResult.getData()); + manager.getMediaProjection( + activityResult.getResultCode(), activityResult.getData()); if (mMediaProjection == null) return false; mBackgroundThread.start();
diff --git a/content/renderer/pepper/pepper_video_capture_host.cc b/content/renderer/pepper/pepper_video_capture_host.cc index c961733..970254e 100644 --- a/content/renderer/pepper/pepper_video_capture_host.cc +++ b/content/renderer/pepper/pepper_video_capture_host.cc
@@ -165,11 +165,8 @@ scoped_refptr<media::VideoFrame> dst_frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_I420, frame->natural_size(), - gfx::Rect(frame->natural_size()), frame->natural_size(), - // TODO(crbug.com/40511450): Remove PPAPI altogether - UNSAFE_TODO( - base::span<uint8_t>(dst, buffers_[i].buffer->size())), - frame->timestamp()); + gfx::Rect(frame->natural_size()), frame->natural_size(), dst, + buffers_[i].buffer->size(), frame->timestamp()); media::EncoderStatus status = frame_converter_.ConvertAndScale(*mapped_frame, *dst_frame); if (!status.is_ok()) {
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc index 7231220..f5a86f57 100644 --- a/content/renderer/pepper/pepper_video_encoder_host.cc +++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -524,11 +524,8 @@ // ppapi/shared_impl/media_stream_buffer_manager.h for details. scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData( media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_), - input_coded_size_, - // TODO(crbug.com/40511450): Remove PPAPI altogether - UNSAFE_TODO( - base::span<uint8_t>(buffer->video.data, buffer->video.data_size)), - base::TimeDelta()); + input_coded_size_, static_cast<uint8_t*>(buffer->video.data), + buffer->video.data_size, base::TimeDelta()); if (!frame) { NotifyPepperError(PP_ERROR_FAILED); return frame;
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt index 43b26c6..afb49277 100644 --- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -229,6 +229,10 @@ crbug.com/365565140 [ angle-metal asan graphite-enabled intel-0x3e9b arch-x86_64 no-clang-coverage release sonoma ] ContextLost_WebGPUUnblockedAfterUserInitiatedReload [ Failure ] crbug.com/365565140 [ angle-opengl debug graphite-disabled intel-0x3e9b arch-x86_64 no-asan no-clang-coverage sonoma ] ContextLost_WebGPUUnblockedAfterUserInitiatedReload [ Failure ] +# Renderer Hung Possibly just Slow +crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan graphite-disabled ] ContextLost_WebGPUUnblockedAfterUserInitiatedReload [ Failure ] +crbug.com/338574390 [ mac intel-0x3e9b angle-metal asan graphite-disabled ] GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash [ Failure ] + ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc index c1c42c5..86cb9fd 100644 --- a/content/utility/utility_main.cc +++ b/content/utility/utility_main.cc
@@ -89,8 +89,6 @@ #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) #include "chromeos/ash/services/libassistant/libassistant_sandbox_hook.h" // nogncheck #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) - -#include "services/shape_detection/shape_detection_sandbox_hook.h" #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_MAC) @@ -351,10 +349,6 @@ case sandbox::mojom::Sandbox::kTts: pre_sandbox_hook = base::BindOnce(&chromeos::tts::TtsPreSandboxHook); break; - case sandbox::mojom::Sandbox::kShapeDetection: - pre_sandbox_hook = - base::BindOnce(&shape_detection::ShapeDetectionPreSandboxHook); - break; #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case sandbox::mojom::Sandbox::kLibassistant: pre_sandbox_hook =
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md index 072e2bc..f41183a2 100644 --- a/docs/android_build_instructions.md +++ b/docs/android_build_instructions.md
@@ -124,7 +124,8 @@ ## Setting up the build -Chromium uses [Ninja](https://ninja-build.org) as its main build tool along with +Chromium uses [Siso](https://pkg.go.dev/go.chromium.org/infra/build/siso#section-readme) +as its main build tool along with a tool called [GN](https://gn.googlesource.com/gn/+/main/docs/quick_start.md) to generate `.ninja` files. You can create any number of *build directories* with different configurations. To create a build directory which builds Chrome @@ -138,7 +139,7 @@ is_component_build = false # Unless you do a lot of native code edits. See "Faster Builds". ``` -* You only have to run this once for each new build directory, Ninja will +* You only have to run this once for each new build directory, Siso will update the build files as needed. * You can replace `Default` with another name, but it should be a subdirectory of `out`. @@ -174,14 +175,14 @@ ## Build Chromium -Build Chromium with Ninja using the command: +Build Chromium with Siso or Ninja using the command: ```shell autoninja -C out/Default chrome_public_apk ``` (`autoninja` is a wrapper that automatically provides optimal values for the -arguments passed to `ninja`.) +arguments passed to `siso` or `ninja`.) You can get a list of all of the other build targets from GN by running `gn ls out/Default` from the command line. To compile one, pass the GN label to Ninja @@ -371,7 +372,7 @@ Args that affect build speed: * `use_remoteexec = true` *(default=false)* - * What it does: Enables distributed builds via Reclient + * What it does: Enables distributed builds with remote exec API. * `symbol_level = 0` *(default=1)* * What it does: Disables most debug information in native code. * Stack traces will still show, but be missing frames for inlined functions and source lines. @@ -421,10 +422,10 @@ build/android/fast_local_dev_server.py --print-status-all ``` -### Use Reclient +### Use Remote Execution *** note -**Warning:** If you are a Google employee, do not follow the Reclient instructions +**Warning:** If you are a Google employee, do not follow the instructions in this section. Set up remote execution as described in [go/building-android-chrome](https://goto.google.com/building-android-chrome) instead. @@ -435,8 +436,8 @@ you to benefit from remote caching and executing many build actions in parallel on a shared cluster of workers. -To use Reclient, follow the corresponding -[Linux build instructions](linux/build_instructions.md#use-reclient). +To use Remote Execution, follow the corresponding +[Linux build instructions](linux/build_instructions.md#use-remote-execution). ### Incremental Install [Incremental Install](/build/android/incremental_install/README.md) uses
diff --git a/extensions/browser/api/declarative/declarative_api.cc b/extensions/browser/api/declarative/declarative_api.cc index 9c2254f..b11fad0f 100644 --- a/extensions/browser/api/declarative/declarative_api.cc +++ b/extensions/browser/api/declarative/declarative_api.cc
@@ -202,7 +202,7 @@ EventsEventAddRulesFunction::~EventsEventAddRulesFunction() = default; bool EventsEventAddRulesFunction::CreateParams() { - ConvertBinaryListElementsToBase64(mutable_args()); + ConvertBinaryListElementsToBase64(GetMutableArgs()); params_ = AddRules::Params::Create(args()); return params_.has_value(); }
diff --git a/extensions/browser/api/storage/storage_api.cc b/extensions/browser/api/storage/storage_api.cc index d2f6050..527433af 100644 --- a/extensions/browser/api/storage/storage_api.cc +++ b/extensions/browser/api/storage/storage_api.cc
@@ -103,10 +103,12 @@ EXTENSION_FUNCTION_PRERUN_VALIDATE(args().size() >= 1); EXTENSION_FUNCTION_PRERUN_VALIDATE(args()[0].is_string()); - // Not a ref since we remove the underlying value after. - std::string storage_area_string = args()[0].GetString(); + base::ListValue& mutable_args = GetMutableArgs(); - mutable_args().erase(args().begin()); + // Not a ref since we remove the underlying value after. + const std::string storage_area_string(std::move(mutable_args[0].GetString())); + + mutable_args.erase(mutable_args.begin()); storage_area_ = StorageAreaFromString(storage_area_string); EXTENSION_FUNCTION_PRERUN_VALIDATE(storage_area_ != StorageAreaNamespace::kInvalid); @@ -187,8 +189,10 @@ return RespondNow(BadMessage()); } - base::Value input = std::move(mutable_args()[0]); - mutable_args().erase(args().begin()); + base::ListValue& mutable_args = GetMutableArgs(); + + base::Value input = std::move(mutable_args[0]); + mutable_args.erase(args().begin()); std::optional<std::vector<std::string>> keys; std::optional<base::Value::Dict> defaults; @@ -343,9 +347,11 @@ return RespondNow(BadMessage()); } + base::ListValue& mutable_args = GetMutableArgs(); + // Retrieve and delete input from `args_` since they will be moved to storage. - base::Value input = std::move(mutable_args()[0]); - mutable_args().erase(args().begin()); + base::Value input = std::move(mutable_args[0]); + mutable_args.erase(args().begin()); StorageFrontend* frontend = StorageFrontend::Get(browser_context()); frontend->Set(
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc index 98771c8..3499d764 100644 --- a/extensions/browser/extension_function.cc +++ b/extensions/browser/extension_function.cc
@@ -11,6 +11,7 @@ #include "base/dcheck_is_on.h" #include "base/debug/crash_logging.h" +#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" @@ -46,6 +47,7 @@ #include "extensions/browser/service_worker/service_worker_keepalive.h" #include "extensions/common/constants.h" #include "extensions/common/extension_api.h" +#include "extensions/common/extension_features.h" #include "extensions/common/mojom/renderer.mojom.h" #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h" @@ -607,6 +609,22 @@ return false; } +const base::Value::List& ExtensionFunction::GetOriginalArgs() const { + CHECK(base::FeatureList::IsEnabled( + extensions_features::kAvoidCloneArgsOnExtensionFunctionDispatch)); + + if (original_args_.has_value()) { + // Return `original_args_`, which were copied from `args_` on the first call + // to GetMutableArgs(). + return *original_args_; + } + + // Return `args_`, which haven't been modified since they were set by + // SetArgs(), since GetMutableArgs() was never called. + DCHECK(args_.has_value()); + return *args_; +} + void ExtensionFunction::OnResponseAck() { // Derived classes must override this if they require and implement an // ACK from the renderer. @@ -698,6 +716,19 @@ transferred_blobs_ = std::move(blobs); } +base::Value::List& ExtensionFunction::GetMutableArgs() { + DCHECK(args_); + if (!original_args_.has_value() && + base::FeatureList::IsEnabled( + extensions_features::kAvoidCloneArgsOnExtensionFunctionDispatch)) { + // Preserve original args before allowing modification of `args_`. Not + // needed when `kAvoidCloneArgsOnExtensionFunctionDispatch` is disabled + // since GetOriginalArgs() is disallowed in that configuration. + original_args_ = args_->Clone(); + } + return *args_; +} + void ExtensionFunction::SendResponseImpl(bool success) { DCHECK(!response_callback_.is_null()); DCHECK(!did_respond()) << name_;
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h index 5ca5c7ee..ead131bb 100644 --- a/extensions/browser/extension_function.h +++ b/extensions/browser/extension_function.h
@@ -449,6 +449,12 @@ // via `AddResponseTarget()`. virtual void OnResponseAck(); + // Returns original args, as they were set by SetArgs() (doesn't include + // modifications via GetMutableArgs()). Can only be called when the + // "AvoidCloneArgsOnExtensionFunctionDispatch" feature is enabled (otherwise + // the `ExtensionFunction` owner has preserved the original args). + const base::Value::List& GetOriginalArgs() const; + // Sets did_respond_ to true so that the function won't DCHECK if it never // sends a response. Typically, this shouldn't be used, even in testing. It's // only for when you want to test functionality that doesn't exercise the @@ -593,15 +599,14 @@ bool has_args() const { return args_.has_value(); } + // Returns args. They may have been modified via GetMutableArgs() since they + // were set with SetArgs(). const base::Value::List& args() const { DCHECK(args_); return *args_; } - base::Value::List& mutable_args() { - DCHECK(args_); - return *args_; - } + base::Value::List& GetMutableArgs(); // The extension that called this function. scoped_refptr<const extensions::Extension> extension_; @@ -629,9 +634,19 @@ // failed, `error_` should be set. void SendResponseImpl(bool success); - // The arguments to the API. Only non-null if arguments were specified. + // The arguments to the API. Populated by SetArgs(). May be modified via + // GetMutableArgs(). std::optional<base::Value::List> args_; + // Original arguments to the API. Populated from `args_` when GetMutableArgs() + // is first invoked, otherwise nullopt. This exists because an extension + // function may modify its args via GetMutableArgs(), but the owner of this + // object may need to access the original args via GetOriginalArgs() (the + // owner could also copy the args before passing them to the extension + // function, but that would result in an unnecessary copy when the extension + // function doesn't modify its args). + std::optional<base::Value::List> original_args_; + base::ElapsedTimer timer_; // The results of the API. This should be populated through the Respond()/
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index 742acc3..0191514 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -48,6 +48,7 @@ #include "extensions/browser/service_worker/service_worker_keepalive.h" #include "extensions/common/constants.h" #include "extensions/common/extension_api.h" +#include "extensions/common/extension_features.h" #include "extensions/common/extension_set.h" #include "extensions/common/extension_urls.h" #include "extensions/common/mojom/context_type.mojom.h" @@ -198,7 +199,7 @@ // TODO(crbug.com/40056469): Validate (or remove) `params.source_url`. DispatchWithCallbackInternal( - *params, &frame, *frame.GetProcess(), + std::move(params), &frame, *frame.GetProcess(), base::BindOnce( [](mojom::LocalFrameHost::RequestCallback callback, ExtensionFunction::ResponseType type, base::Value::List results, @@ -254,7 +255,7 @@ } DispatchWithCallbackInternal( - *params, nullptr, *rph, + std::move(params), nullptr, *rph, base::BindOnce( [](mojom::ServiceWorkerHost::RequestWorkerCallback callback, ExtensionFunction::ResponseType type, base::Value::List results, @@ -268,7 +269,7 @@ } void ExtensionFunctionDispatcher::DispatchWithCallbackInternal( - const mojom::RequestParams& params, + mojom::RequestParamsPtr params, content::RenderFrameHost* render_frame_host, content::RenderProcessHost& render_process_host, ExtensionFunction::ResponseCallback callback) { @@ -293,10 +294,10 @@ ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); const Extension* extension = - registry->enabled_extensions().GetByID(params.extension_id); + registry->enabled_extensions().GetByID(params->extension_id); // Check if the call is from a hosted app. Hosted apps can only make call from // render frames, so we can use `render_frame_host_url`. - // TODO(devlin): Isn't `params.extension_id` still populated for hosted app + // TODO(devlin): Isn't `params->extension_id` still populated for hosted app // calls? if (!extension && render_frame_host_url) { extension = registry->enabled_extensions().GetHostedAppByURL( @@ -304,7 +305,7 @@ } if (!process_map->CanProcessHostContextType(extension, render_process_host, - params.context_type)) { + params->context_type)) { // TODO(crbug.com/40055126): Ideally, we'd be able to mark some // of these as bad messages. We can't do that in all cases because there // are times some of these might legitimately fail (for instance, during @@ -318,7 +319,7 @@ return; } - if (params.context_type == mojom::ContextType::kUntrustedWebUi) { + if (params->context_type == mojom::ContextType::kUntrustedWebUi) { // TODO(crbug.com/40265193): We should, at minimum, be using an // origin here. It'd be even better if we could have a more robust way of // checking that a process can host untrusted webui. @@ -333,11 +334,19 @@ } } - const bool is_worker_request = IsRequestFromServiceWorker(params); + const bool is_worker_request = IsRequestFromServiceWorker(*params); + + base::ListValue arguments; + if (base::FeatureList::IsEnabled( + extensions_features::kAvoidCloneArgsOnExtensionFunctionDispatch)) { + arguments = std::move(params->arguments); + } else { + arguments = params->arguments.Clone(); + } scoped_refptr<ExtensionFunction> function = CreateExtensionFunction( - params, extension, render_process_id, is_worker_request, - render_frame_host_url, params.context_type, + *params, std::move(arguments), extension, render_process_id, + is_worker_request, render_frame_host_url, params->context_type, ExtensionAPI::GetSharedInstance(), std::move(callback), render_frame_host); if (!function.get()) { @@ -373,18 +382,29 @@ // Fetch the ProcessManager before |this| is possibly invalidated. ProcessManager* process_manager = ProcessManager::Get(browser_context_); + // TODO(crbug.com/424432184): When the + // `kAvoidCloneArgsOnExtensionFunctionDispatch` feature is cleaned up, this + // lambda can be removed and references to it can be replaced with + // `function->GetOriginalArgs()`. + auto original_args = [&]() -> const base::ListValue& { + if (base::FeatureList::IsEnabled( + extensions_features::kAvoidCloneArgsOnExtensionFunctionDispatch)) { + return function->GetOriginalArgs(); + } + return params->arguments; + }; + ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_); QuotaService* quota = extension_system->quota_service(); - std::string violation_error = - quota->Assess(extension->id(), function.get(), params.arguments, - base::TimeTicks::Now()); + std::string violation_error = quota->Assess( + extension->id(), function.get(), original_args(), base::TimeTicks::Now()); function->set_request_uuid(base::Uuid::GenerateRandomV4()); // Increment the keepalive to ensure the extension doesn't shut down while // it's executing an API function. This is balanced in // `OnExtensionFunctionCompleted()`. - if (IsRequestFromServiceWorker(params)) { + if (is_worker_request) { CHECK(function->worker_id()); content::ServiceWorkerExternalRequestTimeoutType timeout_type = function->ShouldKeepWorkerAliveIndefinitely() @@ -404,7 +424,7 @@ if (violation_error.empty()) { // See crbug.com/39178. ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler(); - NotifyApiFunctionCalled(extension->id(), params.name, params.arguments, + NotifyApiFunctionCalled(extension->id(), params->name, original_args(), browser_context_); // Since sandboxed frames listed in the manifest don't get access to the @@ -432,7 +452,7 @@ } } - if (IsRequestFromServiceWorker(params)) { + if (is_worker_request) { base::UmaHistogramSparse( "Extensions.Functions.ExtensionServiceWorkerCalls", function->histogram_value()); @@ -535,7 +555,8 @@ scoped_refptr<ExtensionFunction> ExtensionFunctionDispatcher::CreateExtensionFunction( - const mojom::RequestParams& params, + const mojom::RequestParams& params_without_args, + base::ListValue arguments, const Extension* extension, int requesting_process_id, bool is_worker_request, @@ -547,16 +568,17 @@ constexpr char kCreationFailed[] = "Access to extension API denied."; scoped_refptr<ExtensionFunction> function = - ExtensionFunctionRegistry::GetInstance().NewFunction(params.name); + ExtensionFunctionRegistry::GetInstance().NewFunction( + params_without_args.name); if (!function) { - LOG(ERROR) << "Unknown Extension API - " << params.name; + LOG(ERROR) << "Unknown Extension API - " << params_without_args.name; ResponseCallbackOnError(std::move(callback), ExtensionFunction::ResponseType::kFailed, kCreationFailed); return nullptr; } - function->SetArgs(params.arguments.Clone()); + function->SetArgs(std::move(arguments)); // Determine the source URL. When possible, prefer fetching this value from // the RenderFrameHost, but fallback to the value in the `params` object if @@ -566,17 +588,17 @@ if (is_worker_request) { // TODO(crbug.com/40056469): Validate this URL further. Or, better, // remove it from `mojom::RequestParams`. - function->set_source_url(params.source_url); + function->set_source_url(params_without_args.source_url); } else { DCHECK(render_frame_host_url); function->set_source_url(*render_frame_host_url); } - function->set_has_callback(params.has_callback); - function->set_user_gesture(params.user_gesture); + function->set_has_callback(params_without_args.has_callback); + function->set_user_gesture(params_without_args.user_gesture); function->set_extension(extension); - if (params.js_callstack.has_value()) { - function->set_js_callstack(*params.js_callstack); + if (params_without_args.js_callstack.has_value()) { + function->set_js_callstack(*params_without_args.js_callstack); } function->set_response_callback(std::move(callback)); function->set_source_context_type(context_type); @@ -584,8 +606,8 @@ if (is_worker_request) { CHECK(extension); WorkerId worker_id; - worker_id.thread_id = params.worker_thread_id; - worker_id.version_id = params.service_worker_version_id; + worker_id.thread_id = params_without_args.worker_thread_id; + worker_id.version_id = params_without_args.service_worker_version_id; worker_id.render_process_id = requesting_process_id; worker_id.extension_id = extension->id(); function->set_worker_id(std::move(worker_id)); @@ -599,7 +621,7 @@ function->SetDispatcher(weak_ptr_factory_.GetWeakPtr()); if (!function->HasPermission()) { - LOG(ERROR) << "Permission denied for " << params.name; + LOG(ERROR) << "Permission denied for " << params_without_args.name; function->RespondWithError(kCreationFailed); return nullptr; }
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h index 45fc4eb1..e588d0d 100644 --- a/extensions/browser/extension_function_dispatcher.h +++ b/extensions/browser/extension_function_dispatcher.h
@@ -12,6 +12,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/values.h" #include "extensions/browser/extension_function.h" #include "extensions/common/features/feature.h" #include "extensions/common/mojom/context_type.mojom-forward.h" @@ -121,7 +122,8 @@ // `params`. // Does not set subclass properties, or include_incognito. scoped_refptr<ExtensionFunction> CreateExtensionFunction( - const mojom::RequestParams& params, + const mojom::RequestParams& params_without_args, + base::ListValue arguments, const Extension* extension, int requesting_process_id, bool is_worker_request, @@ -132,7 +134,7 @@ content::RenderFrameHost* render_frame_host); void DispatchWithCallbackInternal( - const mojom::RequestParams& params, + mojom::RequestParamsPtr params, content::RenderFrameHost* render_frame_host, content::RenderProcessHost& render_process_host, ExtensionFunction::ResponseCallback callback);
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 1a1e4f2..04c9252 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -252,4 +252,8 @@ "OptimizeServiceWorkerStartRequests", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kAvoidCloneArgsOnExtensionFunctionDispatch, + "AvoidCloneArgsOnExtensionFunctionDispatch", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace extensions_features
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h index 67312520..e239773 100644 --- a/extensions/common/extension_features.h +++ b/extensions/common/extension_features.h
@@ -281,6 +281,12 @@ // initiating a start. BASE_DECLARE_FEATURE(kOptimizeServiceWorkerStartRequests); +// When enabled, a call to base::ListValue::Clone is avoided when dispatching an +// extension function. Behind a feature to assess impact +// (go/chrome-performance-work-should-be-finched). +// TODO(crbug.com/424432184): Clean up when experiment is complete. +BASE_DECLARE_FEATURE(kAvoidCloneArgsOnExtensionFunctionDispatch); + } // namespace extensions_features #endif // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/gpu/command_buffer/client/client_shared_image.cc b/gpu/command_buffer/client/client_shared_image.cc index 635d976..1a973d3 100644 --- a/gpu/command_buffer/client/client_shared_image.cc +++ b/gpu/command_buffer/client/client_shared_image.cc
@@ -25,6 +25,7 @@ #include "mojo/public/cpp/bindings/callback_helpers.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_types.h" +#include "ui/gfx/gpu_memory_buffer.h" namespace gpu { @@ -424,6 +425,25 @@ } } +size_t ClientSharedImage::GetStrideForVideoFrame(uint32_t plane_index) const { + CHECK(gpu_memory_buffer_); + return gpu_memory_buffer_->stride(plane_index); +} + +// Returns whether the underlying resource is shared memory without needing to +// Map() the shared image. This method is supposed to be used by VideoFrame +// temporarily as mentioned above in ::GetStrideForVideoFrame(). +bool ClientSharedImage::IsSharedMemoryForVideoFrame() const { + CHECK(gpu_memory_buffer_); + return gpu_memory_buffer_->GetType() == + gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER; +} + +bool ClientSharedImage::AsyncMappingIsNonBlocking() const { + CHECK(gpu_memory_buffer_); + return gpu_memory_buffer_->AsyncMappingIsNonBlocking(); +} + std::unique_ptr<ClientSharedImage::ScopedMapping> ClientSharedImage::Map() { std::unique_ptr<ClientSharedImage::ScopedMapping> scoped_mapping; if (shared_memory_mapping_.IsValid()) { @@ -445,6 +465,12 @@ std::move(result_cb)); } +gfx::GpuMemoryBufferHandle ClientSharedImage::CloneGpuMemoryBufferHandle() + const { + CHECK(gpu_memory_buffer_); + return gpu_memory_buffer_->CloneHandle(); +} + #if BUILDFLAG(IS_APPLE) void ClientSharedImage::SetColorSpaceOnNativeBuffer( const gfx::ColorSpace& color_space) { @@ -628,6 +654,22 @@ std::nullopt, std::nullopt, texture_target)); } +// static +scoped_refptr<ClientSharedImage> ClientSharedImage::CreateForTesting( + const Mailbox& mailbox, + const SharedImageMetadata& metadata, + const SyncToken& sync_token, + std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer, + gfx::BufferUsage buffer_usage, + scoped_refptr<SharedImageInterfaceHolder> sii_holder) { + SharedImageInfo info(metadata, "CSICreateForTesting"); + auto client_si = base::MakeRefCounted<ClientSharedImage>( + mailbox, info, sync_token, sii_holder, gpu_memory_buffer->GetType()); + client_si->gpu_memory_buffer_ = std::move(gpu_memory_buffer); + client_si->buffer_usage_ = buffer_usage; + return client_si; +} + ClientSharedImage::HelperGpuMemoryBufferManager::HelperGpuMemoryBufferManager( ClientSharedImage* client_shared_image) : client_shared_image_(client_shared_image) {
diff --git a/gpu/command_buffer/client/client_shared_image.h b/gpu/command_buffer/client/client_shared_image.h index 0984add..93057b6 100644 --- a/gpu/command_buffer/client/client_shared_image.h +++ b/gpu/command_buffer/client/client_shared_image.h
@@ -24,9 +24,19 @@ #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkPixmap.h" #include "ui/gfx/color_space.h" -#include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/gpu_memory_buffer_handle.h" +namespace base { +namespace trace_event { +class ProcessMemoryDump; +class MemoryAllocatorDumpGuid; +} // namespace trace_event +} // namespace base + +namespace gfx { +class GpuMemoryBuffer; +} + namespace media { class VideoFrame; } // namespace media @@ -133,10 +143,7 @@ // Returns a clone of the GpuMemoryBufferHandle associated with this ClientSI. // Valid to call only if this instance was created with a non-null // GpuMemoryBuffer. - gfx::GpuMemoryBufferHandle CloneGpuMemoryBufferHandle() const { - CHECK(gpu_memory_buffer_); - return gpu_memory_buffer_->CloneHandle(); - } + gfx::GpuMemoryBufferHandle CloneGpuMemoryBufferHandle() const; #if BUILDFLAG(IS_APPLE) // Sets the color space in which the native buffer backing this SharedImage @@ -217,14 +224,7 @@ const SyncToken& sync_token, std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer, gfx::BufferUsage buffer_usage, - scoped_refptr<SharedImageInterfaceHolder> sii_holder) { - SharedImageInfo info(metadata, "CSICreateForTesting"); - auto client_si = base::MakeRefCounted<ClientSharedImage>( - mailbox, info, sync_token, sii_holder, gpu_memory_buffer->GetType()); - client_si->gpu_memory_buffer_ = std::move(gpu_memory_buffer); - client_si->buffer_usage_ = buffer_usage; - return client_si; - } + scoped_refptr<SharedImageInterfaceHolder> sii_holder); const SyncToken& creation_sync_token() const { return creation_sync_token_; } @@ -341,24 +341,14 @@ // VF can be refactored to behave like OPAQUE storage which does not need // layout info and hence stride. This method will then no longer needed and // can be removed. - size_t GetStrideForVideoFrame(uint32_t plane_index) const { - CHECK(gpu_memory_buffer_); - return gpu_memory_buffer_->stride(plane_index); - } + size_t GetStrideForVideoFrame(uint32_t plane_index) const; // Returns whether the underlying resource is shared memory without needing to // Map() the shared image. This method is supposed to be used by VideoFrame // temporarily as mentioned above in ::GetStrideForVideoFrame(). - bool IsSharedMemoryForVideoFrame() const { - CHECK(gpu_memory_buffer_); - return gpu_memory_buffer_->GetType() == - gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER; - } + bool IsSharedMemoryForVideoFrame() const; - bool AsyncMappingIsNonBlocking() const { - CHECK(gpu_memory_buffer_); - return gpu_memory_buffer_->AsyncMappingIsNonBlocking(); - } + bool AsyncMappingIsNonBlocking() const; // This pair of functions are used by SharedImageTexture to notify // ClientSharedImage of the beginning and the end of a scoped access.
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index eaba446..2ff91f3 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1765,6 +1765,9 @@ adapter.HasFeature(wgpu::FeatureName::SharedTextureMemoryIOSurface); #elif BUILDFLAG(IS_ANDROID) if (adapter_info.backendType == wgpu::BackendType::OpenGLES) { + if (!base::FeatureList::IsEnabled(features::kWebGPUAndroidOpenGLES)) { + return false; + } supports_external_textures = native_adapter.SupportsExternalImages(); } else { supports_external_textures = adapter.HasFeature(
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc index ab4af0d..69ffaad1 100644 --- a/gpu/config/gpu_finch_features.cc +++ b/gpu/config/gpu_finch_features.cc
@@ -910,4 +910,8 @@ "WebGPUCompatibilityMode", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kWebGPUAndroidOpenGLES, + "WebGPUAndroidOpenGLES", + base::FEATURE_ENABLED_BY_DEFAULT); + } // namespace features
diff --git a/gpu/config/gpu_finch_features.h b/gpu/config/gpu_finch_features.h index 0e73f6a..50ba5554 100644 --- a/gpu/config/gpu_finch_features.h +++ b/gpu/config/gpu_finch_features.h
@@ -95,6 +95,7 @@ GPU_CONFIG_EXPORT BASE_DECLARE_FEATURE(kWebGPUUseTintIR); GPU_CONFIG_EXPORT BASE_DECLARE_FEATURE(kWebGPUUseVulkanMemoryModel); GPU_CONFIG_EXPORT BASE_DECLARE_FEATURE(kWebGPUEnableRangeAnalysisForRobustness); +GPU_CONFIG_EXPORT BASE_DECLARE_FEATURE(kWebGPUAndroidOpenGLES); GPU_CONFIG_EXPORT extern const base::FeatureParam<std::string> kWebGPUDisabledToggles; GPU_CONFIG_EXPORT extern const base::FeatureParam<std::string>
diff --git a/gpu/config/webgpu_blocklist_impl.cc b/gpu/config/webgpu_blocklist_impl.cc index 09605cb..195c047 100644 --- a/gpu/config/webgpu_blocklist_impl.cc +++ b/gpu/config/webgpu_blocklist_impl.cc
@@ -52,10 +52,6 @@ } #if BUILDFLAG(IS_ANDROID) - if (info.backendType == wgpu::BackendType::OpenGLES) { - reason = reason | WebGPUBlocklistReason::AndroidGLES; - } - constexpr uint32_t kARMVendorID = 0x13B5; constexpr uint32_t kQualcommVendorID = 0x5143; constexpr uint32_t kIntelVendorID = 0x8086; @@ -180,8 +176,6 @@ {WebGPUBlocklistReason::AndroidLimitedSupport, "crbug.com/40643150: Limited support / testing currently " "available on Android."}, - {WebGPUBlocklistReason::AndroidGLES, - "crbug.com/333858788: OpenGLES not fully supported on Android."}, {WebGPUBlocklistReason::WindowsARM, "crbug.com/42242119: Not supported on Windows arm yet."}, {WebGPUBlocklistReason::IndirectComputeRootConstants,
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder \050dbg\051/targets/chromium.webrtc.fyi.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder \050dbg\051/targets/chromium.webrtc.fyi.json" index 4df8ec6c..f706ed2 100644 --- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder \050dbg\051/targets/chromium.webrtc.fyi.json" +++ "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder \050dbg\051/targets/chromium.webrtc.fyi.json"
@@ -21,12 +21,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -52,12 +50,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" index d2a5059e..23d5aaa 100644 --- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" +++ "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Builder ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json"
@@ -21,12 +21,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -52,12 +50,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051/targets/chromium.webrtc.fyi.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051/targets/chromium.webrtc.fyi.json" index 04a11a8a..a73e27c 100644 --- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051/targets/chromium.webrtc.fyi.json" +++ "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests \050dbg\051/targets/chromium.webrtc.fyi.json"
@@ -20,12 +20,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -51,12 +49,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" index f02fc5e..b685d6a6 100644 --- "a/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json" +++ "b/infra/config/generated/builders/webrtc.fyi/WebRTC Chromium FYI Android Tests ARM64 \050dbg\051/targets/chromium.webrtc.fyi.json"
@@ -20,12 +20,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -51,12 +49,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git a/infra/config/generated/builders/webrtc/WebRTC Chromium Android Builder/targets/chromium.webrtc.json b/infra/config/generated/builders/webrtc/WebRTC Chromium Android Builder/targets/chromium.webrtc.json index 354fb3ed..5360e17 100644 --- a/infra/config/generated/builders/webrtc/WebRTC Chromium Android Builder/targets/chromium.webrtc.json +++ b/infra/config/generated/builders/webrtc/WebRTC Chromium Android Builder/targets/chromium.webrtc.json
@@ -20,12 +20,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -51,12 +49,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git a/infra/config/generated/builders/webrtc/WebRTC Chromium Android Tester/targets/chromium.webrtc.json b/infra/config/generated/builders/webrtc/WebRTC Chromium Android Tester/targets/chromium.webrtc.json index f01b27f..a5e1bd7 100644 --- a/infra/config/generated/builders/webrtc/WebRTC Chromium Android Tester/targets/chromium.webrtc.json +++ b/infra/config/generated/builders/webrtc/WebRTC Chromium Android Tester/targets/chromium.webrtc.json
@@ -19,12 +19,10 @@ "name": "content_browsertests", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, @@ -50,12 +48,10 @@ "name": "content_browsertests_sequential", "swarming": { "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", + "device_os": "AP2A.240705.004", "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android", - "pool": "chromium.tests" + "device_type": "panther", + "os": "Android" }, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" },
diff --git a/infra/config/subprojects/webrtc/webrtc.fyi.star b/infra/config/subprojects/webrtc/webrtc.fyi.star index 17b7fd7..02b596a 100644 --- a/infra/config/subprojects/webrtc/webrtc.fyi.star +++ b/infra/config/subprojects/webrtc/webrtc.fyi.star
@@ -249,7 +249,7 @@ "webrtc_chromium_simple_gtests", ], mixins = [ - "chromium_pixel_2_pie", + "panther_on_14", ], per_test_modifications = { "content_browsertests": targets.mixin( @@ -293,7 +293,7 @@ "webrtc_chromium_simple_gtests", ], mixins = [ - "chromium_pixel_2_pie", + "panther_on_14", ], per_test_modifications = { "content_browsertests": targets.mixin(
diff --git a/infra/config/subprojects/webrtc/webrtc.star b/infra/config/subprojects/webrtc/webrtc.star index fe691df7..e39e598 100644 --- a/infra/config/subprojects/webrtc/webrtc.star +++ b/infra/config/subprojects/webrtc/webrtc.star
@@ -140,7 +140,7 @@ "webrtc_chromium_simple_gtests", ], mixins = [ - "chromium_pixel_2_pie", + "panther_on_14", ], ), targets_settings = targets.settings(
diff --git a/internal b/internal index 81737b4..26795f3 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit 81737b465ba8c0c5686ebf867a1adc05eecdc951 +Subproject commit 26795f31e4ce2586e12dfb1897cbd87573277cff
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_egtest.mm index 972a614..1a4b203 100644 --- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_egtest.mm +++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/password_view_controller_egtest.mm
@@ -1336,6 +1336,11 @@ // Tests that tapping the "Autofill Form" button in the all password list fills // the password form with the right data. - (void)testAutofillFormButtonInAllPasswordListFillsForm { + // TODO(crbug.com/426435086): Test consistently fails on ipad. + if ([ChromeEarlGrey isIPadIdiom]) { + EARL_GREY_TEST_DISABLED(@"Fails on iPad."); + } + if (![AutofillAppInterface isKeyboardAccessoryUpgradeEnabled]) { EARL_GREY_TEST_DISABLED(@"This test is not relevant when the Keyboard " @"Accessory Upgrade feature is disabled.")
diff --git a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm index 94345f1..5627e8c 100644 --- a/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm +++ b/ios/chrome/browser/collaboration/model/ios_collaboration_controller_delegate.mm
@@ -446,11 +446,10 @@ std::string collaboration_group_id, std::string access_token, base::OnceCallback<void(GURL)> callback) { - if (!browser_) { + if (!browser_ || !share_screen_callback_) { return; } - CHECK(share_screen_callback_); link_generation_callback_ = std::move(callback); data_sharing::GroupToken token(data_sharing::GroupId(collaboration_group_id), access_token);
diff --git a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h index fe20326..8bfb00a 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h +++ b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.h
@@ -281,13 +281,6 @@ // The autocomplete controller. __weak OmniboxAutocompleteController* omnibox_autocomplete_controller_ = nil; - // The initial text representing the current URL suitable for editing. - std::u16string url_for_editing_; - - // Used to know what should be displayed. Updated when e.g. the popup - // selection changes, the results change, on navigation, on tab switch etc; it - // should always be up-to-date. - AutocompleteMatch current_match_; // The popup view is nullptr when there's no popup, and is non-null when // a popup view exists (i.e. between calls to `set_popup_view`). raw_ptr<OmniboxPopupViewIOS> popup_view_ = nullptr;
diff --git a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm index c0a412e..1db4908d 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm +++ b/ios/chrome/browser/omnibox/model/omnibox_edit_model_ios.mm
@@ -103,7 +103,7 @@ AutocompleteMatch OmniboxEditModelIOS::CurrentMatch( GURL* alternate_nav_url) const { // If we have a valid match use it. Otherwise get one for the current text. - AutocompleteMatch match = current_match_; + AutocompleteMatch match = text_model_->current_match; if (!match.destination_url.is_valid()) { GetInfoForCurrentText(&match, alternate_nav_url); } else if (alternate_nav_url) { @@ -117,7 +117,7 @@ bool OmniboxEditModelIOS::ResetDisplayTexts() { const std::u16string old_display_text = GetPermanentDisplayText(); - url_for_editing_ = controller_->client()->GetFormattedFullURL(); + text_model_->url_for_editing = controller_->client()->GetFormattedFullURL(); // When there's new permanent text, and the user isn't interacting with the // omnibox, we want to revert the edit to show the new text. We could simply // define "interacting" as "the omnibox has focus", but we still allow updates @@ -134,13 +134,13 @@ } std::u16string OmniboxEditModelIOS::GetPermanentDisplayText() const { - return url_for_editing_; + return text_model_->url_for_editing; } void OmniboxEditModelIOS::SetUserText(const std::u16string& text) { [text_controller_ setInputInProgress:YES]; text_model_->UpdateUserText(text); - GetInfoForCurrentText(¤t_match_, nullptr); + GetInfoForCurrentText(&text_model_->current_match, nullptr); text_model_->paste_state = OmniboxPasteState::kNone; } @@ -171,7 +171,7 @@ omnibox::AdjustTextForCopy( sel_min, text, /*has_user_modified_text=*/text_model_->user_input_in_progress || - *text != url_for_editing_, + *text != text_model_->url_for_editing, /*is_keyword_selected=*/false, PopupIsOpen() ? std::optional<AutocompleteMatch>(CurrentMatch(nullptr)) : std::nullopt, @@ -179,28 +179,7 @@ } void OmniboxEditModelIOS::Revert() { - [text_controller_ setInputInProgress:NO]; - text_model_->input.Clear(); - text_model_->paste_state = OmniboxPasteState::kNone; - text_model_->UpdateUserText(std::u16string()); - size_t start, end; - if (text_controller_) { - [text_controller_ getSelectionBounds:&start end:&end]; - } - current_match_ = AutocompleteMatch(); - // First home the cursor, so view of text is scrolled to left, then correct - // it. `SetCaretPos()` doesn't scroll the text, so doing that first wouldn't - // accomplish anything. - std::u16string current_permanent_url = GetPermanentDisplayText(); - - [text_controller_ setWindowText:current_permanent_url - caretPos:0 - startAutocomplete:false - notifyTextChanged:true]; - [text_controller_ - setCaretPos:std::min(current_permanent_url.length(), start)]; - - controller_->client()->OnRevert(); + [text_controller_ revertState]; } void OmniboxEditModelIOS::OpenSelection(OmniboxPopupSelection selection, @@ -260,8 +239,7 @@ const std::u16string& inline_autocompletion, const std::u16string& additional_text, const AutocompleteMatch& new_match) { - current_match_ = new_match; - + text_model_->current_match = new_match; text_model_->inline_autocompletion = inline_autocompletion; const std::u16string& user_text = text_model_->user_input_in_progress @@ -324,7 +302,7 @@ // user input is in progress. std::u16string text_for_match_generation = text_model_->user_input_in_progress ? text_model_->user_text - : url_for_editing_; + : text_model_->url_for_editing; controller_->client()->GetAutocompleteClassifier()->Classify( text_for_match_generation, false, true, GetPageClassification(), match, @@ -439,8 +417,9 @@ std::u16string input_text(pasted_text); if (input_text.empty()) { - input_text = text_model_->user_input_in_progress ? text_model_->user_text - : url_for_editing_; + input_text = text_model_->user_input_in_progress + ? text_model_->user_text + : text_model_->url_for_editing; } // Create a dummy AutocompleteInput for use in calling VerbatimMatchForInput() // to create an alternate navigational match.
diff --git a/ios/chrome/browser/omnibox/model/omnibox_text_controller.h b/ios/chrome/browser/omnibox/model/omnibox_text_controller.h index 8edd530..b9610bf 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_text_controller.h +++ b/ios/chrome/browser/omnibox/model/omnibox_text_controller.h
@@ -81,6 +81,10 @@ /// Updates the text model input_in_progress state. - (void)setInputInProgress:(BOOL)inProgress; +/// Reverts the text model back to its unedited state (permanent text showing, +/// no user input in progress). +- (void)revertState; + #pragma mark - Autocomplete event /// Sets the additional text.
diff --git a/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm b/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm index cf4e128..cff86a04 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm +++ b/ios/chrome/browser/omnibox/model/omnibox_text_controller.mm
@@ -204,11 +204,7 @@ } - (void)revertAll { - // This will clear the model's `user_input_in_progress_`. - if (_omniboxEditModel) { - _omniboxEditModel->Revert(); - } - + [self revertState]; // This will stop the `AutocompleteController`. This should happen after // `user_input_in_progress_` is cleared above; otherwise, closing the popup // will trigger unnecessary `AutocompleteClassifier::Classify()` calls to @@ -238,6 +234,28 @@ } } +- (void)revertState { + [self setInputInProgress:NO]; + _omniboxTextModel->input.Clear(); + _omniboxTextModel->paste_state = OmniboxPasteState::kNone; + _omniboxTextModel->UpdateUserText(std::u16string()); + size_t start, end; + [self getSelectionBounds:&start end:&end]; + _omniboxTextModel->current_match = AutocompleteMatch(); + // First home the cursor, so view of text is scrolled to left, then correct + // it. `SetCaretPos()` doesn't scroll the text, so doing that first wouldn't + // accomplish anything. + std::u16string current_permanent_url = _omniboxTextModel->url_for_editing; + + [self setWindowText:current_permanent_url + caretPos:0 + startAutocomplete:false + notifyTextChanged:true]; + [self setCaretPos:std::min(current_permanent_url.length(), start)]; + + _omniboxController->client()->OnRevert(); +} + #pragma mark - Autocomplete events - (void)setAdditionalText:(const std::u16string&)text {
diff --git a/ios/chrome/browser/omnibox/model/omnibox_text_model.h b/ios/chrome/browser/omnibox/model/omnibox_text_model.h index 8e043d19..554ca9c 100644 --- a/ios/chrome/browser/omnibox/model/omnibox_text_model.h +++ b/ios/chrome/browser/omnibox/model/omnibox_text_model.h
@@ -118,6 +118,12 @@ // This is needed to properly update the SearchModel state when the user // presses escape. bool in_revert; + // Used to know what should be displayed. Updated when e.g. the popup + // selection changes, the results change, on navigation, on tab switch etc; it + // should always be up-to-date. + AutocompleteMatch current_match; + // The initial text representing the current URL suitable for editing. + std::u16string url_for_editing; }; #endif // IOS_CHROME_BROWSER_OMNIBOX_MODEL_OMNIBOX_TEXT_MODEL_H_
diff --git a/ios/chrome/browser/partial_translate/ui_bundled/BUILD.gn b/ios/chrome/browser/partial_translate/ui_bundled/BUILD.gn index fa3c892..03f8877 100644 --- a/ios/chrome/browser/partial_translate/ui_bundled/BUILD.gn +++ b/ios/chrome/browser/partial_translate/ui_bundled/BUILD.gn
@@ -20,6 +20,7 @@ "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/shared/ui/symbols", + "//ios/chrome/browser/translate/model", "//ios/chrome/browser/web_selection/model", "//ios/public/provider/chrome/browser/partial_translate:partial_translate_api", "//ios/web/public",
diff --git a/ios/chrome/browser/partial_translate/ui_bundled/DEPS b/ios/chrome/browser/partial_translate/ui_bundled/DEPS index d416d38..82139fac 100644 --- a/ios/chrome/browser/partial_translate/ui_bundled/DEPS +++ b/ios/chrome/browser/partial_translate/ui_bundled/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+ios/chrome/browser/browser_container/ui_bundled", "+ios/chrome/browser/fullscreen/ui_bundled", + "+ios/chrome/browser/translate/model", "+ios/chrome/browser/web_selection/model", ]
diff --git a/ios/chrome/browser/partial_translate/ui_bundled/partial_translate_mediator.mm b/ios/chrome/browser/partial_translate/ui_bundled/partial_translate_mediator.mm index d2b1e071..87fae5d4 100644 --- a/ios/chrome/browser/partial_translate/ui_bundled/partial_translate_mediator.mm +++ b/ios/chrome/browser/partial_translate/ui_bundled/partial_translate_mediator.mm
@@ -18,6 +18,7 @@ #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/features/features.h" #import "ios/chrome/browser/shared/ui/symbols/symbols.h" +#import "ios/chrome/browser/translate/model/translate_service_ios.h" #import "ios/chrome/browser/web_selection/model/web_selection_response.h" #import "ios/chrome/browser/web_selection/model/web_selection_tab_helper.h" #import "ios/chrome/grit/ios_strings.h" @@ -168,6 +169,10 @@ if (!self.alertDelegate) { return; } + if (![self URLIsTranslatable]) { + ReportErrorOutcome(error, false); + return; + } NSString* message; switch (error) { case PartialTranslateError::kSelectionTooLong: @@ -267,6 +272,16 @@ return helper; } +- (BOOL)URLIsTranslatable { + web::WebState* webState = + _webStateList ? _webStateList->GetActiveWebState() : nullptr; + if (!webState) { + return NO; + } + return TranslateServiceIOS::IsTranslatableURL( + webState->GetLastCommittedURL()); +} + - (void)addItemWithCompletion:(ProceduralBlockWithItemArray)completion { if (![self canHandlePartialTranslateSelection]) { completion(@[]);
diff --git a/ios/chrome/browser/saved_tab_groups/ui/face_pile_view.mm b/ios/chrome/browser/saved_tab_groups/ui/face_pile_view.mm index 8feb0da..a3d8294 100644 --- a/ios/chrome/browser/saved_tab_groups/ui/face_pile_view.mm +++ b/ios/chrome/browser/saved_tab_groups/ui/face_pile_view.mm
@@ -17,8 +17,8 @@ // Spacing between overlapping avatars. const CGFloat kAvatarSpacing = -6; -// Substracted stroke around avatars. -const CGFloat kAvatarSubstractredStroke = 2; +// Substracted stroke around containers. +const CGFloat kContainerSubstractredStroke = 2; // Font size of `plusXLabel`. const CGFloat kPlusXlabelFontSize = 9; @@ -26,9 +26,6 @@ // horizontal inner margin in for the `_plusXLabelContainer`. const CGFloat kPlusXlabelContainerHorizontalInnerMargin = 6; -// Substracted stroke around `_plusXLabelContainer`. -const CGFloat kPlusXLabelContainerSubstractredStroke = 2; - // Alpha value of the `_plusXLabelContainer` background color. const CGFloat kPlusXlabelContainerBackgroundAlpha = 0.2; @@ -54,6 +51,7 @@ - (instancetype)init { self = [super initWithFrame:CGRectZero]; if (self) { + self.layer.masksToBounds = YES; _facesStackView = [[UIStackView alloc] init]; _facesStackView.translatesAutoresizingMaskIntoConstraints = NO; _facesStackView.spacing = kAvatarSpacing; @@ -82,9 +80,8 @@ if (!backgroundColor) { return; } - // TODO(crbug.com/422737259): Render an outer stroke when the - // `_facePileBackgroundColor` is not nil. _facePileBackgroundColor = backgroundColor; + self.backgroundColor = _facePileBackgroundColor; } - (void)updateWithFaces:(NSArray<id<ShareKitAvatarPrimitive>>*)faces @@ -95,7 +92,7 @@ } _avatars = faces; - CGFloat containerSize = _avatarSize + kAvatarSubstractredStroke * 2; + CGFloat containerSize = _avatarSize + kContainerSubstractredStroke * 2; NSInteger avatarsCount = static_cast<NSUInteger>(_avatars.count); for (NSInteger index = 0; index < avatarsCount; index++) { @@ -138,6 +135,7 @@ // This is needed to avoid anti-aliasing artifacts around the border itself. UIView* plusXContainerView = [self createCircularContainerWithSize:containerSize]; + plusXContainerView.layer.cornerRadius = containerSize / 2.0; [plusXContainerView addSubview:plusXLabel]; [_facesStackView addArrangedSubview:plusXContainerView]; @@ -148,10 +146,10 @@ [plusXLabel.heightAnchor constraintEqualToConstant:_avatarSize], [plusXLabel.leadingAnchor constraintEqualToAnchor:plusXContainerView.leadingAnchor - constant:kPlusXLabelContainerSubstractredStroke], + constant:kContainerSubstractredStroke], [plusXLabel.trailingAnchor constraintEqualToAnchor:plusXContainerView.trailingAnchor - constant:-kPlusXLabelContainerSubstractredStroke], + constant:-kContainerSubstractredStroke], [plusXContainerView.heightAnchor constraintEqualToConstant:containerSize] ]]; @@ -161,6 +159,8 @@ - (void)setAvatarSize:(CGFloat)avatarSize { _avatarSize = avatarSize; + CGFloat containerSize = _avatarSize + kContainerSubstractredStroke * 2; + self.layer.cornerRadius = containerSize / 2.0; } #pragma mark - Private
diff --git a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator.mm b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator.mm index 92430b0..e32e53f6f 100644 --- a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator.mm +++ b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator.mm
@@ -226,6 +226,10 @@ } - (void)updateActiveTabSnapshot:(ProceduralBlock)callback { + if (!self.activeWebState) { + [self runSnapshotCallback:callback]; + return; + } SnapshotTabHelper* snapshotTabHelper = SnapshotTabHelper::FromWebState(self.activeWebState); if (!snapshotTabHelper) {
diff --git a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator_unittest.mm b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator_unittest.mm index fce0b37..6a31c9b 100644 --- a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator_unittest.mm +++ b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_mediator_unittest.mm
@@ -86,9 +86,10 @@ original_web_state->SetBrowserState(profile_.get()); original_web_state_ = original_web_state.get(); - int web_state_index = browser_->GetWebStateList()->InsertWebState( + active_web_state_index_ = browser_->GetWebStateList()->InsertWebState( std::move(original_web_state)); - browser_->GetWebStateList()->ActivateWebStateAt(web_state_index); + browser_->GetWebStateList()->ActivateWebStateAt( + active_web_state_index_.value()); side_swipe_mediator_ = [[SideSwipeMediator alloc] initWithWebStateList:browser_->GetWebStateList()]; @@ -99,6 +100,13 @@ ~SideSwipeMediatorTest() override { [side_swipe_mediator_ disconnect]; } + void CloseActiveWebState() { + browser_->GetWebStateList()->CloseWebStateAt( + active_web_state_index_.value(), + WebStateList::ClosingFlags::CLOSE_NO_FLAGS); + active_web_state_index_.reset(); + } + web::WebTaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<TestProfileIOS> profile_; @@ -110,6 +118,7 @@ WKWebView* web_view_ = nil; CRWWebViewContentView* content_view_ = nil; raw_ptr<web::WebState> original_web_state_ = nil; + std::optional<int> active_web_state_index_; }; TEST_F(SideSwipeMediatorTest, TestConstructor) { @@ -229,6 +238,22 @@ } // Tests that the snapshot update runs the provided callback that updates +// the snapshot state when the active web state is null. +TEST_F(SideSwipeMediatorTest, SnapshotUpdatedWithoutActiveWebState) { + base::RunLoop run_loop; + int snapshot_updated = 0; + CloseActiveWebState(); + [side_swipe_mediator_ + updateActiveTabSnapshot:base::CallbackToBlock( + base::BindLambdaForTesting([&]() { + snapshot_updated++; + run_loop.Quit(); + }))]; + run_loop.Run(); + EXPECT_EQ(1, snapshot_updated); +} + +// Tests that the snapshot update runs the provided callback that updates // the snapshot state only once on completion. TEST_F(SideSwipeMediatorTest, SnapshotUpdatedOnceOnCallback) { SnapshotTabHelper::CreateForWebState(original_web_state_);
diff --git a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller.mm b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller.mm index 8f7931b..3599467a 100644 --- a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller.mm +++ b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller.mm
@@ -90,6 +90,7 @@ - (void)disconnect { [_tabSideSwipeView disconnect]; + [self removeHorizontalGestureRecognizers]; _fullscreenController = nullptr; _webStateList = nullptr; } @@ -114,6 +115,18 @@ [view addGestureRecognizer:_panGestureRecognizer]; } +- (void)removeHorizontalGestureRecognizers { + if (_swipeGestureRecognizer) { + [_swipeGestureRecognizer.view + removeGestureRecognizer:_swipeGestureRecognizer]; + _swipeGestureRecognizer = nil; + } + if (_panGestureRecognizer) { + [_panGestureRecognizer.view removeGestureRecognizer:_panGestureRecognizer]; + _panGestureRecognizer = nil; + } +} + - (void)animateSwipe:(SwipeType)swipeType inDirection:(UISwipeGestureRecognizerDirection)direction { if (_inSwipe || [_sideSwipeUIControllerDelegate preventSideSwipe]) {
diff --git a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller_unittest.mm b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller_unittest.mm index 30d1b30..220fb28 100644 --- a/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller_unittest.mm +++ b/ios/chrome/browser/side_swipe/ui_bundled/side_swipe_ui_controller_unittest.mm
@@ -10,10 +10,11 @@ class SideSwipeUIControllerTest : public PlatformTest { public: - SideSwipeUIControllerTest() { + SideSwipeUIControllerTest() : view_([[UIView alloc] init]) { side_swipe_ui_controller_ = [[SideSwipeUIController alloc] init]; } + UIView* view_; SideSwipeUIController* side_swipe_ui_controller_; }; @@ -66,3 +67,13 @@ // leading edge navigation is enabled. EXPECT_TRUE(edgeNavigationIsEnabledOnRightDirection); } + +// Tests that gesture recognizers are removed from the original view that +// requested these when the UIViewController is disconnected. +TEST_F(SideSwipeUIControllerTest, TestGestureRecognizerRemovedOnDisconnect) { + [side_swipe_ui_controller_ addHorizontalGesturesToView:view_]; + EXPECT_EQ(2U, view_.gestureRecognizers.count); + + [side_swipe_ui_controller_ disconnect]; + EXPECT_EQ(0U, view_.gestureRecognizers.count); +}
diff --git a/ios/chrome/widget_kit_extension/deleted_account_views.swift b/ios/chrome/widget_kit_extension/deleted_account_views.swift index 146ef30f..f84842d 100644 --- a/ios/chrome/widget_kit_extension/deleted_account_views.swift +++ b/ios/chrome/widget_kit_extension/deleted_account_views.swift
@@ -7,11 +7,8 @@ enum DeletedAccountUIConstants { static let cornerRadius: CGFloat = 22 - static let smallWidgetHeight: CGFloat = 140 - static let smallWidgetWidth: CGFloat = 140 - static let mediumWidgetHeight: CGFloat = 140 - static let mediumWidgetWidth: CGFloat = 320 - static let padding: CGFloat = 7 + static let padding: CGFloat = 3 + static let whiteBorder: CGFloat = 11 } // Store in NSUserDefaults that the deleted account view appeared. @@ -24,10 +21,6 @@ VStack { ZStack { RoundedRectangle(cornerRadius: DeletedAccountUIConstants.cornerRadius) - .frame( - width: DeletedAccountUIConstants.smallWidgetHeight, - height: DeletedAccountUIConstants.smallWidgetHeight - ) .foregroundColor(Color("widget_search_bar_color")) .overlay( Text("IDS_IOS_WIDGET_KIT_EXTENSION_DELETED_ACCOUNT") @@ -37,6 +30,8 @@ .padding(DeletedAccountUIConstants.padding) ) } + .frame(minWidth: 0, maxWidth: .infinity) + .padding(DeletedAccountUIConstants.whiteBorder) } .crContainerBackground(Color("widget_background_color").unredacted()) .onAppear { @@ -48,10 +43,6 @@ VStack { ZStack { RoundedRectangle(cornerRadius: DeletedAccountUIConstants.cornerRadius) - .frame( - width: DeletedAccountUIConstants.mediumWidgetWidth, - height: DeletedAccountUIConstants.mediumWidgetHeight - ) .foregroundColor(Color("widget_search_bar_color")) .overlay( VStack { @@ -67,6 +58,8 @@ } ) } + .frame(minWidth: 0, maxWidth: .infinity) + .padding(DeletedAccountUIConstants.whiteBorder) } .crContainerBackground(Color("widget_background_color").unredacted()) .onAppear {
diff --git a/media/base/encoder_status.cc b/media/base/encoder_status.cc index 48f82674..f93b0a1 100644 --- a/media/base/encoder_status.cc +++ b/media/base/encoder_status.cc
@@ -52,6 +52,8 @@ return "No hardware encoder is available."; case EncoderStatus::Codes::kOutOfPlatformEncoders: return "The system ran out of platform encoders."; + case EncoderStatus::Codes::kBadReferenceBuffer: + return "Invalid reference buffer index is specified."; case EncoderStatus::Codes::kOk: NOTREACHED(); }
diff --git a/media/base/encoder_status.h b/media/base/encoder_status.h index ac87f47..0e27e26 100644 --- a/media/base/encoder_status.h +++ b/media/base/encoder_status.h
@@ -58,7 +58,9 @@ kEncoderAccelerationSupportMissing = 20, // The system ran out of platform encoders. kOutOfPlatformEncoders = 21, - kMaxValue = kOutOfPlatformEncoders, + // The client provided a non-existing reference buffer. + kBadReferenceBuffer = 22, + kMaxValue = kBadReferenceBuffer, }; static constexpr StatusGroupType Group() { return "EncoderStatus"; } };
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 30979af..fd3bb8c6 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc
@@ -547,6 +547,22 @@ const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size, + const uint8_t* data, + size_t data_size, + base::TimeDelta timestamp) { + auto layout = GetDefaultLayout(format, coded_size); + if (!layout) + return nullptr; + return WrapExternalDataWithLayout(*layout, visible_rect, natural_size, data, + data_size, timestamp); +} + +// static +scoped_refptr<VideoFrame> VideoFrame::WrapExternalData( + VideoPixelFormat format, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, base::span<const uint8_t> data, base::TimeDelta timestamp) { auto layout = GetDefaultLayout(format, coded_size); @@ -1574,15 +1590,6 @@ WrapReleaseMailboxCB(std::move(release_mailbox_cb)); } -void VideoFrame::SetReleaseMailboxAndGpuMemoryBufferCB( - ReleaseMailboxAndGpuMemoryBufferCB release_mailbox_cb) { - // See remarks in SetReleaseMailboxCB. - DCHECK(release_mailbox_cb); - DCHECK(!mailbox_holder_and_gmb_release_cb_); - DCHECK(!wrapped_frame_); - mailbox_holder_and_gmb_release_cb_ = std::move(release_mailbox_cb); -} - bool VideoFrame::HasReleaseMailboxCB() const { return wrapped_frame_ ? wrapped_frame_->HasReleaseMailboxCB() : !!mailbox_holder_and_gmb_release_cb_;
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 6af1d64..700a346 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -277,6 +277,15 @@ const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size, + const uint8_t* data, + size_t data_size, + base::TimeDelta timestamp); + + static scoped_refptr<VideoFrame> WrapExternalData( + VideoPixelFormat format, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, base::span<const uint8_t> data, base::TimeDelta timestamp); @@ -378,7 +387,7 @@ // For use in contexts where the GPUMemoryBuffer has no SharedImage // associated with it. // NOTE: Clients who want to set a callback on the VideoFrame being destroyed - // should call SetReleaseMailboxAndGpuMemoryBufferCB() after creating the + // should call SetReleaseMailboxCB() after creating the // VideoFrame via this entrypoint. static scoped_refptr<VideoFrame> WrapExternalGpuMemoryBuffer( const gfx::Rect& visible_rect, @@ -731,7 +740,7 @@ int GetDmabufFd(size_t i) const; #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) - // Sets the mailbox (and GpuMemoryBuffer, if desired) release callback. + // Sets the mailbox release callback. // // The callback may be run from ANY THREAD, and so it is up to the client to // ensure thread safety. @@ -739,8 +748,6 @@ // WARNING: This method is not thread safe; it should only be called if you // are still the only owner of this VideoFrame. void SetReleaseMailboxCB(ReleaseMailboxCB release_mailbox_cb); - void SetReleaseMailboxAndGpuMemoryBufferCB( - ReleaseMailboxAndGpuMemoryBufferCB release_mailbox_cb); // Tests whether a mailbox release callback is configured. bool HasReleaseMailboxCB() const;
diff --git a/media/base/video_frame_converter.cc b/media/base/video_frame_converter.cc index 5759bca5..f1dea1d1 100644 --- a/media/base/video_frame_converter.cc +++ b/media/base/video_frame_converter.cc
@@ -34,7 +34,9 @@ scoped_refptr<VideoFrame> tmp_frame) { return VideoFrame::WrapExternalData( override_format, tmp_frame->coded_size(), tmp_frame->visible_rect(), - tmp_frame->natural_size(), tmp_frame->data_span(VideoFrame::Plane::kARGB), + tmp_frame->natural_size(), + tmp_frame->writable_data(VideoFrame::Plane::kARGB), + VideoFrame::AllocationSize(override_format, tmp_frame->coded_size()), tmp_frame->timestamp()); }
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc index e79e697..6a1af98 100644 --- a/media/base/video_frame_unittest.cc +++ b/media/base/video_frame_unittest.cc
@@ -486,14 +486,14 @@ // Create a frame that wraps unowned memory. TEST(VideoFrame, WrapExternalData) { - std::array<uint8_t, 2 * 256 * 256> memory{}; + uint8_t memory[2 * 256 * 256]; gfx::Size coded_size(256, 256); gfx::Rect visible_rect(coded_size); - CreateTestY16Frame(coded_size, visible_rect, memory.data()); + CreateTestY16Frame(coded_size, visible_rect, memory); auto timestamp = base::Milliseconds(1); - auto frame = - VideoFrame::WrapExternalData(PIXEL_FORMAT_Y16, coded_size, visible_rect, - visible_rect.size(), memory, timestamp); + auto frame = VideoFrame::WrapExternalData(PIXEL_FORMAT_Y16, coded_size, + visible_rect, visible_rect.size(), + memory, sizeof(memory), timestamp); EXPECT_EQ(frame->coded_size(), coded_size); EXPECT_EQ(frame->visible_rect(), visible_rect); @@ -513,7 +513,8 @@ auto timestamp = base::Milliseconds(1); auto frame = VideoFrame::WrapExternalData( PIXEL_FORMAT_Y16, coded_size, visible_rect, visible_rect.size(), - mapped_region.mapping.GetMemoryAsSpan<uint8_t>(), timestamp); + mapped_region.mapping.GetMemoryAsSpan<uint8_t>().data(), kDataSize, + timestamp); EXPECT_EQ(frame->storage_type(), VideoFrame::STORAGE_UNOWNED_MEMORY); frame->BackWithSharedMemory(&mapped_region.region); @@ -966,9 +967,9 @@ pixels.resize(coded_size.GetArea() * 4); auto timestamp = base::Milliseconds(0); - auto frame = - VideoFrame::WrapExternalData(format, coded_size, visible_rect, - visible_rect.size(), pixels, timestamp); + auto frame = VideoFrame::WrapExternalData( + format, coded_size, visible_rect, visible_rect.size(), pixels.data(), + pixels.size(), timestamp); int plane_offset = 0; for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) {
diff --git a/media/cast/encoding/external_video_encoder.cc b/media/cast/encoding/external_video_encoder.cc index 9d37ce5..b51aa567 100644 --- a/media/cast/encoding/external_video_encoder.cc +++ b/media/cast/encoding/external_video_encoder.cc
@@ -285,8 +285,8 @@ video_frame->format(), frame_coded_size_, gfx::Rect(video_frame->visible_rect().size()), video_frame->visible_rect().size(), - mapped_region.mapping.GetMemoryAsSpan<uint8_t>(), - video_frame->timestamp()); + static_cast<uint8_t*>(mapped_region.mapping.memory()), + mapped_region.mapping.size(), video_frame->timestamp()); if (!frame || !media::I420CopyWithPadding(*video_frame, frame.get())) { LOG(DFATAL) << "Error: ExternalVideoEncoder: copy failed."; AbortLatestEncodeAttemptDueToErrors();
diff --git a/media/gpu/test/local_gpu_memory_buffer_manager.cc b/media/gpu/test/local_gpu_memory_buffer_manager.cc index c28afd1..9e2e96dde 100644 --- a/media/gpu/test/local_gpu_memory_buffer_manager.cc +++ b/media/gpu/test/local_gpu_memory_buffer_manager.cc
@@ -105,7 +105,7 @@ GpuMemoryBufferImplGbm::GpuMemoryBufferImplGbm(gfx::BufferFormat format, gbm_bo* buffer_object) - : format_(format), buffer_object_(buffer_object), mapped_(false) { + : buffer_object_(buffer_object), mapped_(false) { gfx::NativePixmapHandle native_pixmap_handle; for (size_t i = 0; i < static_cast<size_t>(gbm_bo_get_plane_count(buffer_object)); ++i) { @@ -182,22 +182,10 @@ gbm_bo_get_height(buffer_object_)); } -gfx::BufferFormat GpuMemoryBufferImplGbm::GetFormat() const { - return format_; -} - int GpuMemoryBufferImplGbm::stride(size_t plane) const { return gbm_bo_get_stride_for_plane(buffer_object_, plane); } -gfx::GpuMemoryBufferId GpuMemoryBufferImplGbm::GetId() const { - return handle_.id; -} - -gfx::GpuMemoryBufferType GpuMemoryBufferImplGbm::GetType() const { - return gfx::NATIVE_PIXMAP; -} - gfx::GpuMemoryBufferHandle GpuMemoryBufferImplGbm::CloneHandle() const { DCHECK_EQ(handle_.type, gfx::NATIVE_PIXMAP); gfx::GpuMemoryBufferHandle handle( @@ -206,17 +194,6 @@ return handle; } -void GpuMemoryBufferImplGbm::OnMemoryDump( - base::trace_event::ProcessMemoryDump* pmd, - const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid, - uint64_t tracing_process_id, - int importance) const { - auto shared_buffer_guid = - gfx::GetGenericSharedGpuMemoryGUIDForTracing(tracing_process_id, GetId()); - pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid); - pmd->AddOwnershipEdge(buffer_dump_guid, shared_buffer_guid, importance); -} - LocalGpuMemoryBufferManager::LocalGpuMemoryBufferManager() : gbm_device_(CreateGbmDevice()) {} LocalGpuMemoryBufferManager::~LocalGpuMemoryBufferManager() = default;
diff --git a/media/gpu/test/local_gpu_memory_buffer_manager.h b/media/gpu/test/local_gpu_memory_buffer_manager.h index 2333c53..98d62a2e 100644 --- a/media/gpu/test/local_gpu_memory_buffer_manager.h +++ b/media/gpu/test/local_gpu_memory_buffer_manager.h
@@ -15,13 +15,6 @@ #include "ui/gfx/gpu_memory_buffer_handle.h" #include "ui/gfx/linux/scoped_gbm_device.h" -namespace base { -namespace trace_event { -class ProcessMemoryDump; -class MemoryAllocatorDumpGuid; -} // namespace trace_event -} // namespace base - namespace gfx { class GpuMemoryBuffer; struct NativePixmapHandle; @@ -87,16 +80,8 @@ void* memory(size_t plane); void Unmap(); gfx::Size GetSize() const; - gfx::BufferFormat GetFormat() const; int stride(size_t plane) const; - gfx::GpuMemoryBufferId GetId() const; - gfx::GpuMemoryBufferType GetType() const; gfx::GpuMemoryBufferHandle CloneHandle() const; - void OnMemoryDump( - base::trace_event::ProcessMemoryDump* pmd, - const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid, - uint64_t tracing_process_id, - int importance) const; private: struct MappedPlane { @@ -104,7 +89,6 @@ raw_ptr<void> mapped_data; }; - gfx::BufferFormat format_; raw_ptr<gbm_bo> buffer_object_; gfx::GpuMemoryBufferHandle handle_; bool mapped_;
diff --git a/media/gpu/windows/d3d12_video_encode_delegate.cc b/media/gpu/windows/d3d12_video_encode_delegate.cc index 91c9007d..d807f5db 100644 --- a/media/gpu/windows/d3d12_video_encode_delegate.cc +++ b/media/gpu/windows/d3d12_video_encode_delegate.cc
@@ -509,6 +509,19 @@ } template <size_t maxDpbSize> +void D3D12VideoEncodeDecodedPictureBuffers<maxDpbSize>::EraseFrame( + size_t position) { + CHECK_LT(position, size()); + base::span raw_resources_span = + base::span(raw_resources_).first(size()).subspan(position); + std::ranges::rotate(raw_resources_span, + std::next(raw_resources_span.begin())); + base::span subresources_span = + base::span(subresources_).first(size()).subspan(position); + std::ranges::rotate(subresources_span, std::next(subresources_span.begin())); +} + +template <size_t maxDpbSize> D3D12_VIDEO_ENCODE_REFERENCE_FRAMES D3D12VideoEncodeDecodedPictureBuffers< maxDpbSize>::ToD3D12VideoEncodeReferenceFrames() { return {
diff --git a/media/gpu/windows/d3d12_video_encode_delegate.h b/media/gpu/windows/d3d12_video_encode_delegate.h index 817b1b0e..81a15c0d 100644 --- a/media/gpu/windows/d3d12_video_encode_delegate.h +++ b/media/gpu/windows/d3d12_video_encode_delegate.h
@@ -202,11 +202,13 @@ // Replace the picture buffer at |position| with the last picture buffer // returned by |GetCurrentFrame()|. void ReplaceWithCurrentFrame(size_t position); + // Move the picture buffer at |position| to |size() - 1|. And move the + // picture buffers with index greater than |position| to the previous index. + void EraseFrame(size_t position); // Return the |D3D12_VIDEO_ENCODE_REFERENCE_FRAMES| structure that D3D12 video // encode API expects. - virtual D3D12_VIDEO_ENCODE_REFERENCE_FRAMES - ToD3D12VideoEncodeReferenceFrames(); + D3D12_VIDEO_ENCODE_REFERENCE_FRAMES ToD3D12VideoEncodeReferenceFrames(); private: size_t size_ = 0;
diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate.cc b/media/gpu/windows/d3d12_video_encode_h264_delegate.cc index adddcaf..94f3fb3 100644 --- a/media/gpu/windows/d3d12_video_encode_h264_delegate.cc +++ b/media/gpu/windows/d3d12_video_encode_h264_delegate.cc
@@ -74,23 +74,22 @@ D3D12VideoEncodeH264ReferenceFrameManager:: ~D3D12VideoEncodeH264ReferenceFrameManager() = default; -void D3D12VideoEncodeH264ReferenceFrameManager::EndFrame( - uint32_t frame_num, - uint32_t pic_order_cnt, - uint32_t temporal_layer_id) { - InsertCurrentFrame(0); - if (descriptors_.size() == size()) { - descriptors_.pop_back(); +uint32_t +D3D12VideoEncodeH264ReferenceFrameManager::GetMaxLongTermFrameIndexPlus1() + const { + return max_long_term_frame_index_plus1_; +} + +std::optional<uint32_t> +D3D12VideoEncodeH264ReferenceFrameManager::GetLongTermReferenceFrameResourceId( + uint32_t long_term_frame_index) const { + for (const auto& descriptor : descriptors_) { + if (descriptor.IsLongTermReference && + descriptor.LongTermPictureIdx == long_term_frame_index) { + return descriptor.ReconstructedPictureResourceIndex; + } } - descriptors_.insert(descriptors_.begin(), - { - .PictureOrderCountNumber = pic_order_cnt, - .FrameDecodingOrderNumber = frame_num, - .TemporalLayerIndex = temporal_layer_id, - }); - for (size_t i = 0; i < descriptors_.size(); i++) { - descriptors_[i].ReconstructedPictureResourceIndex = i; - } + return std::nullopt; } base::span<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264> @@ -98,6 +97,102 @@ return descriptors_; } +void D3D12VideoEncodeH264ReferenceFrameManager:: + ProcessMemoryManagementControlOperation( + const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264& pic_params) { + CHECK(pic_params.adaptive_ref_pic_marking_mode_flag); + if (pic_params.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) { + max_long_term_frame_index_plus1_ = 1; + SetCurrentFrameLongTermReference(pic_params.FrameDecodingOrderNumber, + pic_params.PictureOrderCountNumber, 0); + } else { + // SAFETY: Callers should guarantee that |pRefPicMarkingOperationsCommands| + // contains at least |RefPicMarkingOperationsCommandsCount| elements. + for (auto& operation : UNSAFE_BUFFERS( + base::span(pic_params.pRefPicMarkingOperationsCommands, + pic_params.RefPicMarkingOperationsCommandsCount))) { + // Table 7-9 – Memory management control operation + // (memory_management_control_operation) values + switch (operation.memory_management_control_operation) { + case 0: + // 0 End memory_management_control_operation syntax element loop + return; + case 2: { + // 2 Mark a long-term reference picture as "unused for reference" + auto resource_id = + GetLongTermReferenceFrameResourceId(operation.long_term_pic_num); + CHECK_LT(resource_id.value(), size()); + EraseFrame(resource_id.value()); + descriptors_.erase( + std::next(descriptors_.begin(), resource_id.value())); + for (size_t i = resource_id.value(); i < descriptors_.size(); i++) { + descriptors_[i].ReconstructedPictureResourceIndex = i; + } + break; + } + case 4: + // 4 Specify the maximum long-term frame index and mark all long-term + // reference pictures having long-term frame indices greater than the + // maximum value as "unused for reference" + CHECK_LE(operation.max_long_term_frame_idx_plus1, size()); + max_long_term_frame_index_plus1_ = + operation.max_long_term_frame_idx_plus1; + break; + case 5: + // 5 Mark all reference pictures as "unused for reference" and set the + // MaxLongTermFrameIdx variable to "no long-term frame indices" + descriptors_.clear(); + max_long_term_frame_index_plus1_ = 0; + break; + case 6: + // 6 Mark the current picture as "used for long-term reference" and + // assign a long-term frame index to it + CHECK_LT(operation.long_term_frame_idx, + max_long_term_frame_index_plus1_); + SetCurrentFrameLongTermReference(pic_params.FrameDecodingOrderNumber, + pic_params.PictureOrderCountNumber, + operation.long_term_frame_idx); + break; + default: + // memory_management_control_operation being 1 and 3 is not used. + // 1 Mark a short-term reference picture as "unused for reference" + // 3 Mark a short-term reference picture as "used for long-term + // reference" and assign a long-term frame index to it + NOTREACHED(); + } + } + NOTREACHED() << "RefPicMarkingOperations must end with " + "memory_management_control_operation = 0"; + } +} + +void D3D12VideoEncodeH264ReferenceFrameManager:: + SetCurrentFrameLongTermReference(uint32_t frame_num, + uint32_t pic_order_cnt, + uint32_t long_term_frame_index) { + CHECK_LT(long_term_frame_index, size()); + for (auto& descriptor : descriptors_) { + if (descriptor.IsLongTermReference && + descriptor.LongTermPictureIdx == long_term_frame_index) { + ReplaceWithCurrentFrame(descriptor.ReconstructedPictureResourceIndex); + descriptor.FrameDecodingOrderNumber = frame_num; + descriptor.PictureOrderCountNumber = pic_order_cnt; + return; + } + } + + CHECK_LT(descriptors_.size(), size()); + InsertCurrentFrame(descriptors_.size()); + descriptors_.push_back({ + .ReconstructedPictureResourceIndex = + static_cast<UINT>(descriptors_.size()), + .IsLongTermReference = true, + .LongTermPictureIdx = long_term_frame_index, + .PictureOrderCountNumber = pic_order_cnt, + .FrameDecodingOrderNumber = frame_num, + }); +} + // static std::vector<std::pair<VideoCodecProfile, std::vector<VideoPixelFormat>>> D3D12VideoEncodeH264Delegate::GetSupportedProfiles( @@ -148,6 +243,7 @@ // start with 0. pic_params_.idr_pic_id = -1; pic_params_.FrameDecodingOrderNumber = -1; + pic_params_.adaptive_ref_pic_marking_mode_flag = 1; input_arguments_.SequenceControlDesc.CodecGopSequence = { .DataSize = sizeof(gop_structure_), .pH264GroupOfPictures = &gop_structure_, @@ -217,11 +313,51 @@ // https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#6120-struct-d3d12_video_encoder_input_arguments // Frame type, idr_pic_id, decoding order number, and reference frames. - if (++pic_params_.FrameDecodingOrderNumber == gop_structure_.GOPLength) { + if (++pic_params_.FrameDecodingOrderNumber == gop_structure_.GOPLength || + options.key_frame) { pic_params_.FrameDecodingOrderNumber = 0; } - bool is_keyframe = - pic_params_.FrameDecodingOrderNumber == 0 || options.key_frame; + pic_params_.PictureOrderCountNumber = + pic_params_.FrameDecodingOrderNumber * 2; + bool is_keyframe = pic_params_.FrameDecodingOrderNumber == 0; + + // TODO(crbug.com/40275246): Support multiple temporal layers. + absl::InlinedVector<uint8_t, 4> reference_buffers; + std::optional<uint8_t> update_buffer; + std::optional<uint8_t> destroy_buffer; + if (!is_keyframe) { + reference_buffers.push_back(0); + } + update_buffer = 0; + if (destroy_buffer.value_or(0) > 0) { + destroy_buffer = destroy_buffer.value() + 1; + } + + if (update_buffer.has_value() && + update_buffer.value() >= max_num_ref_frames_) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf("Update buffer index %d is out of range [0, %d)", + update_buffer.value(), max_num_ref_frames_)}; + } + if (destroy_buffer.has_value() && + !reference_frame_manager_.GetLongTermReferenceFrameResourceId( + destroy_buffer.value())) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf("Destroy buffer index %d is not found", + destroy_buffer.value())}; + } + + // at most 5 operations: 4 operations for each reference buffer, 1 operation + // for ending op-0. + absl::InlinedVector< + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION, + 5> + reordering_flags; + // at most 3 operations: op-4, op-6, op-0 + absl::InlinedVector< + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION, + 3> + mmco; if (is_keyframe) { H264SPS sps = ToSPS(); H264PPS pps = ToPPS(sps); @@ -232,15 +368,43 @@ input_arguments_.PictureControlDesc.ReferenceFrames = {}; pic_params_.FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME; ++pic_params_.idr_pic_id; - pic_params_.FrameDecodingOrderNumber = 0; pic_params_.ReferenceFramesReconPictureDescriptorsCount = 0; pic_params_.pReferenceFramesReconPictureDescriptors = nullptr; pic_params_.List0ReferenceFramesCount = 0; pic_params_.pList0ReferenceFrames = nullptr; + pic_params_.List0RefPicModificationsCount = 0; + pic_params_.pList0RefPicModifications = nullptr; + // Alternatively, if encoding an IDR frame and setting + // adaptive_ref_pic_marking_mode_flag = 1, the driver will assume that the + // client is attempting to set the H264 slice header + // long_term_reference_flag and will do so in the output bitstream for the + // EncodeFrame call. + // https://learn.microsoft.com/en-us/windows/win32/api/d3d12video/ns-d3d12video-d3d12_video_encoder_picture_control_codec_data_h264_reference_picture_marking_operation#remarks } else { pic_params_.FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME; - list0_reference_frames_[0] = 0; - pic_params_.List0ReferenceFramesCount = 1; + for (size_t i = 0; i < reference_buffers.size(); i++) { + std::optional<uint32_t> descriptor_index = + reference_frame_manager_.GetLongTermReferenceFrameResourceId( + reference_buffers[i]); + if (!descriptor_index.has_value()) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf( + "Long term reference frame index %d is not found", + reference_buffers[i])}; + } + reordering_flags.push_back({.modification_of_pic_nums_idc = 2, + .long_term_pic_num = reference_buffers[i]}); + list0_reference_frames_[i] = descriptor_index.value(); + } + if (!reordering_flags.empty()) { + reordering_flags.push_back({.modification_of_pic_nums_idc = 3}); + pic_params_.List0RefPicModificationsCount = reordering_flags.size(); + pic_params_.pList0RefPicModifications = reordering_flags.data(); + } else { + pic_params_.List0RefPicModificationsCount = 0; + pic_params_.pList0RefPicModifications = nullptr; + } + pic_params_.List0ReferenceFramesCount = reference_buffers.size(); pic_params_.pList0ReferenceFrames = list0_reference_frames_.data(); base::span<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264> descriptors = reference_frame_manager_.ToReferencePictureDescriptors(); @@ -252,8 +416,24 @@ input_arguments_.PictureControlDesc.ReferenceFrames.NumTexture2Ds = descriptors.size(); } - pic_params_.PictureOrderCountNumber = - pic_params_.FrameDecodingOrderNumber * 2; + if (destroy_buffer.has_value()) { + mmco.push_back({.memory_management_control_operation = 2, + .long_term_pic_num = destroy_buffer.value()}); + } + if (update_buffer.has_value()) { + if (update_buffer.value() >= + reference_frame_manager_.GetMaxLongTermFrameIndexPlus1()) { + mmco.push_back({.memory_management_control_operation = 4, + .max_long_term_frame_idx_plus1 = + static_cast<UINT>(update_buffer.value()) + 1}); + } + mmco.push_back({.memory_management_control_operation = 6, + .long_term_frame_idx = update_buffer.value()}); + } + mmco.push_back({.memory_management_control_operation = 0}); + // The adaptive_ref_pic_marking_mode_flag has been set in the constructor. + pic_params_.pRefPicMarkingOperationsCommands = mmco.data(); + pic_params_.RefPicMarkingOperationsCommandsCount = mmco.size(); // Rate control. int qp = -1; @@ -290,25 +470,28 @@ } // Input and output textures. - input_arguments_.PictureControlDesc.Flags = - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; input_arguments_.pInputFrame = input_frame; input_arguments_.InputFrameSubresource = input_frame_subresource; - D3D12PictureBuffer reconstructed_picture = - reference_frame_manager_.GetCurrentFrame(); - EncoderStatus result = video_encoder_wrapper_->Encode( - input_arguments_, - { - .pReconstructedPicture = reconstructed_picture.resource_, - .ReconstructedPictureSubresource = reconstructed_picture.subresource_, - }); + D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE output_arguments{}; + if (update_buffer) { + input_arguments_.PictureControlDesc.Flags = + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; + D3D12PictureBuffer reconstructed_picture = + reference_frame_manager_.GetCurrentFrame(); + output_arguments.pReconstructedPicture = reconstructed_picture.resource_; + output_arguments.ReconstructedPictureSubresource = + reconstructed_picture.subresource_; + } else { + input_arguments_.PictureControlDesc.Flags = + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_NONE; + } + EncoderStatus result = + video_encoder_wrapper_->Encode(input_arguments_, output_arguments); if (!result.is_ok()) { return result; } - reference_frame_manager_.EndFrame(pic_params_.FrameDecodingOrderNumber, - pic_params_.PictureOrderCountNumber, - pic_params_.TemporalLayerIndex); + reference_frame_manager_.ProcessMemoryManagementControlOperation(pic_params_); metadata_.key_frame = is_keyframe; metadata_.qp = qp;
diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate.h b/media/gpu/windows/d3d12_video_encode_h264_delegate.h index 8427704..4f356f9 100644 --- a/media/gpu/windows/d3d12_video_encode_h264_delegate.h +++ b/media/gpu/windows/d3d12_video_encode_h264_delegate.h
@@ -26,26 +26,37 @@ namespace media { -class D3D12VideoEncodeH264ReferenceFrameManager +class MEDIA_GPU_EXPORT D3D12VideoEncodeH264ReferenceFrameManager : public D3D12VideoEncodeDecodedPictureBuffers<H264DPB::kDPBMaxSize> { public: D3D12VideoEncodeH264ReferenceFrameManager(); ~D3D12VideoEncodeH264ReferenceFrameManager() override; - void EndFrame(uint32_t frame_num, - uint32_t pic_order_cnt, - uint32_t temporal_layer_id); + uint32_t GetMaxLongTermFrameIndexPlus1() const; + + // Get the index in the descriptors and picture buffers of the frame with + // |long_term_frame_index|. + std::optional<uint32_t> GetLongTermReferenceFrameResourceId( + uint32_t long_term_frame_index) const; base::span<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264> ToReferencePictureDescriptors(); + void ProcessMemoryManagementControlOperation( + const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264& pic_params); + private: using D3D12VideoEncodeDecodedPictureBuffers::InsertCurrentFrame; using D3D12VideoEncodeDecodedPictureBuffers::ReplaceWithCurrentFrame; + void SetCurrentFrameLongTermReference(uint32_t frame_num, + uint32_t pic_order_cnt, + uint32_t long_term_frame_index); + absl::InlinedVector<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264, H264DPB::kDPBMaxSize> descriptors_; + uint32_t max_long_term_frame_index_plus1_ = 0; }; class MEDIA_GPU_EXPORT D3D12VideoEncodeH264Delegate
diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc index 1011f045..8831904 100644 --- a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc +++ b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc
@@ -19,6 +19,13 @@ namespace media { +class D3D12VideoEncodeH264ReferenceFrameManagerTest : public ::testing::Test { + protected: + void SetUp() override { device_ = MakeComPtr<NiceMock<D3D12DeviceMock>>(); } + + Microsoft::WRL::ComPtr<D3D12DeviceMock> device_; +}; + class D3D12VideoEncodeH264DelegateTest : public D3D12VideoEncodeDelegateTestBase { protected: @@ -154,6 +161,118 @@ Microsoft::WRL::ComPtr<D3D12VideoDevice3Mock> video_device3_; }; +TEST_F(D3D12VideoEncodeH264ReferenceFrameManagerTest, + ProcessMemoryManagementControlOperation) { + // Initialization + D3D12VideoEncodeH264ReferenceFrameManager reference_manager; + ASSERT_TRUE(reference_manager.InitializeTextureArray( + device_.Get(), {1280, 720}, DXGI_FORMAT_NV12, 4)); + EXPECT_EQ(reference_manager.GetMaxLongTermFrameIndexPlus1(), 0u); + EXPECT_EQ(reference_manager.GetLongTermReferenceFrameResourceId(0), + std::nullopt); + EXPECT_EQ(reference_manager.ToReferencePictureDescriptors().size(), 0u); + + // IDR frame #0 with adaptive_ref_pic_marking_mode_flag = true + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 pic_params0{ + .FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME, + .PictureOrderCountNumber = 0, + .FrameDecodingOrderNumber = 0, + .adaptive_ref_pic_marking_mode_flag = true, + }; + reference_manager.ProcessMemoryManagementControlOperation(pic_params0); + EXPECT_EQ(reference_manager.GetMaxLongTermFrameIndexPlus1(), 1u); + EXPECT_NE(reference_manager.GetLongTermReferenceFrameResourceId(0), + std::nullopt); + base::span<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264> + descriptors = reference_manager.ToReferencePictureDescriptors(); + ASSERT_EQ(descriptors.size(), 1u); + EXPECT_TRUE(descriptors[0].IsLongTermReference); + EXPECT_EQ(descriptors[0].LongTermPictureIdx, 0u); + EXPECT_EQ(descriptors[0].ReconstructedPictureResourceIndex, 0u); + EXPECT_EQ(descriptors[0].PictureOrderCountNumber, + pic_params0.PictureOrderCountNumber); + EXPECT_EQ(descriptors[0].FrameDecodingOrderNumber, + pic_params0.FrameDecodingOrderNumber); + + // P frame #1 with mmco 4 and 6 + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION + mmco1[] = { + {.memory_management_control_operation = 4, + .max_long_term_frame_idx_plus1 = 2}, + {.memory_management_control_operation = 6, .long_term_frame_idx = 1}, + {.memory_management_control_operation = 0}, + }; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 pic_params1{ + .FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME, + .PictureOrderCountNumber = 2, + .FrameDecodingOrderNumber = 1, + .adaptive_ref_pic_marking_mode_flag = true, + .RefPicMarkingOperationsCommandsCount = std::size(mmco1), + .pRefPicMarkingOperationsCommands = mmco1, + }; + reference_manager.ProcessMemoryManagementControlOperation(pic_params1); + EXPECT_EQ(reference_manager.GetMaxLongTermFrameIndexPlus1(), 2u); + EXPECT_NE(reference_manager.GetLongTermReferenceFrameResourceId(1), + std::nullopt); + descriptors = reference_manager.ToReferencePictureDescriptors(); + ASSERT_EQ(descriptors.size(), 2u); + EXPECT_TRUE(descriptors[1].IsLongTermReference); + EXPECT_EQ(descriptors[1].LongTermPictureIdx, 1u); + EXPECT_EQ(descriptors[1].ReconstructedPictureResourceIndex, 1u); + EXPECT_EQ(descriptors[1].PictureOrderCountNumber, + pic_params1.PictureOrderCountNumber); + EXPECT_EQ(descriptors[1].FrameDecodingOrderNumber, + pic_params1.FrameDecodingOrderNumber); + + // P frame #2 with mmco 2 + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION + mmco2[] = { + {.memory_management_control_operation = 2, .long_term_pic_num = 0}, + {.memory_management_control_operation = 0}, + }; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 pic_params2{ + .FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME, + .PictureOrderCountNumber = 4, + .FrameDecodingOrderNumber = 2, + .adaptive_ref_pic_marking_mode_flag = true, + .RefPicMarkingOperationsCommandsCount = std::size(mmco2), + .pRefPicMarkingOperationsCommands = mmco2, + }; + reference_manager.ProcessMemoryManagementControlOperation(pic_params2); + EXPECT_EQ(reference_manager.GetMaxLongTermFrameIndexPlus1(), 2u); + EXPECT_EQ(reference_manager.GetLongTermReferenceFrameResourceId(0), + std::nullopt); + descriptors = reference_manager.ToReferencePictureDescriptors(); + ASSERT_EQ(descriptors.size(), 1u); + EXPECT_EQ(descriptors[0].LongTermPictureIdx, 1u); + EXPECT_EQ(descriptors[0].ReconstructedPictureResourceIndex, 0u); + EXPECT_EQ(descriptors[0].PictureOrderCountNumber, + pic_params1.PictureOrderCountNumber); + EXPECT_EQ(descriptors[0].FrameDecodingOrderNumber, + pic_params1.FrameDecodingOrderNumber); + + // P frame #3 with mmco 5 + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION + mmco3[] = { + {.memory_management_control_operation = 5}, + {.memory_management_control_operation = 0}, + }; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 pic_params3{ + .FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME, + .PictureOrderCountNumber = 6, + .FrameDecodingOrderNumber = 3, + .adaptive_ref_pic_marking_mode_flag = true, + .RefPicMarkingOperationsCommandsCount = std::size(mmco3), + .pRefPicMarkingOperationsCommands = mmco3, + }; + reference_manager.ProcessMemoryManagementControlOperation(pic_params3); + EXPECT_EQ(reference_manager.GetMaxLongTermFrameIndexPlus1(), 0u); + EXPECT_EQ(reference_manager.GetLongTermReferenceFrameResourceId(1), + std::nullopt); + descriptors = reference_manager.ToReferencePictureDescriptors(); + EXPECT_EQ(descriptors.size(), 0u); +} + TEST_F(D3D12VideoEncodeH264DelegateTest, UnsupportedCodec) { ON_CALL(*video_device3_.Get(), CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC, _, _))
diff --git a/media/gpu/windows/d3d12_video_encode_h265_delegate.cc b/media/gpu/windows/d3d12_video_encode_h265_delegate.cc index 53dbec53..f79244b 100644 --- a/media/gpu/windows/d3d12_video_encode_h265_delegate.cc +++ b/media/gpu/windows/d3d12_video_encode_h265_delegate.cc
@@ -60,20 +60,52 @@ D3D12VideoEncodeH265ReferenceFrameManager:: ~D3D12VideoEncodeH265ReferenceFrameManager() = default; -void D3D12VideoEncodeH265ReferenceFrameManager::EndFrame( - uint32_t pic_order_count, - uint32_t temporal_layer_id) { - InsertCurrentFrame(0); - if (descriptors_.size() == size()) { - descriptors_.pop_back(); +std::optional<uint32_t> +D3D12VideoEncodeH265ReferenceFrameManager::GetReferenceFrameId( + uint8_t buffer_id) const { + for (size_t i = 0; i < buffer_ids_.size(); i++) { + if (buffer_ids_[i] == buffer_id) { + return i; + } } - descriptors_.insert(descriptors_.begin(), - { - .PictureOrderCountNumber = pic_order_count, - .TemporalLayerIndex = temporal_layer_id, - }); + return std::nullopt; +} + +void D3D12VideoEncodeH265ReferenceFrameManager::MarkCurrentFrameReferenced( + uint32_t pic_order_count, + uint8_t buffer_id, + bool long_term_reference) { + CHECK_LT(buffer_id, size()); for (size_t i = 0; i < descriptors_.size(); i++) { - descriptors_[i].ReconstructedPictureResourceIndex = i; + if (buffer_ids_[i] == buffer_id) { + ReplaceWithCurrentFrame( + descriptors_[i].ReconstructedPictureResourceIndex); + descriptors_[i].PictureOrderCountNumber = pic_order_count; + descriptors_[i].IsLongTermReference = long_term_reference; + return; + } + } + + CHECK_LT(descriptors_.size(), size()); + InsertCurrentFrame(descriptors_.size()); + descriptors_.push_back({ + .ReconstructedPictureResourceIndex = + static_cast<UINT>(descriptors_.size()), + .IsLongTermReference = long_term_reference, + .PictureOrderCountNumber = pic_order_count, + }); + buffer_ids_.push_back(buffer_id); +} + +void D3D12VideoEncodeH265ReferenceFrameManager::MarkFrameUnreferenced( + uint8_t buffer_id) { + for (size_t i = 0; i < descriptors_.size(); i++) { + if (buffer_ids_[i] == buffer_id) { + EraseFrame(descriptors_[i].ReconstructedPictureResourceIndex); + descriptors_.erase(std::next(descriptors_.begin(), i)); + buffer_ids_.erase(std::next(buffer_ids_.begin(), i)); + return; + } } } @@ -211,11 +243,32 @@ // Filling the |input_arguments_| according to // https://github.com/microsoft/DirectX-Specs/blob/master/d3d/D3D12VideoEncoding.md#6120-struct-d3d12_video_encoder_input_arguments - if (++pic_params_.PictureOrderCountNumber == gop_structure_.GOPLength) { + if (++pic_params_.PictureOrderCountNumber == gop_structure_.GOPLength || + options.key_frame) { pic_params_.PictureOrderCountNumber = 0; } - bool is_keyframe = - pic_params_.PictureOrderCountNumber == 0 || options.key_frame; + bool is_keyframe = pic_params_.PictureOrderCountNumber == 0; + + absl::InlinedVector<uint8_t, 4> reference_buffers; + std::optional<uint8_t> update_buffer; + std::optional<uint8_t> destroy_buffer; + if (!is_keyframe) { + reference_buffers.push_back(0); + } + update_buffer = 0; + if (update_buffer.has_value() && + update_buffer.value() >= max_num_ref_frames_) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf("Update buffer index %d is out of range [0, %d)", + update_buffer.value(), max_num_ref_frames_)}; + } + if (destroy_buffer.has_value() && + !reference_frame_manager_.GetReferenceFrameId(destroy_buffer.value())) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf("Destroy buffer index %d is not found", + destroy_buffer.value())}; + } + if (is_keyframe) { H265VPS vps = ToVPS(); H265SPS sps = ToSPS(vps); @@ -227,19 +280,29 @@ input_arguments_.PictureControlDesc.ReferenceFrames = {}; pic_params_.FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME; - pic_params_.PictureOrderCountNumber = 0; pic_params_.ReferenceFramesReconPictureDescriptorsCount = 0; pic_params_.pReferenceFramesReconPictureDescriptors = nullptr; pic_params_.List0ReferenceFramesCount = 0; pic_params_.pList0ReferenceFrames = nullptr; } else { pic_params_.FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME; - list0_reference_frames_[0] = 0; - pic_params_.List0ReferenceFramesCount = 1; + CHECK_LE(reference_buffers.size(), list0_reference_frames_.size()); + for (size_t i = 0; i < reference_buffers.size(); i++) { + std::optional<uint32_t> descriptor_index = + reference_frame_manager_.GetReferenceFrameId(reference_buffers[i]); + if (!descriptor_index.has_value()) { + return {EncoderStatus::Codes::kBadReferenceBuffer, + base::StringPrintf("Reference buffer #%d is never updated", + reference_buffers[i])}; + } + list0_reference_frames_[i] = descriptor_index.value(); + } + pic_params_.List0ReferenceFramesCount = reference_buffers.size(); pic_params_.pList0ReferenceFrames = list0_reference_frames_.data(); reference_frame_manager_ .WriteReferencePictureDescriptorsToPictureParameters( - &pic_params_, base::span(list0_reference_frames_).first(1u)); + &pic_params_, base::span(list0_reference_frames_) + .first(reference_buffers.size())); input_arguments_.PictureControlDesc.ReferenceFrames = reference_frame_manager_.ToD3D12VideoEncodeReferenceFrames(); input_arguments_.PictureControlDesc.ReferenceFrames.NumTexture2Ds = @@ -280,24 +343,35 @@ current_rate_control_.GetD3D12VideoEncoderRateControl(); } - input_arguments_.PictureControlDesc.Flags = - D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; input_arguments_.pInputFrame = input_frame; input_arguments_.InputFrameSubresource = input_frame_subresource; - D3D12PictureBuffer reconstructed_picture = - reference_frame_manager_.GetCurrentFrame(); - EncoderStatus result = video_encoder_wrapper_->Encode( - input_arguments_, - { - .pReconstructedPicture = reconstructed_picture.resource_, - .ReconstructedPictureSubresource = reconstructed_picture.subresource_, - }); + D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE output_arguments{}; + if (update_buffer) { + input_arguments_.PictureControlDesc.Flags = + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; + D3D12PictureBuffer reconstructed_picture = + reference_frame_manager_.GetCurrentFrame(); + output_arguments.pReconstructedPicture = reconstructed_picture.resource_; + output_arguments.ReconstructedPictureSubresource = + reconstructed_picture.subresource_; + } else { + input_arguments_.PictureControlDesc.Flags = + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_NONE; + } + + EncoderStatus result = + video_encoder_wrapper_->Encode(input_arguments_, output_arguments); if (!result.is_ok()) { return result; } - reference_frame_manager_.EndFrame(pic_params_.PictureOrderCountNumber, - pic_params_.TemporalLayerIndex); + if (destroy_buffer.has_value()) { + reference_frame_manager_.MarkFrameUnreferenced(destroy_buffer.value()); + } + if (update_buffer.has_value()) { + reference_frame_manager_.MarkCurrentFrameReferenced( + pic_params_.PictureOrderCountNumber, update_buffer.value(), false); + } metadata_.key_frame = is_keyframe; metadata_.qp = qp; @@ -369,6 +443,7 @@ } codec_config_hevc_ = { .ConfigurationFlags = + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_LONG_TERM_REFERENCES | (codec_config_support_hevc.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT ? D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER @@ -415,7 +490,7 @@ D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, .ResolutionsListCount = 1, .pResolutionList = &input_size_, - .MaxReferenceFramesInDPB = static_cast<UINT>(max_num_ref_frames_), + .MaxReferenceFramesInDPB = max_num_ref_frames_, .SuggestedProfile = {.DataSize = sizeof(suggested_profile), .pHEVCProfile = &suggested_profile}, .SuggestedLevel = {.DataSize = sizeof(suggested_level),
diff --git a/media/gpu/windows/d3d12_video_encode_h265_delegate.h b/media/gpu/windows/d3d12_video_encode_h265_delegate.h index 1ec3eca..8c7fe78b 100644 --- a/media/gpu/windows/d3d12_video_encode_h265_delegate.h +++ b/media/gpu/windows/d3d12_video_encode_h265_delegate.h
@@ -25,13 +25,20 @@ namespace media { -class D3D12VideoEncodeH265ReferenceFrameManager +class MEDIA_GPU_EXPORT D3D12VideoEncodeH265ReferenceFrameManager : public D3D12VideoEncodeDecodedPictureBuffers<kMaxDpbSize> { public: D3D12VideoEncodeH265ReferenceFrameManager(); ~D3D12VideoEncodeH265ReferenceFrameManager() override; - void EndFrame(uint32_t pic_order_count, uint32_t temporal_layer_id); + // Get the index in the descriptors of the frame with |picture_order_count|. + std::optional<uint32_t> GetReferenceFrameId(uint8_t buffer_id) const; + + void MarkCurrentFrameReferenced(uint32_t pic_order_count, + uint8_t buffer_id, + bool long_term_reference); + + void MarkFrameUnreferenced(uint8_t buffer_id); // Write the reference picture descriptors to |pic_params| according to the // ListxReferenceFrames variables. @@ -46,6 +53,7 @@ absl::InlinedVector<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC, kMaxDpbSize> descriptors_; + absl::InlinedVector<uint8_t, kMaxDpbSize> buffer_ids_; }; class MEDIA_GPU_EXPORT D3D12VideoEncodeH265Delegate
diff --git a/media/gpu/windows/d3d12_video_encode_h265_delegate_unittest.cc b/media/gpu/windows/d3d12_video_encode_h265_delegate_unittest.cc index 5244ad3..70b8377 100644 --- a/media/gpu/windows/d3d12_video_encode_h265_delegate_unittest.cc +++ b/media/gpu/windows/d3d12_video_encode_h265_delegate_unittest.cc
@@ -19,6 +19,13 @@ namespace media { +class D3D12VideoEncodeH265ReferenceFrameManagerTest : public ::testing::Test { + protected: + void SetUp() override { device_ = MakeComPtr<NiceMock<D3D12DeviceMock>>(); } + + Microsoft::WRL::ComPtr<D3D12DeviceMock> device_; +}; + class D3D12VideoEncodeH265DelegateTest : public D3D12VideoEncodeDelegateTestBase { protected: @@ -191,6 +198,77 @@ Microsoft::WRL::ComPtr<D3D12VideoDevice3Mock> video_device3_; }; +TEST_F(D3D12VideoEncodeH265ReferenceFrameManagerTest, + MarkReferenceFrameAndCheckDescriptors) { + D3D12VideoEncodeH265ReferenceFrameManager reference_manager; + ASSERT_TRUE(reference_manager.InitializeTextureArray( + device_.Get(), {1280, 720}, DXGI_FORMAT_NV12, 4)); + EXPECT_EQ(reference_manager.GetReferenceFrameId(0), std::nullopt); + + std::vector<uint32_t> list0_reference_frames; + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC pic_params{}; + reference_manager.WriteReferencePictureDescriptorsToPictureParameters( + &pic_params, list0_reference_frames); + EXPECT_EQ(pic_params.ReferenceFramesReconPictureDescriptorsCount, 0u); + + // Mark frame #0 as short-term reference #0. + reference_manager.MarkCurrentFrameReferenced(0, 0, false); + EXPECT_EQ(reference_manager.GetReferenceFrameId(0), 0u); + list0_reference_frames = {0}; + pic_params.List0ReferenceFramesCount = list0_reference_frames.size(); + pic_params.pList0ReferenceFrames = list0_reference_frames.data(); + reference_manager.WriteReferencePictureDescriptorsToPictureParameters( + &pic_params, list0_reference_frames); + ASSERT_EQ(pic_params.ReferenceFramesReconPictureDescriptorsCount, 1u); + // SAFETY: |pReferenceFramesReconPictureDescriptors| is guaranteed to have + // |ReferenceFramesReconPictureDescriptorsCount| elements. + base::span<const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC> + descriptors = UNSAFE_BUFFERS( + base::span(pic_params.pReferenceFramesReconPictureDescriptors, + pic_params.ReferenceFramesReconPictureDescriptorsCount)); + EXPECT_EQ(descriptors[0].IsRefUsedByCurrentPic, true); + EXPECT_EQ(descriptors[0].IsLongTermReference, false); + EXPECT_EQ(descriptors[0].PictureOrderCountNumber, 0u); + + // Mark frame #1 as long-term reference #2. + reference_manager.MarkCurrentFrameReferenced(1, 2, true); + EXPECT_EQ(reference_manager.GetReferenceFrameId(2), 1u); + list0_reference_frames = {1}; + pic_params.List0ReferenceFramesCount = list0_reference_frames.size(); + pic_params.pList0ReferenceFrames = list0_reference_frames.data(); + reference_manager.WriteReferencePictureDescriptorsToPictureParameters( + &pic_params, list0_reference_frames); + ASSERT_EQ(pic_params.ReferenceFramesReconPictureDescriptorsCount, 2u); + // SAFETY: |pReferenceFramesReconPictureDescriptors| is guaranteed to have + // |ReferenceFramesReconPictureDescriptorsCount| elements. + descriptors = UNSAFE_BUFFERS( + base::span(pic_params.pReferenceFramesReconPictureDescriptors, + pic_params.ReferenceFramesReconPictureDescriptorsCount)); + EXPECT_EQ(descriptors[0].IsRefUsedByCurrentPic, false); + EXPECT_EQ(descriptors[1].IsRefUsedByCurrentPic, true); + EXPECT_EQ(descriptors[1].IsLongTermReference, true); + EXPECT_EQ(descriptors[1].PictureOrderCountNumber, 1u); + + // Mark frame #0 as not referenced. + reference_manager.MarkFrameUnreferenced(0); + EXPECT_EQ(reference_manager.GetReferenceFrameId(0), std::nullopt); + EXPECT_EQ(reference_manager.GetReferenceFrameId(2), 0u); + list0_reference_frames = {0}; + pic_params.List0ReferenceFramesCount = list0_reference_frames.size(); + pic_params.pList0ReferenceFrames = list0_reference_frames.data(); + reference_manager.WriteReferencePictureDescriptorsToPictureParameters( + &pic_params, list0_reference_frames); + ASSERT_EQ(pic_params.ReferenceFramesReconPictureDescriptorsCount, 1u); + // SAFETY: |pReferenceFramesReconPictureDescriptors| is guaranteed to have + // |ReferenceFramesReconPictureDescriptorsCount| elements. + descriptors = UNSAFE_BUFFERS( + base::span(pic_params.pReferenceFramesReconPictureDescriptors, + pic_params.ReferenceFramesReconPictureDescriptorsCount)); + EXPECT_EQ(descriptors[0].IsRefUsedByCurrentPic, true); + EXPECT_EQ(descriptors[0].IsLongTermReference, true); + EXPECT_EQ(descriptors[0].PictureOrderCountNumber, 1u); +} + TEST_F(D3D12VideoEncodeH265DelegateTest, UnsupportedCodec) { ON_CALL(*video_device3_.Get(), CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC, _, _))
diff --git a/media/gpu/windows/mf_video_processor_accelerator_unittest.cc b/media/gpu/windows/mf_video_processor_accelerator_unittest.cc index 58ccf02..a4a6be4 100644 --- a/media/gpu/windows/mf_video_processor_accelerator_unittest.cc +++ b/media/gpu/windows/mf_video_processor_accelerator_unittest.cc
@@ -524,7 +524,8 @@ auto timestamp = base::Milliseconds(0); auto frame = VideoFrame::WrapExternalData( VideoPixelFormat::PIXEL_FORMAT_XRGB, {kWidth, kHeight}, - gfx::Rect(0, 0, kWidth, kHeight), {kWidth, kHeight}, image, timestamp); + gfx::Rect(0, 0, kWidth, kHeight), {kWidth, kHeight}, image.data(), + image.size(), timestamp); Microsoft::WRL::ComPtr<IMFSample> sample; ASSERT_HRESULT_SUCCEEDED(video_processor->Convert(frame, &sample));
diff --git a/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc b/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc index fc05fd0..beb226d2 100644 --- a/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc +++ b/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc
@@ -286,8 +286,8 @@ ASSERT_TRUE(shmem.IsValid()); const scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( PIXEL_FORMAT_I420, kInputVisibleSize, gfx::Rect(kInputVisibleSize), - kInputVisibleSize, shmem.mapping.GetMemoryAsSpan<uint8_t>(), - base::TimeDelta()); + kInputVisibleSize, static_cast<uint8_t*>(shmem.mapping.memory()), + shmem.mapping.size(), base::TimeDelta()); video_frame->BackWithSharedMemory(&shmem.region); const bool is_keyframe = true;
diff --git a/media/mojo/test/mojo_video_encode_accelerator_integration_test.cc b/media/mojo/test/mojo_video_encode_accelerator_integration_test.cc index ae74ed0..2e89fd9b 100644 --- a/media/mojo/test/mojo_video_encode_accelerator_integration_test.cc +++ b/media/mojo/test/mojo_video_encode_accelerator_integration_test.cc
@@ -290,8 +290,8 @@ ASSERT_TRUE(shmem.IsValid()); const scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( PIXEL_FORMAT_I420, kInputVisibleSize, gfx::Rect(kInputVisibleSize), - kInputVisibleSize, shmem.mapping.GetMemoryAsSpan<uint8_t>(), - base::TimeDelta()); + kInputVisibleSize, static_cast<uint8_t*>(shmem.mapping.memory()), + shmem.mapping.size(), base::TimeDelta()); video_frame->BackWithSharedMemory(&shmem.region); const bool is_keyframe = true; @@ -335,7 +335,8 @@ const scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( PIXEL_FORMAT_I420, kInvalidInputVisibleSize, gfx::Rect(kInvalidInputVisibleSize), kInvalidInputVisibleSize, - shmem.mapping.GetMemoryAsSpan<uint8_t>(), base::TimeDelta()); + static_cast<uint8_t*>(shmem.mapping.memory()), shmem.mapping.size(), + base::TimeDelta()); video_frame->BackWithSharedMemory(&shmem.region); const bool is_keyframe = true;
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc index 46e11f7..f0f7029 100644 --- a/media/renderers/paint_canvas_video_renderer_unittest.cc +++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -80,7 +80,7 @@ return media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_Y16, coded_size, visible_rect, visible_rect.size(), - base::span(static_cast<uint8_t*>(external_memory), byte_size), timestamp); + static_cast<uint8_t*>(external_memory), byte_size, timestamp); } // Readback the contents of a RGBA texture into an array of RGBA values. @@ -987,7 +987,7 @@ auto video_frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_Y16, coded_size, gfx::Rect(visible_size), - visible_size, memory, base::Milliseconds(4)); + visible_size, &memory[0], fWidth * fHeight * 2, base::Milliseconds(4)); cc::PaintFlags flags; PaintCanvasVideoRenderer::PaintParams params;
diff --git a/media/renderers/video_resource_updater_unittest.cc b/media/renderers/video_resource_updater_unittest.cc index 4d5a3e7..0ec5f8b 100644 --- a/media/renderers/video_resource_updater_unittest.cc +++ b/media/renderers/video_resource_updater_unittest.cc
@@ -96,9 +96,9 @@ scoped_refptr<VideoFrame> CreateTestYUVVideoFrame( const gfx::Size& size = gfx::Size(10, 10)) { constexpr int kMaxDimension = 100; - static std::array<uint8_t, kMaxDimension * kMaxDimension> y_data{}; - static std::array<uint8_t, kMaxDimension * kMaxDimension / 2> u_data{}; - static std::array<uint8_t, kMaxDimension * kMaxDimension / 2> v_data{}; + static uint8_t y_data[kMaxDimension * kMaxDimension] = {}; + static uint8_t u_data[kMaxDimension * kMaxDimension / 2] = {}; + static uint8_t v_data[kMaxDimension * kMaxDimension / 2] = {}; CHECK_LE(size.width() * size.height(), kMaxDimension * kMaxDimension); @@ -118,17 +118,43 @@ return video_frame; } + scoped_refptr<VideoFrame> CreateWonkyTestYUVVideoFrame() { + const int kDimension = 10; + const int kYWidth = kDimension + 5; + const int kUWidth = (kYWidth + 1) / 2 + 200; + const int kVWidth = (kYWidth + 1) / 2 + 1; + static uint8_t y_data[kYWidth * kDimension] = {}; + static uint8_t u_data[kUWidth * kDimension] = {}; + static uint8_t v_data[kVWidth * kDimension] = {}; + + scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalYuvData( + PIXEL_FORMAT_I422, // format + gfx::Size(kYWidth, kDimension), // coded_size + gfx::Rect(2, 0, kDimension, kDimension), // visible_rect + gfx::Size(kDimension, kDimension), // natural_size + -kYWidth, // y_stride (negative) + kUWidth, // u_stride + kVWidth, // v_stride + y_data + kYWidth * (kDimension - 1), // y_data + u_data, // u_data + v_data, // v_data + base::TimeDelta()); // timestamp + EXPECT_TRUE(video_frame); + return video_frame; + } + scoped_refptr<VideoFrame> CreateTestRGBVideoFrame(VideoPixelFormat format) { constexpr int kMaxDimension = 10; constexpr gfx::Size kSize = gfx::Size(kMaxDimension, kMaxDimension); - static std::array<uint8_t, 4 * kMaxDimension * kMaxDimension> rgb_data{}; - scoped_refptr<VideoFrame> video_frame = - VideoFrame::WrapExternalData(format, // format - kSize, // coded_size - gfx::Rect(kSize), // visible_rect - kSize, // natural_size - rgb_data, // data, - base::TimeDelta()); // timestamp + static uint32_t rgb_data[kMaxDimension * kMaxDimension] = {}; + scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( + format, // format + kSize, // coded_size + gfx::Rect(kSize), // visible_rect + kSize, // natural_size + reinterpret_cast<uint8_t*>(rgb_data), // data, + sizeof(rgb_data), // data_size + base::TimeDelta()); // timestamp EXPECT_TRUE(video_frame); return video_frame; } @@ -138,23 +164,23 @@ constexpr int kMaxDimension = 5; constexpr gfx::Size kSize = gfx::Size(kMaxDimension, kMaxDimension); constexpr gfx::Rect kVisibleRect = gfx::Rect(2, 1, 3, 3); -#define PIX 0xFF, 0xFF, 0xFF, 0xFF - static std::array<uint8_t, 4 * kMaxDimension * kMaxDimension> rgb_data{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // - 0, 0, 0, 0, 0, 0, 0, 0, PIX, PIX, PIX, // - 0, 0, 0, 0, 0, 0, 0, 0, PIX, PIX, PIX, // - 0, 0, 0, 0, 0, 0, 0, 0, PIX, PIX, PIX, // - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + constexpr uint32_t kPix = 0xFFFFFFFF; + static uint32_t rgb_data[kMaxDimension * kMaxDimension] = { + 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, 0x00, 0x00, 0x00, // }; -#undef PIX - scoped_refptr<VideoFrame> video_frame = - VideoFrame::WrapExternalData(format, // format - kSize, // coded_size - kVisibleRect, // visible_rect - kVisibleRect.size(), // natural_size - rgb_data, // data, - base::TimeDelta()); // timestamp + scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( + format, // format + kSize, // coded_size + kVisibleRect, // visible_rect + kVisibleRect.size(), // natural_size + reinterpret_cast<uint8_t*>(rgb_data), // data, + sizeof(rgb_data), // data_size + base::TimeDelta()); // timestamp EXPECT_TRUE(video_frame); return video_frame; } @@ -163,21 +189,23 @@ constexpr int kMaxDimension = 5; constexpr gfx::Size kSize = gfx::Size(kMaxDimension, kMaxDimension); constexpr gfx::Rect kVisibleRect = gfx::Rect(2, 1, 3, 3); - static std::array<uint8_t, 2 * kMaxDimension * kMaxDimension> y16_data = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + constexpr uint16_t kPix = 0xFFFF; + static uint16_t y16_data[kMaxDimension * kMaxDimension] = { + 0x00, 0x00, 0x00, 0x00, 0x00, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, kPix, kPix, kPix, // + 0x00, 0x00, 0x00, 0x00, 0x00, // }; - scoped_refptr<VideoFrame> video_frame = - VideoFrame::WrapExternalData(PIXEL_FORMAT_Y16, - kSize, // coded_size - kVisibleRect, // visible_rect - kVisibleRect.size(), // natural_size - y16_data, // data, - base::TimeDelta()); // timestamp + scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapExternalData( + PIXEL_FORMAT_Y16, + kSize, // coded_size + kVisibleRect, // visible_rect + kVisibleRect.size(), // natural_size + reinterpret_cast<uint8_t*>(y16_data), // data, + sizeof(y16_data), // data_size + base::TimeDelta()); // timestamp EXPECT_TRUE(video_frame); return video_frame; }
diff --git a/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc b/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc index 7c90eca..08835b285 100644 --- a/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc +++ b/media/video/renderable_gpu_memory_buffer_video_frame_pool.cc
@@ -114,15 +114,8 @@ // Callback made when the VideoFrame is destroyed. This callback then either // returns |frame_resources| to |available_frame_resources_| or destroys it. - // TODO(crbug.com/40263579): Remove |gpu_memory_buffer| from this method once - // VideoFrame and all its clients are fully converted to use MappableSI - // instead of GpuMemoryBuffer. Currently for this client, VideoFrame runs - // this callback with null |gpu_memory_buffer| always as this client uses - // MappableSI. - void OnVideoFrameDestroyed( - std::unique_ptr<FrameResources> frame_resources, - const gpu::SyncToken& sync_token, - std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer); + void OnVideoFrameDestroyed(std::unique_ptr<FrameResources> frame_resources, + const gpu::SyncToken& sync_token); const VideoPixelFormat format_; const std::unique_ptr<RenderableGpuMemoryBufferVideoFramePool::Context> @@ -334,23 +327,18 @@ return nullptr; } - // Set the ReleaseMailboxAndGpuMemoryBufferCB to return the GpuMemoryBuffer to - // the FrameResources, and return the FrameResources to the available pool. Do - // this on the calling thread. + // Set the ReleaseMailboxCB to return the FrameResources to the available + // pool. Do this on the calling thread. auto callback = base::BindOnce(&InternalRefCountedPool::OnVideoFrameDestroyed, this, std::move(frame_resources)); - video_frame->SetReleaseMailboxAndGpuMemoryBufferCB( + video_frame->SetReleaseMailboxCB( base::BindPostTaskToCurrentDefault(std::move(callback), FROM_HERE)); return video_frame; } void InternalRefCountedPool::OnVideoFrameDestroyed( std::unique_ptr<FrameResources> frame_resources, - const gpu::SyncToken& sync_token, - std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer) { - // |gpu_memory_buffer| returned here by VideoFrame should always be null - // since we use MappableSI. - CHECK(!gpu_memory_buffer); + const gpu::SyncToken& sync_token) { frame_resources->SetSharedImageReleaseSyncToken(sync_token); if (shutting_down_) {
diff --git a/media/video/video_encode_accelerator_adapter.cc b/media/video/video_encode_accelerator_adapter.cc index f4ba7a1..7802b67 100644 --- a/media/video/video_encode_accelerator_adapter.cc +++ b/media/video/video_encode_accelerator_adapter.cc
@@ -37,6 +37,7 @@ #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) #include "media/video/gpu_video_accelerator_factories.h" #include "media/video/video_encoder_info.h" +#include "ui/gfx/gpu_memory_buffer.h" namespace media { @@ -1055,7 +1056,8 @@ : src_frame; auto shared_frame = VideoFrame::WrapExternalData( PIXEL_FORMAT_I420, dest_coded_size, dest_visible_rect, - dest_visible_rect.size(), *mapping, src_frame->timestamp()); + dest_visible_rect.size(), static_cast<const uint8_t*>(mapping->memory()), + mapping->size(), src_frame->timestamp()); if (!shared_frame || !mapped_src_frame) return EncoderStatus(EncoderStatus::Codes::kSystemAPICallError);
diff --git a/net/proxy_resolution/proxy_config_service_linux.cc b/net/proxy_resolution/proxy_config_service_linux.cc index 792a75e..6fb562a1 100644 --- a/net/proxy_resolution/proxy_config_service_linux.cc +++ b/net/proxy_resolution/proxy_config_service_linux.cc
@@ -1243,6 +1243,7 @@ case base::nix::DESKTOP_ENVIRONMENT_PANTHEON: case base::nix::DESKTOP_ENVIRONMENT_UKUI: case base::nix::DESKTOP_ENVIRONMENT_UNITY: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: #if defined(USE_GIO) { auto gs_getter = std::make_unique<SettingGetterImplGSettings>();
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h index 058a28c03..8198ee2 100644 --- a/net/socket/client_socket_pool_manager.h +++ b/net/socket/client_socket_pool_manager.h
@@ -3,7 +3,7 @@ // found in the LICENSE file. // // ClientSocketPoolManager manages access to all ClientSocketPools. It's a -// simple container for all of them. Most importantly, it handles the lifetime +// simple container for all of them. Most importantly, it handles the lifetime // and destruction order properly. #ifndef NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_ @@ -76,9 +76,7 @@ // A helper method that uses the passed in proxy information to initialize a // ClientSocketHandle with the relevant socket pool. Use this method for // HTTP/HTTPS requests. `allowed_bad_certs` is only used if the request -// uses SSL. `resolution_callback` will be invoked after the the hostname is -// resolved. If `resolution_callback` does not return OK, then the connection -// will be aborted with that value. +// uses SSL. int InitSocketHandleForHttpRequest( url::SchemeHostPort endpoint, int request_load_flags, @@ -98,11 +96,8 @@ // A helper method that uses the passed in proxy information to initialize a // ClientSocketHandle with the relevant socket pool. Use this method for -// HTTP/HTTPS requests for WebSocket handshake. -// `ssl_config_for_origin` is only used if the request uses SSL. -// `resolution_callback` will be invoked after the the hostname is resolved. If -// `resolution_callback` does not return OK, then the connection will be aborted -// with that value. This function uses WEBSOCKET_SOCKET_POOL socket pools. +// HTTP/HTTPS requests for WebSocket handshake. This function uses +// WEBSOCKET_SOCKET_POOL socket pools. int InitSocketHandleForWebSocketRequest( url::SchemeHostPort endpoint, int request_load_flags,
diff --git a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc index 209bd71..b673ffe 100644 --- a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc +++ b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
@@ -242,8 +242,6 @@ return std::make_unique<TtsProcessPolicy>(); case sandbox::mojom::Sandbox::kNearby: return std::make_unique<NearbyProcessPolicy>(); - case sandbox::mojom::Sandbox::kShapeDetection: - return std::make_unique<UtilityProcessPolicy>(); #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case sandbox::mojom::Sandbox::kLibassistant: return std::make_unique<LibassistantProcessPolicy>(); @@ -302,7 +300,6 @@ case sandbox::mojom::Sandbox::kIme: case sandbox::mojom::Sandbox::kTts: case sandbox::mojom::Sandbox::kNearby: - case sandbox::mojom::Sandbox::kShapeDetection: #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case sandbox::mojom::Sandbox::kLibassistant: #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
diff --git a/sandbox/policy/mojom/sandbox.mojom b/sandbox/policy/mojom/sandbox.mojom index 59d1555b..8d0c29b 100644 --- a/sandbox/policy/mojom/sandbox.mojom +++ b/sandbox/policy/mojom/sandbox.mojom
@@ -153,7 +153,4 @@ // On Windows the kService sandbox type is used. // TODO(crbug.com/340778819): Implement sandboxing on other platforms. [EnableIf=is_linux|is_mac] kOnDeviceTranslation, - - // Like kUtility but allows loading of the shape detection internal library. - [EnableIf=is_chromeos] kShapeDetection, };
diff --git a/sandbox/policy/sandbox_type.cc b/sandbox/policy/sandbox_type.cc index 882462b..59155ee6 100644 --- a/sandbox/policy/sandbox_type.cc +++ b/sandbox/policy/sandbox_type.cc
@@ -83,7 +83,6 @@ constexpr char kImeSandbox[] = "ime"; constexpr char kTtsSandbox[] = "tts"; constexpr char kNearbySandbox[] = "nearby"; -constexpr char kShapeDetectionSandbox[] = "shape_detection"; #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) constexpr char kLibassistantSandbox[] = "libassistant"; #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) @@ -172,7 +171,6 @@ case Sandbox::kIme: case Sandbox::kTts: case Sandbox::kNearby: - case Sandbox::kShapeDetection: #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case Sandbox::kLibassistant: #endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT) @@ -337,8 +335,6 @@ return kTtsSandbox; case Sandbox::kNearby: return kNearbySandbox; - case Sandbox::kShapeDetection: - return kShapeDetectionSandbox; #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) case Sandbox::kLibassistant: return kLibassistantSandbox; @@ -468,9 +464,6 @@ if (sandbox_string == kNearbySandbox) { return Sandbox::kNearby; } - if (sandbox_string == kShapeDetectionSandbox) { - return Sandbox::kShapeDetection; - } #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT) if (sandbox_string == kLibassistantSandbox) { return Sandbox::kLibassistant;
diff --git a/services/device/public/mojom/BUILD.gn b/services/device/public/mojom/BUILD.gn index 707c08a..346959e57 100644 --- a/services/device/public/mojom/BUILD.gn +++ b/services/device/public/mojom/BUILD.gn
@@ -59,11 +59,8 @@ ] } - if (is_ios) { - enabled_features = [] - if (is_ios && target_platform == "iphoneos") { - enabled_features += [ "is_ios_iphoneos" ] - } + if (is_ios && target_platform == "iphoneos") { + enabled_features = [ "is_ios_iphoneos" ] } cpp_typemaps = [
diff --git a/services/shape_detection/BUILD.gn b/services/shape_detection/BUILD.gn index b2ee546..294c94c 100644 --- a/services/shape_detection/BUILD.gn +++ b/services/shape_detection/BUILD.gn
@@ -2,13 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//services/shape_detection/features.gni") import("//testing/test.gni") import("//third_party/jni_zero/jni_zero.gni") -source_set("api") { - public = [ "chrome_shape_detection_api.h" ] -} +use_barhopper = is_chrome_branded && is_chromeos source_set("lib") { sources = [ @@ -24,12 +21,6 @@ "//ui/gfx/geometry", ] - public_deps = [ - "//base", - "//media/capture", - "//services/shape_detection/public/mojom", - ] - if (is_mac) { sources += [ "detection_utils_mac.h", @@ -80,18 +71,14 @@ ] } else if (is_android) { # No C++ sources needed, barcode detection is provided by Java. - } else if (build_with_internal_shape_detection) { + } else if (use_barhopper) { sources += [ "barcode_detection_impl_chrome.cc", "barcode_detection_impl_chrome.h", "barcode_detection_provider_chrome.cc", "barcode_detection_provider_chrome.h", - "shape_detection_library_holder.cc", - "shape_detection_library_holder.h", ] - public_deps += [ ":api" ] - data_deps = - [ "//services/shape_detection/internal:shape_detection_internal" ] + deps += [ "//third_party/barhopper" ] } else { # Otherwise, use a stub implementation. sources += [ @@ -102,14 +89,14 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] + public_deps = [ + "//base", + "//media/capture", + "//services/shape_detection/public/mojom", + ] + if (is_android) { deps += [ ":shape_detection_jni_headers" ] - } else if (is_chromeos) { - sources += [ - "shape_detection_sandbox_hook.cc", - "shape_detection_sandbox_hook.h", - ] - deps += [ "//sandbox/policy" ] } } @@ -175,7 +162,7 @@ ] } - if (build_with_internal_shape_detection) { + if (use_barhopper) { sources += [ "barcode_detection_impl_chrome_unittest.cc" ] }
diff --git a/services/shape_detection/DEPS b/services/shape_detection/DEPS index bac6e29..205187d 100644 --- a/services/shape_detection/DEPS +++ b/services/shape_detection/DEPS
@@ -4,10 +4,5 @@ "+ui/gfx/codec", "+ui/gfx/geometry/rect_f.h", "+ui/gl/gl_switches.h", + "+third_party/barhopper/barhopper", ] - -specific_include_rules = { - "shape_detection_sandbox_hook\.[cc|h]": [ - "+sandbox/policy/linux", - ], -}
diff --git a/services/shape_detection/OWNERS b/services/shape_detection/OWNERS index 6728fdf..47d63bc 100644 --- a/services/shape_detection/OWNERS +++ b/services/shape_detection/OWNERS
@@ -1,3 +1 @@ file://third_party/blink/renderer/modules/shapedetection/OWNERS - -per-file shape_detection_sandbox_hook.*=file://sandbox/linux/OWNERS
diff --git a/services/shape_detection/barcode_detection_impl_chrome.cc b/services/shape_detection/barcode_detection_impl_chrome.cc index c02f4f7b..d21015b 100644 --- a/services/shape_detection/barcode_detection_impl_chrome.cc +++ b/services/shape_detection/barcode_detection_impl_chrome.cc
@@ -10,11 +10,10 @@ #include <memory> #include <vector> -#include "base/containers/span.h" #include "base/logging.h" #include "base/numerics/checked_math.h" #include "services/shape_detection/public/mojom/barcodedetection.mojom-shared.h" -#include "services/shape_detection/shape_detection_library_holder.h" +#include "third_party/barhopper/barhopper/barcode.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/rect_f.h" @@ -23,7 +22,7 @@ namespace { gfx::RectF CornerPointsToBoundingBox( - base::span<const ChromePointF>& corner_points) { + std::vector<barhopper::Point>& corner_points) { float xmin = std::numeric_limits<float>::infinity(); float ymin = std::numeric_limits<float>::infinity(); float xmax = -std::numeric_limits<float>::infinity(); @@ -37,115 +36,116 @@ return gfx::RectF(xmin, ymin, (xmax - xmin), (ymax - ymin)); } -mojom::BarcodeFormat BarcodeFormatToMojo(ChromeBarcodeFormat format) { +mojom::BarcodeFormat BarhopperFormatToMojo(barhopper::BarcodeFormat format) { switch (format) { - case CHROME_BARCODE_FORMAT_UNKNOWN: - return mojom::BarcodeFormat::UNKNOWN; - case CHROME_BARCODE_FORMAT_AZTEC: + case barhopper::BarcodeFormat::AZTEC: return mojom::BarcodeFormat::AZTEC; - case CHROME_BARCODE_FORMAT_CODE_128: + case barhopper::BarcodeFormat::CODE_128: return mojom::BarcodeFormat::CODE_128; - case CHROME_BARCODE_FORMAT_CODE_39: + case barhopper::BarcodeFormat::CODE_39: return mojom::BarcodeFormat::CODE_39; - case CHROME_BARCODE_FORMAT_CODE_93: + case barhopper::BarcodeFormat::CODE_93: return mojom::BarcodeFormat::CODE_93; - case CHROME_BARCODE_FORMAT_CODABAR: + case barhopper::BarcodeFormat::CODABAR: return mojom::BarcodeFormat::CODABAR; - case CHROME_BARCODE_FORMAT_DATA_MATRIX: + case barhopper::BarcodeFormat::DATA_MATRIX: return mojom::BarcodeFormat::DATA_MATRIX; - case CHROME_BARCODE_FORMAT_EAN_13: + case barhopper::BarcodeFormat::EAN_13: return mojom::BarcodeFormat::EAN_13; - case CHROME_BARCODE_FORMAT_EAN_8: + case barhopper::BarcodeFormat::EAN_8: return mojom::BarcodeFormat::EAN_8; - case CHROME_BARCODE_FORMAT_ITF: + case barhopper::BarcodeFormat::ITF: return mojom::BarcodeFormat::ITF; - case CHROME_BARCODE_FORMAT_PDF417: + case barhopper::BarcodeFormat::PDF417: return mojom::BarcodeFormat::PDF417; - case CHROME_BARCODE_FORMAT_QR_CODE: + case barhopper::BarcodeFormat::QR_CODE: return mojom::BarcodeFormat::QR_CODE; - case CHROME_BARCODE_FORMAT_UPC_A: + case barhopper::BarcodeFormat::UPC_A: return mojom::BarcodeFormat::UPC_A; - case CHROME_BARCODE_FORMAT_UPC_E: + case barhopper::BarcodeFormat::UPC_E: return mojom::BarcodeFormat::UPC_E; + case barhopper::BarcodeFormat::UNRECOGNIZED: + return mojom::BarcodeFormat::UNKNOWN; default: NOTREACHED() << "Invalid barcode format"; } } -ChromeBarcodeFormat GetExpectedFormats( +barhopper::RecognitionOptions GetRecognitionOptions( const shape_detection::mojom::BarcodeDetectorOptionsPtr& options) { - ChromeBarcodeFormat expected_formats = CHROME_BARCODE_FORMAT_UNKNOWN; + barhopper::RecognitionOptions recognition_options; if (options->formats.empty()) { - expected_formats = - CHROME_BARCODE_FORMAT_AZTEC | CHROME_BARCODE_FORMAT_CODE_128 | - CHROME_BARCODE_FORMAT_CODE_39 | CHROME_BARCODE_FORMAT_CODE_93 | - CHROME_BARCODE_FORMAT_CODABAR | CHROME_BARCODE_FORMAT_DATA_MATRIX | - CHROME_BARCODE_FORMAT_EAN_13 | CHROME_BARCODE_FORMAT_EAN_8 | - CHROME_BARCODE_FORMAT_ITF | CHROME_BARCODE_FORMAT_PDF417 | - CHROME_BARCODE_FORMAT_QR_CODE | CHROME_BARCODE_FORMAT_UPC_A | - CHROME_BARCODE_FORMAT_UPC_E; - return expected_formats; + recognition_options.barcode_formats = + barhopper::BarcodeFormat::AZTEC | barhopper::BarcodeFormat::CODE_128 | + barhopper::BarcodeFormat::CODE_39 | barhopper::BarcodeFormat::CODE_93 | + barhopper::BarcodeFormat::CODABAR | + barhopper::BarcodeFormat::DATA_MATRIX | + barhopper::BarcodeFormat::EAN_13 | barhopper::BarcodeFormat::EAN_8 | + barhopper::BarcodeFormat::ITF | barhopper::BarcodeFormat::PDF417 | + barhopper::BarcodeFormat::QR_CODE | barhopper::BarcodeFormat::UPC_A | + barhopper::BarcodeFormat::UPC_E; + return recognition_options; } + int recognition_formats = 0; for (const auto& format : options->formats) { switch (format) { case mojom::BarcodeFormat::AZTEC: - expected_formats |= CHROME_BARCODE_FORMAT_AZTEC; + recognition_formats |= barhopper::BarcodeFormat::AZTEC; break; case mojom::BarcodeFormat::CODE_128: - expected_formats |= CHROME_BARCODE_FORMAT_CODE_128; + recognition_formats |= barhopper::BarcodeFormat::CODE_128; break; case mojom::BarcodeFormat::CODE_39: - expected_formats |= CHROME_BARCODE_FORMAT_CODE_39; + recognition_formats |= barhopper::BarcodeFormat::CODE_39; break; case mojom::BarcodeFormat::CODE_93: - expected_formats |= CHROME_BARCODE_FORMAT_CODE_93; + recognition_formats |= barhopper::BarcodeFormat::CODE_93; break; case mojom::BarcodeFormat::CODABAR: - expected_formats |= CHROME_BARCODE_FORMAT_CODABAR; + recognition_formats |= barhopper::BarcodeFormat::CODABAR; break; case mojom::BarcodeFormat::DATA_MATRIX: - expected_formats |= CHROME_BARCODE_FORMAT_DATA_MATRIX; + recognition_formats |= barhopper::BarcodeFormat::DATA_MATRIX; break; case mojom::BarcodeFormat::EAN_13: - expected_formats |= CHROME_BARCODE_FORMAT_EAN_13; + recognition_formats |= barhopper::BarcodeFormat::EAN_13; break; case mojom::BarcodeFormat::EAN_8: - expected_formats |= CHROME_BARCODE_FORMAT_EAN_8; + recognition_formats |= barhopper::BarcodeFormat::EAN_8; break; case mojom::BarcodeFormat::ITF: - expected_formats |= CHROME_BARCODE_FORMAT_ITF; + recognition_formats |= barhopper::BarcodeFormat::ITF; break; case mojom::BarcodeFormat::PDF417: - expected_formats |= CHROME_BARCODE_FORMAT_PDF417; + recognition_formats |= barhopper::BarcodeFormat::PDF417; break; case mojom::BarcodeFormat::QR_CODE: - expected_formats |= CHROME_BARCODE_FORMAT_QR_CODE; + recognition_formats |= barhopper::BarcodeFormat::QR_CODE; break; case mojom::BarcodeFormat::UPC_E: - expected_formats |= CHROME_BARCODE_FORMAT_UPC_E; + recognition_formats |= barhopper::BarcodeFormat::UPC_E; break; case mojom::BarcodeFormat::UPC_A: - expected_formats |= CHROME_BARCODE_FORMAT_UPC_A; + recognition_formats |= barhopper::BarcodeFormat::UPC_A; break; case mojom::BarcodeFormat::UNKNOWN: - expected_formats |= CHROME_BARCODE_FORMAT_UNKNOWN; + recognition_formats |= barhopper::BarcodeFormat::UNRECOGNIZED; break; } } - - return expected_formats; + recognition_options.barcode_formats = recognition_formats; + return recognition_options; } } // namespace BarcodeDetectionImplChrome::BarcodeDetectionImplChrome( mojom::BarcodeDetectorOptionsPtr options) - : expected_formats_(GetExpectedFormats(options)) {} + : recognition_options_(GetRecognitionOptions(options)) {} BarcodeDetectionImplChrome::~BarcodeDetectionImplChrome() = default; -DISABLE_CFI_DLSYM void BarcodeDetectionImplChrome::Detect( const SkBitmap& bitmap, shape_detection::mojom::BarcodeDetection::DetectCallback callback) { @@ -162,40 +162,21 @@ luminances[y * width + x] = luminance / 8; } } + std::vector<barhopper::Barcode> barcodes; + barhopper::Barhopper::Recognize(width, height, luminances.data(), + recognition_options_, &barcodes); - ChromeBarcodeDetectionResult* detection_results; - size_t num_results; - const auto* holder = ShapeDetectionLibraryHolder::GetInstance(); - // Holder should be valid if it passed pre-sandbox initialization. - CHECK(holder); - holder->api().DetectBarcodes(width, height, luminances.data(), - expected_formats_, &detection_results, - &num_results); - - // SAFTY: `detection_results` was allocated with `num_results` by - // ChromeShapeDetectionAPI. - UNSAFE_BUFFERS( - base::span<ChromeBarcodeDetectionResult> detection_results_span( - detection_results, num_results);) std::vector<mojom::BarcodeDetectionResultPtr> results; - for (const auto& barcode : detection_results_span) { + for (auto& barcode : barcodes) { auto result = shape_detection::mojom::BarcodeDetectionResult::New(); - - // SAFTY: `barcode.corner_points` was allocated with `barcode. - // corner_points_size` by ChromeShapeDetectionAPI. - UNSAFE_BUFFERS(base::span<const ChromePointF> corner_points_span( - barcode.corner_points, barcode.corner_points_size)); - result->bounding_box = CornerPointsToBoundingBox(corner_points_span); - for (auto& corner_point : corner_points_span) { + result->bounding_box = CornerPointsToBoundingBox(barcode.corner_point); + for (auto& corner_point : barcode.corner_point) { result->corner_points.emplace_back(corner_point.x, corner_point.y); } - result->raw_value = std::string( - reinterpret_cast<const char*>(barcode.value), barcode.value_size); - result->format = BarcodeFormatToMojo(barcode.format); + result->raw_value = barcode.raw_value; + result->format = BarhopperFormatToMojo(barcode.format); results.push_back(std::move(result)); } - - holder->api().DestroyDetectionResults(detection_results, num_results); std::move(callback).Run(std::move(results)); }
diff --git a/services/shape_detection/barcode_detection_impl_chrome.h b/services/shape_detection/barcode_detection_impl_chrome.h index fba3837..8abd222f 100644 --- a/services/shape_detection/barcode_detection_impl_chrome.h +++ b/services/shape_detection/barcode_detection_impl_chrome.h
@@ -5,9 +5,9 @@ #ifndef SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_CHROME_H_ #define SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_CHROME_H_ -#include "services/shape_detection/chrome_shape_detection_api.h" #include "services/shape_detection/public/mojom/barcodedetection.mojom.h" #include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h" +#include "third_party/barhopper/barhopper/barhopper.h" #include "third_party/skia/include/core/SkBitmap.h" namespace shape_detection { @@ -29,7 +29,7 @@ GetSupportedFormats(); private: - const ChromeBarcodeFormat expected_formats_; + barhopper::RecognitionOptions recognition_options_; }; } // namespace shape_detection
diff --git a/services/shape_detection/barcode_detection_impl_chrome_unittest.cc b/services/shape_detection/barcode_detection_impl_chrome_unittest.cc index 701b449aca..487ea33 100644 --- a/services/shape_detection/barcode_detection_impl_chrome_unittest.cc +++ b/services/shape_detection/barcode_detection_impl_chrome_unittest.cc
@@ -17,48 +17,27 @@ namespace shape_detection { -constexpr size_t kMaxNumExpectedValues = 2; - -struct ExpectedValue { - std::string_view raw_value; +constexpr struct TestParams { + base::FilePath::StringViewType filename; + std::string_view expected_value; float x; float y; float width; float height; -}; - -constexpr struct TestParams { - base::FilePath::StringViewType filename; - size_t num_expected_values; - std::array<ExpectedValue, kMaxNumExpectedValues> expected_value; } kTestParams[] = { - {FILE_PATH_LITERAL("codabar.png"), - 1u, - {{{"A6.2831853B", 24, 24, 448, 95}}}}, - {FILE_PATH_LITERAL("code_39.png"), 1u, {{{"CHROMIUM", 20, 20, 318, 75}}}}, - {FILE_PATH_LITERAL("code_93.png"), 1u, {{{"CHROMIUM", 20, 20, 216, 75}}}}, - {FILE_PATH_LITERAL("code_128.png"), 1u, {{{"Chromium", 20, 20, 246, 75}}}}, - {FILE_PATH_LITERAL("data_matrix.png"), - 1u, - {{{"Chromium", 11, 11, 53, 53}}}}, - {FILE_PATH_LITERAL("ean_8.png"), 1u, {{{"62831857", 14, 10, 134, 75}}}}, - {FILE_PATH_LITERAL("ean_13.png"), - 1u, - {{{"6283185307179", 27, 10, 190, 75}}}}, - {FILE_PATH_LITERAL("itf.png"), 1u, {{{"62831853071795", 10, 10, 135, 39}}}}, - {FILE_PATH_LITERAL("pdf417.png"), 1u, {{{"Chromium", 20, 20, 240, 44}}}}, - {FILE_PATH_LITERAL("qr_code.png"), - 1u, - {{{"https://chromium.org", 40, 40, 250, 250}}}}, - {FILE_PATH_LITERAL("upc_a.png"), 1u, {{{"628318530714", 23, 10, 190, 75}}}}, - {FILE_PATH_LITERAL("upc_e.png"), 1u, {{{"06283186", 23, 10, 102, 75}}}}, - {FILE_PATH_LITERAL("two_upc_a.png"), - 2u, - {{ - {"326565565892", 191, 265, 358, 174}, - {"565656545454", 731, 260, 357, 5}, - }}}, -}; + {FILE_PATH_LITERAL("codabar.png"), "A6.2831853B", 24, 24, 448, 95}, + {FILE_PATH_LITERAL("code_39.png"), "CHROMIUM", 20, 20, 318, 75}, + {FILE_PATH_LITERAL("code_93.png"), "CHROMIUM", 20, 20, 216, 75}, + {FILE_PATH_LITERAL("code_128.png"), "Chromium", 20, 20, 246, 75}, + {FILE_PATH_LITERAL("data_matrix.png"), "Chromium", 11, 11, 53, 53}, + {FILE_PATH_LITERAL("ean_8.png"), "62831857", 14, 10, 134, 75}, + {FILE_PATH_LITERAL("ean_13.png"), "6283185307179", 27, 10, 190, 75}, + {FILE_PATH_LITERAL("itf.png"), "62831853071795", 10, 10, 135, 39}, + {FILE_PATH_LITERAL("pdf417.png"), "Chromium", 20, 20, 240, 44}, + {FILE_PATH_LITERAL("qr_code.png"), "https://chromium.org", 40, 40, 250, + 250}, + {FILE_PATH_LITERAL("upc_a.png"), "628318530714", 23, 10, 190, 75}, + {FILE_PATH_LITERAL("upc_e.png"), "06283186", 23, 10, 102, 75}}; class BarcodeDetectionImplChromeTest : public testing::TestWithParam<struct TestParams> { @@ -125,17 +104,12 @@ run_loop.Quit(); })); run_loop.Run(); - EXPECT_EQ(GetParam().num_expected_values, results.size()); - ASSERT_LE(results.size(), kMaxNumExpectedValues); - for (size_t i = 0; i < results.size(); ++i) { - EXPECT_EQ(GetParam().expected_value[i].raw_value, results[i]->raw_value); - EXPECT_EQ(GetParam().expected_value[i].x, results[i]->bounding_box.x()); - EXPECT_EQ(GetParam().expected_value[i].y, results[i]->bounding_box.y()); - EXPECT_EQ(GetParam().expected_value[i].width, - results[i]->bounding_box.width()); - EXPECT_EQ(GetParam().expected_value[i].height, - results[i]->bounding_box.height()); - } + EXPECT_EQ(1u, results.size()); + EXPECT_EQ(GetParam().expected_value, results.front()->raw_value); + EXPECT_EQ(GetParam().x, results.front()->bounding_box.x()); + EXPECT_EQ(GetParam().y, results.front()->bounding_box.y()); + EXPECT_EQ(GetParam().width, results.front()->bounding_box.width()); + EXPECT_EQ(GetParam().height, results.front()->bounding_box.height()); } INSTANTIATE_TEST_SUITE_P(,
diff --git a/services/shape_detection/chrome_shape_detection_api.h b/services/shape_detection/chrome_shape_detection_api.h deleted file mode 100644 index 6715d2e..0000000 --- a/services/shape_detection/chrome_shape_detection_api.h +++ /dev/null
@@ -1,70 +0,0 @@ -// 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 SERVICES_SHAPE_DETECTION_CHROME_SHAPE_DETECTION_API_H_ -#define SERVICES_SHAPE_DETECTION_CHROME_SHAPE_DETECTION_API_H_ - -#include <cstddef> -#include <cstdint> - -// This header defines the public interface to the Chrome Shape Detection shared -// library. - -extern "C" { - -#define CHROME_BARCODE_FORMAT_UNKNOWN (0) -#define CHROME_BARCODE_FORMAT_AZTEC (1 << 0) -#define CHROME_BARCODE_FORMAT_CODE_128 (1 << 1) -#define CHROME_BARCODE_FORMAT_CODE_39 (1 << 2) -#define CHROME_BARCODE_FORMAT_CODE_93 (1 << 3) -#define CHROME_BARCODE_FORMAT_CODABAR (1 << 4) -#define CHROME_BARCODE_FORMAT_DATA_MATRIX (1 << 5) -#define CHROME_BARCODE_FORMAT_EAN_13 (1 << 6) -#define CHROME_BARCODE_FORMAT_EAN_8 (1 << 7) -#define CHROME_BARCODE_FORMAT_ITF (1 << 8) -#define CHROME_BARCODE_FORMAT_PDF417 (1 << 9) -#define CHROME_BARCODE_FORMAT_QR_CODE (1 << 10) -#define CHROME_BARCODE_FORMAT_UPC_A (1 << 11) -#define CHROME_BARCODE_FORMAT_UPC_E (1 << 12) - -// Bitmap of expected barcode formats. -using ChromeBarcodeFormat = uint32_t; - -struct ChromePointF { - float x; - float y; -}; - -struct ChromeBarcodeDetectionResult { - uint8_t* value; - size_t value_size; - ChromePointF* corner_points; - size_t corner_points_size; - ChromeBarcodeFormat format; -}; - -// IMPORTANT: All functions that call ChromeShapeDetectionAPI should be -// annotated with DISABLE_CFI_DLSYM. - -// Table of C API functions defined within the library. -struct ChromeShapeDetectionAPI { - // Detects barcodes in the given grayscale image. - void (*DetectBarcodes)(size_t width, - size_t height, - uint8_t* data, - ChromeBarcodeFormat expected_formats, - ChromeBarcodeDetectionResult** results, - size_t* results_size); - - void (*DestroyDetectionResults)(ChromeBarcodeDetectionResult* results, - size_t size); -}; - -// Signature of the GetChromeShapeDetectionAPI() function which the shared -// library exports. -using ChromeShapeDetectionAPIGetter = const ChromeShapeDetectionAPI* (*)(); - -} // extern "C" - -#endif // SERVICES_SHAPE_DETECTION_CHROME_SHAPE_DETECTION_API_H_
diff --git a/services/shape_detection/features.gni b/services/shape_detection/features.gni deleted file mode 100644 index 11c5139..0000000 --- a/services/shape_detection/features.gni +++ /dev/null
@@ -1,14 +0,0 @@ -# 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("//build/config/chrome_build.gni") -import("//build/config/compiler/compiler.gni") - -declare_args() { - if (is_chrome_branded && is_chromeos) { - build_with_internal_shape_detection = true - } else { - build_with_internal_shape_detection = false - } -}
diff --git a/services/shape_detection/internal b/services/shape_detection/internal deleted file mode 160000 index 8fd3ed0..0000000 --- a/services/shape_detection/internal +++ /dev/null
@@ -1 +0,0 @@ -Subproject commit 8fd3ed03363d2155b038613ff3e2d094a2ad98a3
diff --git a/services/shape_detection/public/mojom/shape_detection_service.mojom b/services/shape_detection/public/mojom/shape_detection_service.mojom index 29be00d5..e6502d1 100644 --- a/services/shape_detection/public/mojom/shape_detection_service.mojom +++ b/services/shape_detection/public/mojom/shape_detection_service.mojom
@@ -10,8 +10,7 @@ import "services/shape_detection/public/mojom/textdetection.mojom"; [EnableIf=has_shape_detection_utility] -const sandbox.mojom.Sandbox kShapeDetectionSandbox - = sandbox.mojom.Sandbox.kShapeDetection; +const sandbox.mojom.Sandbox kShapeDetectionSandbox = sandbox.mojom.Sandbox.kUtility; [EnableIfNot=has_shape_detection_utility] const sandbox.mojom.Sandbox kShapeDetectionSandbox = sandbox.mojom.Sandbox.kGpu;
diff --git a/services/shape_detection/shape_detection_library_holder.cc b/services/shape_detection/shape_detection_library_holder.cc deleted file mode 100644 index 7883699..0000000 --- a/services/shape_detection/shape_detection_library_holder.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// 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 "services/shape_detection/shape_detection_library_holder.h" - -#include <memory> - -#include "base/base_paths.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/no_destructor.h" -#include "base/path_service.h" - -namespace shape_detection { - -namespace { -constexpr std::string_view kChromeShapeDetectionLibraryName = - "shape_detection_internal"; -} // namespace - -base::FilePath GetChromeShapeDetectionPath() { - base::FilePath base_dir; - CHECK(base::PathService::Get(base::DIR_MODULE, &base_dir)); - return base_dir.AppendASCII( - base::GetNativeLibraryName(kChromeShapeDetectionLibraryName)); -} - -ShapeDetectionLibraryHolder::ShapeDetectionLibraryHolder( - base::PassKey<ShapeDetectionLibraryHolder>, - base::ScopedNativeLibrary library, - const ChromeShapeDetectionAPI* api) - : library_(std::move(library)), api_(api) {} - -ShapeDetectionLibraryHolder::~ShapeDetectionLibraryHolder() = default; - -// static -ShapeDetectionLibraryHolder* ShapeDetectionLibraryHolder::GetInstance() { - static base::NoDestructor<std::unique_ptr<ShapeDetectionLibraryHolder>> - holder{Create()}; - return holder->get(); -} - -// static -DISABLE_CFI_DLSYM -std::unique_ptr<ShapeDetectionLibraryHolder> -ShapeDetectionLibraryHolder::Create() { - base::NativeLibraryLoadError error; - base::NativeLibrary library = - base::LoadNativeLibrary(GetChromeShapeDetectionPath(), &error); - if (!library) { - LOG(ERROR) << "Error loading native library: " << error.ToString(); - return {}; - } - - base::ScopedNativeLibrary scoped_library(library); - auto get_api = reinterpret_cast<ChromeShapeDetectionAPIGetter>( - scoped_library.GetFunctionPointer("GetChromeShapeDetectionAPI")); - if (!get_api) { - LOG(ERROR) << "Unable to resolve GetChromeShapeDetectionAPI symbol."; - return {}; - } - - const ChromeShapeDetectionAPI* api = get_api(); - if (!api) { - LOG(ERROR) << "GetChromeShapeDetectionAPI() returned null."; - return {}; - } - - return std::make_unique<ShapeDetectionLibraryHolder>( - base::PassKey<ShapeDetectionLibraryHolder>(), std::move(scoped_library), - api); -} - -} // namespace shape_detection
diff --git a/services/shape_detection/shape_detection_library_holder.h b/services/shape_detection/shape_detection_library_holder.h deleted file mode 100644 index fc279ae..0000000 --- a/services/shape_detection/shape_detection_library_holder.h +++ /dev/null
@@ -1,54 +0,0 @@ -// 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 SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_LIBRARY_HOLDER_H_ -#define SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_LIBRARY_HOLDER_H_ - -#include <memory> - -#include "base/memory/raw_ptr.h" -#include "base/scoped_native_library.h" -#include "base/types/pass_key.h" -#include "services/shape_detection/chrome_shape_detection_api.h" - -namespace shape_detection { - -base::FilePath GetChromeShapeDetectionPath(); - -// A ShapeDetectionLibraryHolder object encapsulates a reference to the -// ChromeShapeDetectionAPI shared library, exposing the library's API -// functions to callers and ensuring that the library remains loaded and usable -// throughout the object's lifetime. -class ShapeDetectionLibraryHolder { - public: - ShapeDetectionLibraryHolder(base::PassKey<ShapeDetectionLibraryHolder>, - base::ScopedNativeLibrary library, - const ChromeShapeDetectionAPI* api); - ShapeDetectionLibraryHolder(const ShapeDetectionLibraryHolder& other) = - delete; - ShapeDetectionLibraryHolder& operator=( - const ShapeDetectionLibraryHolder& other) = delete; - ShapeDetectionLibraryHolder(ShapeDetectionLibraryHolder&& other) = default; - ShapeDetectionLibraryHolder& operator=(ShapeDetectionLibraryHolder&& other) = - default; - ~ShapeDetectionLibraryHolder(); - - // Returns the singleton ShapeDetectionLibraryHolder. Creates it if it does - // not exist. May return nullopt if the underlying library could not be - // loaded. - static ShapeDetectionLibraryHolder* GetInstance(); - - // Exposes the raw ChromeShapeDetectionAPI functions defined by the library. - const ChromeShapeDetectionAPI& api() const { return *api_; } - - private: - static std::unique_ptr<ShapeDetectionLibraryHolder> Create(); - - base::ScopedNativeLibrary library_; - raw_ptr<const ChromeShapeDetectionAPI> api_; -}; - -} // namespace shape_detection - -#endif // SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_LIBRARY_HOLDER_H_
diff --git a/services/shape_detection/shape_detection_sandbox_hook.cc b/services/shape_detection/shape_detection_sandbox_hook.cc deleted file mode 100644 index 27725212..0000000 --- a/services/shape_detection/shape_detection_sandbox_hook.cc +++ /dev/null
@@ -1,39 +0,0 @@ -// 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 "services/shape_detection/shape_detection_sandbox_hook.h" - -#include <dlfcn.h> - -#include "build/branding_buildflags.h" - -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include "services/shape_detection/shape_detection_library_holder.h" -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - -namespace shape_detection { - -bool ShapeDetectionPreSandboxHook( - sandbox::policy::SandboxLinux::Options options) { -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Ensure the shape_detection_internal shared library is loaded before the - // sandbox is initialized. - const auto path = shape_detection::GetChromeShapeDetectionPath(); - // We don't want to unload the library so not using - // `ShapeDetectionLibraryHolder` here. - void* dl = - dlopen(path.value().c_str(), RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE); - if (!dl) { - LOG(ERROR) << "Failed to open Chrome Shape Detection shared library!"; - return false; - } else { - DVLOG(1) << "Successfully opened Chrome Shape Detection shared library."; - } -#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) - auto* instance = sandbox::policy::SandboxLinux::GetInstance(); - instance->EngageNamespaceSandboxIfPossible(); - return true; -} - -} // namespace shape_detection
diff --git a/services/shape_detection/shape_detection_sandbox_hook.h b/services/shape_detection/shape_detection_sandbox_hook.h deleted file mode 100644 index 33da3ee..0000000 --- a/services/shape_detection/shape_detection_sandbox_hook.h +++ /dev/null
@@ -1,17 +0,0 @@ -// 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 SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_SANDBOX_HOOK_H_ -#define SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_SANDBOX_HOOK_H_ - -#include "sandbox/policy/linux/sandbox_linux.h" - -namespace shape_detection { - -bool ShapeDetectionPreSandboxHook( - sandbox::policy::SandboxLinux::Options options); - -} // namespace shape_detection - -#endif // SERVICES_SHAPE_DETECTION_SHAPE_DETECTION_SANDBOX_HOOK_H_
diff --git a/services/test/data/two_upc_a.png b/services/test/data/two_upc_a.png deleted file mode 100644 index 0911b7b..0000000 --- a/services/test/data/two_upc_a.png +++ /dev/null Binary files differ
diff --git a/services/webnn/ort/graph_builder_ort.cc b/services/webnn/ort/graph_builder_ort.cc index 9c6352b..e35ba42 100644 --- a/services/webnn/ort/graph_builder_ort.cc +++ b/services/webnn/ort/graph_builder_ort.cc
@@ -190,7 +190,7 @@ operand_id); } -std::string GraphBuilderOrt::GenerateOperationName(std::string_view label) { +std::string GraphBuilderOrt::GenerateNodeName(std::string_view label) { return base::JoinString({label, base::NumberToString(next_operation_id_++)}, kUnderscore); } @@ -234,7 +234,7 @@ template <typename T> void GraphBuilderOrt::AddBinaryOperation(const T& operation, base::cstring_view op_type) { - const std::string node = GenerateOperationName(operation.label); + const std::string node_name = GenerateNodeName(operation.label); const std::string lhs = GetOperandNameById(operation.lhs_operand_id); const std::string rhs = GetOperandNameById(operation.rhs_operand_id); const std::string output = GetOperandNameById(operation.output_operand_id); @@ -242,24 +242,24 @@ std::array<const char*, 2> inputs = {lhs.c_str(), rhs.c_str()}; std::array<const char*, 1> outputs = {output.c_str()}; - model_editor_.AddNode(op_type, node, inputs, outputs); + model_editor_.AddNode(op_type, node_name, inputs, outputs); } template <typename T> void GraphBuilderOrt::AddUnaryOperation(const T& operation, base::cstring_view op_type) { - const std::string node = GenerateOperationName(operation.label); + const std::string node_name = GenerateNodeName(operation.label); const std::string input = GetOperandNameById(operation.input_operand_id); const std::string output = GetOperandNameById(operation.output_operand_id); std::array<const char*, 1> inputs = {input.c_str()}; std::array<const char*, 1> outputs = {output.c_str()}; - model_editor_.AddNode(op_type, node, inputs, outputs); + model_editor_.AddNode(op_type, node_name, inputs, outputs); } void GraphBuilderOrt::AddCastOperation(const mojom::ElementWiseUnary& cast) { - const std::string node = GenerateOperationName(cast.label); + const std::string node_name = GenerateNodeName(cast.label); const std::string input = GetOperandNameById(cast.input_operand_id); const std::string output = GetOperandNameById(cast.output_operand_id); @@ -274,11 +274,11 @@ std::array<ScopedOrtOpAttr, 1> attributes = { model_editor_.CreateAttribute(kAttrTo, attr_to_data)}; - model_editor_.AddNode(kOpTypeCast, node, inputs, outputs, attributes); + model_editor_.AddNode(kOpTypeCast, node_name, inputs, outputs, attributes); } void GraphBuilderOrt::AddConv2dOperation(const mojom::Conv2d& conv2d) { - const std::string node_name = GenerateOperationName(conv2d.label); + const std::string node_name = GenerateNodeName(conv2d.label); const std::string input = GetOperandNameById(conv2d.input_operand_id); const std::string filter = GetOperandNameById(conv2d.filter_operand_id); const std::string output = GetOperandNameById(conv2d.output_operand_id); @@ -506,7 +506,7 @@ } void GraphBuilderOrt::AddClampOperation(const mojom::Clamp& clamp) { - const std::string node = GenerateOperationName(clamp.label); + const std::string node_name = GenerateNodeName(clamp.label); const std::string input = GetOperandNameById(clamp.input_operand_id); const std::string output = GetOperandNameById(clamp.output_operand_id); @@ -582,11 +582,11 @@ std::array<const char*, 3> inputs = {input.c_str(), min.c_str(), max.c_str()}; std::array<const char*, 1> outputs = {output.c_str()}; - model_editor_.AddNode(kOpTypeClamp, node, inputs, outputs); + model_editor_.AddNode(kOpTypeClamp, node_name, inputs, outputs); } void GraphBuilderOrt::AddGemmOperation(const mojom::Gemm& gemm) { - const std::string node = GenerateOperationName(gemm.label); + const std::string node_name = GenerateNodeName(gemm.label); const std::string input_a = GetOperandNameById(gemm.a_operand_id); const std::string input_b = GetOperandNameById(gemm.b_operand_id); const std::string output = GetOperandNameById(gemm.output_operand_id); @@ -625,7 +625,7 @@ model_editor_.CreateAttribute(kAttrTransB, static_cast<int64_t>(gemm.b_transpose))}; - model_editor_.AddNode(kOpTypeGemm, node, inputs, outputs, attributes); + model_editor_.AddNode(kOpTypeGemm, node_name, inputs, outputs, attributes); } void GraphBuilderOrt::AddPool2dOperation(const mojom::Pool2d& pool2d) { @@ -704,17 +704,17 @@ } } - const std::string node = GenerateOperationName(pool2d.label); + const std::string node_name = GenerateNodeName(pool2d.label); const std::string input = GetOperandNameById(pool2d.input_operand_id); const std::string output = GetOperandNameById(pool2d.output_operand_id); std::array<const char*, 1> inputs = {input.c_str()}; std::array<const char*, 1> outputs = {output.c_str()}; - model_editor_.AddNode(op_type, node, inputs, outputs, attributes); + model_editor_.AddNode(op_type, node_name, inputs, outputs, attributes); } void GraphBuilderOrt::AddReshapeOperation(const mojom::Reshape& reshape) { - const std::string node = GenerateOperationName(reshape.label); + const std::string node_name = GenerateNodeName(reshape.label); const std::string input = GetOperandNameById(reshape.input_operand_id); const std::string output = GetOperandNameById(reshape.output_operand_id); @@ -734,11 +734,11 @@ std::array<const char*, 2> inputs = {input.c_str(), new_shape.c_str()}; std::array<const char*, 1> outputs = {output.c_str()}; - model_editor_.AddNode(kOpTypeReshape, node, inputs, outputs); + model_editor_.AddNode(kOpTypeReshape, node_name, inputs, outputs); } void GraphBuilderOrt::AddSoftmaxOperation(const mojom::Softmax& softmax) { - const std::string node = GenerateOperationName(softmax.label); + const std::string node_name = GenerateNodeName(softmax.label); const std::string input = GetOperandNameById(softmax.input_operand_id); const std::string output = GetOperandNameById(softmax.output_operand_id); @@ -752,11 +752,11 @@ std::array<ScopedOrtOpAttr, 1> attributes = {model_editor_.CreateAttribute( kAttrAxis, static_cast<int64_t>(softmax.axis))}; - model_editor_.AddNode(kOpTypeSoftmax, node, inputs, outputs, attributes); + model_editor_.AddNode(kOpTypeSoftmax, node_name, inputs, outputs, attributes); } void GraphBuilderOrt::AddTransposeOperation(const mojom::Transpose& transpose) { - const std::string node = GenerateOperationName(transpose.label); + const std::string node_name = GenerateNodeName(transpose.label); const std::string input = GetOperandNameById(transpose.input_operand_id); const std::string output = GetOperandNameById(transpose.output_operand_id); @@ -772,7 +772,8 @@ std::array<ScopedOrtOpAttr, 1> attributes = { model_editor_.CreateAttribute(kAttrPerm, perm_value)}; - model_editor_.AddNode(kOpTypeTranspose, node, inputs, outputs, attributes); + model_editor_.AddNode(kOpTypeTranspose, node_name, inputs, outputs, + attributes); } [[nodiscard]] base::expected<std::unique_ptr<ModelEditor::ModelInfo>,
diff --git a/services/webnn/ort/graph_builder_ort.h b/services/webnn/ort/graph_builder_ort.h index d1438b7..5963693b 100644 --- a/services/webnn/ort/graph_builder_ort.h +++ b/services/webnn/ort/graph_builder_ort.h
@@ -89,10 +89,9 @@ // "inserted" and `next_operand_id_`, and then increase `next_operand_id_`. std::string GenerateOperandName(); - // Generate a unique name for a newly created operation by combining - // `label` and `next_operation_id_`. ORT model doesn't allow duplicate - // names. - std::string GenerateOperationName(std::string_view label); + // Generate a unique name for a newly created node by combining `label` and + // `next_operation_id_`. ORT model doesn't allow duplicate names. + std::string GenerateNodeName(std::string_view label); // Create a new initializer for the graph with the given shape and data, // returning the name of the initializer.
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc index 96ce6a3d..b50d7f1 100644 --- a/services/webnn/tflite/graph_builder_tflite.cc +++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -1851,6 +1851,99 @@ } std::optional<GraphBuilderTflite::TensorInfo> +GraphBuilderTflite::CanFuseQuantizeAndGetOutput(const mojom::Gemm& gemm) { + // TODO(crbug.com/372932099): Fuse quantized gemm when gemm.alpha or gemm.beta + // isn't 1.0. + if (!IsDequantizeOutput(gemm.a_operand_id) || + !IsDequantizeOutput(gemm.b_operand_id) || gemm.alpha != 1.0f || + gemm.beta != 1.0f) { + return std::nullopt; + } + + // The a operand scale and output scale have to be scaler, see quantization + // requirements of FULLY_CONNECTED at + // https://ai.google.dev/edge/litert/models/quantization_spec#int8_quantized_operator_specifications + const mojom::DequantizeLinear& a_dequantize = + GetDequantizeOp(gemm.a_operand_id); + const mojom::DequantizeLinear& b_dequantize = + GetDequantizeOp(gemm.b_operand_id); + const OperandDataType quantized_type = + GetOperand(a_dequantize.input_operand_id).descriptor.data_type(); + // TODO(crbug.com/425746878): Support int4 quantization for b operand. + if (!IsInts8AndScalarScale(a_dequantize) || + GetOperand(b_dequantize.input_operand_id).descriptor.data_type() != + quantized_type) { + return std::nullopt; + } + + // The c operand must be optional or int32 data type. + // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/fully_connected.cc;drc=7930f629a820b2233128fb591789f4d8a41be8d9;l=216 + if (gemm.c_operand_id) { + if (!IsDequantizeOutput(*gemm.c_operand_id)) { + return std::nullopt; + } + const mojom::DequantizeLinear& c_dequantize = + GetDequantizeOp(*gemm.c_operand_id); + if (GetOperand(c_dequantize.input_operand_id).descriptor.data_type() != + OperandDataType::kInt32) { + return std::nullopt; + } + } + + std::optional<std::pair<OperationId, QuantizateParametersOffset>> next_op = + IsNextOpQuantize(gemm.output_operand_id, {quantized_type}); + if (!next_op) { + return std::nullopt; + } + const mojom::QuantizeLinear& output_quantize = GetQuantizeOp(next_op->first); + if (!IsInts8AndScalarScale(output_quantize)) { + return std::nullopt; + } + + // Only Int8 is supported for per-channel quantization. + // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/fully_connected.cc;l=446;drc=997022c9de8c1e4ed9081b8789c1057d0fce0e28 + size_t number_of_b_scale = + GetOperand(b_dequantize.scale_operand_id).descriptor.NumberOfElements(); + const bool per_channel_quantization = number_of_b_scale != 1; + if (per_channel_quantization && quantized_type != OperandDataType::kInt8) { + return std::nullopt; + } + // The transpose operation will be inserted if gemm.b_transpose is false, but + // quantized transpose only supports per-tensor quantization. + // https://source.chromium.org/chromium/chromium/src/+/main:services/webnn/tflite/graph_builder_tflite.cc;drc=87413efa62e18726d73e7f283efef63d4bfd1023;l=4581 + if (per_channel_quantization && !gemm.b_transpose) { + return std::nullopt; + } + + // The a_scale * b_scale should be about the same as c_scale for per-tensor + // quantization. + // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/kernel_util.cc;l=303;drc=492dc9719f6e1845f4f5c0553cd5c7651115f671 + if (!per_channel_quantization && gemm.c_operand_id) { + base::span<const float> a_scale_values = + GetConstantValue<float>(a_dequantize.scale_operand_id); + base::span<const float> b_scale_values = + GetConstantValue<float>(b_dequantize.scale_operand_id); + const mojom::DequantizeLinear& c_dequantize = + GetDequantizeOp(*gemm.c_operand_id); + base::span<const float> c_scale_values = + GetConstantValue<float>(c_dequantize.scale_operand_id); + base::span<const float> output_scale_values = + GetConstantValue<float>(output_quantize.scale_operand_id); + const double a_scale = static_cast<double>(a_scale_values[0]); + const double output_scale = static_cast<double>(output_scale_values[0]); + auto a_product_b = + base::MakeCheckedNum<double>(a_scale) * b_scale_values[0]; + auto scale_diff = a_product_b - static_cast<double>(c_scale_values[0]); + scale_diff = scale_diff.Abs() / output_scale; + if (!scale_diff.IsValid() || scale_diff.ValueOrDie() > 0.02) { + return std::nullopt; + } + } + + return SerializeQuantizedOutput(*next_op); +} + +std::optional<GraphBuilderTflite::TensorInfo> GraphBuilderTflite::CanFuseQuantizeAndGetOutput(const mojom::Pad& pad) { // For edge padding mode, it is not supported in tflite schema. // @@ -3326,7 +3419,8 @@ output_shape[i] = input_tensor_info.dimensions[permutation[i]]; } const TensorIndex output_tensor_index = - SerializeTemporaryTensor(output_shape, input_tensor_info.data_type); + SerializeTemporaryTensor(output_shape, input_tensor_info.data_type, + input_tensor_info.quantize_params); operators_.emplace_back( SerializeTransposeOperation(input_tensor_info.index, output_tensor_index, input_tensor_info.dimensions, permutation)); @@ -4548,8 +4642,31 @@ {GetOperand(gemm.a_operand_id).descriptor, GetOperand(gemm.b_operand_id).descriptor})); + // The TFLite fully connected operator only supports a 1-D bias tensor with + // `output_channels` dimensions. + // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/kernels/fully_connected.cc;drc=7930f629a820b2233128fb591789f4d8a41be8d9;l=425 + bool is_emulated_c_expression = false; + if (gemm.c_operand_id) { + const std::vector<uint32_t>& output_shape = + GetOperand(gemm.output_operand_id).descriptor.shape(); + CHECK_EQ(output_shape.size(), 2u); + const uint32_t output_channels = output_shape[1]; + const std::vector<uint32_t>& c_shape = + GetOperand(*gemm.c_operand_id).descriptor.shape(); + if (c_shape.size() != 1 || c_shape[0] != output_channels) { + is_emulated_c_expression = true; + } + } + + std::optional<TensorInfo> quantized_output = + is_emulated_c_expression ? std::nullopt + : CanFuseQuantizeAndGetOutput(gemm); + const bool fuse_dequantize = quantized_output.has_value(); ASSIGN_OR_RETURN(const TensorInfo& a_tensor_info, - SerializeInputTensorInfo(gemm.a_operand_id)); + SerializeInputTensorInfo( + gemm.a_operand_id, + /*quantize_params=*/0, + /*operation_supports_float16=*/false, fuse_dequantize)); TensorIndex a_tensor_index = a_tensor_info.index; // The permutation transpose first or second 2-D tensor. static constexpr std::array<uint32_t, 2> permutation = {1u, 0u}; @@ -4577,7 +4694,10 @@ // input_channels], so the Transpose operator need to be inserted before // Gemm When bTranspose option is false. ASSIGN_OR_RETURN(const TensorInfo& b_tensor_info, - SerializeInputTensorInfo(gemm.b_operand_id)); + SerializeInputTensorInfo( + gemm.b_operand_id, + /*quantize_params=*/0, + /*operation_supports_float16=*/false, fuse_dequantize)); TensorIndex b_tensor_index = b_tensor_info.index; if (!gemm.b_transpose) { b_tensor_index = InsertTransposeOperation(b_tensor_info, permutation); @@ -4585,15 +4705,29 @@ std::vector<TensorIndex> fully_connected_inputs = {a_tensor_index, b_tensor_index}; - const TensorInfo output_tensor_info = - SerializeOutputTensorInfo(gemm.output_operand_id); - CHECK_EQ(output_tensor_info.dimensions.size(), 2u); + TensorIndex output_tensor_index; + std::vector<int32_t> output_tensor_dimensions; + ::tflite::TensorType output_tensor_type; + if (fuse_dequantize) { + output_tensor_index = quantized_output->index; + } else { + const TensorInfo output_tensor_info = + SerializeOutputTensorInfo(gemm.output_operand_id); + CHECK_EQ(output_tensor_info.dimensions.size(), 2u); + output_tensor_index = output_tensor_info.index; + output_tensor_dimensions = std::move(output_tensor_info.dimensions); + output_tensor_type = output_tensor_info.data_type; + } std::optional<TensorIndex> c_tensor_index; if (gemm.c_operand_id && gemm.beta != 0.0f) { CHECK(context_properties_.data_type_limits.gemm_c.Supports( GetOperand(gemm.c_operand_id.value()).descriptor)); - ASSIGN_OR_RETURN(const TensorInfo& c_tensor_info, - SerializeInputTensorInfo(*gemm.c_operand_id)); + ASSIGN_OR_RETURN( + const TensorInfo& c_tensor_info, + SerializeInputTensorInfo(*gemm.c_operand_id, + /*quantize_params=*/0, + /*operation_supports_float16=*/false, + fuse_dequantize)); c_tensor_index = c_tensor_info.index; if (gemm.beta != 1.0f) { const TensorIndex beta_tensor_index = SerializeTensorWithBuffer<float>( @@ -4607,37 +4741,33 @@ c_tensor_index = output_tensor_index_of_mul; } - // The TFLite fully connected operator only supports a 1-D bias tensor with - // `output_channels` dimensions. - const int32_t output_channels = output_tensor_info.dimensions[1]; - if (c_tensor_info.dimensions.size() == 1 && - c_tensor_info.dimensions[0] == output_channels) { + if (!is_emulated_c_expression) { fully_connected_inputs.push_back(*c_tensor_index); } } // Add the `beta * C` subexpression if it's not fused into FULLY_CONNECTED // operator. - const bool addition_c_expression = - c_tensor_index && fully_connected_inputs.size() == 2; - TensorIndex output_tensor_index = output_tensor_info.index; - if (addition_c_expression) { - output_tensor_index = SerializeTemporaryTensor( - output_tensor_info.dimensions, output_tensor_info.data_type); + TensorIndex addition_c_tensor_index = output_tensor_index; + if (is_emulated_c_expression) { + CHECK(!fuse_dequantize); + addition_c_tensor_index = + SerializeTemporaryTensor(output_tensor_dimensions, output_tensor_type); } const OperatorCodeIndex operator_code_index = GetOperatorCodeIndex(::tflite::BuiltinOperator_FULLY_CONNECTED); - const std::array<TensorIndex, 1> op_outputs = {output_tensor_index}; + const std::array<TensorIndex, 1> op_outputs = {addition_c_tensor_index}; OperatorOffset operator_offset = ::tflite::CreateOperator( builder_, operator_code_index, builder_.CreateVector<TensorIndex>(fully_connected_inputs), builder_.CreateVector<TensorIndex>(op_outputs)); - if (addition_c_expression) { + if (is_emulated_c_expression) { + CHECK(!fuse_dequantize); operators_.push_back(operator_offset); operator_offset = SerializeBinaryOperation( - ::tflite::BuiltinOperator_ADD, output_tensor_index, *c_tensor_index, - output_tensor_info.index); + ::tflite::BuiltinOperator_ADD, addition_c_tensor_index, *c_tensor_index, + output_tensor_index); } return operator_offset; }
diff --git a/services/webnn/tflite/graph_builder_tflite.h b/services/webnn/tflite/graph_builder_tflite.h index c15b40c..9cadc2b8 100644 --- a/services/webnn/tflite/graph_builder_tflite.h +++ b/services/webnn/tflite/graph_builder_tflite.h
@@ -745,6 +745,8 @@ std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(const mojom::Elu& elu); std::optional<TensorInfo> CanFuseQuantizeAndGetOutput( const mojom::Gather& gather); + std::optional<TensorInfo> CanFuseQuantizeAndGetOutput( + const mojom::Gemm& gemm); std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(const mojom::Pad& pad); std::optional<TensorInfo> CanFuseQuantizeAndGetOutput( const mojom::Pool2d& pool2d);
diff --git a/testing/buildbot/filters/layer_list_mode.cc_unittests.filter b/testing/buildbot/filters/layer_list_mode.cc_unittests.filter index 6c420d6..4f59b0e 100644 --- a/testing/buildbot/filters/layer_list_mode.cc_unittests.filter +++ b/testing/buildbot/filters/layer_list_mode.cc_unittests.filter
@@ -846,7 +846,6 @@ -CommitToActiveTreeScrollbarLayerTest.UpdatePropertiesOfScrollBarWhenThumbRemoved -DontUpdateLayersWithEmptyBounds.RunMultiThread_DelegatingRenderer -DontUpdateLayersWithEmptyBounds.RunSingleThread_DelegatingRenderer --DroppedFrameCounterNoDropTest.RunMultiThread_DelegatingRenderer -HudWithRootLayerChange.RunMultiThread_DelegatingRenderer -HudWithRootLayerChange.RunSingleThread_DelegatingRenderer -ImplSideInvalidationWithoutCommitTestFilter.RunMultiThread_DelegatingRenderer
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index e79f1fd..ede79ee 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3509,6 +3509,21 @@ ] } ], + "BocaOnTaskMuteArcAudio": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "BocaOnTaskMuteArcAudio" + ] + } + ] + } + ], "BookmarksUseBinaryTreeInTitledUrlIndex": [ { "platforms": [
diff --git a/third_party/android_build_tools/README.chromium b/third_party/android_build_tools/README.chromium index 0d842c1..ca29bb39 100644 --- a/third_party/android_build_tools/README.chromium +++ b/third_party/android_build_tools/README.chromium
@@ -2,6 +2,7 @@ Short Name: Android tools Version: N/A Revision: DEPS +Update Mechanism: Autoroll License: Apache-2.0 URL: https://developer.android.com/studio Security Critical: No
diff --git a/third_party/android_build_tools/aapt2/README.chromium b/third_party/android_build_tools/aapt2/README.chromium index 1a2541f8..7bb114e7 100644 --- a/third_party/android_build_tools/aapt2/README.chromium +++ b/third_party/android_build_tools/aapt2/README.chromium
@@ -2,6 +2,7 @@ Short name: aapt2 Version: N/A Revision: DEPS +Update Mechanism: Autoroll URL: https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/${Version}/aapt2-${Version}-linux.jar Security Critical: no Shipped: no
diff --git a/third_party/android_build_tools/error_prone_javac/README.chromium b/third_party/android_build_tools/error_prone_javac/README.chromium index 22854ef0..dfa16db 100644 --- a/third_party/android_build_tools/error_prone_javac/README.chromium +++ b/third_party/android_build_tools/error_prone_javac/README.chromium
@@ -1,6 +1,7 @@ Name: Error Prone Javac Short Name: Error Prone Javac Version: 9+181-r4173-1 +Update Mechanism: Autoroll License: GPL-2.0-with-classpath-exception License File: LICENSE Security Critical: No
diff --git a/third_party/android_build_tools/lint/README.chromium b/third_party/android_build_tools/lint/README.chromium index 215cc45..427b7ef6 100644 --- a/third_party/android_build_tools/lint/README.chromium +++ b/third_party/android_build_tools/lint/README.chromium
@@ -2,6 +2,7 @@ Short Name: lint Version: N/A Revision: DEPS +Update Mechanism: Autoroll License: Apache-2.0 License File: LICENSE Security Critical: No
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle index 2d00e592..1de158f 100644 --- a/third_party/androidx/build.gradle +++ b/third_party/androidx/build.gradle
@@ -307,7 +307,7 @@ google() maven { // This URL is generated by the fetch_all_androidx.py script. - url 'https://androidx.dev/snapshots/builds/13670804/artifacts/repository' + url 'https://androidx.dev/snapshots/builds/13672893/artifacts/repository' } mavenCentral() }
diff --git a/third_party/angle b/third_party/angle index 6495149..9e629bb 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 649514930e65cb7a9baa489092431010df5e8b4a +Subproject commit 9e629bbb0f732b071f3c7ca6d13b4692b02f6cef
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 189331d..56f604e 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -7360,6 +7360,8 @@ ]) source_node.accumulator.add_include_headers([ "base/containers/span.h", + "base/notimplemented.h", + "base/notreached.h", "third_party/blink/renderer/platform/bindings/script_state.h", "third_party/blink/renderer/platform/bindings/v8_per_context_data.h", "third_party/blink/public/mojom/origin_trials/origin_trial_feature.mojom-shared.h",
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc index 9351724..60c2ec6a 100644 --- a/third_party/blink/renderer/core/css/media_query_evaluator.cc +++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -1712,7 +1712,7 @@ state, value.GetCSSValue()); query_fallback = ToPhysicalFallback(query_fallback, media_values); fallback = ToPhysicalFallback(fallback, media_values); - return fallback == query_fallback; + return fallback.Matches(query_fallback); } static MediaQueryOperator ReverseOperator(MediaQueryOperator op) {
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc index 7c12305..96bc537 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -3677,7 +3677,7 @@ Element* div = InsertHTMLElement("<div id='sample' contenteditable></div>", "sample"); - // Add character U+200C: 'kZeroWidthNonJoinerCharacter' and Myanmar vowel + // Add character U+200C: 'kZeroWidthNonJoiner' and Myanmar vowel Controller().SetComposition(String::FromUTF8("\xE2\x80\x8C\xE1\x80\xB1"), Vector<ImeTextSpan>(), 0, 0); @@ -3691,7 +3691,7 @@ Vector<ImeTextSpan>(), 1); EXPECT_EQ(String::FromUTF8("\xE2\x80\x8C\xE1\x80\xB1"), div->innerHTML()); - // Add character U+200C: 'kZeroWidthNonJoinerCharacter' and Myanmar vowel + // Add character U+200C: 'kZeroWidthNonJoiner' and Myanmar vowel Controller().SetComposition(String::FromUTF8("\xE2\x80\x8C\xE1\x80\xB1"), Vector<ImeTextSpan>(), 2, 2); Controller().CommitText(String::FromUTF8("\xE2\x80\x8C\xE1\x80\xB1"),
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc index 7406861..270534ed 100644 --- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc +++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -486,7 +486,13 @@ // sibling shadow root, if any. const auto* shadow_root = DynamicTo<ShadowRoot>(node_); if (!shadow_root) { +#if !BUILDFLAG(IS_ANDROID) + // TODO(crbug.com/421311110): Hits at chrome://extensions, + // chrome://flags, etc. NOTREACHED(); +#endif // !BUILDFLAG(IS_ANDROID) + should_stop_ = true; + return; } if (shadow_root->IsOpen()) { // We are the shadow root; exit from here and go back to
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h index 356e2f45..7829496c 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h +++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -70,6 +70,7 @@ namespace blink { +class CanvasResourceProvider; class CanvasElementHitTestRegion; class ComputedStyle; class Document; @@ -206,6 +207,11 @@ } void DidDraw(const SkIRect& dirty_rect, CanvasPerformanceMonitor::DrawType); + virtual std::unique_ptr<CanvasResourceProvider> + CreateCanvasResourceProvider() { + NOTREACHED(); + } + // Returns a StaticBitmapImage containing the current content, or nullptr if // it was not possible to obtain that content. virtual scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
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 6854f0a6..e9383d3a 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
@@ -35,10 +35,6 @@ namespace blink { -BASE_FEATURE(kUseSharedBitmapProviderForSoftwareCompositing, - "UseSharedBitmapProviderForSoftwareCompositing", - base::FEATURE_ENABLED_BY_DEFAULT); - CanvasRenderingContextHost::CanvasRenderingContextHost(HostType host_type, const gfx::Size& size) : CanvasResourceHost(size), host_type_(host_type) {} @@ -171,7 +167,9 @@ auto* provider = GetResourceProviderForWebGL(); if (!provider && !did_fail_to_create_resource_provider_) { if (IsValidImageSize()) { - CreateCanvasResourceProviderWebGL(); + resource_provider_for_webgl_ = + RenderingContext()->CreateCanvasResourceProvider(); + UpdateMemoryUsage(); provider = GetResourceProviderForWebGL(); } if (!provider) { @@ -219,91 +217,6 @@ } } -void CanvasRenderingContextHost::CreateCanvasResourceProviderWebGL() { - CHECK(!GetResourceProviderForWebGL()); - - base::WeakPtr<CanvasResourceDispatcher> dispatcher = - GetOrCreateResourceDispatcher() - ? GetOrCreateResourceDispatcher()->GetWeakPtr() - : nullptr; - - std::unique_ptr<CanvasResourceProvider> provider; - const SkAlphaType alpha_type = GetRenderingContextAlphaType(); - const viz::SharedImageFormat format = GetRenderingContextFormat(); - const gfx::ColorSpace color_space = GetRenderingContextColorSpace(); - // Do not initialize the CRP using Skia. The CRP can have bottom left origin - // in which case Skia Graphite won't be able to render into it, and WebGL is - // responsible for clearing the CRP when it renders anyway and we have clear - // rect tracking in the shared image system to enforce this. - constexpr auto kShouldInitialize = - CanvasResourceProvider::ShouldInitialize::kNo; - if (SharedGpuContext::IsGpuCompositingEnabled() && LowLatencyEnabled()) { - // If LowLatency is enabled, we need a resource that is able to perform well - // in such mode. It will first try a PassThrough provider and, if that is - // not possible, it will try a SharedImage with the appropriate flags. - bool using_swapchain = - RenderingContext() && RenderingContext()->UsingSwapChain(); - bool using_webgl_image_chromium = - SharedGpuContext::MaySupportImageChromium() && - (RuntimeEnabledFeatures::WebGLImageChromiumEnabled() || - base::FeatureList::IsEnabled(features::kLowLatencyWebGLImageChromium)); - if (using_swapchain || using_webgl_image_chromium) { - // If either SwapChain is enabled or WebGLImage mode is enabled, we can - // try a passthrough provider. - DCHECK(LowLatencyEnabled()); - provider = CanvasResourceProvider::CreatePassThroughProvider( - Size(), format, alpha_type, color_space, - SharedGpuContext::ContextProviderWrapper(), this); - } - if (!provider) { - // If PassThrough failed, try a SharedImage with usage display enabled. - gpu::SharedImageUsageSet shared_image_usage_flags = - gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; - provider = CanvasResourceProvider::CreateSharedImageProvider( - Size(), format, alpha_type, color_space, kShouldInitialize, - SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU, - shared_image_usage_flags, this); - } - } else if (SharedGpuContext::IsGpuCompositingEnabled()) { - // If there is no LowLatency mode, and GPU is enabled, will try a GPU - // SharedImage that should support Usage Display and probably Usage Scanout - // if WebGLImageChromium is enabled. - gpu::SharedImageUsageSet shared_image_usage_flags = - gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; - if (SharedGpuContext::MaySupportImageChromium() && - RuntimeEnabledFeatures::WebGLImageChromiumEnabled()) { - shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; - } - provider = CanvasResourceProvider::CreateSharedImageProvider( - Size(), format, alpha_type, color_space, kShouldInitialize, - SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU, - shared_image_usage_flags, this); - } - - // If either of the other modes failed and / or it was not possible to do, we - // will backup with a software SharedImage, and if that was not possible with - // a Bitmap provider. - bool use_software_shared_image_provider = - base::FeatureList::IsEnabled( - kUseSharedBitmapProviderForSoftwareCompositing) - ? !SharedGpuContext::IsGpuCompositingEnabled() - : !!dispatcher; - - if (!provider && use_software_shared_image_provider) { - provider = - CanvasResourceProvider::CreateSharedImageProviderForSoftwareCompositor( - Size(), format, alpha_type, color_space, kShouldInitialize, - SharedGpuContext::SharedImageInterfaceProvider(), this); - } - if (!provider) { - provider = CanvasResourceProvider::CreateBitmapProvider( - Size(), format, alpha_type, color_space, kShouldInitialize, this); - } - - resource_provider_for_webgl_ = std::move(provider); - UpdateMemoryUsage(); -} - void CanvasRenderingContextHost::CreateCanvasResourceProvider2D() { CHECK(!GetResourceProviderForCanvas2D()); @@ -377,13 +290,7 @@ // If either of the other modes failed and / or it was not possible to do, we // will backup with a software SharedImage, and if that was not possible with // a Bitmap provider. - bool use_software_shared_image_provider = - base::FeatureList::IsEnabled( - kUseSharedBitmapProviderForSoftwareCompositing) - ? !SharedGpuContext::IsGpuCompositingEnabled() - : !!dispatcher; - - if (!provider && use_software_shared_image_provider) { + if (!provider && !SharedGpuContext::IsGpuCompositingEnabled()) { // In this case, we are using CPU raster and CPU compositing. Create a // CanvasResourceProvider that uses a SharedImage backed by a shared-memory // buffer that can be written by canvas raster and read by the compositor.
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 ecb1cc2..8869c4d 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
@@ -203,7 +203,6 @@ private: void CreateCanvasResourceProvider2D(); - void CreateCanvasResourceProviderWebGL(); void CreateCanvasResourceProviderWebGPU(); std::unique_ptr<CanvasResourceProvider> resource_provider_for_canvas2d_;
diff --git a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc index 9f6b2d3..84168eb 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/layout/grid/grid_break_token_data.h" #include "third_party/blink/renderer/core/layout/grid/grid_item.h" #include "third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h" +#include "third_party/blink/renderer/core/layout/layout_utils.h" #include "third_party/blink/renderer/core/layout/length_utils.h" #include "third_party/blink/renderer/core/layout/logical_box_fragment.h" #include "third_party/blink/renderer/core/layout/relative_utils.h" @@ -1938,34 +1939,6 @@ namespace { -// Returns the alignment offset for either the inline or block direction. -LayoutUnit AlignmentOffset(LayoutUnit container_size, - LayoutUnit size, - LayoutUnit margin_start, - LayoutUnit margin_end, - LayoutUnit baseline_offset, - AxisEdge axis_edge, - bool is_overflow_safe) { - LayoutUnit free_space = container_size - size - margin_start - margin_end; - // If overflow is 'safe', we have to make sure we don't overflow the - // 'start' edge (potentially cause some data loss as the overflow is - // unreachable). - if (is_overflow_safe) - free_space = free_space.ClampNegativeToZero(); - switch (axis_edge) { - case AxisEdge::kStart: - return margin_start; - case AxisEdge::kCenter: - return margin_start + (free_space / 2); - case AxisEdge::kEnd: - return margin_start + free_space; - case AxisEdge::kFirstBaseline: - case AxisEdge::kLastBaseline: - return baseline_offset; - } - NOTREACHED(); -} - void AlignmentOffsetForOutOfFlow(AxisEdge inline_axis_edge, AxisEdge block_axis_edge, LogicalSize container_size,
diff --git a/third_party/blink/renderer/core/layout/layout_utils.cc b/third_party/blink/renderer/core/layout/layout_utils.cc index 9dc118d..2c1eba9 100644 --- a/third_party/blink/renderer/core/layout/layout_utils.cc +++ b/third_party/blink/renderer/core/layout/layout_utils.cc
@@ -689,4 +689,32 @@ return true; } +LayoutUnit AlignmentOffset(LayoutUnit container_size, + LayoutUnit size, + LayoutUnit margin_start, + LayoutUnit margin_end, + LayoutUnit baseline_offset, + AxisEdge axis_edge, + bool is_overflow_safe) { + LayoutUnit free_space = container_size - size - margin_start - margin_end; + // If overflow is 'safe', we have to make sure we don't overflow the + // 'start' edge (potentially cause some data loss as the overflow is + // unreachable). + if (is_overflow_safe) { + free_space = free_space.ClampNegativeToZero(); + } + switch (axis_edge) { + case AxisEdge::kStart: + return margin_start; + case AxisEdge::kCenter: + return margin_start + (free_space / 2); + case AxisEdge::kEnd: + return margin_start + free_space; + case AxisEdge::kFirstBaseline: + case AxisEdge::kLastBaseline: + return baseline_offset; + } + NOTREACHED(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_utils.h b/third_party/blink/renderer/core/layout/layout_utils.h index cb831eb..9aee587 100644 --- a/third_party/blink/renderer/core/layout/layout_utils.h +++ b/third_party/blink/renderer/core/layout/layout_utils.h
@@ -8,6 +8,7 @@ #include <optional> #include "third_party/blink/renderer/core/layout/block_node.h" +#include "third_party/blink/renderer/core/layout/grid/grid_item.h" namespace blink { @@ -61,6 +62,15 @@ LayoutUnit* block_offset_delta, MarginStrut* end_margin_strut); +// Returns the alignment offset for either the inline or block direction. +LayoutUnit AlignmentOffset(LayoutUnit container_size, + LayoutUnit size, + LayoutUnit margin_start, + LayoutUnit margin_end, + LayoutUnit baseline_offset, + AxisEdge axis_edge, + bool is_overflow_safe); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_UTILS_H_
diff --git a/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc b/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc index 6674d4f..ee8bfed6 100644 --- a/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/masonry/masonry_layout_algorithm.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/layout/grid/grid_item.h" #include "third_party/blink/renderer/core/layout/grid/grid_track_collection.h" #include "third_party/blink/renderer/core/layout/grid/grid_track_sizing_algorithm.h" +#include "third_party/blink/renderer/core/layout/layout_utils.h" #include "third_party/blink/renderer/core/layout/logical_box_fragment.h" #include "third_party/blink/renderer/core/layout/masonry/masonry_running_positions.h" @@ -103,23 +104,6 @@ namespace { -LayoutUnit CalculateAlignmentOffset(AxisEdge alignment, LayoutUnit free_space) { - if (!free_space) { - return LayoutUnit(); - } - - switch (alignment) { - case AxisEdge::kCenter: - return free_space / 2; - case AxisEdge::kEnd: - return free_space; - case AxisEdge::kStart: - return LayoutUnit(); - default: - NOTREACHED(); - } -} - // TODO(almaher): Should we consolidate this with LayoutGridItemForMeasure()? const LayoutResult* LayoutMasonryItemForMeasure( const GridItemData& masonry_item, @@ -197,41 +181,50 @@ masonry_item, track_collection, &containing_rect); const auto& item_node = masonry_item.node; + const auto& item_style = item_node.Style(); const auto* result = item_node.Layout(space); const auto& physical_fragment = To<PhysicalBoxFragment>(result->GetPhysicalFragment()); const LogicalBoxFragment fragment(container_writing_direction, physical_fragment); - // Adjust item's position in the track based on style. - auto FreeSpace = [&]() -> LayoutUnit { - const auto free_space = - is_for_columns - ? containing_rect.size.inline_size - fragment.InlineSize() - : containing_rect.size.block_size - fragment.BlockSize(); - - // If overflow is 'safe', make sure we don't overflow the 'start' edge - // (potentially causing some data loss as the overflow is unreachable). - return masonry_item.IsOverflowSafe(grid_axis_direction) - ? free_space.ClampNegativeToZero() - : free_space; - }; - const auto offset = CalculateAlignmentOffset( - masonry_item.Alignment(grid_axis_direction), FreeSpace()); - (is_for_columns ? containing_rect.offset.inline_offset - : containing_rect.offset.block_offset) += offset; + // TODO(celestepan): Account for extra margins from sub-masonry items. + // + // Adjust item's position in the track based on style. We only want offset + // applied to the grid axis at the moment. + // + // TODO(celestepan): Update alignment logic if needed once we resolve on + // https://github.com/w3c/csswg-drafts/issues/10275. + const auto margins = ComputeMarginsFor(space, item_style, container_space); + const auto inline_alignment = + is_for_columns ? masonry_item.Alignment(kForColumns) : AxisEdge::kStart; + const auto block_alignment = + is_for_columns ? AxisEdge::kStart : masonry_item.Alignment(kForRows); + containing_rect.offset += LogicalOffset( + AlignmentOffset(containing_rect.size.inline_size, fragment.InlineSize(), + margins.inline_start, margins.inline_end, + /*baseline_offset=*/LayoutUnit(), inline_alignment, + masonry_item.IsOverflowSafe(kForColumns)), + AlignmentOffset(containing_rect.size.block_size, fragment.BlockSize(), + margins.block_start, margins.block_end, + /*baseline_offset=*/LayoutUnit(), block_alignment, + masonry_item.IsOverflowSafe(kForRows))); // Update `running_positions` of the tracks that the items spans to include - // the size of the item + the size of the gap in the stacking axis. + // the size of the item, the size of the gap in the stacking axis, and the + // margin. + // + // TODO(celestepan): Once we account for writing direction, we may have to + // ensure that we are adding the block/inline size of the item based on + // whether or not it is parallel to the direction of the masonry axis. auto new_running_position = max_position + stacking_axis_gap + - (is_for_columns ? fragment.BlockSize() : fragment.InlineSize()); + (is_for_columns ? fragment.BlockSize() + margins.BlockSum() + : fragment.InlineSize() + margins.InlineSum()); running_positions.UpdateRunningPositionsForSpan(item_span, new_running_position); - container_builder_.AddResult( - *result, containing_rect.offset, - ComputeMarginsFor(space, item_node.Style(), container_space)); + container_builder_.AddResult(*result, containing_rect.offset, margins); } if (is_for_columns) { // Remove last gap that was added, since there is no item after it.
diff --git a/third_party/blink/renderer/core/style/position_try_fallbacks.cc b/third_party/blink/renderer/core/style/position_try_fallbacks.cc index f51f69dc29..8f221b1 100644 --- a/third_party/blink/renderer/core/style/position_try_fallbacks.cc +++ b/third_party/blink/renderer/core/style/position_try_fallbacks.cc
@@ -12,6 +12,23 @@ position_area_ == other.position_area_; } +bool PositionTryFallback::Matches(const PositionTryFallback& other) const { + AtomicString name; + AtomicString other_name; + // TODO(crbug.com/417621241): Currently, TreeScope is ignored, which means + // anchored(fallback: --foo) will match --foo from any tree, regardless of + // where the @container rule or position-try-fallbacks property value + // originates from. + if (position_try_name_) { + name = position_try_name_->GetName(); + } + if (other.position_try_name_) { + other_name = other.position_try_name_->GetName(); + } + return tactic_list_ == other.tactic_list_ && name == other_name && + position_area_ == other.position_area_; +} + void PositionTryFallback::Trace(Visitor* visitor) const { visitor->Trace(position_try_name_); }
diff --git a/third_party/blink/renderer/core/style/position_try_fallbacks.h b/third_party/blink/renderer/core/style/position_try_fallbacks.h index aee1eb84..6fdd3d3 100644 --- a/third_party/blink/renderer/core/style/position_try_fallbacks.h +++ b/third_party/blink/renderer/core/style/position_try_fallbacks.h
@@ -39,6 +39,12 @@ bool operator==(const PositionTryFallback& other) const; + // Returns true if this fallback matches 'other' for anchored(fallback) + // container queries. This differs from operator== in that this method handles + // tree-scoped names per spec, and does not require the TreeScopes to be the + // same when matching @position-try names. + bool Matches(const PositionTryFallback& other) const; + bool IsNone() const { return !position_try_name_ && tactic_list_[0] == TryTactic::kNone && position_area_.IsNone();
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc index 7cbaf11a..080bb17 100644 --- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc +++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -1491,9 +1491,9 @@ auto utf16_entity = base::span(entity.data).first(entity.length); auto entity_buffer = base::as_writable_bytes(base::span(g_shared_xhtml_entity_result)); - WTF::unicode::ConversionResult conversion_result = - WTF::unicode::ConvertUTF16ToUTF8(utf16_entity, entity_buffer); - if (conversion_result.status != WTF::unicode::kConversionOK) { + unicode::ConversionResult conversion_result = + unicode::ConvertUtf16ToUtf8(utf16_entity, entity_buffer); + if (conversion_result.status != unicode::kConversionOK) { return {}; }
diff --git a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc index ebfe0279..e7fbb09 100644 --- a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc +++ b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
@@ -193,10 +193,10 @@ UNSAFE_BUFFERS(base::span(buffer, base::checked_cast<size_t>(len))); StringBuffer<UChar> string_buffer(len); - WTF::unicode::ConversionResult result = WTF::unicode::ConvertUTF8ToUTF16( + unicode::ConversionResult result = unicode::ConvertUtf8ToUtf16( base::as_bytes(source_buffer), string_buffer.Span()); - CHECK(result.status == WTF::unicode::kConversionOK || - result.status == WTF::unicode::kSourceExhausted); + CHECK(result.status == unicode::kConversionOK || + result.status == unicode::kSourceExhausted); StringBuilder& result_output = *static_cast<StringBuilder*>(context); result_output.Append(result.converted);
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc index 7f5c363..2aa99d1 100644 --- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc +++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -813,11 +813,10 @@ return Vector<uint8_t>(); Vector<uint8_t> buffer_vector(length * 3); - WTF::unicode::ConversionResult result = - WTF::unicode::ConvertLatin1ToUTF8(input.Span8(), - base::span(buffer_vector)); + unicode::ConversionResult result = unicode::ConvertLatin1ToUtf8( + input.Span8(), base::span(buffer_vector)); // (length * 3) should be sufficient for any conversion - DCHECK_NE(result.status, WTF::unicode::kTargetExhausted); + DCHECK_NE(result.status, unicode::kTargetExhausted); buffer_vector.Shrink(static_cast<wtf_size_t>(result.converted.size())); return buffer_vector; }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index d01b1e2..254cc63 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1908,6 +1908,84 @@ return nullptr; } +std::unique_ptr<CanvasResourceProvider> +WebGLRenderingContextBase::CreateCanvasResourceProvider() { + base::WeakPtr<CanvasResourceDispatcher> dispatcher = + Host()->GetOrCreateResourceDispatcher() + ? Host()->GetOrCreateResourceDispatcher()->GetWeakPtr() + : nullptr; + + std::unique_ptr<CanvasResourceProvider> provider; + const SkAlphaType alpha_type = GetAlphaType(); + const viz::SharedImageFormat format = GetSharedImageFormat(); + const gfx::ColorSpace color_space = GetColorSpace(); + // Do not initialize the CRP using Skia. The CRP can have bottom left origin + // in which case Skia Graphite won't be able to render into it, and WebGL is + // responsible for clearing the CRP when it renders anyway and we have clear + // rect tracking in the shared image system to enforce this. + constexpr auto kShouldInitialize = + CanvasResourceProvider::ShouldInitialize::kNo; + if (SharedGpuContext::IsGpuCompositingEnabled() && + Host()->LowLatencyEnabled()) { + // If LowLatency is enabled, we need a resource that is able to perform well + // in such mode. It will first try a PassThrough provider and, if that is + // not possible, it will try a SharedImage with the appropriate flags. + bool using_swapchain = UsingSwapChain(); + bool using_webgl_image_chromium = + SharedGpuContext::MaySupportImageChromium() && + (RuntimeEnabledFeatures::WebGLImageChromiumEnabled() || + base::FeatureList::IsEnabled(features::kLowLatencyWebGLImageChromium)); + if (using_swapchain || using_webgl_image_chromium) { + // If either SwapChain is enabled or WebGLImage mode is enabled, we can + // try a passthrough provider. + DCHECK(Host()->LowLatencyEnabled()); + provider = CanvasResourceProvider::CreatePassThroughProvider( + Host()->Size(), format, alpha_type, color_space, + SharedGpuContext::ContextProviderWrapper(), Host()); + } + if (!provider) { + // If PassThrough failed, try a SharedImage with usage display enabled. + gpu::SharedImageUsageSet shared_image_usage_flags = + gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; + provider = CanvasResourceProvider::CreateSharedImageProvider( + Host()->Size(), format, alpha_type, color_space, kShouldInitialize, + SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU, + shared_image_usage_flags, Host()); + } + } else if (SharedGpuContext::IsGpuCompositingEnabled()) { + // If there is no LowLatency mode, and GPU is enabled, will try a GPU + // SharedImage that should support Usage Display and probably Usage Scanout + // if WebGLImageChromium is enabled. + gpu::SharedImageUsageSet shared_image_usage_flags = + gpu::SHARED_IMAGE_USAGE_DISPLAY_READ; + if (SharedGpuContext::MaySupportImageChromium() && + RuntimeEnabledFeatures::WebGLImageChromiumEnabled()) { + shared_image_usage_flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; + } + provider = CanvasResourceProvider::CreateSharedImageProvider( + Host()->Size(), format, alpha_type, color_space, kShouldInitialize, + SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU, + shared_image_usage_flags, Host()); + } + + // If either of the other modes failed and / or it was not possible to do, we + // will backup with a software SharedImage, and if that was not possible with + // a Bitmap provider. + if (!provider && !SharedGpuContext::IsGpuCompositingEnabled()) { + provider = + CanvasResourceProvider::CreateSharedImageProviderForSoftwareCompositor( + Host()->Size(), format, alpha_type, color_space, kShouldInitialize, + SharedGpuContext::SharedImageInterfaceProvider(), Host()); + } + if (!provider) { + provider = CanvasResourceProvider::CreateBitmapProvider( + Host()->Size(), format, alpha_type, color_space, kShouldInitialize, + Host()); + } + + return provider; +} + CanvasResourceProvider* WebGLRenderingContextBase::PaintRenderingResultsToCanvas( SourceDrawingBuffer source_buffer, @@ -9068,6 +9146,10 @@ } } + if (!Host()) { + return buffer_count; + } + auto* provider = Host()->GetResourceProviderForWebGL(); if (provider) { buffer_count++;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index 27c0eaf..c182f60 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -714,6 +714,8 @@ bool IsAccelerated() const override; bool UsingSwapChain() const override; void PageVisibilityChanged() override; + std::unique_ptr<CanvasResourceProvider> CreateCanvasResourceProvider() + override; scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot( SourceDrawingBuffer source_buffer, FlushReason reason) override;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc index d8fa1d8..e7903b7 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
@@ -3493,8 +3493,13 @@ int WebGLRenderingContextWebGPUBase::AllocatedBufferCountPerPixel() { // Front and back buffers. + // TODO(413078308): Add support configuring MSAA and depth-stencil. int buffer_count = 2; + if (!Host()) { + return buffer_count; + } + auto* provider = Host()->GetResourceProviderForWebGL(); if (provider) { buffer_count++; @@ -3507,7 +3512,6 @@ } } - // TODO(413078308): Add support configuring MSAA and depth-stencil. return buffer_count; }
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index a4de956b..b3f4416 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -173,7 +173,7 @@ resource_provider_(std::move(resource_provider)), roughness_reporter_(std::make_unique<cc::VideoPlaybackRoughnessReporter>( std::move(roughness_reporting_callback))), - frame_trackers_(false, nullptr) { + frame_trackers_(false) { frame_sorter_.AddObserver(&frame_trackers_); DETACH_FROM_THREAD(thread_checker_); }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc index acc48c8..c72713e4 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -2112,7 +2112,8 @@ // The timestamp is set later in EncodeOneFrame(). auto frame = media::VideoFrame::WrapExternalData( media::PIXEL_FORMAT_I420, input_frame_coded_size_, - gfx::Rect(input_visible_size_), input_visible_size_, mapping, + gfx::Rect(input_visible_size_), input_visible_size_, + static_cast<uint8_t*>(mapping.memory()), mapping.size(), base::TimeDelta()); if (!frame) { NotifyErrorStatus({media::EncoderStatus::Codes::kEncoderFailedEncode,
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc index 50ac61d6..a49c2bc 100644 --- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc +++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -48,6 +48,7 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "ui/gfx/gpu_memory_buffer.h" #if BUILDFLAG(IS_MAC) #include "media/base/mac/video_frame_mac.h" @@ -64,17 +65,14 @@ using VideoFrameBufferHandleType = media::mojom::blink::VideoBufferHandle::Tag; // A collection of all types of handles that we use to reference a camera buffer -// backed with GpuMemoryBuffer. +// backed with GpuMemoryBufferHandle. struct GpuMemoryBufferResources { explicit GpuMemoryBufferResources(gfx::GpuMemoryBufferHandle handle) : gpu_memory_buffer_handle(std::move(handle)) {} // Stores the GpuMemoryBufferHandle when a new buffer is first registered. - // |gpu_memory_buffer_handle| is converted to |gpu_memory_buffer| below when + // |gpu_memory_buffer_handle| is converted to |shared_image| below when // the camera frame is ready for the first time. gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle; - // The GpuMemoryBuffer backing the camera frame. - std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; - // The SharedImage created from |gpu_memory_buffer|. scoped_refptr<gpu::ClientSharedImage> shared_image; // The release sync token for |shared_images|. gpu::SyncToken release_sync_token; @@ -142,14 +140,6 @@ return gmb_resources_->gpu_memory_buffer_handle.Clone(); } - void SetGpuMemoryBuffer( - std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer) { - gmb_resources_->gpu_memory_buffer = std::move(gpu_memory_buffer); - } - gfx::GpuMemoryBuffer* GetGpuMemoryBuffer() { - return gmb_resources_->gpu_memory_buffer.get(); - } - static void MailboxHolderReleased( scoped_refptr<BufferContext> buffer_context, const gpu::SyncToken& release_sync_token, @@ -161,8 +151,8 @@ release_sync_token, std::move(gpu_memory_buffer))); return; } + CHECK(!gpu_memory_buffer); buffer_context->gmb_resources_->release_sync_token = release_sync_token; - // Free |gpu_memory_buffer|. } static void DestroyTextureOnMediaThread( @@ -453,9 +443,9 @@ gmb_handle.type == gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE; #endif - // Convert the GpuMemoryBuffer to a VideoFrame by posting a task on media - // thread. This is because SharedImageInterface is only accessible on - // media thread. + // Convert the GpuMemoryBufferHandle to a VideoFrame by posting a task on + // media thread. This is because SharedImageInterface is only accessible + // on media thread. media_task_runner_->PostTask( FROM_HERE, base::BindOnce( @@ -532,7 +522,7 @@ } #endif - // Create GPU texture and bind GpuMemoryBuffer to the texture. + // Create GPU texture and bind GpuMemoryBufferHandle to the texture. auto* sii = video_frame_init_data.buffer_context->gpu_factories() ->SharedImageInterface(); if (!sii) { @@ -607,7 +597,7 @@ video_frame_init_data.ready_buffer->info->timestamp); if (!frame) { - LOG(ERROR) << "Can't wrap GpuMemoryBuffer as VideoFrame"; + LOG(ERROR) << "Can't wrap SharedImage as VideoFrame"; return false; } frame->set_metadata(video_frame_init_data.ready_buffer->info->metadata); @@ -956,7 +946,7 @@ // Process the `buffer` to convert it into a media::VideoFrame directly or via // creating GpuMemoryBuffers. if (!ProcessBuffer(std::move(buffer))) { - // Error during initialization of the VideoFrame or GpuMemoryBuffer. + // Error during initialization of the VideoFrame or SharedImage. OnFrameDropped(media::VideoCaptureFrameDropReason:: kVideoCaptureImplFailedToWrapDataAsMediaVideoFrame); GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, @@ -973,7 +963,7 @@ scoped_refptr<media::VideoFrame> video_frame = video_frame_init_data.frame; // If we don't have a media::VideoFrame here then we've failed to convert the - // gfx::GpuMemoryBuffer, dropping frame. + // gfx::GpuMemoryBufferHandle, dropping frame. if (!video_frame) { OnFrameDropped(media::VideoCaptureFrameDropReason:: kVideoCaptureImplFailedToWrapDataAsMediaVideoFrame); @@ -1012,9 +1002,9 @@ const auto& cb_iter = client_buffers_.find(buffer_id); if (cb_iter != client_buffers_.end()) { - // If the BufferContext is non-null, the GpuMemoryBuffer-backed frames can - // have more than one reference (held by MailboxHolderReleased). Otherwise, - // only one reference should be held. + // If the BufferContext is non-null, the GpuMemoryBufferHandle-backed frames + // can have more than one reference (held by MailboxHolderReleased). + // Otherwise, only one reference should be held. DCHECK(!cb_iter->second.get() || cb_iter->second->buffer_type() == VideoFrameBufferHandleType::kGpuMemoryBufferHandle || @@ -1062,7 +1052,7 @@ BufferContext* const buffer_raw_ptr = buffer_context.get(); buffer_context = nullptr; // For non-GMB case, there should be only one reference, from - // |client_buffers_|. This DCHECK is invalid for GpuMemoryBuffer backed + // |client_buffers_|. This DCHECK is invalid for GpuMemoryBufferHandle-backed // frames, because MailboxHolderReleased may hold on to a reference to // |buffer_context|. if (buffer_raw_ptr->buffer_type() !=
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc index 47a691b1..5baa889 100644 --- a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc +++ b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.cc
@@ -445,15 +445,15 @@ bool seen_non_ascii = false; bool seen_non_latin1 = false; - unsigned utf16_length = unicode::CalculateStringLengthFromUTF8( + unsigned utf16_length = blink::unicode::CalculateStringLengthFromUtf8( characters_span, seen_non_ascii, seen_non_latin1); if (!seen_non_ascii) { return Add(characters_span.data(), utf16_length); } auto utf16_buf = base::HeapArray<UChar>::Uninit(utf16_length); - if (unicode::ConvertUTF8ToUTF16(characters_span, utf16_buf).status != - unicode::kConversionOK) { + if (blink::unicode::ConvertUtf8ToUtf16(characters_span, utf16_buf).status != + blink::unicode::kConversionOK) { NOTREACHED(); }
diff --git a/third_party/blink/renderer/platform/wtf/text/string_view.cc b/third_party/blink/renderer/platform/wtf/text/string_view.cc index 61a4083..47a54b2 100644 --- a/third_party/blink/renderer/platform/wtf/text/string_view.cc +++ b/third_party/blink/renderer/platform/wtf/text/string_view.cc
@@ -65,6 +65,8 @@ } std::string StringView::Utf8(Utf8ConversionMode mode) const { + using blink::unicode::ConversionResult; + using blink::unicode::ConversionStatus; unsigned length = this->length(); if (!length) @@ -86,10 +88,10 @@ size_t buffer_written = 0; if (Is8Bit()) { - unicode::ConversionResult result = unicode::ConvertLatin1ToUTF8( + ConversionResult result = blink::unicode::ConvertLatin1ToUtf8( Span8(), base::as_writable_byte_span(buffer_vector)); // (length * 3) should be sufficient for any conversion - DCHECK_NE(result.status, unicode::kTargetExhausted); + DCHECK_NE(result.status, ConversionStatus::kTargetExhausted); buffer_written = result.converted.size(); } else { base::span<const UChar> characters = Span16(); @@ -98,14 +100,14 @@ if (mode == Utf8ConversionMode::kStrictReplacingErrors) { while (!characters.empty()) { // Use strict conversion to detect unpaired surrogates. - unicode::ConversionResult result = - unicode::ConvertUTF16ToUTF8(characters, buffer, true); - DCHECK_NE(result.status, unicode::kTargetExhausted); + ConversionResult result = + blink::unicode::ConvertUtf16ToUtf8(characters, buffer, true); + DCHECK_NE(result.status, ConversionStatus::kTargetExhausted); buffer = buffer.subspan(result.converted.size()); // Conversion fails when there is an unpaired surrogate. Put // replacement character (U+FFFD) instead of the unpaired // surrogate. - if (result.status != unicode::kConversionOK) { + if (result.status != ConversionStatus::kConversionOK) { DCHECK_LE(0xD800, characters[result.consumed]); DCHECK_LE(characters[result.consumed], 0xDFFF); // There should be room left, since one UChar hasn't been @@ -122,19 +124,19 @@ } else { const bool strict = mode == Utf8ConversionMode::kStrict; - unicode::ConversionResult result = - unicode::ConvertUTF16ToUTF8(characters, buffer, strict); + ConversionResult result = + blink::unicode::ConvertUtf16ToUtf8(characters, buffer, strict); // (length * 3) should be sufficient for any conversion - DCHECK_NE(result.status, unicode::kTargetExhausted); + DCHECK_NE(result.status, ConversionStatus::kTargetExhausted); // Only produced from strict conversion. - if (result.status == unicode::kSourceIllegal) { + if (result.status == ConversionStatus::kSourceIllegal) { DCHECK(strict); return std::string(); } // Check for an unconverted high surrogate. - if (result.status == unicode::kSourceExhausted) { + if (result.status == ConversionStatus::kSourceExhausted) { if (strict) return std::string(); buffer = buffer.subspan(result.converted.size());
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc index ec6de128..3a79a37c 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc +++ b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
@@ -451,7 +451,7 @@ // ICU decodes it as U+E5E5. if (encoding_.GetName() != "GBK") { if (EqualIgnoringASCIICase(encoding_.GetName(), "gb18030")) - result_string.Replace(0xE5E5, kIdeographicSpaceCharacter); + result_string.Replace(0xE5E5, uchar::kIdeographicSpace); // Make GBK compliant to the encoding spec and align with GB18030 result_string.Replace(0x01F9, 0xE7C8); // FIXME: Once https://www.w3.org/Bugs/Public/show_bug.cgi?id=28740#c3
diff --git a/third_party/blink/renderer/platform/wtf/text/utf8.cc b/third_party/blink/renderer/platform/wtf/text/utf8.cc index 616e8b9..dd49bbd7 100644 --- a/third_party/blink/renderer/platform/wtf/text/utf8.cc +++ b/third_party/blink/renderer/platform/wtf/text/utf8.cc
@@ -34,12 +34,11 @@ #include "third_party/blink/renderer/platform/wtf/text/character_names.h" #include "third_party/blink/renderer/platform/wtf/text/string_hasher.h" -namespace WTF { -namespace unicode { +namespace blink::unicode { namespace { -inline size_t InlineUTF8SequenceLengthNonASCII(uint8_t b0) { +inline size_t InlineUtf8SequenceLengthNonAscii(uint8_t b0) { if ((b0 & 0xC0) != 0xC0) return 0; if ((b0 & 0xE0) == 0xC0) @@ -51,8 +50,8 @@ return 0; } -inline size_t InlineUTF8SequenceLength(uint8_t b0) { - return IsASCII(b0) ? 1 : InlineUTF8SequenceLengthNonASCII(b0); +inline size_t InlineUtf8SequenceLength(uint8_t b0) { + return IsASCII(b0) ? 1 : InlineUtf8SequenceLengthNonAscii(b0); } // Once the bits are split out into bytes of UTF-8, this is a mask OR-ed @@ -63,7 +62,7 @@ static constexpr std::array<uint8_t, 7> kFirstByteMark = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; -ConversionStatus ConvertLatin1ToUTF8Internal(base::span<const LChar>& source, +ConversionStatus ConvertLatin1ToUtf8Internal(base::span<const LChar>& source, base::span<uint8_t>& target) { ConversionStatus status = kConversionOK; size_t source_cursor = 0; @@ -109,7 +108,7 @@ return status; } -ConversionStatus ConvertUTF16ToUTF8Internal(base::span<const UChar>& source, +ConversionStatus ConvertUtf16ToUtf8Internal(base::span<const UChar>& source, base::span<uint8_t>& target, bool strict) { ConversionStatus status = kConversionOK; @@ -204,7 +203,7 @@ // This must be called with the length pre-determined by the first byte. // If presented with a length > 4, this returns false. The Unicode // definition of UTF-8 goes up to 4-byte sequences. -bool IsLegalUTF8(const base::span<const uint8_t> source) { +bool IsLegalUtf8(const base::span<const uint8_t> source) { uint8_t a; size_t src_cursor = source.size(); switch (source.size()) { @@ -263,7 +262,7 @@ // Magic values subtracted from a buffer value during UTF8 conversion. // This table contains as many values as there might be trailing bytes // in a UTF-8 sequence. -static constexpr std::array<UChar32, 6> kOffsetsFromUTF8 = { +static constexpr std::array<UChar32, 6> kOffsetsFromUtf8 = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, @@ -271,7 +270,7 @@ static_cast<UChar32>(0xFA082080UL), static_cast<UChar32>(0x82082080UL)}; -inline UChar32 ReadUTF8Sequence(base::span<const uint8_t> source, +inline UChar32 ReadUtf8Sequence(base::span<const uint8_t> source, size_t length) { UChar32 character = 0; size_t sequence_cursor = 0; @@ -301,10 +300,10 @@ character += source[sequence_cursor++]; } - return character - kOffsetsFromUTF8[length - 1]; + return character - kOffsetsFromUtf8[length - 1]; } -ConversionStatus ConvertUTF8ToUTF16Internal(base::span<const uint8_t>& source, +ConversionStatus ConvertUtf8ToUtf16Internal(base::span<const uint8_t>& source, base::span<UChar>& target, bool strict) { ConversionStatus status = kConversionOK; @@ -312,19 +311,19 @@ size_t target_end = target.size(); while (!source.empty()) { - size_t utf8_sequence_length = InlineUTF8SequenceLength(source[0]); + size_t utf8_sequence_length = InlineUtf8SequenceLength(source[0]); if (source.size() < utf8_sequence_length) { status = kSourceExhausted; break; } // Do this check whether lenient or strict - if (!IsLegalUTF8(source.first(utf8_sequence_length))) { + if (!IsLegalUtf8(source.first(utf8_sequence_length))) { status = kSourceIllegal; break; } auto original_source = source; - UChar32 character = ReadUTF8Sequence(source, utf8_sequence_length); + UChar32 character = ReadUtf8Sequence(source, utf8_sequence_length); source = source.subspan(utf8_sequence_length); if (target_cursor >= target_end) { @@ -368,11 +367,11 @@ } // namespace -ConversionResult<uint8_t> ConvertLatin1ToUTF8(base::span<const LChar> source, +ConversionResult<uint8_t> ConvertLatin1ToUtf8(base::span<const LChar> source, base::span<uint8_t> target) { auto original_source = source; auto original_target = target; - auto status = ConvertLatin1ToUTF8Internal(source, target); + auto status = ConvertLatin1ToUtf8Internal(source, target); return { original_target.first(original_target.size() - target.size()), original_source.size() - source.size(), @@ -380,12 +379,12 @@ }; } -ConversionResult<uint8_t> ConvertUTF16ToUTF8(base::span<const UChar> source, +ConversionResult<uint8_t> ConvertUtf16ToUtf8(base::span<const UChar> source, base::span<uint8_t> target, bool strict) { auto original_source = source; auto original_target = target; - auto status = ConvertUTF16ToUTF8Internal(source, target, strict); + auto status = ConvertUtf16ToUtf8Internal(source, target, strict); return { original_target.first(original_target.size() - target.size()), original_source.size() - source.size(), @@ -393,12 +392,12 @@ }; } -ConversionResult<UChar> ConvertUTF8ToUTF16(base::span<const uint8_t> source, +ConversionResult<UChar> ConvertUtf8ToUtf16(base::span<const uint8_t> source, base::span<UChar> target, bool strict) { auto original_source = source; auto original_target = target; - auto status = ConvertUTF8ToUTF16Internal(source, target, strict); + auto status = ConvertUtf8ToUtf16Internal(source, target, strict); return { original_target.first(original_target.size() - target.size()), original_source.size() - source.size(), @@ -406,7 +405,7 @@ }; } -unsigned CalculateStringLengthFromUTF8(base::span<const uint8_t> data, +unsigned CalculateStringLengthFromUtf8(base::span<const uint8_t> data, bool& seen_non_ascii, bool& seen_non_latin1) { seen_non_ascii = false; @@ -429,18 +428,18 @@ seen_non_ascii = true; size_t utf8_sequence_length = - InlineUTF8SequenceLengthNonASCII(data[data_cursor]); + InlineUtf8SequenceLengthNonAscii(data[data_cursor]); if (data_end - data_cursor < utf8_sequence_length) { return 0; } - if (!IsLegalUTF8(data.subspan(data_cursor, utf8_sequence_length))) { + if (!IsLegalUtf8(data.subspan(data_cursor, utf8_sequence_length))) { return 0; } UChar32 character = - ReadUTF8Sequence(data.subspan(data_cursor), utf8_sequence_length); + ReadUtf8Sequence(data.subspan(data_cursor), utf8_sequence_length); DCHECK(!IsASCII(character)); data_cursor += utf8_sequence_length; @@ -464,5 +463,4 @@ return utf16_length; } -} // namespace unicode -} // namespace WTF +} // namespace blink::unicode
diff --git a/third_party/blink/renderer/platform/wtf/text/utf8.h b/third_party/blink/renderer/platform/wtf/text/utf8.h index 666d518..717b4566 100644 --- a/third_party/blink/renderer/platform/wtf/text/utf8.h +++ b/third_party/blink/renderer/platform/wtf/text/utf8.h
@@ -30,8 +30,7 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_uchar.h" #include "third_party/blink/renderer/platform/wtf/wtf_export.h" -namespace WTF { -namespace unicode { +namespace blink::unicode { typedef enum { kConversionOK, // conversion successful @@ -66,27 +65,26 @@ // 0x10FFFF; in UTF-8, the 4-byte form is similarly unable to encode codepoints // higher than 0x10FFFF. -WTF_EXPORT ConversionResult<UChar> ConvertUTF8ToUTF16( +WTF_EXPORT ConversionResult<UChar> ConvertUtf8ToUtf16( base::span<const uint8_t> source, base::span<UChar> target, bool strict = true); -WTF_EXPORT ConversionResult<uint8_t> ConvertLatin1ToUTF8( +WTF_EXPORT ConversionResult<uint8_t> ConvertLatin1ToUtf8( base::span<const LChar> source, base::span<uint8_t> target); -WTF_EXPORT ConversionResult<uint8_t> ConvertUTF16ToUTF8( +WTF_EXPORT ConversionResult<uint8_t> ConvertUtf16ToUtf8( base::span<const UChar> source, base::span<uint8_t> target, bool strict = true); // Returns the number of UTF-16 code points. -WTF_EXPORT unsigned CalculateStringLengthFromUTF8( +WTF_EXPORT unsigned CalculateStringLengthFromUtf8( base::span<const uint8_t> data, bool& seen_non_ascii, bool& seen_non_latin1); -} // namespace unicode -} // namespace WTF +} // namespace blink::unicode #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_UTF8_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.cc b/third_party/blink/renderer/platform/wtf/text/wtf_string.cc index 445e620..8f0135d2 100644 --- a/third_party/blink/renderer/platform/wtf/text/wtf_string.cc +++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.cc
@@ -474,9 +474,9 @@ Vector<UChar, 1024> buffer(length); - unicode::ConversionResult result = - unicode::ConvertUTF8ToUTF16(bytes, base::span(buffer)); - if (result.status != unicode::kConversionOK) { + blink::unicode::ConversionResult result = + blink::unicode::ConvertUtf8ToUtf16(bytes, base::span(buffer)); + if (result.status != blink::unicode::kConversionOK) { return String(); }
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index 6037da6..ebb0515 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -1897,3 +1897,9 @@ crbug.com/41442253 [ Fuchsia ] external/wpt/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html [ Skip ] crbug.com/41442253 [ Mac ] external/wpt/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html [ Skip ] crbug.com/41442253 [ iOS18-simulator ] external/wpt/clipboard-apis/async-navigator-clipboard-change-event.tentative.https.html [ Skip ] + +# These tests are run exclusively in the prefetch-proxy VirtualTestSuite. +virtual/prefetch/external/wpt/speculation-rules/prefetch/anonymous-client.https.html [ Skip ] +virtual/prefetch/external/wpt/speculation-rules/prefetch/cross-origin-cookies-anonymous-client-ip-duplicate.https.html [ Skip ] +virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/anonymous-client.https.html [ Skip ] +virtual/prefetch-sw/external/wpt/speculation-rules/prefetch/cross-origin-cookies-anonymous-client-ip-duplicate.https.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b9d4474..b4a909fb 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1124,17 +1124,12 @@ crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-005.html [ Failure ] crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-006.html [ Failure ] crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-007.html [ Failure ] -# Masonry tests failing because of missing margins during item placement -crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/gap/masonry-gap-001.html [ Failure ] -crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/gap/masonry-gap-002.html [ Failure ] -crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-003.html [ Failure ] -crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001.html [ Failure ] -crbug.com/1076027 wpt_internal/css/css-masonry/column-explicit-placement-001.html [ Failure ] -crbug.com/1076027 wpt_internal/css/css-masonry/row-explicit-placement-002.html [ Failure ] -crbug.com/1076027 wpt_internal/css/css-masonry/row-explicit-placement-006.html [ Failure ] # Masonry sizing test failures crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/intrinsic-sizing/* [ Crash Failure Skip ] crbug.com/1076027 wpt_internal/css/css-masonry/column-explicit-placement-002.html [ Failure ] +crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001.html [ Failure ] +crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/gap/masonry-gap-002.html [ Failure ] +crbug.com/1076027 wpt_internal/css/css-masonry/row-explicit-placement-006.html [ Failure ] # Masonry named line failures crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/grid-placement/masonry-grid-placement-named-lines-001.html [ Crash Failure ] crbug.com/1076027 external/wpt/css/css-grid/masonry/tentative/grid-placement/masonry-grid-placement-named-lines-002.html [ Crash Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 42ebc7b8..52edcdb 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2613,6 +2613,32 @@ "almaher@microsoft.com" ] }, + "These tests involve requiring a prefetch proxy, but since WPT origins are ", + "not allowed to use the proxy in Chromium, we pass an argument telling ", + "Chromium to bypass the proxy and pretend it was used instead. See also", + "external/wpt/speculation-rules/prefetch/resources/utils.sub.js.", + "These tests are skipped in other configurations via text expectations.", + { + "prefix": "prefetch-proxy", + "owners": [ + "domenic@chromium.org", + "nhiroki@chromium.org" + ], + "platforms": [ + "Linux", + "Mac", + "Win" + ], + "bases": [ + "external/wpt/speculation-rules/prefetch/anonymous-client.https.html", + "external/wpt/speculation-rules/prefetch/cross-origin-cookies-anonymous-client-ip-duplicate.https.html" + ], + "exclusive_tests": "ALL", + "args": [ + "--bypass-prefetch-proxy-for-host=not-web-platform.test" + ], + "expires": "never" + }, "These tests require the experimental speculative prefetch feature, and", "requires extra switches to enable content implementation of speculation", "rules prefetch.", @@ -2633,8 +2659,7 @@ ], "exclusive_tests": "ALL", "args": [ - "--disable-features=PrefetchServiceWorker", - "--bypass-prefetch-proxy-for-host=not-web-platform.test" + "--disable-features=PrefetchServiceWorker" ], "expires": "Oct 1, 2025" }, @@ -2654,8 +2679,7 @@ ], "exclusive_tests": "ALL", "args": [ - "--enable-features=Prerender2FallbackPrefetchSpecRules,PrefetchServiceWorker", - "--bypass-prefetch-proxy-for-host=not-web-platform.test" + "--enable-features=Prerender2FallbackPrefetchSpecRules,PrefetchServiceWorker" ], "expires": "Oct 1, 2025" }, @@ -2734,7 +2758,6 @@ "args": [ "--enable-features=Prerender2FallbackPrefetchSpecRules", "--disable-features=PrefetchServiceWorker", - "--bypass-prefetch-proxy-for-host=not-web-platform.test", "--disable-threaded-compositing", "--disable-threaded-animation" ],
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js index 6231213..9c7ef62 100644 --- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js +++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
@@ -1815,6 +1815,142 @@ } }, { + 'name': 'quantized gemm with bias', + 'graph': { + 'inputs': { + 'inputA': { + 'data': [ + 49.1112174987793, 11.907459259033203, 11.115795135498047, + 21.115795135498047, 70.7490005493164, 31.115795135498047 + ], + 'descriptor': {shape: [2, 3], dataType: 'float32'}, + 'constant': false + }, + 'inputAScale': { + 'data': [0.003921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputAZeroPoint': { + 'data': [-128], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'inputB': { + 'data': [ + 21, 24, 8, 15, 6, 7 + ], + 'descriptor': {shape: [3, 2], dataType: 'int8'}, + 'constant': true + }, + 'inputBScale': { + 'data': [0.023458752938762234], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputBZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + 'inputC': { + 'data': [ + 8, 15 + ], + 'descriptor': {shape: [2], dataType: 'int32'}, + 'constant': true + }, + 'inputCScale': { + 'data': [0.000091995115004270], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'inputCZeroPoint': { + 'data': [0], + 'descriptor': {shape: [1], dataType: 'int32'}, + 'constant': true + }, + 'outputScale': { + 'data': [0.3921568859368563], + 'descriptor': {shape: [1], dataType: 'float32'}, + 'constant': true + }, + 'outputZeroPoint': { + 'data': [16], + 'descriptor': {shape: [1], dataType: 'int8'}, + 'constant': true + }, + }, + 'operators': [ + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'inputA'}, + {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'} + ], + 'outputs': 'quantizedInputA' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedInputA'}, + {'scale': 'inputAScale', 'zeroPoint': 'inputAZeroPoint'} + ], + 'outputs': 'dequantizedInputA' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'inputB'}, + {'scale': 'inputBScale', 'zeroPoint': 'inputBZeroPoint'} + ], + 'outputs': 'dequantizedInputB' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'inputC'}, + {'scale': 'inputCScale', 'zeroPoint': 'inputCZeroPoint'} + ], + 'outputs': 'dequantizedInputC' + }, + { + 'name': 'gemm', + 'arguments': [ + {'a': 'dequantizedInputA'}, {'b': 'dequantizedInputB'}, + {'options': {'c': 'dequantizedInputC'}} + ], + 'outputs': 'gemmOutput' + }, + { + 'name': 'quantizeLinear', + 'arguments': [ + {'input': 'gemmOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'quantizedGemmOutput' + }, + { + 'name': 'dequantizeLinear', + 'arguments': [ + {'input': 'quantizedGemmOutput'}, + {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'} + ], + 'outputs': 'output' + } + ], + 'expectedOutputs': { + 'output': { + 'data': [ + 0.7843137979507446, 1.1764707565307617, + 0.7843137979507446, 1.1764707565307617, + ], + 'descriptor': {shape: [2, 2], dataType: 'float32'} + } + } + } + }, + { 'name': 'quantized transpose', 'graph': { 'inputs': {
diff --git a/third_party/blink/web_tests/virtual/prefetch-proxy/DIR_METADATA b/third_party/blink/web_tests/virtual/prefetch-proxy/DIR_METADATA new file mode 100644 index 0000000..8138849 --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-proxy/DIR_METADATA
@@ -0,0 +1,3 @@ +buganizer_public: { + component_id: 1456735 +}
diff --git a/third_party/blink/web_tests/virtual/prefetch-proxy/README.md b/third_party/blink/web_tests/virtual/prefetch-proxy/README.md new file mode 100644 index 0000000..38421ce --- /dev/null +++ b/third_party/blink/web_tests/virtual/prefetch-proxy/README.md
@@ -0,0 +1,2 @@ +This test suite is for tests of speculation rules prefetch with the +`requires: ["anonymous-client-ip-when-crossorigin"]` feature.
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/anchored/anchored-fallback-name.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/anchored/anchored-fallback-name.html new file mode 100644 index 0000000..3bd1fac --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/anchored/anchored-fallback-name.html
@@ -0,0 +1,58 @@ +<!DOCTYPE html> +<title>CSS Conditional Test: @container anchored(fallback) matching <custom-ident></title> +<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#container-rule"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/8171"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/css-conditional/container-queries/support/cq-testcommon.js"></script> +<style> + #anchor { + anchor-name: --a; + width: 100px; + height: 100px; + } + @position-try --foo { + position-area: bottom; + } + @position-try --bar { + position-area: top; + } + .anchored { + position: absolute; + position-anchor: --a; + position-area: top; + width: 100px; + /* Too tall to fit over the anchor to trigger fallback */ + height: 100px; + container-type: anchored; + } + #a1 { + position-try-fallbacks: --foo; + } + #t1 { + @container anchored(fallback: --foo) { --pass: yes; } + } + #a2 { + position-try-fallbacks: --bar, --bar flip-block; + } + #t2 { + @container anchored(fallback: --bar flip-block) { --pass: yes; } + @container anchored(fallback: --bar) { --pass: no; } + } +</style> +<div id="anchor"></div> +<div id="a1" class="anchored"> + <div id="t1"></div> +</div> +<div id="a2" class="anchored"> + <div id="t2"></div> +</div> +<script> + test(() => { + assert_equals(getComputedStyle(t1).getPropertyValue("--pass"), "yes"); + }, "@container anchored(fallback) matching name"); + + test(() => { + assert_equals(getComputedStyle(t2).getPropertyValue("--pass"), "yes"); + }, "@container anchored(fallback) matching name with tactics, but not name"); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001-ref.html index 34493f5..85106196 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001-ref.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001-ref.html
@@ -2,6 +2,7 @@ <html> <link rel="help" href="https://drafts.csswg.org/css-grid-3"> <link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> <style> .grid { display: grid; @@ -26,6 +27,13 @@ .third-track { background: lightgreen; grid-column-start: 3; + margin-top: 40px; + margin-right: 40px; +} + +.fourth-track { + background: purple; + grid-column-start: 4; } </style> <body> @@ -34,6 +42,7 @@ <div class="first-track">This is some text</div> <div class="second-track">Some larger words in this sentence</div> <div class="third-track">The cat cannot be separated from milk</div> + <div class="fourth-track">The cat cannot be separated from milk</div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001.html index 5cc985a6b..0b4c746 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/column-explicit-placement-001.html
@@ -3,6 +3,7 @@ <link rel="help" href="https://drafts.csswg.org/css-grid-3"> <link rel="match" href="column-explicit-placement-001-ref.html"> <link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="author" title="Celeste Pan" href="mailto:celestepan@microsoft.com"> <style> .masonry { display: masonry; @@ -28,6 +29,13 @@ .third-track { background: lightgreen; grid-column-start: 3; + margin-top: 40px; + margin-right: 40px; +} + +.fourth-track { + background: purple; + grid-column-start: 4; } </style> <body> @@ -36,6 +44,7 @@ <div class="first-track">This is some text</div> <div class="second-track">Some larger words in this sentence</div> <div class="third-track">The cat cannot be separated from milk</div> + <div class="fourth-track">The cat cannot be separated from milk</div> </div> </body> </html>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001-ref.html index f14a0ac..fa340f4 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001-ref.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001-ref.html
@@ -5,7 +5,7 @@ <style> .grid { display: grid; - grid-template-rows: 100px 100px 100px; + grid-template-rows: 100px auto 100px; align-items: start; background: gray; width: 300px; @@ -17,6 +17,7 @@ flex-direction: row; overflow: visible; flex-wrap: nowrap; + align-items: flex-start; } .square-100x100 { @@ -25,31 +26,31 @@ } </style> <body> - <p>Test that masonry items with auto placement are correctly positioned when the grid-axis is the block axis.</p> + <p>Test that masonry items with auto placement are correctly positioned when the grid-axis is the block axis. Ensure that margin affects placement.</p> <div class="grid"> <div class="flex"> - <div class="square-100x100" style="background: lightskyblue;"> + <div class="square-100x100" style="background: lightskyblue; margin-right: 100px;"> Number 1 </div> - <div class="square-100x100" style="background: lightpink;"> - Number 4 - </div> - <div style="background: brown; width: 100px; height: 200px;"> + <div style="background: brown; width: 100px; height: 210px;"> Number 6 </div> </div> <div class="flex"> - <div class="square-100x100" style="background: lightcoral;"> + <div class="square-100x100" style="background: lightcoral; margin-bottom: 10px;"> Number 2 </div> - <div class="square-100x100" style="background: lightpink;"> - Number 5 + <div class="square-100x100" style="background: lightpink; margin-bottom: 10px;"> + Number 4 </div> </div> <div class="flex"> - <div class="square-100x100" style="background: lightgreen;"> + <div class="square-100x100" style="background: lightgreen; margin-right: 40px;"> Number 3 </div> + <div class="square-100x100" style="background: lightpink; margin-left: -20px;"> + Number 5 + </div> </div> </div> </body>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001.html index 47eec2e2..267bb56 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-auto-placement-001.html
@@ -17,17 +17,17 @@ .first-track { background: lightskyblue; - grid-column-start: 1; + grid-row-start: 1; } .second-track { background: lightcoral; - grid-column-start: 2; + grid-row-start: 2; } .third-track { background: lightgreen; - grid-column-start: 3; + grid-row-start: 3; } .square-100x100 { @@ -36,21 +36,21 @@ } </style> <body> - <p>Test that masonry items with auto placement are correctly positioned when the grid-axis is the block axis.</p> + <p>Test that masonry items with auto placement are correctly positioned when the grid-axis is the block axis. Ensure that margin affects placement.</p> <div class="masonry"> - <div class="first-track square-100x100"> + <div class="first-track square-100x100" style="margin-right: 40px;"> Number 1 </div> - <div class="second-track square-100x100"> + <div class="second-track square-100x100" style="margin-bottom: 10px;"> Number 2 </div> - <div class="third-track square-100x100"> + <div class="third-track square-100x100" style="margin-right: 40px;"> Number 3 </div> <div class="square-100x100" style="background-color: lightpink;"> Number 4 </div> - <div class="square-100x100" style="background-color: lightpink;"> + <div class="square-100x100" style="background-color: lightpink; margin-left: -20px;"> Number 5 </div> <div style="grid-row: span 2; background: brown; width: 100px;">
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-defined-height.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-defined-height.html index 9c2695c..6f62b0f 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-defined-height.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-defined-height.html
@@ -18,17 +18,17 @@ .first-track { background: lightskyblue; - grid-column-start: 1; + grid-row-start: 1; } .second-track { background: lightcoral; - grid-column-start: 2; + grid-row-start: 2; } .third-track { background: lightgreen; - grid-column-start: 3; + grid-row-start: 3; } .square-100x100 {
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002-ref.html index 5409699..3c1c3558 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002-ref.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002-ref.html
@@ -14,6 +14,7 @@ .first-track { background: lightskyblue; grid-row-start: 1; + margin: 20px; } .second-track { @@ -21,11 +22,13 @@ grid-row-start: 2; height: 80px; margin-top: 40px; + margin-bottom: 80px; } .third-track { background: lightgreen; grid-row-start: 3; + margin-left: 40px; } </style> <body>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002.html b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002.html index 91ae275..446161e 100644 --- a/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002.html +++ b/third_party/blink/web_tests/wpt_internal/css/css-masonry/row-explicit-placement-002.html
@@ -18,6 +18,7 @@ .first-track { background: lightskyblue; grid-row-start: 1; + margin: 20px; } .second-track { @@ -25,11 +26,13 @@ grid-row-start: 2; height: 80px; margin-top: 40px; + margin-bottom: 80px; } .third-track { background: lightgreen; grid-row-start: 3; + margin-left: 40px; } </style> <body>
diff --git a/third_party/compiler-rt/src b/third_party/compiler-rt/src index 0ceada7..3b1c4b0e 160000 --- a/third_party/compiler-rt/src +++ b/third_party/compiler-rt/src
@@ -1 +1 @@ -Subproject commit 0ceada7e63a869692256f956cc22869007469c55 +Subproject commit 3b1c4b0e4fee85b10a2272117315d520c607a328
diff --git a/third_party/crossbench b/third_party/crossbench index 1fcf64f..76223ae 160000 --- a/third_party/crossbench +++ b/third_party/crossbench
@@ -1 +1 @@ -Subproject commit 1fcf64fb04e2c8477aeda4ad6eaea8ac1ae9422d +Subproject commit 76223aed1ca101a8c6ceabf50b2d912424860f74
diff --git a/third_party/dawn b/third_party/dawn index 168d54a..6a294b9 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit 168d54a050758eb88e25757111b850bb1e97ed90 +Subproject commit 6a294b931ac942984bdeb350d608c93c0fef8cae
diff --git a/third_party/depot_tools b/third_party/depot_tools index 3f633ff..9a17210 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 3f633ff2f98baa7bd2563b710bc4168691eda7bb +Subproject commit 9a172103022289fcd1374c4d12d0192204343f59
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index 5d9af44..89f560f 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit 5d9af4427b5620b138701f9e9a12f70860cdae4d +Subproject commit 89f560fc68315d20519c66ed54d61a368308d034
diff --git a/third_party/fuchsia-sdk/README.chromium b/third_party/fuchsia-sdk/README.chromium index 148e507..8ea5c66 100644 --- a/third_party/fuchsia-sdk/README.chromium +++ b/third_party/fuchsia-sdk/README.chromium
@@ -2,6 +2,7 @@ URL: https://fuchsia.dev/fuchsia-src/development/sdk Version: N/A Revision: DEPS +Update Mechanism: Autoroll Security Critical: yes Shipped: yes License: BSD-2-Clause, Apache-2.0, MIT
diff --git a/third_party/icu4j/README.chromium b/third_party/icu4j/README.chromium index 0886bac..c71ef7f 100644 --- a/third_party/icu4j/README.chromium +++ b/third_party/icu4j/README.chromium
@@ -1,6 +1,7 @@ Name: International Components for Unicode for Java (ICU4J) URL: http://site.icu-project.org/ Version: 53.1 +Update Mechanism: Autoroll License: Unicode-DFS-2015, NAIST-2003, BSD-3-Clause, BSD-2-Clause, ICU License File: LICENSE Security Critical: no
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium index 8c9e1297f..a00221f 100644 --- a/third_party/inspector_protocol/README.chromium +++ b/third_party/inspector_protocol/README.chromium
@@ -3,6 +3,7 @@ URL: https://chromium.googlesource.com/deps/inspector_protocol/ Version: N/A Revision: 6d1ae0f13aae6ad381ca31b17b88a0f5af29ca94 +Update Mechanism: Autoroll License: BSD-3-Clause License File: LICENSE Security Critical: yes
diff --git a/third_party/jetstream/README.chromium b/third_party/jetstream/README.chromium index 6a358cd..a2a23bbd1 100644 --- a/third_party/jetstream/README.chromium +++ b/third_party/jetstream/README.chromium
@@ -3,6 +3,7 @@ URL: https://github.com/WebKit/JetStream Version: N/A Revision: DEPS +Update Mechanism: Autoroll License: BSD-2-Clause License File: LICENSE Shipped: no
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src index 66ae6e2..e09972e 160000 --- a/third_party/llvm-libc/src +++ b/third_party/llvm-libc/src
@@ -1 +1 @@ -Subproject commit 66ae6e2bd8e09c7a20b8b623b7a0249a5262f87c +Subproject commit e09972e0948f01cace57c08ba82b61fc171c739c
diff --git a/third_party/speedometer/README.chromium b/third_party/speedometer/README.chromium index 67ef5b8a..29adf79 100644 --- a/third_party/speedometer/README.chromium +++ b/third_party/speedometer/README.chromium
@@ -3,6 +3,7 @@ URL: https://github.com/WebKit/Speedometer Version: N/A Revision: DEPS +Update Mechanism: Autoroll License: BSD-2-Clause License File: LICENSE Shipped: no
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps index 4e2ba67..316ed08 160000 --- a/third_party/vulkan-deps +++ b/third_party/vulkan-deps
@@ -1 +1 @@ -Subproject commit 4e2ba677d4d655a0b0d69b596f1c076ee0d4b516 +Subproject commit 316ed08fbc9a673e93c8960324cad4801e24a5dd
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src index 7cee394..4b207ee 160000 --- a/third_party/vulkan-validation-layers/src +++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@ -Subproject commit 7cee394fda75d7b33d52b06b9e637abeb23c991c +Subproject commit 4b207eefa09f304a06c237fcf4913304e0b7d8d1
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src index 9773380..2a8d4a8 160000 --- a/third_party/webgpu-cts/src +++ b/third_party/webgpu-cts/src
@@ -1 +1 @@ -Subproject commit 97733807d3c40aeb165cf2fbe4137f23c92446ea +Subproject commit 2a8d4a83f751286302ce34573409ad75cc318508
diff --git a/third_party/wpt_tools/README.chromium b/third_party/wpt_tools/README.chromium index 9345d1d..8e70bab 100644 --- a/third_party/wpt_tools/README.chromium +++ b/third_party/wpt_tools/README.chromium
@@ -3,6 +3,7 @@ URL: https://github.com/web-platform-tests/wpt/ Version: N/A Revision: d74262218de2e9419380ea4750e93e8993da81db +Update Mechanism: Autoroll License: BSD-3-Clause Security Critical: no Shipped: no
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp index b0b4541..e4637e1 100644 --- a/tools/clang/spanify/Spanifier.cpp +++ b/tools/clang/spanify/Spanifier.cpp
@@ -84,6 +84,7 @@ kAdaptBinaryOperationPrecedence, kEmitSingleVariableSpanPrecedence, kAdaptBinaryPlusEqOperationPrecedence, + kRewriteUnaryOperationPrecedence, // Higher priority (stronger ties to the target) }; @@ -1505,6 +1506,97 @@ } // Rewrite: +// `ptr++` or `++ptr` +// Into: +// `base::PreIncrementSpan(span)` or `base::PostIncrementSpan(span)`. +void RewriteUnaryOperation(const MatchFinder::MatchResult& result) { + const clang::SourceManager& source_manager = *result.SourceManager; + const auto& lang_opts = result.Context->getLangOpts(); + + const clang::Expr* operand = nullptr; + bool is_prefix = false; + clang::SourceLocation operator_loc; + + if (const auto* unary_op = + result.Nodes.getNodeAs<clang::UnaryOperator>("unaryOperator")) { + operand = unary_op->getSubExpr(); + is_prefix = unary_op->isPrefix(); + operator_loc = unary_op->getOperatorLoc(); + } else if (const auto* cxx_op_call = + result.Nodes.getNodeAs<clang::CXXOperatorCallExpr>( + "raw_ptr_operator++")) { + operand = cxx_op_call->getArg(0); + const auto* method_decl = + clang::dyn_cast<clang::CXXMethodDecl>(cxx_op_call->getCalleeDecl()); + assert(method_decl); + // For CXXOperatorCallExpr, prefix increment has 0 parameters (e.g., + // operator++()) postfix increment has 1 parameter (e.g., operator++(int)). + is_prefix = (method_decl->getNumParams() == 0); + operator_loc = cxx_op_call->getOperatorLoc(); + } + + if (!operand) { + // This block should ideally not be reached if matchers are well-defined. + llvm::errs() + << "\n" + << "Error: RewriteUnaryOperation() encountered an unexpected match.\n" + << "Expected a unaryOperator or raw_ptr_operator++ to be bound.\n"; + DumpMatchResult(result); + assert(false && "Unexpected match in RewriteUnaryOperation()"); + return; + } + + assert(operator_loc.isValid()); + + // Get the source range of the operand (the 'ptr' part). + clang::SourceRange operand_range = + getExprRange(operand->IgnoreParenImpCasts(), source_manager, lang_opts); + assert(operand_range.isValid()); + + clang::SourceLocation operator_end_loc = clang::Lexer::getLocForEndOfToken( + operator_loc, 0, source_manager, lang_opts); + assert(operator_end_loc.isValid()); + clang::SourceRange op_token_range(operator_loc, operator_end_loc); + + std::string begin_insert_text; + clang::SourceRange begin_replacement_range; + clang::SourceRange end_replacement_range; + + if (is_prefix) { + begin_insert_text = "base::preIncrementSpan("; + // Replace the '++' with "base::preIncrementSpan(". + begin_replacement_range = op_token_range; + // Insert ")" at the end of the operand. + end_replacement_range = + clang::SourceRange(operand_range.getEnd(), operand_range.getEnd()); + } else { + begin_insert_text = "base::postIncrementSpan("; + // Insert "base::postIncrementSpan(" at the beginning of the operand. + begin_replacement_range = + clang::SourceRange(operand_range.getBegin(), operand_range.getBegin()); + // Replace "++"" with ")". + end_replacement_range = op_token_range; + } + + assert(begin_replacement_range.isValid()); + assert(end_replacement_range.isValid()); + + const std::string key = GetRHS(result); + + EmitReplacement(key, GetReplacementDirective( + begin_replacement_range, begin_insert_text, + source_manager, kRewriteUnaryOperationPrecedence)); + + EmitReplacement( + key, GetReplacementDirective(end_replacement_range, ")", source_manager, + -kRewriteUnaryOperationPrecedence)); + + EmitReplacement(key, + GetIncludeDirective(operand_range, source_manager, + kBaseAutoSpanificationHelperIncludePath)); +} + +// Rewrite: // `sizeof(c_array)` // Into: // `base::SpanificationSizeofForStdArray(std_array)` @@ -2976,6 +3068,19 @@ parmVarDecl()))))); Match(buffer_to_external_func, AppendDataCall); + // Handles unary arithmetic operations (pre/post increment) + auto unary_op = traverse( + clang::TK_IgnoreUnlessSpelledInSource, + expr(ignoringParenCasts(anyOf( + unaryOperator(hasOperatorName("++"), hasUnaryOperand(rhs_expr)) + .bind("unaryOperator"), + cxxOperatorCallExpr( + callee(cxxMethodDecl(ofClass(hasName("raw_ptr")))), + hasOperatorName("++"), hasArgument(0, rhs_expr)) + .bind("raw_ptr_operator++")))) + .bind("unary_op")); + Match(unary_op, RewriteUnaryOperation); + // Handles expressions of the form: // a + m, a + n + m, ... // which need to be rewritten to:
diff --git a/tools/clang/spanify/tests/assignment-expected.cc b/tools/clang/spanify/tests/assignment-expected.cc index 70013779..586e062 100644 --- a/tools/clang/spanify/tests/assignment-expected.cc +++ b/tools/clang/spanify/tests/assignment-expected.cc
@@ -5,6 +5,7 @@ #include <cstdint> #include <vector> +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_span.h" @@ -63,7 +64,9 @@ // ee = dd; ee = dd; - ee++; // Buffer usage, leads e to be rewritten. + // Expected rewrite: + // base::postIncrementSpan(ee); + base::postIncrementSpan(ee); // Buffer usage, leads e to be rewritten. // Expected rewrite: // base::span<int> ff = {}; @@ -71,7 +74,9 @@ ff = get<int>(); - ++ff; // Leads to ff being rewritten. + // Expected rewrite: + // base::preIncrementSpan(ff); + base::preIncrementSpan(ff); // Leads to ff being rewritten. // Exptected rewrite: // base::span<int> gg = {};
diff --git a/tools/clang/spanify/tests/assignment-original.cc b/tools/clang/spanify/tests/assignment-original.cc index 4d13411..4477cc4 100644 --- a/tools/clang/spanify/tests/assignment-original.cc +++ b/tools/clang/spanify/tests/assignment-original.cc
@@ -59,6 +59,8 @@ // ee = dd; ee = dd.get(); + // Expected rewrite: + // base::postIncrementSpan(ee); ee++; // Buffer usage, leads e to be rewritten. // Expected rewrite: @@ -67,6 +69,8 @@ ff = get<int>(); + // Expected rewrite: + // base::preIncrementSpan(ff); ++ff; // Leads to ff being rewritten. // Exptected rewrite:
diff --git a/tools/clang/spanify/tests/basics-expected.cc b/tools/clang/spanify/tests/basics-expected.cc index 1a70414..ff85fab 100644 --- a/tools/clang/spanify/tests/basics-expected.cc +++ b/tools/clang/spanify/tests/basics-expected.cc
@@ -8,6 +8,7 @@ #include <cstring> #include <vector> +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/numerics/safe_conversions.h" @@ -77,11 +78,11 @@ } int index = buf.size() - 1; // Expected rewrite: - // char* temp = expected_data++.data(); - char* temp = (expected_data++).data(); + // char* temp = (base::postIncrementSpan(expected_data)).data(); + char* temp = (base::postIncrementSpan(expected_data)).data(); // Expected rewrite: - // temp = (++expected_data).data(); - temp = (++expected_data).data(); + // temp = (base::preIncrementSpan(expected_data)).data(); + temp = (base::preIncrementSpan(expected_data)).data(); // Expected rewrite: // temp = expected_data.subspan(1u).data(); temp = expected_data.subspan(1u).data(); @@ -181,7 +182,9 @@ // base::span<int> buf = malloc(4*sizeof(int)); base::span<char> buf = (char*)malloc(4 * sizeof(int)); // Leads buf to be rewritten. - buf++; + // Expected rewrite: + // base::postIncrementSpan(buf); + base::postIncrementSpan(buf); const char* buf2 = nullptr; (void)buf2[0]; @@ -241,8 +244,10 @@ memcpy(buf2.data(), buf.data(), 10); // Expected rewrite: - // memcpy((buf2++).data(), (++buf).data(), 10) - memcpy((buf2++).data(), (++buf).data(), 10); + // memcpy((base::postIncrementSpan(buf2)).data(), + // (base::preIncrementSpan(buf)).data(), 10); + memcpy((base::postIncrementSpan(buf2)).data(), + (base::preIncrementSpan(buf)).data(), 10); int index = 11; // Expected rewrite: @@ -252,10 +257,10 @@ buf.subspan(base::checked_cast<size_t>(index)).data(), 10); // Expected rewrite: - // int i = (buf++)[0]; - int i = (buf++)[0]; - // i = (++buf)[0] - i = (++buf)[0]; + // int i = (base::postIncrementSpan(buf))[0]; + int i = (base::postIncrementSpan(buf))[0]; + // i = (base::preIncrementSpan(buf))[0]; + i = (base::preIncrementSpan(buf))[0]; // i = (buf.subspan(base::checked_cast<size_t>(index))[0]); i = (buf.subspan(base::checked_cast<size_t>(index))[0]); // i = buf[0];
diff --git a/tools/clang/spanify/tests/basics-original.cc b/tools/clang/spanify/tests/basics-original.cc index 19cd862..e6ec74e 100644 --- a/tools/clang/spanify/tests/basics-original.cc +++ b/tools/clang/spanify/tests/basics-original.cc
@@ -74,10 +74,10 @@ } int index = buf.size() - 1; // Expected rewrite: - // char* temp = expected_data++.data(); + // char* temp = (base::postIncrementSpan(expected_data)).data(); char* temp = expected_data++; // Expected rewrite: - // temp = (++expected_data).data(); + // temp = (base::preIncrementSpan(expected_data)).data(); temp = ++expected_data; // Expected rewrite: // temp = expected_data.subspan(1u).data(); @@ -170,6 +170,8 @@ // base::span<int> buf = malloc(4*sizeof(int)); char* buf = (char*)malloc(4 * sizeof(int)); // Leads buf to be rewritten. + // Expected rewrite: + // base::postIncrementSpan(buf); buf++; const char* buf2 = nullptr; @@ -230,7 +232,8 @@ memcpy(buf2, buf, 10); // Expected rewrite: - // memcpy((buf2++).data(), (++buf).data(), 10) + // memcpy((base::postIncrementSpan(buf2)).data(), + // (base::preIncrementSpan(buf)).data(), 10); memcpy(buf2++, ++buf, 10); int index = 11; @@ -240,9 +243,9 @@ memcpy(buf2 + 1, buf + index, 10); // Expected rewrite: - // int i = (buf++)[0]; + // int i = (base::postIncrementSpan(buf))[0]; int i = *buf++; - // i = (++buf)[0] + // i = (base::preIncrementSpan(buf))[0]; i = *++buf; // i = (buf.subspan(base::checked_cast<size_t>(index))[0]); i = *(buf + index);
diff --git a/tools/clang/spanify/tests/initializers-expected.cc b/tools/clang/spanify/tests/initializers-expected.cc index dd684306..6c1d30b0 100644 --- a/tools/clang/spanify/tests/initializers-expected.cc +++ b/tools/clang/spanify/tests/initializers-expected.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <vector> +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_span.h" @@ -14,8 +15,8 @@ A(base::span<int> ptr) : member(ptr) {} // Expecte rewrite: - // int* advanceAndGet() { return member++.data(); } - int* advanceAndGet() { return member++.data(); } + // int* advanceAndGet() { return base::postIncrementSpan(member).data(); } + int* advanceAndGet() { return base::postIncrementSpan(member).data(); } // Expected rewrite: // int* get() { return member.data(); }
diff --git a/tools/clang/spanify/tests/initializers-original.cc b/tools/clang/spanify/tests/initializers-original.cc index 34cb5ab..7c33487 100644 --- a/tools/clang/spanify/tests/initializers-original.cc +++ b/tools/clang/spanify/tests/initializers-original.cc
@@ -12,7 +12,7 @@ A(int* ptr) : member(ptr) {} // Expecte rewrite: - // int* advanceAndGet() { return member++.data(); } + // int* advanceAndGet() { return base::postIncrementSpan(member).data(); } int* advanceAndGet() { return member++; } // Expected rewrite:
diff --git a/tools/clang/spanify/tests/raw-ptr-fields-expected.cc b/tools/clang/spanify/tests/raw-ptr-fields-expected.cc index d5c99148..973d33f 100644 --- a/tools/clang/spanify/tests/raw-ptr-fields-expected.cc +++ b/tools/clang/spanify/tests/raw-ptr-fields-expected.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_span.h" @@ -84,8 +85,8 @@ int* get_and_advance() { // Expected rewrite: - // return ptr_++.data(); - return ptr_++.data(); + // return base::postIncrementSpan(ptr_).data(); + return base::postIncrementSpan(ptr_).data(); } // Expected rewrite:
diff --git a/tools/clang/spanify/tests/raw-ptr-fields-original.cc b/tools/clang/spanify/tests/raw-ptr-fields-original.cc index 256653b..552c3a5 100644 --- a/tools/clang/spanify/tests/raw-ptr-fields-original.cc +++ b/tools/clang/spanify/tests/raw-ptr-fields-original.cc
@@ -79,7 +79,7 @@ int* get_and_advance() { // Expected rewrite: - // return ptr_++.data(); + // return base::postIncrementSpan(ptr_).data(); return ptr_++; }
diff --git a/tools/clang/spanify/tests/return-stmts-expected.cc b/tools/clang/spanify/tests/return-stmts-expected.cc index 6df5b56..041fed7 100644 --- a/tools/clang/spanify/tests/return-stmts-expected.cc +++ b/tools/clang/spanify/tests/return-stmts-expected.cc
@@ -4,6 +4,7 @@ #include <cstdint> #include <vector> +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/numerics/safe_conversions.h" @@ -36,7 +37,8 @@ // Expected rewrite: // base::span<int> var1 = new int[1024]; base::span<int> var1 = new int[1024]; - return var1++; + // return base::postIncrementSpan(var1); + return base::postIncrementSpan(var1); } // Expected rewrite: @@ -46,7 +48,8 @@ // Expected rewrite: // base::span<int> var1 = new int[1024]; base::span<int> var1 = new int[1024]; - return ++var1; + // return base::preIncrementSpan(var1); + return base::preIncrementSpan(var1); } // Expected rewrite: @@ -110,30 +113,36 @@ // Expected rewrite: // base::span<int> v1 = fct1(); base::span<int> v1 = fct1(); - v1++; + // base::postIncrementSpan(v1); + base::postIncrementSpan(v1); // Expected rewrite: // base::span<int> v2 = fct2(); base::span<int> v2 = fct2(); - v2++; + // base::postIncrementSpan(v2); + base::postIncrementSpan(v2); // Expected rewrite: // base::span<int> v3 = fct3(); base::span<int> v3 = fct3(); - v3++; + // base::postIncrementSpan(v3); + base::postIncrementSpan(v3); // Expected rewrite: // base::span<int> v4 = fct4(); base::span<int> v4 = fct4(); - v4++; + // base::postIncrementSpan(v4); + base::postIncrementSpan(v4); // Expected rewrite: // base::span<int> v5 = fct5(); base::span<int> v5 = fct5(); - v5++; + // base::postIncrementSpan(v5); + base::postIncrementSpan(v5); // Expected rewrite: // base::span<char> v6 = fct6(); base::span<char> v6 = fct6(); - v6++; + // base::postIncrementSpan(v6); + base::postIncrementSpan(v6); }
diff --git a/tools/clang/spanify/tests/return-stmts-original.cc b/tools/clang/spanify/tests/return-stmts-original.cc index 123d6f0..99c01594 100644 --- a/tools/clang/spanify/tests/return-stmts-original.cc +++ b/tools/clang/spanify/tests/return-stmts-original.cc
@@ -32,6 +32,7 @@ // Expected rewrite: // base::span<int> var1 = new int[1024]; int* var1 = new int[1024]; + // return base::postIncrementSpan(var1); return var1++; } @@ -42,6 +43,7 @@ // Expected rewrite: // base::span<int> var1 = new int[1024]; int* var1 = new int[1024]; + // return base::preIncrementSpan(var1); return ++var1; } @@ -103,30 +105,36 @@ // Expected rewrite: // base::span<int> v1 = fct1(); int* v1 = fct1(); + // base::postIncrementSpan(v1); v1++; // Expected rewrite: // base::span<int> v2 = fct2(); int* v2 = fct2(); + // base::postIncrementSpan(v2); v2++; // Expected rewrite: // base::span<int> v3 = fct3(); int* v3 = fct3(); + // base::postIncrementSpan(v3); v3++; // Expected rewrite: // base::span<int> v4 = fct4(); int* v4 = fct4(); + // base::postIncrementSpan(v4); v4++; // Expected rewrite: // base::span<int> v5 = fct5(); int* v5 = fct5(); + // base::postIncrementSpan(v5); v5++; // Expected rewrite: // base::span<char> v6 = fct6(); char* v6 = fct6(); + // base::postIncrementSpan(v6); v6++; }
diff --git a/tools/clang/spanify/tests/var-construction-expected.cc b/tools/clang/spanify/tests/var-construction-expected.cc index 6e54c49..601479a 100644 --- a/tools/clang/spanify/tests/var-construction-expected.cc +++ b/tools/clang/spanify/tests/var-construction-expected.cc
@@ -5,6 +5,7 @@ #include <cstdint> #include <vector> +#include "base/containers/auto_spanification_helper.h" #include "base/containers/span.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_span.h" @@ -51,13 +52,17 @@ // base::span<int> e = d; base::span<int> e = d; - e++; // Buffer usage, leads e to be rewritten. + // Expected rewrite: + // base::postIncrementSpan(e); + base::postIncrementSpan(e); // Buffer usage, leads e to be rewritten. // Expected rewrite: // base::span<int> f = get<int>(); base::span<int> f = get<int>(); - ++f; // Leads to f being rewritten. + // Expected rewrite: + // base::preIncrementSpan(f); + base::preIncrementSpan(f); // Leads to f being rewritten. // Exptected rewrite: // base::span<int> g = (condition) ? ctn1 : ctn2; @@ -112,6 +117,7 @@ // Expected rewrite: // base::span<char> buf2 = new char[5]; + // buf2 = buf2.subspan(1); base::span<char> buf2 = new char[5]; // Expected rewrite: // buf2 = buf2.subspan(1u); @@ -119,6 +125,7 @@ // Expected rewrite: // base::raw_span<char> buf3 = buf2; + // buf3 = buf3.subspan(1); base::raw_span<char> buf3 = buf2; // Expected rewrite: // buf3 = buf3.subspan(1u); @@ -126,11 +133,13 @@ // Expected rewrite: // base::raw_span<char> buf4 = buf3; + // base::postIncrementSpan(buf4); base::base::raw_span<char> buf4 = buf3; - buf4++; + base::postIncrementSpan(buf4); // Expected rewrite: // base::raw_span<char> buf5 = buf4; + // buf5 = buf5.subspan(1); base::raw_span<char> buf5 = buf4; // Expected rewrite: // buf5 = buf5.subspan(1u); @@ -138,8 +147,9 @@ // Expected rewrite: // base::raw_span<char> buf6 = buf5; + // base::preIncrementSpan(buf6); base::raw_span<char> buf6 = buf5; - ++buf6; + base::preIncrementSpan(buf6); // Expected rewrite: // buf6[0] = 'c';
diff --git a/tools/clang/spanify/tests/var-construction-original.cc b/tools/clang/spanify/tests/var-construction-original.cc index 7502e8dc..16873af 100644 --- a/tools/clang/spanify/tests/var-construction-original.cc +++ b/tools/clang/spanify/tests/var-construction-original.cc
@@ -47,12 +47,16 @@ // base::span<int> e = d; int* e = d.get(); + // Expected rewrite: + // base::postIncrementSpan(e); e++; // Buffer usage, leads e to be rewritten. // Expected rewrite: // base::span<int> f = get<int>(); int* f = get<int>(); + // Expected rewrite: + // base::preIncrementSpan(f); ++f; // Leads to f being rewritten. // Exptected rewrite: @@ -108,6 +112,7 @@ // Expected rewrite: // base::span<char> buf2 = new char[5]; + // buf2 = buf2.subspan(1); char* buf2 = new char[5]; // Expected rewrite: // buf2 = buf2.subspan(1u); @@ -115,6 +120,7 @@ // Expected rewrite: // base::raw_span<char> buf3 = buf2; + // buf3 = buf3.subspan(1); raw_ptr<char> buf3 = buf2; // Expected rewrite: // buf3 = buf3.subspan(1u); @@ -122,11 +128,13 @@ // Expected rewrite: // base::raw_span<char> buf4 = buf3; + // base::postIncrementSpan(buf4); base::raw_ptr<char> buf4 = buf3; buf4++; // Expected rewrite: // base::raw_span<char> buf5 = buf4; + // buf5 = buf5.subspan(1); raw_ptr<char> buf5 = buf4; // Expected rewrite: // buf5 = buf5.subspan(1u); @@ -134,6 +142,7 @@ // Expected rewrite: // base::raw_span<char> buf6 = buf5; + // base::preIncrementSpan(buf6); raw_ptr<char> buf6 = buf5; ++buf6;
diff --git a/tools/metrics/histograms/metadata/android/enums.xml b/tools/metrics/histograms/metadata/android/enums.xml index 4a2bd76..0280a4c 100644 --- a/tools/metrics/histograms/metadata/android/enums.xml +++ b/tools/metrics/histograms/metadata/android/enums.xml
@@ -799,7 +799,7 @@ <int value="4" label="Hardware unavailable"/> <int value="5" label="Not enrolled"/> <int value="6" label="Security update required"/> - <int value="7" label="Android version not supported"/> + <int value="7" label="(obsolete) Android version not supported"/> <int value="8" label="Biometric auth is mandatory"/> <int value="9" label="Biometric auth is mandatory, but has an error"/> </enum>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index b7e5a099..f0578c8 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1238,6 +1238,21 @@ </summary> </histogram> +<histogram name="Android.ChildProcessConnection.OnServiceConnectedCounts" + units="count" expires_after="M143"> + <owner>boliu@chromium.org</owner> + <owner>kawasin@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Record the accumulated count of + ChildServiceConnectionDelegate.onServiceConnected. This is recorded every + time the callback is triggered. The metric with number more than 1 indicates + that the child process is restarted after the service process connected. + Note that the lower buckets double-counts the higher buckets since this is + recorded at each restart (e.g. when 4 is recorded, 1,2,3 are also recorded). + </summary> +</histogram> + <histogram name="Android.ChildProcessStartTimeV2.{Type}" units="ms" expires_after="2023-02-22"> <owner>cduvall@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/enums.xml b/tools/metrics/histograms/metadata/autofill/enums.xml index 0d1e312..d98f6d14 100644 --- a/tools/metrics/histograms/metadata/autofill/enums.xml +++ b/tools/metrics/histograms/metadata/autofill/enums.xml
@@ -34,7 +34,7 @@ </summary> <int value="0" label="Available and turned on in Chrome settings"/> <int value="1" label="Not allowed by policy"/> - <int value="2" label="Android OS version is too old"/> + <int value="2" label="(obsolete) Android OS version is too old"/> <int value="3" label="The system's AutofillManager is not available"/> <int value="4" label="The system does not support autofill"/> <int value="5" label="The system's AutofillService cannot be determined."/>
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn index a5bb190f..7136fb22 100644 --- a/tools/perf/BUILD.gn +++ b/tools/perf/BUILD.gn
@@ -22,11 +22,15 @@ } } } else { + import("//build/config/android/config.gni") template("perf_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) { testonly = true data = COMMON_PERF_DATA + if (enable_chrome_android_internal) { + data += [ "//clank/android_webview/tools/crossbench_config/" ] + } data_deps = [ ":perf_without_chrome", "//chrome/test/chromedriver:chromedriver_server($host_toolchain)",
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index a63fea66..1cb8ea9 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -786,8 +786,8 @@ weak_ptr_factory_.GetWeakPtr()); } -double Compositor::GetPercentDroppedFrames() const { - return host_->GetPercentDroppedFrames(); +double Compositor::GetAverageThroughput() const { + return host_->GetAverageThroughput(); } std::unique_ptr<cc::EventsMetricsManager::ScopedMonitor>
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 0470e28..f1a4674 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -386,8 +386,8 @@ // Creates a CompositorMetricsTracker for tracking this Compositor. CompositorMetricsTracker RequestNewCompositorMetricsTracker(); - // Returns a percentage of dropped frames of the last second. - double GetPercentDroppedFrames() const; + // Returns average throughput as measured by the FrameSorter. + double GetAverageThroughput() const; // Activates a scoped monitor for the current event to track its metrics. // `done_callback` is called when the monitor goes out of scope.
diff --git a/ui/linux/linux_ui_factory.cc b/ui/linux/linux_ui_factory.cc index f31b4ab..f7c49e9 100644 --- a/ui/linux/linux_ui_factory.cc +++ b/ui/linux/linux_ui_factory.cc
@@ -190,6 +190,7 @@ case base::nix::DESKTOP_ENVIRONMENT_PANTHEON: case base::nix::DESKTOP_ENVIRONMENT_UNITY: case base::nix::DESKTOP_ENVIRONMENT_XFCE: + case base::nix::DESKTOP_ENVIRONMENT_COSMIC: return SystemTheme::kGtk; case base::nix::DESKTOP_ENVIRONMENT_KDE3: case base::nix::DESKTOP_ENVIRONMENT_KDE4: